fix(canvas): 分镜生成 - 强化模型选择提示并补齐资产引用与角色音频

This commit is contained in:
ddCat
2026-08-30 19:03:10 +08:00
parent 75bde772b5
commit 6b341e284e
8 changed files with 90 additions and 17 deletions

View File

@@ -25,7 +25,7 @@ describe("章节分镜写入分镜制作", () => {
cameraAngle: "平视,35mm",
cameraMovement: "缓慢推进",
imagePrompt: "雨夜旧屋中的林默",
videoPrompt: "林默推门,镜头缓慢推进",
videoPrompt: "林默推门,镜头缓慢推进\n\n【角色参考】\n林默:@[asset:character-1]\n\n【场景与道具参考】\n旧信封:@[asset:prop-1]",
continuityNotes: "林默停在门内,右手仍扶着门把",
actionBeats: [{ description: "0-2 秒推门;2-5 秒环顾" }],
},

View File

@@ -0,0 +1,12 @@
import { expect, test } from "bun:test";
test("分镜生成模型选择器具有明确的下拉控件状态", async () => {
const css = await Bun.file(new URL("../src/pages/projects/detail/workflow.css", import.meta.url)).text();
const rule = css.match(/\.workflow-model-picker\.canvas-composer-model-picker\s*\{([\s\S]*?)\}/)?.[1] || "";
expect(rule).toContain("border: 1px solid var(--workspace-border-strong)");
expect(rule).toContain("height: 44px");
expect(css).toContain('.workflow-model-picker.canvas-composer-model-picker[aria-expanded="true"]');
expect(css).toContain(".workflow-model-picker .canvas-model-picker-chevron");
expect(css).toContain("box-shadow: 0 0 0 2px");
});

View File

@@ -6,6 +6,13 @@ import type { GenerationTask } from "../src/services/api/task-center";
import type { ProjectDetail } from "../src/services/api/projects";
import { buildShotAssetReferenceContext, resolveShotAssetMentionPrompt } from "../src/pages/projects/detail/workflow-shot-references";
test("production workbench does not silently drop bound voice samples before backend validation", async () => {
const source = await Bun.file(new URL("../src/pages/projects/detail/workflow-production-workbench.tsx", import.meta.url)).text();
expect(source).toContain('const generationReferenceAudios = generationCapability === "video" ? shotAssetReferenceContext.referenceAudios : [];');
expect(source).not.toContain("selectedVideoProfile?.references.maxAudios");
});
test("shot generation submits historical character image, current voice and asset prompt", async () => {
const detail = {
assets: [

View File

@@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test";
import { canvasResourceMentionToken } from "@/lib/canvas/canvas-resource-references";
import type { ProjectAsset, ProjectDetail } from "@/services/api/projects";
import { buildShotAssetReferenceContext, resolveShotAssetMentionPrompt } from "@/pages/projects/detail/workflow-shot-references";
import { buildShotAssetReferenceContext, ensureShotAssetMentionPrompt, resolveShotAssetMentionPrompt } from "@/pages/projects/detail/workflow-shot-references";
describe("workflow shot asset references", () => {
test("builds ordered image references for bound media and characters", () => {
@@ -26,6 +26,15 @@ describe("workflow shot asset references", () => {
expect(() => resolveShotAssetMentionPrompt("跟随 @[asset:missing]", context)).toThrow("未绑定到当前镜头");
});
test("adds bound assets as editable mention tokens without duplicating existing mentions", () => {
const context = buildShotAssetReferenceContext(detail(), "shot-1");
const prompt = ensureShotAssetMentionPrompt("让 @[asset:asset-character] 走近镜头", context.mentionReferences);
expect(prompt).toContain("@[asset:asset-character]");
expect(prompt.match(/@\[asset:asset-character\]/g)).toHaveLength(1);
expect(prompt).toContain("【场景与道具参考】\n雨夜街道:@[asset:asset-scene]");
});
});
function detail(): ProjectDetail {