video-flow-b/app/service/Interaction/ScriptService.ts

292 lines
8.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useCallback, useMemo } from "react";
import { ScriptSlice } from "../domain/valueObject";
import { ScriptEditUseCase } from "../usecase/ScriptEditUseCase";
import { getProjectScript, saveScript as saveScriptAPI, createProject as createProjectAPI } from "../../../api/video_flow";
import { throttle } from "@/utils/tools";
/**
* 剧本服务Hook接口
* 定义剧本服务Hook的所有状态和操作方法
*/
export interface UseScriptService {
// 响应式状态
/** 当前剧本文本 */
scriptText: string;
/** 剧本片段列表 */
scriptSlices: ScriptSlice[];
/** 用户提示词(可编辑) */
userPrompt: string;
/** 加载状态 */
loading: boolean;
/** 项目ID */
projectId: string;
// 操作方法
/** 获取根据用户想法调用接口AI生成剧本用户提示词 */
fetchScriptData: (prompt: string) => Promise<void>;
/** 根据项目ID获取已存在的剧本数据 */
fetchProjectScript: (projectId: string) => Promise<void>;
/** 更新用户提示词 */
updateUserPrompt: (prompt: string) => void;
/** 重置剧本内容到初始状态 */
resetScript: () => void;
/** 应用剧本 */
applyScript: () => Promise<void>;
/** 中断剧本生成 */
abortGenerateScript: () => void;
/** 保存剧本 */
saveScript: () => Promise<void>;
/** 创建项目 */
createProject: () => Promise<void>;
}
/**
* 剧本服务Hook
* 提供剧本相关的所有状态管理和操作方法
* 包括剧本数据获取、片段管理等功能
*/
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 [projectId, setProjectId] = useState<string>("");
// UseCase实例
const [scriptEditUseCase, setScriptEditUseCase] = useState<ScriptEditUseCase | null>(null);
/**
* 初始化ai生成剧本用户提示词
* @param prompt 用户提示词
*/
const fetchScriptData = useCallback(async (prompt: string): Promise<void> => {
try {
setLoading(true);
// 清空当前状态
setScriptText("");
setScriptSlices([]);
// 更新用户提示词状态
setUserPrompt(prompt);
// 创建新的剧本编辑用例
const newScriptEditUseCase = new ScriptEditUseCase('');
setScriptEditUseCase(newScriptEditUseCase);
// 调用AI生成剧本
await newScriptEditUseCase.generateScript(prompt,throttle((newContent)=>{
// 获取生成的剧本文本
const generatedScriptText = newScriptEditUseCase.toString();
setScriptText(generatedScriptText);
console.log(scriptText);
// 获取剧本片段列表
const slices = newScriptEditUseCase.getScriptSlices();
setScriptSlices(slices);
// 保存初始剧本文本(只在第一次获取时保存)
if (!initialScriptText) {
setInitialScriptText(generatedScriptText);
}
}));
} catch (error) {
console.error('获取剧本数据失败:', error);
throw error;
} finally {
setLoading(false);
}
}, [initialScriptText]);
/**
* 根据项目ID获取已存在的剧本数据
* @param projectId 项目ID
*/
const fetchProjectScript = useCallback(async (projectId: string): Promise<void> => {
try {
setLoading(true);
// 清空当前状态
setScriptText("");
setScriptSlices([]);
// 设置项目ID
setProjectId(projectId);
// 调用API获取项目剧本数据
const response = await getProjectScript({ projectId });
if (!response.successful) {
throw new Error(response.message || '获取项目剧本失败');
}
const { prompt, scriptText } = response.data;
// 更新用户提示词状态
setUserPrompt(prompt);
// 保存初始剧本文本(只在第一次获取时保存)
if (!initialScriptText) {
setInitialScriptText(scriptText);
}
// 创建新的剧本编辑用例并初始化数据
const newScriptEditUseCase = new ScriptEditUseCase(scriptText);
setScriptEditUseCase(newScriptEditUseCase);
// 设置剧本文本
setScriptText(scriptText);
// 从UseCase获取解析后的剧本片段
const scriptSlices = newScriptEditUseCase.getScriptSlices();
setScriptSlices(scriptSlices);
} catch (error) {
console.error('获取项目剧本数据失败:', error);
throw error;
} finally {
setLoading(false);
}
}, [initialScriptText]);
/**
* 更新用户提示词
* @param prompt 新的用户提示词
*/
const updateUserPrompt = useCallback((prompt: string): void => {
setUserPrompt(prompt);
}, []);
/**
* 重置剧本内容到初始状态
*/
const resetScript = useCallback((): void => {
if (initialScriptText && scriptEditUseCase) {
// 重置剧本文本到初始状态
setScriptText(initialScriptText);
// 更新现有剧本编辑用例的数据
scriptEditUseCase.updateScript(initialScriptText);
// 从UseCase获取解析后的剧本片段
const scriptSlices = scriptEditUseCase.getScriptSlices();
setScriptSlices(scriptSlices);
}
}, [initialScriptText, scriptEditUseCase]);
/**
* 应用剧本
*/
const applyScript = useCallback(async (): Promise<void> => {
try {
setLoading(true);
if (!scriptEditUseCase) {
throw new Error("剧本编辑用例未初始化");
}
await scriptEditUseCase.applyScript(projectId);
} catch (error) {
console.error("应用剧本失败:", error);
throw error;
} finally {
setLoading(false);
}
}, [scriptEditUseCase, projectId]);
/**
* 中断剧本生成
*/
const abortGenerateScript = useCallback((): void => {
if (scriptEditUseCase) {
scriptEditUseCase.abortGenerateScript();
setLoading(false);
}
}, [scriptEditUseCase]);
/**
* 保存剧本
*/
const saveScript = useCallback(async (): Promise<void> => {
try {
setLoading(true);
if (!projectId) {
throw new Error("项目ID未设置");
}
if (!scriptEditUseCase) {
throw new Error("剧本编辑用例未初始化");
}
// 调用保存剧本接口
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) {
throw new Error(response.message || '创建项目失败');
}
const { projectId: newProjectId } = response.data;
setProjectId(newProjectId);
console.log("项目创建成功");
} catch (error) {
console.error("创建项目失败:", error);
throw error;
} finally {
setLoading(false);
}
}, [userPrompt, scriptText]);
return {
// 响应式状态
scriptText,
scriptSlices,
userPrompt,
loading,
projectId,
// 操作方法
fetchScriptData,
fetchProjectScript,
updateUserPrompt,
resetScript,
applyScript,
abortGenerateScript,
saveScript,
createProject,
};
};