forked from 77media/video-flow
删除多余内容
This commit is contained in:
parent
073bc6db13
commit
5686ebd6f2
@ -1,8 +1,6 @@
|
|||||||
import { useState, useCallback, useMemo } from "react";
|
import { useState, useCallback } from "react";
|
||||||
import { ScriptSlice } from "../domain/valueObject";
|
|
||||||
import { ScriptEditUseCase } from "../usecase/ScriptEditUseCase";
|
import { ScriptEditUseCase } from "../usecase/ScriptEditUseCase";
|
||||||
import { getProjectScript, saveScript as saveScriptAPI, createProject as createProjectAPI } from "../../../api/video_flow";
|
import { getProjectScript, abortVideoTask } from "../../../api/video_flow";
|
||||||
import { throttle } from "@/utils/tools";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 剧本服务Hook接口
|
* 剧本服务Hook接口
|
||||||
@ -10,170 +8,179 @@ import { throttle } from "@/utils/tools";
|
|||||||
*/
|
*/
|
||||||
export interface UseScriptService {
|
export interface UseScriptService {
|
||||||
// 响应式状态
|
// 响应式状态
|
||||||
/** 当前剧本文本 */
|
|
||||||
scriptText: string;
|
|
||||||
/** 剧本片段列表 */
|
|
||||||
scriptSlices: ScriptSlice[];
|
|
||||||
/** 用户提示词(可编辑) */
|
|
||||||
userPrompt: string;
|
|
||||||
/** 加载状态 */
|
/** 加载状态 */
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
/** 故事梗概 */
|
||||||
|
synopsis: string;
|
||||||
|
/** 故事分类 */
|
||||||
|
categories: string[];
|
||||||
|
/** 主角名称 */
|
||||||
|
protagonist: string;
|
||||||
|
/** 激励事件 */
|
||||||
|
incitingIncident: string;
|
||||||
|
/** 问题与新目标 */
|
||||||
|
problem: string;
|
||||||
|
/** 冲突与障碍 */
|
||||||
|
conflict: string;
|
||||||
|
/** 赌注 */
|
||||||
|
stakes: string;
|
||||||
|
/** 人物弧线完成 */
|
||||||
|
characterArc: string;
|
||||||
/** 项目ID */
|
/** 项目ID */
|
||||||
projectId: string;
|
projectId: string;
|
||||||
|
/** 计划ID */
|
||||||
|
planId: string;
|
||||||
|
|
||||||
// 操作方法
|
// 操作方法
|
||||||
/** 获取根据用户想法调用接口AI生成剧本(用户提示词) */
|
/** 根据用户想法生成剧本并自动创建项目 */
|
||||||
fetchScriptData: (prompt: string) => Promise<void>;
|
generateScriptFromIdea: (idea: string) => Promise<void>;
|
||||||
/** 根据项目ID获取已存在的剧本数据 */
|
/** 根据项目ID初始化已有剧本 */
|
||||||
fetchProjectScript: (projectId: string) => Promise<void>;
|
initializeFromProject: (projectId: string) => Promise<void>;
|
||||||
/** 更新用户提示词 */
|
/** 修改剧本 */
|
||||||
updateUserPrompt: (prompt: string) => void;
|
updateScript: (scriptText: string) => void;
|
||||||
/** 重置剧本内容到初始状态 */
|
/** 应用剧本到视频生成流程 */
|
||||||
resetScript: () => void;
|
|
||||||
/** 应用剧本 */
|
|
||||||
applyScript: () => Promise<void>;
|
applyScript: () => Promise<void>;
|
||||||
/** 中断剧本生成 */
|
/** 中断视频任务 */
|
||||||
abortGenerateScript: () => void;
|
abortVideoTask: () => Promise<void>;
|
||||||
/** 保存剧本 */
|
|
||||||
saveScript: () => Promise<void>;
|
|
||||||
/** 创建项目 */
|
|
||||||
createProject: () => Promise<void>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 剧本服务Hook
|
* 剧本服务Hook
|
||||||
* 提供剧本相关的所有状态管理和操作方法
|
* 提供剧本相关的所有状态管理和操作方法
|
||||||
* 包括剧本数据获取、片段管理等功能
|
* 包括剧本生成、项目创建、剧本保存等功能
|
||||||
*/
|
*/
|
||||||
export const useScriptService = (): UseScriptService => {
|
export const useScriptService = (): UseScriptService => {
|
||||||
// 响应式状态
|
// 响应式状态
|
||||||
const [scriptText, setScriptText] = useState<string>("");
|
|
||||||
const [scriptSlices, setScriptSlices] = useState<ScriptSlice[]>([]);
|
|
||||||
const [userPrompt, setUserPrompt] = useState<string>("");
|
|
||||||
const [initialScriptText, setInitialScriptText] = useState<string>("");
|
|
||||||
const [loading, setLoading] = useState<boolean>(false);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
const [synopsis, setSynopsis] = useState<string>("");
|
||||||
|
const [categories, setCategories] = useState<string[]>([]);
|
||||||
|
const [protagonist, setProtagonist] = useState<string>("");
|
||||||
|
const [incitingIncident, setIncitingIncident] = useState<string>("");
|
||||||
|
const [problem, setProblem] = useState<string>("");
|
||||||
|
const [conflict, setConflict] = useState<string>("");
|
||||||
|
const [stakes, setStakes] = useState<string>("");
|
||||||
|
const [characterArc, setCharacterArc] = useState<string>("");
|
||||||
const [projectId, setProjectId] = useState<string>("");
|
const [projectId, setProjectId] = useState<string>("");
|
||||||
|
const [planId, setPlanId] = useState<string>("");
|
||||||
|
|
||||||
// UseCase实例
|
// UseCase实例
|
||||||
const [scriptEditUseCase, setScriptEditUseCase] = useState<ScriptEditUseCase | null>(null);
|
const [scriptEditUseCase, setScriptEditUseCase] = useState<ScriptEditUseCase | null>(null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化,ai生成剧本(用户提示词)
|
* 根据用户想法生成剧本并自动创建项目
|
||||||
* @param prompt 用户提示词
|
* @param idea 用户想法
|
||||||
*/
|
*/
|
||||||
const fetchScriptData = useCallback(async (prompt: string): Promise<void> => {
|
const generateScriptFromIdea = useCallback(async (idea: string): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// 清空当前状态
|
|
||||||
setScriptText("");
|
|
||||||
setScriptSlices([]);
|
|
||||||
|
|
||||||
// 更新用户提示词状态
|
|
||||||
setUserPrompt(prompt);
|
|
||||||
|
|
||||||
// 创建新的剧本编辑用例
|
// 创建新的剧本编辑用例
|
||||||
const newScriptEditUseCase = new ScriptEditUseCase('');
|
const newScriptEditUseCase = new ScriptEditUseCase('');
|
||||||
setScriptEditUseCase(newScriptEditUseCase);
|
setScriptEditUseCase(newScriptEditUseCase);
|
||||||
|
|
||||||
// 调用AI生成剧本
|
// 调用AI生成剧本
|
||||||
await newScriptEditUseCase.generateScript(prompt,throttle((newContent)=>{
|
await newScriptEditUseCase.generateScript(idea, (content) => {
|
||||||
// 获取生成的剧本文本
|
// 获取解析后的故事详情
|
||||||
const generatedScriptText = newScriptEditUseCase.toString();
|
const storyDetails = newScriptEditUseCase.getStoryDetails();
|
||||||
setScriptText(generatedScriptText);
|
setSynopsis(storyDetails.synopsis || "");
|
||||||
console.log(scriptText);
|
setCategories(storyDetails.categories || []);
|
||||||
|
setProtagonist(storyDetails.protagonist || "");
|
||||||
|
setIncitingIncident(storyDetails.incitingIncident || "");
|
||||||
|
setProblem(storyDetails.problem || "");
|
||||||
|
setConflict(storyDetails.conflict || "");
|
||||||
|
setStakes(storyDetails.stakes || "");
|
||||||
|
setCharacterArc(storyDetails.characterArc || "");
|
||||||
|
});
|
||||||
|
|
||||||
// 获取剧本片段列表
|
// 剧本生成完成后,自动创建项目
|
||||||
const slices = newScriptEditUseCase.getScriptSlices();
|
const projectData = await newScriptEditUseCase.createProject(
|
||||||
setScriptSlices(slices);
|
idea,
|
||||||
|
"user123",
|
||||||
|
"auto",
|
||||||
|
"720p"
|
||||||
|
);
|
||||||
|
|
||||||
// 保存初始剧本文本(只在第一次获取时保存)
|
setProjectId(projectData.project_id);
|
||||||
if (!initialScriptText) {
|
setPlanId(projectData.plan_id);
|
||||||
setInitialScriptText(generatedScriptText);
|
|
||||||
}
|
// 自动保存剧本到项目
|
||||||
}));
|
await newScriptEditUseCase.saveScript(projectData.project_id);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取剧本数据失败:', error);
|
console.error('生成剧本失败:', error);
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [initialScriptText]);
|
}, []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据项目ID获取已存在的剧本数据
|
* 根据项目ID初始化已有剧本
|
||||||
* @param projectId 项目ID
|
* @param projectId 项目ID
|
||||||
*/
|
*/
|
||||||
const fetchProjectScript = useCallback(async (projectId: string): Promise<void> => {
|
const initializeFromProject = useCallback(async (projectId: string): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// 清空当前状态
|
|
||||||
setScriptText("");
|
|
||||||
setScriptSlices([]);
|
|
||||||
|
|
||||||
// 设置项目ID
|
// 设置项目ID
|
||||||
setProjectId(projectId);
|
setProjectId(projectId);
|
||||||
|
|
||||||
// 调用API获取项目剧本数据
|
// 调用API获取项目剧本数据
|
||||||
const response = await getProjectScript({ 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 { prompt, scriptText } = response.data;
|
const { generated_script } = response.data;
|
||||||
|
|
||||||
// 更新用户提示词状态
|
|
||||||
setUserPrompt(prompt);
|
|
||||||
|
|
||||||
// 保存初始剧本文本(只在第一次获取时保存)
|
|
||||||
if (!initialScriptText) {
|
|
||||||
setInitialScriptText(scriptText);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建新的剧本编辑用例并初始化数据
|
// 创建新的剧本编辑用例并初始化数据
|
||||||
const newScriptEditUseCase = new ScriptEditUseCase(scriptText);
|
const newScriptEditUseCase = new ScriptEditUseCase(generated_script);
|
||||||
setScriptEditUseCase(newScriptEditUseCase);
|
setScriptEditUseCase(newScriptEditUseCase);
|
||||||
|
|
||||||
// 设置剧本文本
|
// 获取解析后的故事详情
|
||||||
setScriptText(scriptText);
|
const storyDetails = newScriptEditUseCase.getStoryDetails();
|
||||||
|
setSynopsis(storyDetails.synopsis || "");
|
||||||
// 从UseCase获取解析后的剧本片段
|
setCategories(storyDetails.categories || []);
|
||||||
const scriptSlices = newScriptEditUseCase.getScriptSlices();
|
setProtagonist(storyDetails.protagonist || "");
|
||||||
setScriptSlices(scriptSlices);
|
setIncitingIncident(storyDetails.incitingIncident || "");
|
||||||
|
setProblem(storyDetails.problem || "");
|
||||||
|
setConflict(storyDetails.conflict || "");
|
||||||
|
setStakes(storyDetails.stakes || "");
|
||||||
|
setCharacterArc(storyDetails.characterArc || "");
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取项目剧本数据失败:', error);
|
console.error('初始化项目剧本失败:', error);
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [initialScriptText]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新用户提示词
|
|
||||||
* @param prompt 新的用户提示词
|
|
||||||
*/
|
|
||||||
const updateUserPrompt = useCallback((prompt: string): void => {
|
|
||||||
setUserPrompt(prompt);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重置剧本内容到初始状态
|
* 修改剧本
|
||||||
|
* @param scriptText 新的剧本文本
|
||||||
*/
|
*/
|
||||||
const resetScript = useCallback((): void => {
|
const updateScript = useCallback((scriptText: string): void => {
|
||||||
if (initialScriptText && scriptEditUseCase) {
|
if (scriptEditUseCase) {
|
||||||
// 重置剧本文本到初始状态
|
scriptEditUseCase.updateScript(scriptText);
|
||||||
setScriptText(initialScriptText);
|
|
||||||
// 更新现有剧本编辑用例的数据
|
// 更新解析后的故事详情
|
||||||
scriptEditUseCase.updateScript(initialScriptText);
|
const storyDetails = scriptEditUseCase.getStoryDetails();
|
||||||
// 从UseCase获取解析后的剧本片段
|
setSynopsis(storyDetails.synopsis || "");
|
||||||
const scriptSlices = scriptEditUseCase.getScriptSlices();
|
setCategories(storyDetails.categories || []);
|
||||||
setScriptSlices(scriptSlices);
|
setProtagonist(storyDetails.protagonist || "");
|
||||||
|
setIncitingIncident(storyDetails.incitingIncident || "");
|
||||||
|
setProblem(storyDetails.problem || "");
|
||||||
|
setConflict(storyDetails.conflict || "");
|
||||||
|
setStakes(storyDetails.stakes || "");
|
||||||
|
setCharacterArc(storyDetails.characterArc || "");
|
||||||
}
|
}
|
||||||
}, [initialScriptText, scriptEditUseCase]);
|
}, [scriptEditUseCase]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用剧本
|
* 应用剧本到视频生成流程
|
||||||
*/
|
*/
|
||||||
const applyScript = useCallback(async (): Promise<void> => {
|
const applyScript = useCallback(async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
@ -183,7 +190,11 @@ export const useScriptService = (): UseScriptService => {
|
|||||||
throw new Error("剧本编辑用例未初始化");
|
throw new Error("剧本编辑用例未初始化");
|
||||||
}
|
}
|
||||||
|
|
||||||
await scriptEditUseCase.applyScript(projectId);
|
if (!projectId || !planId) {
|
||||||
|
throw new Error("项目ID或计划ID未设置");
|
||||||
|
}
|
||||||
|
|
||||||
|
await scriptEditUseCase.applyScript(projectId, planId);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("应用剧本失败:", error);
|
console.error("应用剧本失败:", error);
|
||||||
@ -191,101 +202,55 @@ export const useScriptService = (): UseScriptService => {
|
|||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [scriptEditUseCase, projectId]);
|
}, [scriptEditUseCase, projectId, planId]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 中断剧本生成
|
* 中断视频任务
|
||||||
*/
|
*/
|
||||||
const abortGenerateScript = useCallback((): void => {
|
const abortVideoTaskHandler = useCallback(async (): Promise<void> => {
|
||||||
if (scriptEditUseCase) {
|
|
||||||
scriptEditUseCase.abortGenerateScript();
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}, [scriptEditUseCase]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存剧本
|
|
||||||
*/
|
|
||||||
const saveScript = useCallback(async (): Promise<void> => {
|
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
|
||||||
|
|
||||||
if (!projectId) {
|
if (!projectId || !planId) {
|
||||||
throw new Error("项目ID未设置");
|
throw new Error("项目ID或计划ID未设置");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!scriptEditUseCase) {
|
// 调用中断视频任务API
|
||||||
throw new Error("剧本编辑用例未初始化");
|
const response = await abortVideoTask({
|
||||||
}
|
project_id: projectId,
|
||||||
|
plan_id: planId
|
||||||
// 调用保存剧本接口
|
|
||||||
const scriptText = scriptEditUseCase.toString();
|
|
||||||
const response = await saveScriptAPI({ projectId, scriptText });
|
|
||||||
|
|
||||||
if (!response.successful) {
|
|
||||||
throw new Error(response.message || '保存剧本失败');
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("剧本保存成功");
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error("保存剧本失败:", error);
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}, [projectId, scriptEditUseCase]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建项目
|
|
||||||
* @throws {Error} - 创建项目失败时抛出异常
|
|
||||||
*/
|
|
||||||
const createProject = useCallback(async (): Promise<void> => {
|
|
||||||
try {
|
|
||||||
setLoading(true);
|
|
||||||
|
|
||||||
// 直接使用当前state中的userPrompt和scriptText
|
|
||||||
const currentUserPrompt = userPrompt;
|
|
||||||
const currentScriptContent = scriptText;
|
|
||||||
|
|
||||||
const response = await createProjectAPI({
|
|
||||||
userPrompt: currentUserPrompt,
|
|
||||||
scriptContent: currentScriptContent
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.successful) {
|
if (!response.successful) {
|
||||||
throw new Error(response.message || '创建项目失败');
|
throw new Error(response.message || "中断视频任务失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
const { projectId: newProjectId } = response.data;
|
console.log("视频任务中断成功");
|
||||||
setProjectId(newProjectId);
|
|
||||||
|
|
||||||
console.log("项目创建成功");
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("创建项目失败:", error);
|
console.error("中断视频任务失败:", error);
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
}
|
||||||
}, [userPrompt, scriptText]);
|
}, [projectId, planId]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// 响应式状态
|
// 响应式状态
|
||||||
scriptText,
|
|
||||||
scriptSlices,
|
|
||||||
userPrompt,
|
|
||||||
loading,
|
loading,
|
||||||
|
synopsis,
|
||||||
|
categories,
|
||||||
|
protagonist,
|
||||||
|
incitingIncident,
|
||||||
|
problem,
|
||||||
|
conflict,
|
||||||
|
stakes,
|
||||||
|
characterArc,
|
||||||
projectId,
|
projectId,
|
||||||
|
planId,
|
||||||
|
|
||||||
// 操作方法
|
// 操作方法
|
||||||
fetchScriptData,
|
generateScriptFromIdea,
|
||||||
fetchProjectScript,
|
initializeFromProject,
|
||||||
updateUserPrompt,
|
updateScript,
|
||||||
resetScript,
|
|
||||||
applyScript,
|
applyScript,
|
||||||
abortGenerateScript,
|
abortVideoTask: abortVideoTaskHandler,
|
||||||
saveScript,
|
|
||||||
createProject,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user