+ {typeof predictedPrice === 'string' && (
+
+
+ {predictedPrice}
+
+ )}
{typeVersions['image'] &&
(typeVersions['image'].length === 0 ||
typeVersions['image'].includes(currentVersion)) && (
@@ -0,0 +1 @@
+export { usePredictPrice } from './use-predict-price'
@@ -0,0 +1,68 @@
+import { useEffect, useRef, useState } from 'react'
+import { debounce } from 'lodash'
+
+import { predictPrice } from '#/shared/api/models/predict-price'
+
+interface UsePredictPriceParams {
+ modelSlug: string
+ content: string
+ fileExists: boolean
+ info: Record
+ token?: string
+ enabled?: boolean
+}
+
+export function usePredictPrice({
+ modelSlug,
+ content,
+ fileExists,
+ info,
+ token,
+ enabled = true,
+}: UsePredictPriceParams) {
+ const [price, setPrice] = useState(null)
+
+ const debouncedPredictRef = useRef(
+ debounce(
+ async (
+ slug: string,
+ text: string,
+ hasFile: boolean,
+ params: Record,
+ accessToken?: string
+ ) => {
+ try {
+ const result = await predictPrice(
+ {
+ model_slug: slug,
+ content: text,
+ file_exists: hasFile,
+ info: params,
+ },
+ accessToken
+ )
+ setPrice(typeof result.price === 'string' ? result.price : null)
+ } catch {
+ setPrice(null)
+ }
+ },
+ 500
+ )
+ )
+
+ useEffect(() => {
+ if (!enabled || !modelSlug || !token) {
+ setPrice(null)
+ return
+ }
+
+ const debouncedPredict = debouncedPredictRef.current
+ debouncedPredict(modelSlug, content, fileExists, info, token)
+
+ return () => {
+ debouncedPredict.cancel()
+ }
+ }, [modelSlug, content, fileExists, info, token, enabled])
+
+ return price
+}
@@ -0,0 +1,31 @@
+import axios from 'axios'
+
+import { API_URL } from '#/shared/lib/constants'
+
+export interface PredictPriceRequest {
+ model_slug: string
+ content: string
+ file_exists: boolean
+ info: Record
+}
+
+export interface PredictPriceResponse {
+ price: string | null
+}
+
+export async function predictPrice(
+ data: PredictPriceRequest,
+ token?: string
+): Promise {
+ const { data: result } = await axios.post(
+ API_URL + '/ml_model/predict-price/',
+ data,
+ {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ 'Content-Type': 'application/json',
+ },
+ }
+ )
+ return result as PredictPriceResponse
+}
@@ -16,6 +16,7 @@ import { useImagesBotFilters } from '#/features/image-bot-filters'
import { useImagesUniqInput } from '#/features/image-bot-input'
import { useMediaBotPagination } from '#/features/image-bot-pagination'
import { ModelInput } from '#/features/model-input'
+import { usePredictPrice } from '#/features/predict-price/model/use-predict-price'
import Title from '#/features/title/title'
import { NextPageWithLayout } from '#/pages/_app'
import { DrawerCustom, Loader } from '#/shared'
@@ -123,6 +124,20 @@ const AudioModelPage: NextPageWithLayout = () => {
})
}, [botParams?.inputs, version])
+ const predictPriceInfo = useMemo(
+ () => ({ ...(includeParams || {}), ...(version ? { version } : {}) }),
+ [includeParams, version]
+ )
+
+ const predictedPrice = usePredictPrice({
+ modelSlug: modelType,
+ content: prompt,
+ fileExists: !!image,
+ info: predictPriceInfo,
+ token: session?.access,
+ enabled: !!modelType && !!session?.access && scope === 'playground',
+ })
+
return (
<>
@@ -200,6 +215,7 @@ const AudioModelPage: NextPageWithLayout = () => {
sendMessage={onCreateImage}
unpinImage={() => setImage(null)}
viewMobileSettings={() => setOpenFiltersMobile(true)}
+ predictedPrice={predictedPrice}
/>
)}
@@ -303,6 +319,7 @@ const AudioModelPage: NextPageWithLayout = () => {
sendMessage={onCreateImage}
unpinImage={() => setImage(null)}
viewMobileSettings={() => setOpenFiltersMobile(true)}
+ predictedPrice={predictedPrice}
/>
)}
{isProgressVisible && (
@@ -17,6 +17,7 @@ import { TutorialContext } from '#/features/tutorial-context/tutorial-context'
import { NextPageWithLayout } from '#/pages/_app'
import { DrawerCustom, useModel } from '#/shared'
import model_api from '#/shared/api/models/api'
+import { usePredictPrice } from '#/features/predict-price/model/use-predict-price'
import { getDeviceType, getOs } from '#/shared/lib/helpers'
import { useShowDataStore } from '#/shared/lib/hooks/use-show-data'
import { SvgIcon } from '#/shared/ui/svg'
@@ -37,6 +38,7 @@ const Page: NextPageWithLayout = () => {
const [params, setParams] = React.useState(false)
const [file, setFile] = React.useState(null)
+ const [inputContent, setInputContent] = React.useState('')
const { showMessage } = useShowDataStore()
const [scope, setScope] = React.useState<'playground' | 'api'>('playground')
@@ -199,6 +201,20 @@ const Page: NextPageWithLayout = () => {
})
}, [botParams?.inputs, version])
+ const predictPriceInfo = useMemo(
+ () => ({ ...(includeParams || {}), ...(version ? { version } : {}) }),
+ [includeParams, version]
+ )
+
+ const predictedPrice = usePredictPrice({
+ modelSlug: modelType,
+ content: inputContent,
+ fileExists: !!file,
+ info: predictPriceInfo,
+ token: data?.access,
+ enabled: !!modelType && !!data?.access && scope === 'playground',
+ })
+
return (
<>
@@ -259,6 +275,9 @@ const Page: NextPageWithLayout = () => {
modelTitle={botParams?.title}
currentVersion={version}
tags={botParams?.tags ?? []}
+ inputValue={inputContent}
+ onInputValueChange={setInputContent}
+ predictedPrice={predictedPrice}
/>
@@ -14,6 +14,7 @@ import { useImagesBotFilters } from '#/features/image-bot-filters'
import { useImagesUniqInput } from '#/features/image-bot-input'
import { useMediaBotPagination } from '#/features/image-bot-pagination'
import { ModelInput } from '#/features/model-input'
+import { usePredictPrice } from '#/features/predict-price/model/use-predict-price'
import Title from '#/features/title/title'
import { NextPageWithLayout } from '#/pages/_app'
import { DrawerCustom, Loader } from '#/shared'
@@ -33,6 +34,7 @@ const ImageModelPage: NextPageWithLayout = () => {
const { data: session } = useSession()
const [scope, setScope] = useState<'playground' | 'api'>('playground')
+ const [prompt, setPrompt] = useState('')
const { botParams, version, modelType, fetchBotParams, resetParams, setDefaultParams, setVersion } = useImageBot(query.slug as string)
const { desktop } = useDeviceType(deviceType, deviceOs)
@@ -113,6 +115,20 @@ const ImageModelPage: NextPageWithLayout = () => {
})
}, [botParams?.inputs, version])
+ const predictPriceInfo = useMemo(
+ () => ({ ...(includeParams || {}), ...(version ? { version } : {}) }),
+ [includeParams, version]
+ )
+
+ const predictedPrice = usePredictPrice({
+ modelSlug: modelType,
+ content: prompt,
+ fileExists: !!image,
+ info: predictPriceInfo,
+ token: session?.access,
+ enabled: !!modelType && !!session?.access && scope === 'playground',
+ })
+
return (
<>
@@ -180,6 +196,8 @@ const ImageModelPage: NextPageWithLayout = () => {
styles={'images'}
input_types={botParams.inputs}
image={image}
+ value={prompt}
+ onValueChange={(value: string) => setPrompt(value)}
desktop={desktop}
blocked={scope === 'playground' ? botParams.blocked : true}
loading={createLoading}
@@ -187,6 +205,7 @@ const ImageModelPage: NextPageWithLayout = () => {
sendMessage={onCreateImage}
unpinImage={() => setImage(null)}
viewMobileSettings={() => setOpenFiltersMobile(true)}
+ predictedPrice={predictedPrice}
/>
)}
{botParams?.blocked && (
@@ -279,6 +298,8 @@ const ImageModelPage: NextPageWithLayout = () => {
styles={'images'}
input_types={botParams.inputs}
image={image}
+ value={prompt}
+ onValueChange={(value: string) => setPrompt(value)}
blocked={scope === 'playground' ? botParams.blocked : true}
desktop={desktop}
loading={createLoading}
@@ -286,6 +307,7 @@ const ImageModelPage: NextPageWithLayout = () => {
sendMessage={onCreateImage}
unpinImage={() => setImage(null)}
viewMobileSettings={() => setOpenFiltersMobile(true)}
+ predictedPrice={predictedPrice}
/>
)}
{botParams?.blocked && (
@@ -16,6 +16,7 @@ import { useImagesBotFilters } from '#/features/image-bot-filters'
import { useImagesUniqInput } from '#/features/image-bot-input'
import { useMediaBotPagination } from '#/features/image-bot-pagination'
import { ModelInput } from '#/features/model-input'
+import { usePredictPrice } from '#/features/predict-price/model/use-predict-price'
import Title from '#/features/title/title'
import { NextPageWithLayout } from '#/pages/_app'
import { DrawerCustom, Error, Loader } from '#/shared'
@@ -121,6 +122,20 @@ const VideoModelPage: NextPageWithLayout = () => {
})
}, [botParams?.inputs, version])
+ const predictPriceInfo = useMemo(
+ () => ({ ...(includeParams || {}), ...(version ? { version } : {}) }),
+ [includeParams, version]
+ )
+
+ const predictedPrice = usePredictPrice({
+ modelSlug: modelType,
+ content: prompt,
+ fileExists: !!image,
+ info: predictPriceInfo,
+ token: session?.access,
+ enabled: !!modelType && !!session?.access && scope === 'playground',
+ })
+
return (
<>
@@ -198,6 +213,7 @@ const VideoModelPage: NextPageWithLayout = () => {
sendMessage={onCreateImage}
unpinImage={() => setImage(null)}
viewMobileSettings={() => setOpenFiltersMobile(true)}
+ predictedPrice={predictedPrice}
/>
)}
@@ -299,6 +315,7 @@ const VideoModelPage: NextPageWithLayout = () => {
sendMessage={onCreateImage}
unpinImage={() => setImage(null)}
viewMobileSettings={() => setOpenFiltersMobile(true)}
+ predictedPrice={predictedPrice}
/>
)}
{isProgressVisible && (
@@ -43,6 +43,9 @@ export interface ChatProps {
currentVersion: string
botParams: IModel | null
tags: IModelTag[]
+ inputValue?: string
+ onInputValueChange?: (value: string) => void
+ predictedPrice?: string | null
}
function Chat({
@@ -63,6 +66,9 @@ function Chat({
currentVersion,
deviceOs,
tags,
+ inputValue,
+ onInputValueChange,
+ predictedPrice,
}: ChatProps) {
const desktop = device === 'desktop'
@@ -139,6 +145,9 @@ function Chat({
image={file}
unpinImage={clearImage}
imageLoad={onLoadImage}
+ value={inputValue}
+ onValueChange={onInputValueChange}
+ predictedPrice={predictedPrice}
/>
{blocked && (