diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index e27bd9cd0a..b3fb0bdf0d 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -4659,6 +4659,10 @@ }, "input_reference": { "add": { + "error": { + "format": "Not a image", + "size": "This image is too large. It should be under 5MB." + }, "tooltip": "Add image reference" } }, diff --git a/src/renderer/src/pages/video/VideoPage.tsx b/src/renderer/src/pages/video/VideoPage.tsx index 646fd02241..7ec571d3ae 100644 --- a/src/renderer/src/pages/video/VideoPage.tsx +++ b/src/renderer/src/pages/video/VideoPage.tsx @@ -5,9 +5,9 @@ import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' import { useProvider } from '@renderer/hooks/useProvider' import { SystemProviderIds } from '@renderer/types' import { CreateVideoParams } from '@renderer/types/video' +import { deepUpdate } from '@renderer/utils/deepUpdate' import { isVideoModel } from '@renderer/utils/model/video' import { DeepPartial } from 'ai' -import { merge } from 'lodash' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -33,7 +33,7 @@ export const VideoPage = () => { }) const updateParams = useCallback((update: DeepPartial>) => { - setParams((prev) => merge({}, prev, update)) + setParams((prev) => deepUpdate(prev, update)) }, []) const updateModelId = useCallback( diff --git a/src/renderer/src/pages/video/VideoPanel.tsx b/src/renderer/src/pages/video/VideoPanel.tsx index 7fab56af7d..18b5f21c96 100644 --- a/src/renderer/src/pages/video/VideoPanel.tsx +++ b/src/renderer/src/pages/video/VideoPanel.tsx @@ -1,13 +1,15 @@ -import { Button, Skeleton, Textarea, Tooltip } from '@heroui/react' +import { Button, cn, Image, Skeleton, Textarea, Tooltip } from '@heroui/react' import { loggerService } from '@logger' import { useAddOpenAIVideo } from '@renderer/hooks/video/useAddOpenAIVideo' import { createVideo } from '@renderer/services/ApiService' import { Provider } from '@renderer/types' import { CreateVideoParams, Video } from '@renderer/types/video' import { getErrorMessage } from '@renderer/utils' +import { MB } from '@shared/config/constant' import { DeepPartial } from 'ai' -import { ArrowUp, ImageIcon } from 'lucide-react' -import { useCallback, useState } from 'react' +import { isEmpty } from 'lodash' +import { ArrowUp, CircleXIcon, ImageIcon } from 'lucide-react' +import { useCallback, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { VideoViewer } from './VideoViewer' @@ -23,11 +25,18 @@ const logger = loggerService.withContext('VideoPanel') export const VideoPanel = ({ provider, video, params, updateParams }: VideoPanelProps) => { const { t } = useTranslation() - const [isProcessing, setIsProcessing] = useState(false) const addOpenAIVideo = useAddOpenAIVideo(provider.id) + const [isProcessing, setIsProcessing] = useState(false) + const fileInputRef = useRef(null) + const inputReference = params.params.input_reference + + const couldCreateVideo = useMemo( + () => !isProcessing && !isEmpty(params.params.prompt), + [isProcessing, params.params.prompt] + ) const handleCreateVideo = useCallback(async () => { - if (isProcessing) return + if (!couldCreateVideo) return setIsProcessing(true) try { const result = await createVideo(params) @@ -44,10 +53,49 @@ export const VideoPanel = ({ provider, video, params, updateParams }: VideoPanel } finally { setIsProcessing(false) } - }, [addOpenAIVideo, isProcessing, params, t]) + }, [addOpenAIVideo, couldCreateVideo, params, t]) + + const handleUploadFile = useCallback(() => { + fileInputRef.current?.click() + }, []) const setPrompt = useCallback((value: string) => updateParams({ params: { prompt: value } }), [updateParams]) + const UploadImageReferenceButton = useCallback(() => { + const content = inputReference ? ( +
+ +
+ ) : ( + t('video.input_reference.add.tooltip') + ) + return ( + <> + +