From 942c239d14fdda60d282237a1a94de0170c8c217 Mon Sep 17 00:00:00 2001 From: icarus Date: Sun, 12 Oct 2025 07:56:45 +0800 Subject: [PATCH] feat(video): add mock data and improve video panel handling - Add mock video data for testing purposes - Improve video panel state management with useEffect - Export video types from index file --- src/renderer/src/config/models/video.ts | 133 +++++++++++++++++- src/renderer/src/pages/video/VideoList.tsx | 134 +------------------ src/renderer/src/pages/video/VideoPage.tsx | 8 +- src/renderer/src/pages/video/VideoPanel.tsx | 9 +- src/renderer/src/pages/video/VideoViewer.tsx | 5 +- src/renderer/src/types/index.ts | 1 + 6 files changed, 152 insertions(+), 138 deletions(-) diff --git a/src/renderer/src/config/models/video.ts b/src/renderer/src/config/models/video.ts index cfbf3d628f..4779516f8a 100644 --- a/src/renderer/src/config/models/video.ts +++ b/src/renderer/src/config/models/video.ts @@ -1,6 +1,137 @@ -import { SystemProviderId } from '@renderer/types' +import { SystemProviderId, Video } from '@renderer/types' // Hard-encoded for now. We may implement a function to filter video generation model from provider.models. export const videoModelsMap = { openai: ['sora-2', 'sora-2-pro'] as const } as const satisfies Partial> + +// Mock data for testing +export const mockVideos: Video[] = [ + { + id: '1', + type: 'openai', + status: 'downloaded', + prompt: 'A beautiful sunset over the ocean with waves crashing', + thumbnail: 'https://picsum.photos/200/200?random=1', + fileId: 'file-001', + metadata: { + id: 'video-001', + object: 'video', + created_at: Math.floor(Date.now() / 1000), + completed_at: Math.floor(Date.now() / 1000), + expires_at: null, + error: null, + model: 'sora-2', + progress: 100, + remixed_from_video_id: null, + seconds: '4', + size: '1280x720', + status: 'completed' + } + }, + { + id: '2', + type: 'openai', + status: 'in_progress', + prompt: 'A cat playing with a ball of yarn in slow motion', + progress: 65, + metadata: { + id: 'video-002', + object: 'video', + created_at: Math.floor(Date.now() / 1000), + completed_at: null, + expires_at: null, + error: null, + model: 'sora-2-pro', + progress: 65, + remixed_from_video_id: null, + seconds: '8', + size: '1792x1024', + status: 'in_progress' + } + }, + { + id: '3', + type: 'openai', + status: 'queued', + prompt: 'Time-lapse of flowers blooming in a garden', + metadata: { + id: 'video-003', + object: 'video', + created_at: Math.floor(Date.now() / 1000), + completed_at: null, + expires_at: null, + error: null, + model: 'sora-2', + progress: 0, + remixed_from_video_id: null, + seconds: '12', + size: '1280x720', + status: 'queued' + } + }, + { + id: '4', + type: 'openai', + prompt: 'Birds flying in formation against blue sky', + status: 'downloading', + progress: 80, + thumbnail: 'https://picsum.photos/200/200?random=4', + metadata: { + id: 'video-004', + object: 'video', + created_at: Math.floor(Date.now() / 1000), + completed_at: Math.floor(Date.now() / 1000), + expires_at: null, + error: null, + model: 'sora-2-pro', + progress: 100, + remixed_from_video_id: null, + seconds: '8', + size: '1792x1024', + status: 'completed' + } + }, + { + id: '5', + type: 'openai', + status: 'failed', + error: { code: '400', message: 'Video generation failed' }, + prompt: 'Mountain landscape with snow peaks and forest', + metadata: { + id: 'video-005', + object: 'video', + created_at: Math.floor(Date.now() / 1000), + completed_at: Math.floor(Date.now() / 1000), + expires_at: null, + error: { code: '400', message: 'Video generation failed' }, + model: 'sora-2', + progress: 0, + remixed_from_video_id: null, + seconds: '4', + size: '1280x720', + status: 'failed' + } + }, + { + id: '6', + type: 'openai', + status: 'completed', + thumbnail: 'https://picsum.photos/200/200?random=6', + prompt: 'City street at night with neon lights reflecting on wet pavement', + metadata: { + id: 'video-006', + object: 'video', + created_at: Math.floor(Date.now() / 1000), + completed_at: Math.floor(Date.now() / 1000), + expires_at: null, + error: null, + model: 'sora-2-pro', + progress: 100, + remixed_from_video_id: null, + seconds: '12', + size: '1024x1792', + status: 'completed' + } + } +] diff --git a/src/renderer/src/pages/video/VideoList.tsx b/src/renderer/src/pages/video/VideoList.tsx index 11bd58d5b8..4445eb7bc6 100644 --- a/src/renderer/src/pages/video/VideoList.tsx +++ b/src/renderer/src/pages/video/VideoList.tsx @@ -1,6 +1,7 @@ import { cn, Progress, Spinner } from '@heroui/react' +import { mockVideos } from '@renderer/config/models/video' import { useVideos } from '@renderer/hooks/video/useVideos' -import { Video } from '@renderer/types/video' +import { Video } from '@renderer/types' import { CheckCircleIcon, CircleXIcon, ClockIcon, DownloadIcon } from 'lucide-react' import { useTranslation } from 'react-i18next' @@ -9,137 +10,6 @@ export type VideoListProps = { providerId: string; activeVideoId?: string; setAc export const VideoList = ({ providerId, activeVideoId, setActiveVideoId }: VideoListProps) => { const { videos } = useVideos(providerId) - // Mock data for testing - const mockVideos: Video[] = [ - { - id: '1', - type: 'openai', - status: 'downloaded', - prompt: 'A beautiful sunset over the ocean with waves crashing', - thumbnail: 'https://picsum.photos/200/200?random=1', - fileId: 'file-001', - metadata: { - id: 'video-001', - object: 'video', - created_at: Math.floor(Date.now() / 1000), - completed_at: Math.floor(Date.now() / 1000), - expires_at: null, - error: null, - model: 'sora-2', - progress: 100, - remixed_from_video_id: null, - seconds: '4', - size: '1280x720', - status: 'completed' - } - }, - { - id: '2', - type: 'openai', - status: 'in_progress', - prompt: 'A cat playing with a ball of yarn in slow motion', - progress: 65, - metadata: { - id: 'video-002', - object: 'video', - created_at: Math.floor(Date.now() / 1000), - completed_at: null, - expires_at: null, - error: null, - model: 'sora-2-pro', - progress: 65, - remixed_from_video_id: null, - seconds: '8', - size: '1792x1024', - status: 'in_progress' - } - }, - { - id: '3', - type: 'openai', - status: 'queued', - prompt: 'Time-lapse of flowers blooming in a garden', - metadata: { - id: 'video-003', - object: 'video', - created_at: Math.floor(Date.now() / 1000), - completed_at: null, - expires_at: null, - error: null, - model: 'sora-2', - progress: 0, - remixed_from_video_id: null, - seconds: '12', - size: '1280x720', - status: 'queued' - } - }, - { - id: '4', - type: 'openai', - prompt: 'Birds flying in formation against blue sky', - status: 'downloading', - progress: 80, - thumbnail: 'https://picsum.photos/200/200?random=4', - metadata: { - id: 'video-004', - object: 'video', - created_at: Math.floor(Date.now() / 1000), - completed_at: Math.floor(Date.now() / 1000), - expires_at: null, - error: null, - model: 'sora-2-pro', - progress: 100, - remixed_from_video_id: null, - seconds: '8', - size: '1792x1024', - status: 'completed' - } - }, - { - id: '5', - type: 'openai', - status: 'failed', - error: { code: '400', message: 'Video generation failed' }, - prompt: 'Mountain landscape with snow peaks and forest', - metadata: { - id: 'video-005', - object: 'video', - created_at: Math.floor(Date.now() / 1000), - completed_at: Math.floor(Date.now() / 1000), - expires_at: null, - error: { code: '400', message: 'Video generation failed' }, - model: 'sora-2', - progress: 0, - remixed_from_video_id: null, - seconds: '4', - size: '1280x720', - status: 'failed' - } - }, - { - id: '6', - type: 'openai', - status: 'completed', - thumbnail: 'https://picsum.photos/200/200?random=6', - prompt: 'City street at night with neon lights reflecting on wet pavement', - metadata: { - id: 'video-006', - object: 'video', - created_at: Math.floor(Date.now() / 1000), - completed_at: Math.floor(Date.now() / 1000), - expires_at: null, - error: null, - model: 'sora-2-pro', - progress: 100, - remixed_from_video_id: null, - seconds: '12', - size: '1024x1792', - status: 'completed' - } - } - ] - // Use mock data instead of real videos for now const displayVideos = mockVideos diff --git a/src/renderer/src/pages/video/VideoPage.tsx b/src/renderer/src/pages/video/VideoPage.tsx index 7d64822822..4cd53c8f80 100644 --- a/src/renderer/src/pages/video/VideoPage.tsx +++ b/src/renderer/src/pages/video/VideoPage.tsx @@ -2,13 +2,14 @@ import { Divider } from '@heroui/react' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' +import { mockVideos } from '@renderer/config/models/video' 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 { useCallback, useState } from 'react' +import { useCallback, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { ModelSetting } from './settings/ModelSetting' @@ -46,6 +47,8 @@ export const VideoPage = () => { [updateParams] ) + const activeVideo = useMemo(() => mockVideos.find((v) => v.id === activeVideoId), [activeVideoId]) + return (
@@ -65,8 +68,7 @@ export const VideoPage = () => { {provider.type === 'openai-response' && }
- {/* TODO: pass video prop. retrieve correct video by swr */} - + {/* Video list */} diff --git a/src/renderer/src/pages/video/VideoPanel.tsx b/src/renderer/src/pages/video/VideoPanel.tsx index 18b5f21c96..4968391bac 100644 --- a/src/renderer/src/pages/video/VideoPanel.tsx +++ b/src/renderer/src/pages/video/VideoPanel.tsx @@ -9,7 +9,7 @@ import { MB } from '@shared/config/constant' import { DeepPartial } from 'ai' import { isEmpty } from 'lodash' import { ArrowUp, CircleXIcon, ImageIcon } from 'lucide-react' -import { useCallback, useMemo, useRef, useState } from 'react' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { VideoViewer } from './VideoViewer' @@ -35,6 +35,13 @@ export const VideoPanel = ({ provider, video, params, updateParams }: VideoPanel () => !isProcessing && !isEmpty(params.params.prompt), [isProcessing, params.params.prompt] ) + + useEffect(() => { + if (video) { + updateParams({ params: { prompt: video.prompt } }) + } + }, [updateParams, video]) + const handleCreateVideo = useCallback(async () => { if (!couldCreateVideo) return setIsProcessing(true) diff --git a/src/renderer/src/pages/video/VideoViewer.tsx b/src/renderer/src/pages/video/VideoViewer.tsx index 589fda6752..59cee71fba 100644 --- a/src/renderer/src/pages/video/VideoViewer.tsx +++ b/src/renderer/src/pages/video/VideoViewer.tsx @@ -1,7 +1,7 @@ import { Button, Progress, Radio, RadioGroup, Spinner } from '@heroui/react' import { Video, VideoStatus } from '@renderer/types/video' import { CheckCircleIcon, CircleXIcon } from 'lucide-react' -import { useState } from 'react' +import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' export interface VideoProps { @@ -12,6 +12,9 @@ export const VideoViewer = ({ video: _video }: VideoProps) => { const { t } = useTranslation() const [video, setVideo] = useState