forked from 77media/video-flow
153 lines
4.0 KiB
TypeScript
153 lines
4.0 KiB
TypeScript
import { ScriptSlice, ScriptValueObject } from "../domain/valueObject";
|
||
import { generateScriptStream, applyScriptToShot } from "@/api/video_flow";
|
||
|
||
export class ScriptEditUseCase {
|
||
loading: boolean = false;
|
||
private scriptValueObject: ScriptValueObject;
|
||
private abortController: AbortController | null = null;
|
||
|
||
constructor(script: string) {
|
||
this.scriptValueObject = new ScriptValueObject(script);
|
||
}
|
||
|
||
/**
|
||
* @description: AI生成剧本方法
|
||
* @param prompt 剧本提示词
|
||
* @param stream_callback 流式数据回调函数
|
||
* @returns Promise<void>
|
||
*/
|
||
async generateScript(prompt: string, stream_callback?: (data: any) => void): Promise<void> {
|
||
try {
|
||
this.loading = true;
|
||
|
||
// 创建新的中断控制器
|
||
this.abortController = new AbortController();
|
||
|
||
// 使用API接口生成剧本
|
||
const response = await generateScriptStream({
|
||
text: prompt,
|
||
});
|
||
|
||
if (!response.successful) {
|
||
throw new Error(response.message || "AI生成剧本失败");
|
||
}
|
||
|
||
// 使用for await处理流式数据
|
||
for await (const data of response.data) {
|
||
// 检查是否被中断
|
||
if (this.abortController.signal.aborted) {
|
||
console.log("剧本生成被中断");
|
||
break;
|
||
}
|
||
|
||
// TODO: 根据流式数据更新剧本片段
|
||
// 这里需要根据实际的流式数据格式来处理
|
||
// 可能需要将流式数据转换为ScriptSlice并添加到scriptValueObject中
|
||
stream_callback?.(data);
|
||
}
|
||
} catch (error) {
|
||
if (this.abortController?.signal.aborted) {
|
||
console.log("剧本生成被中断");
|
||
return;
|
||
}
|
||
console.error("AI生成剧本出错:", error);
|
||
throw error;
|
||
} finally {
|
||
this.loading = false;
|
||
this.abortController = null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description: 中断剧本生成
|
||
*/
|
||
abortGenerateScript(): void {
|
||
if (this.abortController) {
|
||
this.abortController.abort();
|
||
this.loading = false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description: 应用剧本方法
|
||
* @returns Promise<void>
|
||
*/
|
||
async applyScript(projectId: string): Promise<void> {
|
||
try {
|
||
this.loading = true;
|
||
|
||
// 调用应用剧本接口
|
||
const response = await applyScriptToShot({
|
||
projectId,
|
||
scriptText: this.scriptValueObject.toString(),
|
||
});
|
||
|
||
if (!response.successful) {
|
||
throw new Error(response.message || "应用剧本失败");
|
||
}
|
||
|
||
console.log("剧本应用成功");
|
||
} catch (error) {
|
||
console.error("应用剧本失败:", error);
|
||
throw error;
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description: 获取当前剧本片段列表
|
||
* @returns ScriptSlice[]
|
||
*/
|
||
getScriptSlices(): ScriptSlice[] {
|
||
return this.scriptValueObject.scriptSlices;
|
||
}
|
||
|
||
/**
|
||
* @description: 获取加载状态
|
||
* @returns boolean
|
||
*/
|
||
isLoading(): boolean {
|
||
return this.loading;
|
||
}
|
||
|
||
/**
|
||
* @description: 更新剧本
|
||
* @param scriptText 剧本文本字符串
|
||
*/
|
||
updateScript(scriptText: string): void {
|
||
this.scriptValueObject = new ScriptValueObject(scriptText);
|
||
}
|
||
|
||
/**
|
||
* @description: 将当前剧本片段转换为字符串
|
||
* @returns string
|
||
*/
|
||
toString(): string {
|
||
return this.scriptValueObject.toString();
|
||
}
|
||
|
||
/**
|
||
* @description: 更新指定ID的剧本片段
|
||
* @param id 剧本片段唯一标识
|
||
* @param text 新的文本内容
|
||
* @param metaData 新的元数据
|
||
* @returns boolean 是否更新成功
|
||
*/
|
||
updateScriptSlice(id: string, text: string, metaData?: Record<string, any>): boolean {
|
||
const index = this.scriptValueObject.scriptSlices.findIndex(slice => slice.id === id);
|
||
if (index === -1) {
|
||
return false;
|
||
}
|
||
|
||
// 只更新text和metaData字段,保持其他字段不变
|
||
this.scriptValueObject.scriptSlices[index] = {
|
||
...this.scriptValueObject.scriptSlices[index],
|
||
text,
|
||
metaData: metaData || this.scriptValueObject.scriptSlices[index].metaData
|
||
};
|
||
|
||
return true;
|
||
}
|
||
}
|