forked from 77media/video-flow
256 lines
6.2 KiB
TypeScript
256 lines
6.2 KiB
TypeScript
import { ScriptSlice, ScriptValueObject } from "../domain/valueObject";
|
||
import {
|
||
generateScriptStream,
|
||
applyScriptToShot,
|
||
createMovieProjectV1,
|
||
saveScript,
|
||
enhanceScriptStream,
|
||
} from "@/api/video_flow";
|
||
|
||
export type ScriptEditKey = 'synopsis' | 'categories' | 'protagonist' | 'incitingIncident' | 'problem' | 'conflict' | 'stakes' | 'characterArc';
|
||
|
||
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接口生成剧本
|
||
await generateScriptStream(
|
||
{
|
||
text: prompt,
|
||
},
|
||
(content) => {
|
||
stream_callback?.(content);
|
||
this.scriptValueObject.parseFromString(content);
|
||
}
|
||
);
|
||
} 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: 增强剧本方法
|
||
* @param scriptData 剧本数据
|
||
* @param stream_callback 流式数据回调函数
|
||
* @returns Promise<void>
|
||
*/
|
||
async enhanceScript(
|
||
newScript: string|string[],
|
||
key: ScriptEditKey,
|
||
aiOptimizing: string,
|
||
stream_callback?: (data: any) => void
|
||
): Promise<void> {
|
||
try {
|
||
this.loading = true;
|
||
|
||
// 创建新的中断控制器
|
||
this.abortController = new AbortController();
|
||
|
||
// 获取当前剧本文本
|
||
const originalScript = this.scriptValueObject.toString();
|
||
// 清空当前剧本
|
||
this.scriptValueObject = new ScriptValueObject("");
|
||
// 使用API接口增强剧本
|
||
await enhanceScriptStream(
|
||
{
|
||
original_script: originalScript,
|
||
[key]: newScript,
|
||
aiOptimizing,
|
||
},
|
||
(content) => {
|
||
stream_callback?.(content);
|
||
this.scriptValueObject.parseFromString(content);
|
||
}
|
||
);
|
||
} catch (error) {
|
||
if (this.abortController?.signal.aborted) {
|
||
console.log("剧本增强被中断");
|
||
return;
|
||
}
|
||
console.error("AI增强剧本出错:", error);
|
||
throw error;
|
||
} finally {
|
||
this.loading = false;
|
||
this.abortController = null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description: 创建项目
|
||
* @param prompt 用户提示词
|
||
* @param userId 用户ID
|
||
* @param mode automatic | manual
|
||
* @param resolution 分辨率:720p | 1080p | 4k
|
||
* @returns Promise<string> 返回项目ID
|
||
*/
|
||
async createProject(
|
||
prompt: string,
|
||
userId: string ,
|
||
mode: "automatic" | "manual" = "automatic",
|
||
resolution: "720p" | "1080p" | "4k" = "720p",
|
||
language: string
|
||
) {
|
||
try {
|
||
// 调用创建项目API
|
||
const response = await createMovieProjectV1({
|
||
script: prompt,
|
||
user_id: userId,
|
||
mode,
|
||
resolution,
|
||
language,
|
||
});
|
||
|
||
if (!response.successful) {
|
||
throw new Error(response.message || "创建项目失败");
|
||
}
|
||
return response.data;
|
||
} catch (error) {
|
||
console.error("创建项目失败:", error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description: 保存剧本
|
||
* @param projectId 项目ID
|
||
* @param scriptData 剧本数据
|
||
* @returns Promise<void>
|
||
*/
|
||
async saveScript(
|
||
projectId: string,
|
||
): Promise<void> {
|
||
try {
|
||
this.loading = true;
|
||
|
||
// 获取当前剧本文本
|
||
const scriptText = this.scriptValueObject.toString();
|
||
|
||
// 调用保存剧本API
|
||
const response = await saveScript({
|
||
project_id: projectId,
|
||
generated_script: scriptText,
|
||
});
|
||
|
||
if (!response.successful) {
|
||
throw new Error(response.message || "保存剧本失败");
|
||
}
|
||
return response.data;
|
||
} catch (error) {
|
||
console.error("保存剧本失败:", error);
|
||
throw error;
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
}
|
||
/**
|
||
* @description: 应用剧本方法
|
||
* @returns Promise<void>
|
||
*/
|
||
async applyScript(projectId: string, planId: string): Promise<void> {
|
||
try {
|
||
this.loading = true;
|
||
|
||
// 调用应用剧本接口
|
||
const response = await applyScriptToShot({
|
||
project_id: projectId,
|
||
plan_id: planId,
|
||
});
|
||
|
||
if (!response.successful) {
|
||
throw new Error(response.message || "应用剧本失败");
|
||
}
|
||
|
||
console.log("剧本应用成功");
|
||
} catch (error) {
|
||
console.error("应用剧本失败:", error);
|
||
throw error;
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description: 获取当前剧本故事详情
|
||
* @returns StoryDetails
|
||
*/
|
||
getStoryDetails() {
|
||
return this.scriptValueObject.storyDetails.toObject();
|
||
}
|
||
/**
|
||
* @description: 更新剧本
|
||
* @param scriptText 新的剧本文本
|
||
*/
|
||
updateScript(scriptText: string): void {
|
||
this.scriptValueObject = new ScriptValueObject(scriptText);
|
||
}
|
||
|
||
/**
|
||
* @description: 更新故事详情字段
|
||
* @param field 字段名
|
||
* @param value 字段值
|
||
*/
|
||
updateStoryField(field: ScriptEditKey, value: string | string[]): void {
|
||
const storyDetails = this.scriptValueObject.storyDetails;
|
||
if(field === 'categories'){
|
||
storyDetails.categories = value as string[];
|
||
}else{
|
||
storyDetails[field] = value as string;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description: 获取加载状态
|
||
* @returns boolean
|
||
*/
|
||
isLoading(): boolean {
|
||
return this.loading;
|
||
}
|
||
|
||
/**
|
||
* @description: 将当前剧本片段转换为字符串
|
||
* @returns string
|
||
*/
|
||
toString(): string {
|
||
return this.scriptValueObject.toString();
|
||
}
|
||
}
|