diff --git a/api/DTO/movie_start_dto.ts b/api/DTO/movie_start_dto.ts index 655e9ec..e9a4670 100644 --- a/api/DTO/movie_start_dto.ts +++ b/api/DTO/movie_start_dto.ts @@ -14,12 +14,16 @@ export interface CharacterRegion { /** 角色分析信息 */ export interface CharacterAnalysis { + /** 角色头像URL */ + crop_url: string; /** 角色ID */ id: string; /** 角色名称 */ role_name: string; /** 角色区域 */ region: CharacterRegion|null; + /** 角色描述 */ + whisk_caption: string; /** 角色头像URL(可选,用于存储裁剪后的头像) */ avatarUrl?: string; } @@ -41,3 +45,108 @@ export interface MovieStartDTO { /** 错误信息 */ error: string | null; } +/** + * 创建电影项目V2请求参数 + */ +export interface CreateMovieProjectV2Request { + /** 剧本内容 */ + script: string; + /** 用户ID */ + user_id: string; + /** 模式:auto | manual */ + mode: "auto" | "manual"; + /** 分辨率:720p | 1080p | 4k */ + resolution: "720p" | "1080p" | "4k"; + /** 类型 */ + genre: string; + /** 角色简介数组 */ + character_briefs: string[]; + /** 语言 */ + language: string; + /** 图片URL */ + image_url: string; + } + + /** + * 创建电影项目V2响应数据 + */ + export interface CreateMovieProjectV2Response { + /** 原始文本 */ + original_text: string; + /** 项目ID */ + project_id: string; + /** 视频数据 */ + video: Record; + /** 扩展数据2 */ + ext2: Record; + /** 多语言视频 */ + multilingual_video: Record; + /** 制作手册 */ + production_bible: string; + /** 项目名称 */ + name: string; + /** 音乐数据 */ + music: Record; + /** 扩展数据3 */ + ext3: Record; + /** 语言 */ + language: string; + /** 分镜头 */ + storyboard: string; + /** 状态 */ + status: string; + /** 最终视频 */ + final_video: Record; + /** 扩展数据4 */ + ext4: string; + /** 产品代码 */ + pcode: string; + /** 制作手册JSON */ + production_bible_json: Record; + /** 步骤 */ + step: string; + /** 最终简单视频 */ + final_simple_video: Record; + /** 扩展数据5 */ + ext5: string; + /** 产品代码版本 */ + pcode_version: string; + /** 分辨率 */ + resolution: string; + /** 剧本分镜头 */ + script_shots: string; + /** 最后消息 */ + last_message: string; + /** 扩展数据 */ + ext: Record; + /** 角色草稿 */ + character_draft: any; + /** 模式 */ + mode: string; + /** 提示词 */ + prompts: string; + /** 草图 */ + sketch: Record; + /** 当前任务ID */ + current_task_id: string; + /** 创建时间 */ + created_at: string; + /** ID */ + id: number; + /** 描述 */ + description: string; + /** 镜头草图 */ + shot_sketch: Record; + /** 扩展数据1 */ + ext1: Record; + /** 当前计划ID */ + current_plan_id: string; + /** 用户ID */ + user_id: string; + /** 生成的剧本 */ + generated_script: string; + /** 角色数据 */ + character: Record; + /** 更新时间 */ + updated_at: string; + } diff --git a/api/video_flow.ts b/api/video_flow.ts index f24c9ac..bc7433f 100644 --- a/api/video_flow.ts +++ b/api/video_flow.ts @@ -18,6 +18,7 @@ import { task_item, VideoSegmentEntityAdapter } from "@/app/service/adapter/oldE import { VideoFlowProjectResponse, NewCharacterItem, NewCharacterListResponse, CharacterListByProjectWithHighlightResponse, CharacterUpdateAndRegenerateRequest, CharacterUpdateAndRegenerateResponse } from "./DTO/movieEdit"; import { RoleResponse } from "./DTO/movieEdit"; import { RoleRecognitionResponse } from "./DTO/movieEdit"; +import { CreateMovieProjectV2Request, CreateMovieProjectV2Response } from "./DTO/movie_start_dto"; /** * 角色替换参数接口 @@ -1149,3 +1150,19 @@ export const modifyCharacterOrScene = async (request: { }; + +/** + * 创建电影项目V2 + * @param request - 创建项目请求参数 + * @returns Promise> + */ +export const createMovieProjectV2 = async ( + request: CreateMovieProjectV2Request +)=> { + return post>( + "/movie/create_movie_project_v2", + request + ); +}; + + diff --git a/app/service/Interaction/ImageStoryService.ts b/app/service/Interaction/ImageStoryService.ts index feefc7d..b122566 100644 --- a/app/service/Interaction/ImageStoryService.ts +++ b/app/service/Interaction/ImageStoryService.ts @@ -8,7 +8,9 @@ import { Dispatch, SetStateAction, } from "react"; -import { CharacterAnalysis } from "@/api/DTO/movie_start_dto"; +import { CharacterAnalysis, CreateMovieProjectV2Request, CreateMovieProjectV2Response } from "@/api/DTO/movie_start_dto"; +import { createMovieProjectV2 } from "@/api/video_flow"; +import { ApiResponse } from "@/api/common"; interface UseImageStoryService { /** 当前图片故事数据 */ @@ -48,7 +50,12 @@ interface UseImageStoryService { /** 重置图片故事数据 */ resetImageStory: (showAnalysisState?: boolean) => void; /** 生成动作电影 */ - actionMovie: () => Promise; + actionMovie: ( + user_id: string, + mode?: "auto" | "manual", + resolution?: "720p" | "1080p" | "4k", + language?: string + ) => Promise; /** 设置角色分析 */ setCharactersAnalysis: Dispatch>; /** 设置原始用户描述 */ @@ -212,6 +219,7 @@ export const useImageStoryServiceHook = (): UseImageStoryService => { } return charactersAnalysis.map((character) => { + console.log('character', character) // 如果已经有头像URL,直接返回 if (character.avatarUrl) { return { @@ -266,12 +274,7 @@ export const useImageStoryServiceHook = (): UseImageStoryService => { } finally { setIsLoading(false); } - }, [ - activeImageUrl, - imageStoryUseCase, - storyContent, - setOriginalUserDescription, - ]); + }, [imageStoryUseCase, activeImageUrl, storyContent]); /** * 触发生成剧本函数 @@ -378,14 +381,7 @@ export const useImageStoryServiceHook = (): UseImageStoryService => { imageStoryUseCase.resetImageStory(); // 清理生成的头像URL,避免内存泄漏 - setCharactersAnalysis((prev) => { - prev.forEach((char) => { - if (char.avatarUrl) { - URL.revokeObjectURL(char.avatarUrl); - } - }); - return []; - }); + setCharactersAnalysis([]); // 重置所有状态 setImageStory({ @@ -453,18 +449,36 @@ export const useImageStoryServiceHook = (): UseImageStoryService => { }); }, [uploadFile]); - const actionMovie = useCallback(async (): Promise => { + const actionMovie = useCallback(async ( + user_id: string, + mode: "auto" | "manual" = "auto", + resolution: "720p" | "1080p" | "4k" = "720p", + language: string = "English" + ) => { try { if (hasAnalyzed) { - const params = { - content: storyContent, - category: selectedCategory, + // 从charactersAnalysis中提取whisk_caption字段组成数组 + const character_briefs = charactersAnalysis.map(char => char.whisk_caption); + + const params: CreateMovieProjectV2Request = { + script: storyContent, + user_id, + mode, + resolution, + genre: selectedCategory, + character_briefs, + language, + image_url: activeImageUrl, }; + + // 调用create_movie_project_v2接口 + const result = await createMovieProjectV2(params) + return result.data; } } catch (error) { - console.error("图片上传分析失败:", error); + console.error("创建电影项目失败:", error); } - }, [activeImageUrl, imageStoryUseCase]); + }, [hasAnalyzed, storyContent, charactersAnalysis, selectedCategory, activeImageUrl]); return { imageStory, activeImageUrl, diff --git a/app/service/usecase/imageStoryUseCase.ts b/app/service/usecase/imageStoryUseCase.ts index e9d1bde..9e598e9 100644 --- a/app/service/usecase/imageStoryUseCase.ts +++ b/app/service/usecase/imageStoryUseCase.ts @@ -95,6 +95,7 @@ export class ImageStoryUseCase { async analyzeImageWithAI() { console.log('this.imageStory.imageUrl', this.imageStory.imageUrl) try { + // // 调用AI分析接口 const response = await AIGenerateImageStory({ image_url: this.imageStory.imageUrl || "", diff --git a/components/common/ChatInputBox.tsx b/components/common/ChatInputBox.tsx index 9178556..83f531b 100644 --- a/components/common/ChatInputBox.tsx +++ b/components/common/ChatInputBox.tsx @@ -508,7 +508,12 @@ export function ChatInputBox() { const [isCreating, setIsCreating] = useState(false); // 视频创建过程中的加载状态 // 配置选项状态 - 整合所有配置项到一个对象 - const [configOptions, setConfigOptions] = useState({ + const [configOptions, setConfigOptions] = useState<{ + mode: "auto" | "manual"; + resolution: "720p" | "1080p" | "4k"; + language: string; + videoDuration: string; + }>({ mode: "auto", resolution: "720p", language: "english", @@ -699,10 +704,11 @@ export function ChatInputBox() { {/* 图片故事弹窗 */} - setIsPhotoStoryModalOpen(false)} - /> + setIsPhotoStoryModalOpen(false)} + configOptions={configOptions} + /> {/* 右侧Action按钮 */} @@ -1003,9 +1009,21 @@ const RoleHighlightEditor = ({ const PhotoStoryModal = ({ isOpen, onClose, + configOptions = { + mode: "auto" as "auto" | "manual", + resolution: "720p" as "720p" | "1080p" | "4k", + language: "english", + videoDuration: "1min", + }, }: { isOpen: boolean; onClose: () => void; + configOptions?: { + mode: "auto" | "manual"; + resolution: "720p" | "1080p" | "4k"; + language: string; + videoDuration: string; + }; }) => { // 使用图片故事服务hook管理状态 const { @@ -1023,7 +1041,8 @@ const PhotoStoryModal = ({ avatarComputed, uploadAndAnalyzeImage, setCharactersAnalysis, - originalUserDescription + originalUserDescription, + actionMovie } = useImageStoryServiceHook(); const { loadingText } = useLoadScriptText(isLoading); // 重置状态 @@ -1031,7 +1050,7 @@ const PhotoStoryModal = ({ resetImageStory(); onClose(); }; - + const router = useRouter(); // 处理图片上传 const handleImageUpload = async () => { try { @@ -1042,8 +1061,31 @@ const PhotoStoryModal = ({ }; // 处理确认 - const handleConfirm = () => { - if (hasAnalyzed) { + const handleConfirm = async () => { + try { + // 获取当前用户信息 + const User = JSON.parse(localStorage.getItem("currentUser") || "{}"); + + if (!User.id) { + console.error("用户未登录"); + return; + } + + // 调用actionMovie接口 + const episodeResponse = await actionMovie( + String(User.id), + configOptions.mode as "auto" | "manual", + configOptions.resolution as "720p" | "1080p" | "4k", + configOptions.language + ); + if(!episodeResponse) return + let episodeId = episodeResponse.project_id; + // let episodeId = '9c34fcc4-c8d8-44fc-879e-9bd56f608c76'; + router.push(`/create/work-flow?episodeId=${episodeId}`); + // 成功后关闭弹窗 + handleClose(); + } catch (error) { + console.error("创建电影项目失败:", error); } };