修复问题

This commit is contained in:
海龙 2025-08-07 19:30:29 +08:00
parent 4291704b0b
commit f7b1c62df3
5 changed files with 87 additions and 97 deletions

View File

@ -617,8 +617,6 @@ export const generateScriptStream = (
export const applyScriptToShot = async (request: { export const applyScriptToShot = async (request: {
/** 项目ID */ /** 项目ID */
project_id: string; project_id: string;
/** 计划Id*/
plan_id: string;
})=> { })=> {
return post<ApiResponse<any>>("/movie/create_movie_project_plan_v1", request); return post<ApiResponse<any>>("/movie/create_movie_project_plan_v1", request);
}; };
@ -659,17 +657,14 @@ export const saveScript = async (request: {
/** /**
* V1版本 *
* @param request
* @returns Promise<ApiResponse<{ projectId: string }>> * @returns Promise<ApiResponse<{ projectId: string }>>
*/ */
export const abortVideoTask = async (request: { export const abortVideoTask = async (request: {
/** 项目ID */ /** 项目ID */
project_id: string; project_id: string;
/** 计划ID */
plan_id: string;
}): Promise<ApiResponse<any>> => { }): Promise<ApiResponse<any>> => {
return post("/api/v1/video/abort", request); return post("/movie/abort_video_task", request);
}; };
export const pausePlanFlow = async (request: { export const pausePlanFlow = async (request: {

View File

@ -41,8 +41,6 @@ export interface UseScriptService {
characterArc: string; characterArc: string;
/** 项目ID */ /** 项目ID */
projectId: string; projectId: string;
/** 计划ID */
planId: string;
/** AI优化要求 */ /** AI优化要求 */
aiOptimizing: string; aiOptimizing: string;
/** 渲染数据 */ /** 渲染数据 */
@ -58,18 +56,6 @@ export interface UseScriptService {
applyScript: () => Promise<void>; applyScript: () => Promise<void>;
/** 中断视频任务 */ /** 中断视频任务 */
abortVideoTask: () => Promise<void>; abortVideoTask: () => Promise<void>;
/** 聚焦处理函数 */
focusHandler: (
field:
| "synopsis"
| "categories"
| "protagonist"
| "incitingIncident"
| "problem"
| "conflict"
| "stakes"
| "characterArc"
) => Promise<void>;
/** 增强剧本 */ /** 增强剧本 */
enhanceScript: () => Promise<void>; enhanceScript: () => Promise<void>;
/** 设置AI优化要求 */ /** 设置AI优化要求 */
@ -95,8 +81,6 @@ export interface UseScriptService {
/** 设置项目ID */ /** 设置项目ID */
setProjectId: Dispatch<SetStateAction<string>>; setProjectId: Dispatch<SetStateAction<string>>;
/** 设置计划ID */
setPlanId: Dispatch<SetStateAction<string>>;
/** 创建项目 */ /** 创建项目 */
createMovieProjectV1: ( createMovieProjectV1: (
idea: string, idea: string,
@ -127,9 +111,8 @@ export const useScriptService = (): UseScriptService => {
const [stakes, setStakes] = useState<string>(""); const [stakes, setStakes] = useState<string>("");
const [characterArc, setCharacterArc] = useState<string>(""); const [characterArc, setCharacterArc] = useState<string>("");
const [projectId, setProjectId] = useState<string>(""); const [projectId, setProjectId] = useState<string>("");
const [planId, setPlanId] = useState<string>("");
const [aiOptimizing, setAiOptimizing] = useState<string>(""); const [aiOptimizing, setAiOptimizing] = useState<string>("");
const [focusedField, setFocusedField] = useState<string>(""); const [fieldOld, setFieldOld] = useState<string>("");//旧的剧本内容
// UseCase实例 // UseCase实例
const [scriptEditUseCase, setScriptEditUseCase] = useState<ScriptEditUseCase>( const [scriptEditUseCase, setScriptEditUseCase] = useState<ScriptEditUseCase>(
@ -193,7 +176,6 @@ export const useScriptService = (): UseScriptService => {
); );
setProjectId(projectData.project_id); setProjectId(projectData.project_id);
setPlanId(projectData.plan_id);
} catch (error) { } catch (error) {
console.error("创建项目失败:", error); console.error("创建项目失败:", error);
throw error; throw error;
@ -278,32 +260,31 @@ export const useScriptService = (): UseScriptService => {
throw new Error("剧本编辑用例未初始化"); throw new Error("剧本编辑用例未初始化");
} }
if (!projectId || !planId) { if (!projectId) {
throw new Error("项目ID或计划ID未设置"); throw new Error("项目ID或计划ID未设置");
} }
await scriptEditUseCase.applyScript(projectId, planId); await scriptEditUseCase.applyScript(projectId);
} catch (error) { } catch (error) {
console.error("应用剧本失败:", error); console.error("应用剧本失败:", error);
throw error; throw error;
} finally { } finally {
setLoading(false); setLoading(false);
} }
}, [scriptEditUseCase, projectId, planId]); }, [scriptEditUseCase, projectId]);
/** /**
* *
*/ */
const abortVideoTaskHandler = useCallback(async (): Promise<void> => { const abortVideoTaskHandler = useCallback(async (): Promise<void> => {
try { try {
if (!projectId || !planId) { if (!projectId) {
throw new Error("项目ID或计划ID未设置"); throw new Error("项目ID或计划ID未设置");
} }
// 调用中断视频任务API // 调用中断视频任务API
const response = await abortVideoTask({ const response = await abortVideoTask({
project_id: projectId, project_id: projectId,
plan_id: planId,
}); });
if (!response.successful) { if (!response.successful) {
@ -315,7 +296,7 @@ export const useScriptService = (): UseScriptService => {
console.error("中断视频任务失败:", error); console.error("中断视频任务失败:", error);
throw error; throw error;
} }
}, [projectId, planId]); }, [projectId]);
// 封装的setter函数同时更新hook状态和scriptEditUseCase中的值对象 // 封装的setter函数同时更新hook状态和scriptEditUseCase中的值对象
const setSynopsisWrapper = useCallback( const setSynopsisWrapper = useCallback(
@ -413,44 +394,42 @@ export const useScriptService = (): UseScriptService => {
(type: string, value: SetStateAction<string>, tags?: string[]) => { (type: string, value: SetStateAction<string>, tags?: string[]) => {
console.log('setAnyAttributeWrapper', type); console.log('setAnyAttributeWrapper', type);
if (type === 'synopsis') { if (type === 'synopsis') {
setFieldOld(synopsis)
scriptEditUseCase.replaceScript(fieldOld,synopsis)
setSynopsisWrapper(value); setSynopsisWrapper(value);
} else if (type === 'categories') { } else if (type === 'categories') {
setFieldOld(categories.join(','))
scriptEditUseCase.replaceScript(fieldOld,categories.join(','))
setCategoriesWrapper(tags || []); setCategoriesWrapper(tags || []);
} else if (type === 'protagonist') { } else if (type === 'protagonist') {
setFieldOld(protagonist)
scriptEditUseCase.replaceScript(fieldOld,protagonist)
setProtagonistWrapper(value); setProtagonistWrapper(value);
} else if (type === 'incitingIncident') { } else if (type === 'incitingIncident') {
setFieldOld(incitingIncident)
scriptEditUseCase.replaceScript(fieldOld,incitingIncident)
setIncitingIncidentWrapper(value); setIncitingIncidentWrapper(value);
} else if (type === 'problem') { } else if (type === 'problem') {
setFieldOld(problem)
scriptEditUseCase.replaceScript(fieldOld,problem)
setProblemWrapper(value); setProblemWrapper(value);
} else if (type === 'conflict') { } else if (type === 'conflict') {
setFieldOld(conflict)
scriptEditUseCase.replaceScript(fieldOld,conflict)
setConflictWrapper(value); setConflictWrapper(value);
} else if (type === 'stakes') { } else if (type === 'stakes') {
setFieldOld(stakes)
scriptEditUseCase.replaceScript(fieldOld,stakes)
setStakesWrapper(value); setStakesWrapper(value);
} else if (type === 'characterArc') { } else if (type === 'characterArc') {
setFieldOld(characterArc)
scriptEditUseCase.replaceScript(fieldOld,characterArc)
setCharacterArcWrapper(value); setCharacterArcWrapper(value);
} }
}, },
[scriptEditUseCase] [categories, characterArc, conflict, fieldOld, incitingIncident, problem, protagonist, scriptEditUseCase, setCategoriesWrapper, setCharacterArcWrapper, setConflictWrapper, setIncitingIncidentWrapper, setProblemWrapper, setProtagonistWrapper, setStakesWrapper, setSynopsisWrapper, stakes, synopsis]
); );
/**
*
*/
const focusHandler = useCallback(
async (field: ScriptEditKey): Promise<void> => {
try {
// 如果当前已经有聚焦的字段,先处理暂停/继续逻辑
// 设置新的聚焦字段
setFocusedField(field);
} catch (error) {
console.error("聚焦处理失败:", error);
throw error;
}
},
[]
);
/** /**
* *
*/ */
@ -540,7 +519,6 @@ export const useScriptService = (): UseScriptService => {
stakes, stakes,
characterArc, characterArc,
projectId, projectId,
planId,
aiOptimizing, aiOptimizing,
scriptBlocksMemo, scriptBlocksMemo,
// 操作方法 // 操作方法
@ -549,11 +527,9 @@ export const useScriptService = (): UseScriptService => {
updateScript, updateScript,
applyScript, applyScript,
abortVideoTask: abortVideoTaskHandler, abortVideoTask: abortVideoTaskHandler,
focusHandler,
enhanceScript, enhanceScript,
setAiOptimizing, setAiOptimizing,
setProjectId, setProjectId,
setPlanId,
createMovieProjectV1, createMovieProjectV1,
// 封装的set函数 // 封装的set函数
setSynopsis: setSynopsisWrapper, setSynopsis: setSynopsisWrapper,

View File

@ -243,44 +243,47 @@ export class StoryDetails {
let content = ""; let content = "";
// 定义多种匹配模式,按优先级排序 // 定义多种匹配模式,按优先级排序
const patterns = [ const patterns = [
// 1. 匹配带编号的主标题:数字. **标题:** 格式 // 1. 匹配带编号的主标题:数字. **标题:** 格式
new RegExp( new RegExp(
`\\d+\\.\\s*\\*\\*${escapedHeaderName}:?\\*\\*\\s*([\\s\\S]*?)(?=\\d+\\.\\s*\\*\\*[^*]+:?\\*\\*|\\*\\*[A-Z]+:\\*\\*|---|\$)`, `\\d+\\.\\s*\\*\\*${escapedHeaderName}:?\\*\\*\\s*([\\s\\S]*?)(?=\\d+\\.\\s*\\*\\*[^*]+:?\\*\\*|\\*\\*[A-Z]+:\\*\\*|---|\$)`,
"i" "i"
), ),
// 2. 匹配子标题:*标题:* 格式(在主标题下的子项) // 2. 匹配子标题:*标题:* 格式(在主标题下的子项)
new RegExp( new RegExp(
`\\*\\s*\\*\\*${escapedHeaderName}:?\\*\\*\\s*([\\s\\S]*?)(?=\\*\\s*\\*\\*[^*]+:?\\*\\*|\\d+\\.\\s*\\*\\*[^*]+:?\\*\\*|\\*\\*[A-Z]+:\\*\\*|---|\$)`, `\\*\\s*\\*\\*${escapedHeaderName}:?\\*\\*\\s*([\\s\\S]*?)(?=\\*\\s*\\*\\*[^*]+:?\\*\\*|\\d+\\.\\s*\\*\\*[^*]+:?\\*\\*|\\*\\*[A-Z]+:\\*\\*|---|\$)`,
"i" "i"
), ),
// 3. 匹配独立的粗体标题:**标题:** 格式 // 3. 匹配独立的粗体标题:**标题:** 格式
new RegExp( new RegExp(
`^\\s*\\*\\*${escapedHeaderName}:?\\*\\*\\s*([\\s\\S]*?)(?=^\\s*\\*\\*[^*]+:?\\*\\*|\\d+\\.\\s*\\*\\*[^*]+:?\\*\\*|^\\s*\\*\\*[A-Z]+:\\*\\*|^---|\$)`, `^\\s*\\*\\*${escapedHeaderName}:?\\*\\*\\s*([\\s\\S]*?)(?=^\\s*\\*\\*[^*]+:?\\*\\*|\\d+\\.\\s*\\*\\*[^*]+:?\\*\\*|^\\s*\\*\\*[A-Z]+:\\*\\*|^---|\$)`,
"im" "im"
), ),
// 4. 匹配简单的**标题:**格式(可能在段落中) // 4. 匹配简单的粗体键值对格式:**标题:** 值(适用于简单的键值对,如 **GENRE:** Drama
new RegExp( new RegExp(`\\*\\*${escapedHeaderName}:?\\*\\*\\s*([^\\n]+)`, "i"),
`\\*\\*${escapedHeaderName}:?\\*\\*\\s*([\\s\\S]*?)(?=\\*\\*[^*]+:?\\*\\*|\\d+\\.\\s*\\*\\*[^*]+:?\\*\\*|\\n\\n|---|\$)`,
"i"
),
// 5. 匹配markdown标题## 标题 格式 // 5. 匹配简单的**标题:**格式(可能在段落中)
new RegExp( new RegExp(
`^#{1,6}\\s*${escapedHeaderName}:?\\s*\\n([\\s\\S]*?)(?=^#{1,6}\\s|^\\*\\*[^*]+:?\\*\\*|^---|\$)`, `\\*\\*${escapedHeaderName}:?\\*\\*\\s*([\\s\\S]*?)(?=\\*\\*[^*]+:?\\*\\*|\\d+\\.\\s*\\*\\*[^*]+:?\\*\\*|\\n\\n|---|\$)`,
"im" "i"
), ),
// 6. 匹配冒号后的内容:标题: 内容(适用于简单的键值对格式) // 6. 匹配markdown标题## 标题 格式
new RegExp( new RegExp(
`^\\s*${escapedHeaderName}:?\\s*([\\s\\S]*?)(?=^\\s*[A-Za-z][^:]*:|^\\*\\*[^*]+:?\\*\\*|^---|\$)`, `^#{1,6}\\s*${escapedHeaderName}:?\\s*\\n([\\s\\S]*?)(?=^#{1,6}\\s|^\\*\\*[^*]+:?\\*\\*|^---|\$)`,
"im" "im"
), ),
];
// 7. 匹配冒号后的内容:标题: 内容(适用于简单的键值对格式)
new RegExp(
`^\\s*${escapedHeaderName}:?\\s*([\\s\\S]*?)(?=^\\s*[A-Za-z][^:]*:|^\\*\\*[^*]+:?\\*\\*|^---|\$)`,
"im"
),
];
// 尝试每种模式 // 尝试每种模式
for (let i = 0; i < patterns.length; i++) { for (let i = 0; i < patterns.length; i++) {
@ -317,7 +320,7 @@ export class StoryDetails {
content = cleanMarkdownContent(content); content = cleanMarkdownContent(content);
// 如果内容太短,可能是匹配错误,返回空 // 如果内容太短,可能是匹配错误,返回空
if (content.length < 10) { if (content.length < 20&&headerName!=='GENRE') {
debug && console.log("匹配到的内容太短,可能匹配错误"); debug && console.log("匹配到的内容太短,可能匹配错误");
return ""; return "";
} }

View File

@ -28,7 +28,6 @@ describe("ScriptService 业务逻辑测试", () => {
"在阳光明媚的码头上,两只柴犬展开了一场薯条吃比赛。一只优雅的母猫担任裁判,端坐高处,威严地监督比赛。两只鸽子站在一旁,歪着头有趣地看着,偶尔咕咕低鸣。柴犬们瞪大眼睛,尾巴摇得飞快,争抢盘子里的金黄薯条。从日出到天黑,它们吃个不停,薯条堆成了小山,母猫无奈摇头,鸽子仍兴致勃勃,场面热闹非凡。"; "在阳光明媚的码头上,两只柴犬展开了一场薯条吃比赛。一只优雅的母猫担任裁判,端坐高处,威严地监督比赛。两只鸽子站在一旁,歪着头有趣地看着,偶尔咕咕低鸣。柴犬们瞪大眼睛,尾巴摇得飞快,争抢盘子里的金黄薯条。从日出到天黑,它们吃个不停,薯条堆成了小山,母猫无奈摇头,鸽子仍兴致勃勃,场面热闹非凡。";
let projectId: string; let projectId: string;
let planId: string;
// let name: string; // let name: string;
it("想法生成剧本", async () => { it("想法生成剧本", async () => {
@ -48,14 +47,13 @@ describe("ScriptService 业务逻辑测试", () => {
); );
expect(createRes.project_id).toBeDefined(); expect(createRes.project_id).toBeDefined();
projectId = createRes.project_id; projectId = createRes.project_id;
planId = createRes.plan_id;
}); });
it("保存剧本", async () => { it("保存剧本", async () => {
const res = await newScriptEditUseCase.saveScript(projectId); const res = await newScriptEditUseCase.saveScript(projectId);
console.log(res); console.log(res);
}); });
it("应用剧本", async () => { it("应用剧本", async () => {
await newScriptEditUseCase.applyScript(projectId, planId); await newScriptEditUseCase.applyScript(projectId);
console.log(projectId); console.log(projectId);
}); });
}); });
@ -101,8 +99,14 @@ describe("解析测试", () => {
describe("剧本功能对接测试",()=>{ describe("剧本功能对接测试",()=>{
it("初始化 解析剧本" , async()=>{ it("初始化 解析剧本" , async()=>{
const response = await getProjectScript({ project_id: "21f194df-cb4b-4e3a-8d44-ca14f23fd1c2" }); const response = await getProjectScript({ project_id: "21f194df-cb4b-4e3a-8d44-ca14f23fd1c2" });
console.log(response.data.generated_script);
const newScriptEditUseCase = new ScriptEditUseCase(response.data.generated_script); const newScriptEditUseCase = new ScriptEditUseCase(response.data.generated_script);
console.log(newScriptEditUseCase.getStoryDetails()); })
it("分类解析",()=>{
// 测试代码
const testText = `**GENRE:** Drama\n\n---\n\n**SCENE 1**`;
const s = new StoryDetails("");
const result = s.extractContentByHeader(testText, "GENRE", true);
console.log("测试结果:", result); // 应该输出 "Drama"
}) })
} ) } )

View File

@ -183,14 +183,13 @@ export class ScriptEditUseCase {
* @description: * @description:
* @returns Promise<void> * @returns Promise<void>
*/ */
async applyScript(projectId: string, planId: string): Promise<void> { async applyScript(projectId: string): Promise<void> {
try { try {
this.loading = true; this.loading = true;
// 调用应用剧本接口 // 调用应用剧本接口
const response = await applyScriptToShot({ const response = await applyScriptToShot({
project_id: projectId, project_id: projectId
plan_id: planId,
}); });
if (!response.successful) { if (!response.successful) {
@ -250,4 +249,17 @@ export class ScriptEditUseCase {
toString(): string { toString(): string {
return this.scriptValueObject.toString(); return this.scriptValueObject.toString();
} }
/**
* @description:
* @returns string
*/
replaceScript(old: string, newScript: string): void {
// 获取当前剧本文本
const scriptText = this.scriptValueObject.toString();
// 替换剧本文本
const newScriptText = scriptText.replace(old, newScript);
// 更新剧本
this.scriptValueObject = new ScriptValueObject(newScriptText);
}
} }