fix(canvas): 任务结果恢复 - 兼容结构化文本结果
This commit is contained in:
@@ -139,6 +139,14 @@ function parseStoryboardRowsPayload(raw: string): { title?: string; rows?: Array
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parsed.text && typeof parsed.text === "object") {
|
||||
try {
|
||||
const nested = parseStoryboardRowsPayload(JSON.stringify(parsed.text));
|
||||
if (Array.isArray(nested.rows)) return nested;
|
||||
} catch {
|
||||
// 对象形式的 text 不是分镜载荷时,交由统一缺行校验报错。
|
||||
}
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
@@ -146,7 +154,9 @@ export function storyboardRowsFromTask(task: GenerationTask) {
|
||||
const result = parseStoryboardRowsPayload(task.resultJson || "{}");
|
||||
if (!Array.isArray(result.rows) || !result.rows.length) throw new Error("分镜任务没有返回镜头行");
|
||||
return {
|
||||
title: result.title?.trim(),
|
||||
// 旧任务和部分模型会把 title 返回成对象/数组;恢复路径必须只接受字符串,
|
||||
// 否则可选链只能防 undefined,仍会在对象上调用 trim 使整页恢复失败。
|
||||
title: typeof result.title === "string" ? result.title.trim() : undefined,
|
||||
rows: result.rows.map((row, index) => {
|
||||
const next = createStoryboardRow(index + 1, {
|
||||
...row,
|
||||
|
||||
@@ -498,7 +498,27 @@ function omittedImageQuality(value: string | undefined) {
|
||||
|
||||
export function parseBackendGenerationResult(task: GenerationTask): BackendGenerationResult {
|
||||
if (!task.resultJson) throw new Error("后端任务没有返回结果");
|
||||
const result = JSON.parse(task.resultJson) as BackendGenerationResult;
|
||||
const result = JSON.parse(task.resultJson) as BackendGenerationResult & { text?: unknown };
|
||||
if (!result || typeof result !== "object") throw new Error("后端任务结果格式错误");
|
||||
return result;
|
||||
return { ...result, text: normalizeBackendText(result.text) };
|
||||
}
|
||||
|
||||
function normalizeBackendText(value: unknown): string | undefined {
|
||||
if (typeof value === "string") return value;
|
||||
if (value === null || value === undefined) return undefined;
|
||||
if (Array.isArray(value)) {
|
||||
const text = value.map((item) => normalizeBackendText(item)).filter((item): item is string => Boolean(item)).join("");
|
||||
return text || undefined;
|
||||
}
|
||||
if (typeof value === "object") {
|
||||
const record = value as Record<string, unknown>;
|
||||
for (const key of ["text", "content", "output_text", "value"]) {
|
||||
if (!(key in record)) continue;
|
||||
const nested = normalizeBackendText(record[key]);
|
||||
if (nested !== undefined) return nested;
|
||||
}
|
||||
// 某些结构化文本任务直接把 JSON 载荷放进 text 对象,保留 JSON 供上层契约解析。
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
return String(value);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,17 @@ describe("storyboardRowsFromTask", () => {
|
||||
expect(storyboardRowsFromTask(task).rows).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("title 不是字符串时仍可恢复任务结果", () => {
|
||||
const task = storyboardTask(JSON.stringify({ title: { value: "章节" }, rows: [{ shotNumber: 1, plotDescription: "单镜头" }] }));
|
||||
expect(storyboardRowsFromTask(task).title).toBeUndefined();
|
||||
expect(storyboardRowsFromTask(task).rows).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("text 为结构化对象时仍可解析分镜行", () => {
|
||||
const task = storyboardTask(JSON.stringify({ text: { title: "章节", rows: [{ shotNumber: 1, plotDescription: "单镜头" }] } }));
|
||||
expect(storyboardRowsFromTask(task).rows).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("text 内层不是 JSON 时抛出缺行错误", () => {
|
||||
// 无契约时期模型返回 Markdown 表格的真实场景。
|
||||
const task = storyboardTask(JSON.stringify({ mode: "text", text: "| 7-41 | 全景/拉远 | 桃园结义 |" }));
|
||||
|
||||
Reference in New Issue
Block a user