对接修复

This commit is contained in:
海龙 2025-08-07 14:08:16 +08:00
parent 6df87250fb
commit 86bb1bf4c1
4 changed files with 270 additions and 164 deletions

View File

@ -699,6 +699,8 @@ export const createMovieProjectV1 = async (request: {
mode: "auto" | "manual"; mode: "auto" | "manual";
/** 分辨率720p | 1080p | 4k */ /** 分辨率720p | 1080p | 4k */
resolution: "720p" | "1080p" | "4k"; resolution: "720p" | "1080p" | "4k";
/** 语言 */
language: string;
}) => { }) => {
return post<ApiResponse<{ return post<ApiResponse<{
/** 项目ID */ /** 项目ID */

View File

@ -1,6 +1,17 @@
import { useState, useCallback, Dispatch, SetStateAction, useMemo } from "react"; import {
import { ScriptEditUseCase,ScriptEditKey } from "../usecase/ScriptEditUseCase"; useState,
import { getProjectScript, abortVideoTask, pausePlanFlow, resumePlanFlow } from "../../../api/video_flow"; useCallback,
Dispatch,
SetStateAction,
useMemo,
} from "react";
import { ScriptEditUseCase, ScriptEditKey } from "../usecase/ScriptEditUseCase";
import {
getProjectScript,
abortVideoTask,
pausePlanFlow,
resumePlanFlow,
} from "../../../api/video_flow";
import { parseScriptBlock } from "../domain/service"; import { parseScriptBlock } from "../domain/service";
import { ScriptBlock } from "@/components/script-renderer/types"; import { ScriptBlock } from "@/components/script-renderer/types";
@ -48,7 +59,17 @@ export interface UseScriptService {
/** 中断视频任务 */ /** 中断视频任务 */
abortVideoTask: () => Promise<void>; abortVideoTask: () => Promise<void>;
/** 聚焦处理函数 */ /** 聚焦处理函数 */
focusHandler: (field: 'synopsis' | 'categories' | 'protagonist' | 'incitingIncident' | 'problem' | 'conflict' | 'stakes' | 'characterArc') => Promise<void>; focusHandler: (
field:
| "synopsis"
| "categories"
| "protagonist"
| "incitingIncident"
| "problem"
| "conflict"
| "stakes"
| "characterArc"
) => Promise<void>;
/** 增强剧本 */ /** 增强剧本 */
enhanceScript: () => Promise<void>; enhanceScript: () => Promise<void>;
/** 设置AI优化要求 */ /** 设置AI优化要求 */
@ -72,6 +93,18 @@ export interface UseScriptService {
/** 设置人物弧线完成 */ /** 设置人物弧线完成 */
setCharacterArc: Dispatch<SetStateAction<string>>; setCharacterArc: Dispatch<SetStateAction<string>>;
/** 设置项目ID */
setProjectId: Dispatch<SetStateAction<string>>;
/** 设置计划ID */
setPlanId: Dispatch<SetStateAction<string>>;
/** 创建项目 */
createMovieProjectV1: (
idea: string,
userId: string,
mode: "auto" | "manual",
resolution: string,
language: string
) => Promise<void>;
} }
/** /**
@ -96,24 +129,25 @@ export const useScriptService = (): UseScriptService => {
const [focusedField, setFocusedField] = useState<string>(""); const [focusedField, setFocusedField] = useState<string>("");
// UseCase实例 // UseCase实例
const [scriptEditUseCase, setScriptEditUseCase] = useState<ScriptEditUseCase | null>(null); const [scriptEditUseCase, setScriptEditUseCase] = useState<ScriptEditUseCase>(
new ScriptEditUseCase("")
);
/** /**
* *
* @param idea * @param idea
*/ */
const generateScriptFromIdea = useCallback(async (idea: string): Promise<void> => { const generateScriptFromIdea = useCallback(
async (idea: string,project_id?:string): Promise<void> => {
try { try {
setLoading(true); setLoading(true);
if(project_id){
// 创建新的剧本编辑用例 setProjectId(project_id);
const newScriptEditUseCase = new ScriptEditUseCase(''); }
setScriptEditUseCase(newScriptEditUseCase);
// 调用AI生成剧本 // 调用AI生成剧本
await newScriptEditUseCase.generateScript(idea, (content) => { await scriptEditUseCase.generateScript(idea, (content) => {
// 获取解析后的故事详情 // 获取解析后的故事详情
const storyDetails = newScriptEditUseCase.getStoryDetails(); const storyDetails = scriptEditUseCase.getStoryDetails();
setSynopsis(storyDetails.synopsis || ""); setSynopsis(storyDetails.synopsis || "");
setCategories(storyDetails.categories || []); setCategories(storyDetails.categories || []);
setProtagonist(storyDetails.protagonist || ""); setProtagonist(storyDetails.protagonist || "");
@ -124,33 +158,55 @@ export const useScriptService = (): UseScriptService => {
setCharacterArc(storyDetails.characterArc || ""); setCharacterArc(storyDetails.characterArc || "");
}); });
// 剧本生成完成后,自动创建项目
const projectData = await newScriptEditUseCase.createProject(
idea,
JSON.parse(localStorage.getItem('currentUser') || '{}').id,
"auto",
"720p"
);
setProjectId(projectData.project_id);
setPlanId(projectData.plan_id);
// 自动保存剧本到项目 // 自动保存剧本到项目
await newScriptEditUseCase.saveScript(projectData.project_id); await scriptEditUseCase.saveScript((projectId||project_id) as string);
} catch (error) { } catch (error) {
console.error('生成剧本失败:', error); console.error("生成剧本失败:", error);
throw error; throw error;
} finally { } finally {
setLoading(false); setLoading(false);
} }
}, []); },
[]
);
const createMovieProjectV1 = useCallback(
async (
idea: string,
userId: string,
mode: "auto" | "manual",
resolution: string,
language: string
): Promise<void> => {
try {
setLoading(true);
// 剧本生成完成后,自动创建项目
const projectData = await scriptEditUseCase.createProject(
idea,
userId,
mode as "auto" | "manual",
resolution as "720p" | "1080p" | "4k",
language
);
setProjectId(projectData.project_id);
setPlanId(projectData.plan_id);
} catch (error) {
console.error("创建项目失败:", error);
throw error;
} finally {
setLoading(false);
}
},
[scriptEditUseCase]
);
/** /**
* ID初始化已有剧本 * ID初始化已有剧本
* @param projectId ID * @param projectId ID
*/ */
const initializeFromProject = useCallback(async (projectId: string): Promise<void> => { const initializeFromProject = useCallback(
async (projectId: string): Promise<void> => {
try { try {
setLoading(true); setLoading(true);
@ -161,7 +217,7 @@ export const useScriptService = (): UseScriptService => {
const response = await getProjectScript({ project_id: projectId }); const response = await getProjectScript({ project_id: projectId });
if (!response.successful) { if (!response.successful) {
throw new Error(response.message || '获取项目剧本失败'); throw new Error(response.message || "获取项目剧本失败");
} }
const { generated_script } = response.data; const { generated_script } = response.data;
@ -180,14 +236,15 @@ export const useScriptService = (): UseScriptService => {
setConflict(storyDetails.conflict || ""); setConflict(storyDetails.conflict || "");
setStakes(storyDetails.stakes || ""); setStakes(storyDetails.stakes || "");
setCharacterArc(storyDetails.characterArc || ""); setCharacterArc(storyDetails.characterArc || "");
} catch (error) { } catch (error) {
console.error('初始化项目剧本失败:', error); console.error("初始化项目剧本失败:", error);
throw error; throw error;
} finally { } finally {
setLoading(false); setLoading(false);
} }
}, []); },
[]
);
/** /**
* *
@ -220,7 +277,6 @@ export const useScriptService = (): UseScriptService => {
} }
await scriptEditUseCase.applyScript(projectId, planId); await scriptEditUseCase.applyScript(projectId, planId);
} catch (error) { } catch (error) {
console.error("应用剧本失败:", error); console.error("应用剧本失败:", error);
throw error; throw error;
@ -234,7 +290,6 @@ export const useScriptService = (): UseScriptService => {
*/ */
const abortVideoTaskHandler = useCallback(async (): Promise<void> => { const abortVideoTaskHandler = useCallback(async (): Promise<void> => {
try { try {
if (!projectId || !planId) { if (!projectId || !planId) {
throw new Error("项目ID或计划ID未设置"); throw new Error("项目ID或计划ID未设置");
} }
@ -242,7 +297,7 @@ export const useScriptService = (): UseScriptService => {
// 调用中断视频任务API // 调用中断视频任务API
const response = await abortVideoTask({ const response = await abortVideoTask({
project_id: projectId, project_id: projectId,
plan_id: planId plan_id: planId,
}); });
if (!response.successful) { if (!response.successful) {
@ -250,7 +305,6 @@ export const useScriptService = (): UseScriptService => {
} }
console.log("视频任务中断成功"); console.log("视频任务中断成功");
} catch (error) { } catch (error) {
console.error("中断视频任务失败:", error); console.error("中断视频任务失败:", error);
throw error; throw error;
@ -258,85 +312,113 @@ export const useScriptService = (): UseScriptService => {
}, [projectId, planId]); }, [projectId, planId]);
// 封装的setter函数同时更新hook状态和scriptEditUseCase中的值对象 // 封装的setter函数同时更新hook状态和scriptEditUseCase中的值对象
const setSynopsisWrapper = useCallback((value: SetStateAction<string>) => { const setSynopsisWrapper = useCallback(
const newValue = typeof value === 'function' ? value(synopsis) : value; (value: SetStateAction<string>) => {
const newValue = typeof value === "function" ? value(synopsis) : value;
setSynopsis(newValue); setSynopsis(newValue);
if (scriptEditUseCase) { if (scriptEditUseCase) {
scriptEditUseCase.updateStoryField('synopsis', newValue); scriptEditUseCase.updateStoryField("synopsis", newValue);
} }
}, [synopsis, scriptEditUseCase]); },
[synopsis, scriptEditUseCase]
);
const setCategoriesWrapper = useCallback((value: SetStateAction<string[]>) => { const setCategoriesWrapper = useCallback(
const newValue = typeof value === 'function' ? value(categories) : value; (value: SetStateAction<string[]>) => {
const newValue = typeof value === "function" ? value(categories) : value;
setCategories(newValue); setCategories(newValue);
if (scriptEditUseCase) { if (scriptEditUseCase) {
scriptEditUseCase.updateStoryField('categories', newValue); scriptEditUseCase.updateStoryField("categories", newValue);
} }
}, [categories, scriptEditUseCase]); },
[categories, scriptEditUseCase]
);
const setProtagonistWrapper = useCallback((value: SetStateAction<string>) => { const setProtagonistWrapper = useCallback(
const newValue = typeof value === 'function' ? value(protagonist) : value; (value: SetStateAction<string>) => {
const newValue = typeof value === "function" ? value(protagonist) : value;
setProtagonist(newValue); setProtagonist(newValue);
if (scriptEditUseCase) { if (scriptEditUseCase) {
scriptEditUseCase.updateStoryField('protagonist', newValue); scriptEditUseCase.updateStoryField("protagonist", newValue);
} }
}, [protagonist, scriptEditUseCase]); },
[protagonist, scriptEditUseCase]
);
const setIncitingIncidentWrapper = useCallback((value: SetStateAction<string>) => { const setIncitingIncidentWrapper = useCallback(
const newValue = typeof value === 'function' ? value(incitingIncident) : value; (value: SetStateAction<string>) => {
const newValue =
typeof value === "function" ? value(incitingIncident) : value;
setIncitingIncident(newValue); setIncitingIncident(newValue);
if (scriptEditUseCase) { if (scriptEditUseCase) {
scriptEditUseCase.updateStoryField('incitingIncident', newValue); scriptEditUseCase.updateStoryField("incitingIncident", newValue);
} }
}, [incitingIncident, scriptEditUseCase]); },
[incitingIncident, scriptEditUseCase]
);
const setProblemWrapper = useCallback((value: SetStateAction<string>) => { const setProblemWrapper = useCallback(
const newValue = typeof value === 'function' ? value(problem) : value; (value: SetStateAction<string>) => {
const newValue = typeof value === "function" ? value(problem) : value;
setProblem(newValue); setProblem(newValue);
if (scriptEditUseCase) { if (scriptEditUseCase) {
scriptEditUseCase.updateStoryField('problem', newValue); scriptEditUseCase.updateStoryField("problem", newValue);
} }
}, [problem, scriptEditUseCase]); },
[problem, scriptEditUseCase]
);
const setConflictWrapper = useCallback((value: SetStateAction<string>) => { const setConflictWrapper = useCallback(
const newValue = typeof value === 'function' ? value(conflict) : value; (value: SetStateAction<string>) => {
const newValue = typeof value === "function" ? value(conflict) : value;
setConflict(newValue); setConflict(newValue);
if (scriptEditUseCase) { if (scriptEditUseCase) {
scriptEditUseCase.updateStoryField('conflict', newValue); scriptEditUseCase.updateStoryField("conflict", newValue);
} }
}, [conflict, scriptEditUseCase]); },
[conflict, scriptEditUseCase]
);
const setStakesWrapper = useCallback((value: SetStateAction<string>) => { const setStakesWrapper = useCallback(
const newValue = typeof value === 'function' ? value(stakes) : value; (value: SetStateAction<string>) => {
const newValue = typeof value === "function" ? value(stakes) : value;
setStakes(newValue); setStakes(newValue);
if (scriptEditUseCase) { if (scriptEditUseCase) {
scriptEditUseCase.updateStoryField('stakes', newValue); scriptEditUseCase.updateStoryField("stakes", newValue);
} }
}, [stakes, scriptEditUseCase]); },
[stakes, scriptEditUseCase]
);
const setCharacterArcWrapper = useCallback((value: SetStateAction<string>) => { const setCharacterArcWrapper = useCallback(
const newValue = typeof value === 'function' ? value(characterArc) : value; (value: SetStateAction<string>) => {
const newValue =
typeof value === "function" ? value(characterArc) : value;
setCharacterArc(newValue); setCharacterArc(newValue);
if (scriptEditUseCase) { if (scriptEditUseCase) {
scriptEditUseCase.updateStoryField('characterArc', newValue); scriptEditUseCase.updateStoryField("characterArc", newValue);
} }
}, [characterArc, scriptEditUseCase]); },
[characterArc, scriptEditUseCase]
);
/** /**
* *
*/ */
const focusHandler = useCallback(async (field: ScriptEditKey): Promise<void> => { const focusHandler = useCallback(
async (field: ScriptEditKey): Promise<void> => {
try { try {
// 如果当前已经有聚焦的字段,先处理暂停/继续逻辑 // 如果当前已经有聚焦的字段,先处理暂停/继续逻辑
// 设置新的聚焦字段 // 设置新的聚焦字段
setFocusedField(field); setFocusedField(field);
} catch (error) { } catch (error) {
console.error("聚焦处理失败:", error); console.error("聚焦处理失败:", error);
throw error; throw error;
} }
}, []); },
[]
);
/** /**
* *
@ -372,7 +454,6 @@ export const useScriptService = (): UseScriptService => {
if (projectId) { if (projectId) {
await scriptEditUseCase.saveScript(projectId); await scriptEditUseCase.saveScript(projectId);
} }
} catch (error) { } catch (error) {
console.error("增强剧本失败:", error); console.error("增强剧本失败:", error);
throw error; throw error;
@ -382,18 +463,35 @@ export const useScriptService = (): UseScriptService => {
}, [scriptEditUseCase, synopsis, focusedField, aiOptimizing, projectId]); }, [scriptEditUseCase, synopsis, focusedField, aiOptimizing, projectId]);
// 在ScriptService中添加一个方法来获取渲染数据 // 在ScriptService中添加一个方法来获取渲染数据
const scriptBlocksMemo = useMemo((): ScriptBlock[] => { const scriptBlocksMemo = useMemo((): ScriptBlock[] => {
return [ return [
parseScriptBlock('synopsis', 'Logline', synopsis || ''), parseScriptBlock("synopsis", "Logline", synopsis || ""),
parseScriptBlock('categories', 'GENRE', categories.join(', ') || ''), parseScriptBlock("categories", "GENRE", categories.join(", ") || ""),
parseScriptBlock('protagonist', 'Core Identity', protagonist || ''), parseScriptBlock("protagonist", "Core Identity", protagonist || ""),
parseScriptBlock('incitingIncident', 'The Inciting Incident', incitingIncident || ''), parseScriptBlock(
parseScriptBlock('problem', 'The Problem & New Goal', problem || ''), "incitingIncident",
parseScriptBlock('conflict', 'Conflict & Obstacles', conflict || ''), "The Inciting Incident",
parseScriptBlock('stakes', 'The Stakes', stakes || ''), incitingIncident || ""
parseScriptBlock('characterArc', 'Character Arc Accomplished', characterArc || '') ),
parseScriptBlock("problem", "The Problem & New Goal", problem || ""),
parseScriptBlock("conflict", "Conflict & Obstacles", conflict || ""),
parseScriptBlock("stakes", "The Stakes", stakes || ""),
parseScriptBlock(
"characterArc",
"Character Arc Accomplished",
characterArc || ""
),
]; ];
}, [synopsis, categories, protagonist, incitingIncident, problem, conflict, stakes, characterArc]); }, [
synopsis,
categories,
protagonist,
incitingIncident,
problem,
conflict,
stakes,
characterArc,
]);
return { return {
// 响应式状态 // 响应式状态
@ -419,6 +517,9 @@ const scriptBlocksMemo = useMemo((): ScriptBlock[] => {
focusHandler, focusHandler,
enhanceScript, enhanceScript,
setAiOptimizing, setAiOptimizing,
setProjectId,
setPlanId,
createMovieProjectV1,
// 封装的set函数 // 封装的set函数
setSynopsis: setSynopsisWrapper, setSynopsis: setSynopsisWrapper,
setCategories: setCategoriesWrapper, setCategories: setCategoriesWrapper,

View File

@ -38,7 +38,8 @@ describe("ScriptService 业务逻辑测试", () => {
script, script,
"user123", "user123",
"auto", "auto",
"720p" "720p",
"en"
); );
expect(createRes.project_id).toBeDefined(); expect(createRes.project_id).toBeDefined();
projectId = createRes.project_id; projectId = createRes.project_id;

View File

@ -126,7 +126,8 @@ export class ScriptEditUseCase {
prompt: string, prompt: string,
userId: string , userId: string ,
mode: "auto" | "manual" = "auto", mode: "auto" | "manual" = "auto",
resolution: "720p" | "1080p" | "4k" = "720p" resolution: "720p" | "1080p" | "4k" = "720p",
language: string
) { ) {
try { try {
// 调用创建项目API // 调用创建项目API
@ -135,6 +136,7 @@ export class ScriptEditUseCase {
user_id: userId, user_id: userId,
mode, mode,
resolution, resolution,
language,
}); });
if (!response.successful) { if (!response.successful) {