From 680ddd7cc6551a76859db19f5cb023535d74455e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Mon, 20 Oct 2025 20:20:59 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E5=85=A5=E5=8F=A3=EF=BC=9AV4=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/DTO/movie_start_dto.ts | 40 +++++++ api/create_movie.ts | 15 +++ .../Interaction/MovieProjectService.ts | 10 +- .../CreateInput/VideoCreationForm.tsx | 110 +++++++++++++++--- 4 files changed, 156 insertions(+), 19 deletions(-) diff --git a/api/DTO/movie_start_dto.ts b/api/DTO/movie_start_dto.ts index 0180ed8..72e621a 100644 --- a/api/DTO/movie_start_dto.ts +++ b/api/DTO/movie_start_dto.ts @@ -334,3 +334,43 @@ export interface TextToImageResponse { /** 是否成功 */ successful: boolean; } + +/** + * 创建电影V4接口请求数据 + */ +export interface CreateMovieProjectV4Request { + /** 剧本内容 */ + script: string; + /** 模式 */ + mode: "auto" | "manual"; + /** 分辨率 */ + resolution: "720p" | "1080p" | "4k"; + /** 语言 */ + language: string; + /** 画面比例(横/竖屏) */ + aspect_ratio: AspectRatioValue; + /** 是否是图生 */ + is_image_to_video: boolean; + /** pcode编码 */ + pcode: string; + /** 角色简介数组 */ + character_briefs?: { + character_name:string; + character_description:string; + image_url:string; + }[]; + /** 场景简介数组 */ + scene_briefs?: { + scene_name:string; + scene_description:string; + image_url:string; + scene_type:string; + }[]; + /** 道具简介数组 */ + prop_briefs?: { + prop_name:string; + prop_description:string; + image_url:string; + prop_type:string; + }[]; +} \ No newline at end of file diff --git a/api/create_movie.ts b/api/create_movie.ts index 89db035..3801262 100644 --- a/api/create_movie.ts +++ b/api/create_movie.ts @@ -1,6 +1,7 @@ import { CreateMovieProjectV2Request, CreateMovieProjectV3Request, + CreateMovieProjectV4Request } from "./DTO/movie_start_dto"; import { post } from "./request"; import { getClientUserData } from './common'; @@ -40,4 +41,18 @@ export const createMovieProjectV3 = async ( post("/movie/create_movie_project_v3", params); const user_data = getClientUserData(); return withQueuePolling(apiCall, { ...(request as any), user_data } as any); +}; + +/** + * 创建电影项目V4 + * @param request - 创建项目请求参数 + * @returns Promise + */ +export const createMovieProjectV4 = async ( + request: CreateMovieProjectV4Request +): Promise => { + const apiCall = (params: CreateMovieProjectV4Request) => + post("/movie/create_movie_project_v4", params); + const user_data = getClientUserData(); + return withQueuePolling(apiCall, { ...(request as any), user_data } as any); }; \ No newline at end of file diff --git a/app/service/Interaction/MovieProjectService.ts b/app/service/Interaction/MovieProjectService.ts index 428bd44..6c7f1d7 100644 --- a/app/service/Interaction/MovieProjectService.ts +++ b/app/service/Interaction/MovieProjectService.ts @@ -1,5 +1,4 @@ - -import { createMovieProject, createMovieProjectV2, createMovieProjectV3 } from "@/api/create_movie"; +import { createMovieProject, createMovieProjectV2, createMovieProjectV3, createMovieProjectV4 } from "@/api/create_movie"; import { QueueResponse, withQueuePolling, QueueResponseData } from "@/api/movie_queue"; /** @@ -11,7 +10,9 @@ export enum MovieProjectMode { /** 照片生成模式 */ IMAGE = "image", /** 模板生成模式 */ - TEMPLATE = "template" + TEMPLATE = "template", + /** V4增强模式(支持角色、场景、道具等) */ + V4 = "v4" } /** 创建项目响应数据 */ @@ -43,6 +44,9 @@ export class MovieProjectService { case MovieProjectMode.TEMPLATE: apiCall = createMovieProjectV3 as (p: T) => Promise; break; + case MovieProjectMode.V4: + apiCall = createMovieProjectV4 as (p: T) => Promise; + break; default: throw new Error(`不支持的创建模式: ${mode}`); } diff --git a/components/pages/create-video/CreateInput/VideoCreationForm.tsx b/components/pages/create-video/CreateInput/VideoCreationForm.tsx index 42c52df..9310014 100644 --- a/components/pages/create-video/CreateInput/VideoCreationForm.tsx +++ b/components/pages/create-video/CreateInput/VideoCreationForm.tsx @@ -18,6 +18,9 @@ import { AddItemModal } from './AddItemModal'; import { defaultConfig } from './config-options'; import type { ConfigOptions } from './config-options'; import { useDeviceType } from '@/hooks/useDeviceType'; +import { MovieProjectService, MovieProjectMode } from '@/app/service/Interaction/MovieProjectService'; +import type { CreateMovieProjectV4Request } from '@/api/DTO/movie_start_dto'; +import { getCurrentUser } from '@/lib/auth'; export default function VideoCreationForm() { const [photos, setPhotos] = useState([]); @@ -28,6 +31,7 @@ export default function VideoCreationForm() { const [currentItemType, setCurrentItemType] = useState(null); const [editingIndex, setEditingIndex] = useState(null); const [replacingIndex, setReplacingIndex] = useState(null); + const [isCreating, setIsCreating] = useState(false); const { isMobile, isDesktop } = useDeviceType(); @@ -74,13 +78,6 @@ export default function VideoCreationForm() { setConfigOptions(prev => ({ ...prev, [key]: value })); }; - /** Handle opening add item modal */ - const handleOpenAddItemModal = (type: PhotoType) => { - setCurrentItemType(type); - setEditingIndex(null); - setAddItemModalVisible(true); - }; - /** Handle editing a photo */ const handleEditPhoto = (index: number) => { const photo = photos[index]; @@ -165,13 +162,89 @@ export default function VideoCreationForm() { }; /** Handle video creation */ - const handleCreate = () => { - console.log({ - text: inputText, - photos, - config: configOptions, - }); - // TODO: Implement video creation logic + const handleCreate = async () => { + if (isCreating) return; + + if (!inputText.trim()) { + window.msg?.warning('Please enter your story description'); + return; + } + + try { + setIsCreating(true); + + const user = getCurrentUser(); + if (!user?.id) { + window.msg?.error('Please login first'); + return; + } + + /** Separate photos by type */ + const characterPhotos = photos.filter(p => p.type === 'character'); + const scenePhotos = photos.filter(p => p.type === 'scene'); + const propPhotos = photos.filter(p => p.type === 'prop'); + + /** Build request parameters */ + const requestParams: CreateMovieProjectV4Request = { + script: inputText, + mode: configOptions.expansion_mode ? 'auto' : 'manual', + resolution: '720p', + language: configOptions.language, + aspect_ratio: configOptions.aspect_ratio, + is_image_to_video: photos.length > 0, + pcode: configOptions.pcode, + }; + + /** Add character briefs if exists */ + if (characterPhotos.length > 0) { + requestParams.character_briefs = characterPhotos.map(photo => ({ + character_name: photo.name || 'Character', + character_description: photo.description || '', + image_url: photo.url, + })); + } + + /** Add scene briefs if exists */ + if (scenePhotos.length > 0) { + requestParams.scene_briefs = scenePhotos.map(photo => ({ + scene_name: photo.name || 'Scene', + scene_description: photo.description || '', + image_url: photo.url, + scene_type: 'custom', + })); + } + + /** Add prop briefs if exists */ + if (propPhotos.length > 0) { + requestParams.prop_briefs = propPhotos.map(photo => ({ + prop_name: photo.name || 'Prop', + prop_description: photo.description || '', + image_url: photo.url, + prop_type: 'custom', + })); + } + + console.log('Creating video with params:', requestParams); + + /** Call MovieProjectService V4 API */ + const result = await MovieProjectService.createProject( + MovieProjectMode.V4, + requestParams + ); + + console.log('Video creation successful, project_id:', result.project_id); + window.msg?.success(`Video created successfully! Project ID: ${result.project_id}`); + + /** TODO: Navigate to project detail page or next step */ + // window.location.href = `/movies/${result.project_id}`; + } catch (error) { + console.error('Failed to create video:', error); + if (error instanceof Error && error.message !== '操作已取消') { + window.msg?.error(error.message || 'Failed to create video'); + } + } finally { + setIsCreating(false); + } }; return ( @@ -298,10 +371,15 @@ export default function VideoCreationForm() { {/* Right Side - Create Button */} From 3e7a27cb7a8ca8b4804b9e63bfbff60e25ceadc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Mon, 20 Oct 2025 20:48:03 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E5=85=A5=E5=8F=A3=EF=BC=9A=E5=89=A7=E6=9C=AC=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/DTO/movie_start_dto.ts | 2 ++ .../pages/create-video/CreateInput/VideoCreationForm.tsx | 5 +++-- components/pages/create-video/CreateInput/config-options.ts | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/api/DTO/movie_start_dto.ts b/api/DTO/movie_start_dto.ts index 72e621a..c0a47bc 100644 --- a/api/DTO/movie_start_dto.ts +++ b/api/DTO/movie_start_dto.ts @@ -349,6 +349,8 @@ export interface CreateMovieProjectV4Request { language: string; /** 画面比例(横/竖屏) */ aspect_ratio: AspectRatioValue; + /** 扩展模式 */ + expansion_mode: boolean; /** 是否是图生 */ is_image_to_video: boolean; /** pcode编码 */ diff --git a/components/pages/create-video/CreateInput/VideoCreationForm.tsx b/components/pages/create-video/CreateInput/VideoCreationForm.tsx index 9310014..053e4ce 100644 --- a/components/pages/create-video/CreateInput/VideoCreationForm.tsx +++ b/components/pages/create-video/CreateInput/VideoCreationForm.tsx @@ -187,12 +187,13 @@ export default function VideoCreationForm() { /** Build request parameters */ const requestParams: CreateMovieProjectV4Request = { script: inputText, - mode: configOptions.expansion_mode ? 'auto' : 'manual', + mode: configOptions.mode, resolution: '720p', language: configOptions.language, aspect_ratio: configOptions.aspect_ratio, + expansion_mode: configOptions.expansion_mode, is_image_to_video: photos.length > 0, - pcode: configOptions.pcode, + pcode: configOptions.pcode === 'portrait' ? '' : configOptions.pcode, }; /** Add character briefs if exists */ diff --git a/components/pages/create-video/CreateInput/config-options.ts b/components/pages/create-video/CreateInput/config-options.ts index fd94b1d..b8c6e8c 100644 --- a/components/pages/create-video/CreateInput/config-options.ts +++ b/components/pages/create-video/CreateInput/config-options.ts @@ -43,14 +43,16 @@ export interface ConfigOptions { videoDuration: VideoDurationValue; aspect_ratio: AspectRatioValue; pcode: PortraitAnimeValue; + mode: "auto" | "manual"; } /** Default configuration */ export const defaultConfig: ConfigOptions = { language: 'english', - expansion_mode: false, + expansion_mode: true, videoDuration: 'unlimited', aspect_ratio: 'VIDEO_ASPECT_RATIO_LANDSCAPE', pcode: 'portrait', + mode: 'auto', }; From 8260f0160861dd69cc5576493b3593d6416d370b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Mon, 20 Oct 2025 21:01:03 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=85=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=9A=E5=88=9B=E5=BB=BA=E6=88=90=E5=8A=9F=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/create-video/CreateInput/VideoCreationForm.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/pages/create-video/CreateInput/VideoCreationForm.tsx b/components/pages/create-video/CreateInput/VideoCreationForm.tsx index 053e4ce..4eea06f 100644 --- a/components/pages/create-video/CreateInput/VideoCreationForm.tsx +++ b/components/pages/create-video/CreateInput/VideoCreationForm.tsx @@ -21,7 +21,7 @@ import { useDeviceType } from '@/hooks/useDeviceType'; import { MovieProjectService, MovieProjectMode } from '@/app/service/Interaction/MovieProjectService'; import type { CreateMovieProjectV4Request } from '@/api/DTO/movie_start_dto'; import { getCurrentUser } from '@/lib/auth'; - +import { useRouter } from 'next/navigation'; export default function VideoCreationForm() { const [photos, setPhotos] = useState([]); const [inputText, setInputText] = useState(''); @@ -34,7 +34,7 @@ export default function VideoCreationForm() { const [isCreating, setIsCreating] = useState(false); const { isMobile, isDesktop } = useDeviceType(); - + const router = useRouter(); const characterInputRef = useRef(null); const sceneInputRef = useRef(null); const propInputRef = useRef(null); @@ -235,6 +235,7 @@ export default function VideoCreationForm() { console.log('Video creation successful, project_id:', result.project_id); window.msg?.success(`Video created successfully! Project ID: ${result.project_id}`); + router.push(`/movies/work-flow?episodeId=${result.project_id}`); /** TODO: Navigate to project detail page or next step */ // window.location.href = `/movies/${result.project_id}`; From 0131a430356be80150b2e4be0a1b5daf6441c272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Mon, 20 Oct 2025 21:13:59 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=EF=BC=9A8s=E4=B8=8D=E6=89=A9=E5=B1=95=E5=89=A7=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/create-video/CreateInput/ConfigPanel.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/components/pages/create-video/CreateInput/ConfigPanel.tsx b/components/pages/create-video/CreateInput/ConfigPanel.tsx index 0f8ceec..ea4d917 100644 --- a/components/pages/create-video/CreateInput/ConfigPanel.tsx +++ b/components/pages/create-video/CreateInput/ConfigPanel.tsx @@ -100,7 +100,14 @@ export const ConfigPanel = ({ onConfigChange('videoDuration', key as VideoDurationValue), + onClick: ({ key }) => { + onConfigChange('videoDuration', key as VideoDurationValue); + if (key === '8s') { + onConfigChange('expansion_mode', false); + } else { + onConfigChange('expansion_mode', true); + } + }, className: 'bg-[#1a1a1a] border border-white/10' }} trigger={['click']} From 3dd300950a77eedf8032542e1be1aa3ac2ec116a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Mon, 20 Oct 2025 21:29:20 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=EF=BC=9A=E8=A7=86=E9=A2=91=E6=97=B6=E9=95=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/DTO/movie_start_dto.ts | 2 ++ components/pages/create-video/CreateInput/VideoCreationForm.tsx | 1 + 2 files changed, 3 insertions(+) diff --git a/api/DTO/movie_start_dto.ts b/api/DTO/movie_start_dto.ts index c0a47bc..220fc95 100644 --- a/api/DTO/movie_start_dto.ts +++ b/api/DTO/movie_start_dto.ts @@ -351,6 +351,8 @@ export interface CreateMovieProjectV4Request { aspect_ratio: AspectRatioValue; /** 扩展模式 */ expansion_mode: boolean; + /** 视频时长 */ + video_duration: string; /** 是否是图生 */ is_image_to_video: boolean; /** pcode编码 */ diff --git a/components/pages/create-video/CreateInput/VideoCreationForm.tsx b/components/pages/create-video/CreateInput/VideoCreationForm.tsx index 4eea06f..f01d29e 100644 --- a/components/pages/create-video/CreateInput/VideoCreationForm.tsx +++ b/components/pages/create-video/CreateInput/VideoCreationForm.tsx @@ -192,6 +192,7 @@ export default function VideoCreationForm() { language: configOptions.language, aspect_ratio: configOptions.aspect_ratio, expansion_mode: configOptions.expansion_mode, + video_duration: configOptions.videoDuration, is_image_to_video: photos.length > 0, pcode: configOptions.pcode === 'portrait' ? '' : configOptions.pcode, };