From f6546ecaa66e5a5982733967749daac01589510a Mon Sep 17 00:00:00 2001 From: Codex Date: Fri, 13 Nov 2026 11:47:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 6 ---- .../backend/tests/storyboard-coverage.test.ts | 35 ++++++++++++++++++- .../tests/storyboard-generated-prompt.test.ts | 5 +++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index e168818..97e22c8 100644 --- a/.gitignore +++ b/.gitignore @@ -69,12 +69,6 @@ coverage/ *.[oO][gG][vV] # Runtime databases, secrets and local configuration. -*.db -*.db-* -*.sqlite -*.sqlite-* -*.sqlite3 -*.sqlite3-* *.log *.bak *.pem diff --git a/huobao-source/backend/tests/storyboard-coverage.test.ts b/huobao-source/backend/tests/storyboard-coverage.test.ts index 2e278df..4b7dbe0 100644 --- a/huobao-source/backend/tests/storyboard-coverage.test.ts +++ b/huobao-source/backend/tests/storyboard-coverage.test.ts @@ -1,6 +1,6 @@ import test from 'node:test' import assert from 'node:assert/strict' -import {buildStoryboardPlan,dialogueTimingProblems,sectionBatchProblems,sectionCoverage,spokenLiterals,splitSpeech,speechSeconds,fitDraftDialogueTiming} from '../src/utils/storyboard-coverage.js' +import {buildStoryboardPlan,dialogueTimingProblems,sectionBatchProblems,sectionCoverage,spokenLiterals,splitSpeech,speechSeconds,fitDraftDialogueTiming,coverageAdvanced,resumableDraftPrefix} from '../src/utils/storyboard-coverage.js' const dialogue='请先检查每一扇窗户是否关好,再把桌上的图纸按照编号摆放整齐,确认材料数量以后我们才能开始修理屋顶。' test('long dialogue cannot fit in a four-second timeline slot even with a long total duration',()=>{ @@ -70,3 +70,36 @@ test('coverage requires repeated speech in original order',()=>{ shot.video_prompt+='甲说:「准备好了。」' assert.equal(sectionCoverage(section,[shot]).ready,true) }) + +test('shouting and cries with intervening performance details are spoken dialogue',()=>{ + for(const cue of ['怒吼','大叫','咆哮','惊呼','嘀咕','低语','哭诉','惨叫着猛甩手,脸上满是惊恐']) { + assert.deepEqual(spokenLiterals(`0-9秒:@工人 ${cue}:「先关窗户,再检查工具!」`),['先关窗户,再检查工具!']) + } + const [section]=buildStoryboardPlan('工人:先关窗户,再检查工具!\n同事:啊!') + const shot={shot_number:1,duration:12,source_ids:section.units.map(u=>u.id),video_prompt:'0-8秒:@工人 怒吼:「先关窗户,再检查工具!」\n8-12秒:@同事 惨叫着后退,手遮住脸:「啊!」'} + assert.equal(sectionCoverage(section,[shot]).ready,true) + assert.deepEqual(dialogueTimingProblems(shot),[]) + assert.ok(dialogueTimingProblems({...shot,duration:8,video_prompt:`0-8秒:@工人 怒吼:「${dialogue}」`}).length) +}) + +test('onscreen quotations cannot satisfy dialogue coverage',()=>{ + for(const p of ['门牌写着:「先关窗户。」','@工人 指向显示屏,屏幕显示:「先关窗户。」','旁白停止,字幕:「先关窗户。」'])assert.deepEqual(spokenLiterals(p),[]) +}) + +test('repeated shots do not count as progress once time and source quotas are met',()=>{ + const [section]=buildStoryboardPlan('工人:先关窗户,再检查工具。') + const shot={shot_number:1,duration:12,source_ids:section.units.map(u=>u.id),video_prompt:'0-12秒:工人看着工具。'} + const before=sectionCoverage(section,[shot]) + assert.equal(coverageAdvanced(before,sectionCoverage(section,[shot,{...shot,shot_number:2}])),false) + assert.equal(coverageAdvanced(before,sectionCoverage(section,[{...shot,video_prompt:'0-12秒:工人怒吼:「先关窗户,再检查工具。」'}])),true) +}) + +test('resuming reuses only validated complete scenes, never inflated failed retries',()=>{ + const sections=buildStoryboardPlan('## S01 | 修复室\n工人:工具准备好了。\n## S02 | 屋顶\n同事:先检查安全绳。') + const shots=[{shot_number:1,source_section:0,duration:12,source_ids:sections[0].units.map(u=>u.id),video_prompt:'0-12秒:工人说:「工具准备好了。」'},...Array.from({length:20},(_,i)=>({shot_number:i+2,source_section:1,duration:12,source_ids:sections[1].units.map(u=>u.id),video_prompt:'0-12秒:同事检查工具。'}))] + const prefix=resumableDraftPrefix(sections,shots,1) + assert.equal(prefix.sectionIndex,1);assert.deepEqual(prefix.drafts,[shots[0]]) + assert.equal(shots.length,21) + shots[0].video_prompt='0-12秒:工人走进房间。' + assert.equal(resumableDraftPrefix(sections,shots,1).sectionIndex,0) +}) diff --git a/huobao-source/backend/tests/storyboard-generated-prompt.test.ts b/huobao-source/backend/tests/storyboard-generated-prompt.test.ts index afe608e..0610dad 100644 --- a/huobao-source/backend/tests/storyboard-generated-prompt.test.ts +++ b/huobao-source/backend/tests/storyboard-generated-prompt.test.ts @@ -22,6 +22,11 @@ test('screen text instructions are still rejected, including quoted instructions assert.ok(storyboardSegmentProblems({shot_number:1,duration:9,video_prompt:p},[]).some(p=>p.includes('画面里出现文字'))) } }) + +test('shouted words use the same speech classifier as timing and coverage',()=>{ + const p='0-9秒:@高天明怒吼:「血红文字写着什么?」画面中不出现任何文字。' + assert.deepEqual(storyboardSegmentProblems({shot_number:1,duration:9,video_prompt:p,character_ids:[2]},characters),[]) +}) test('timeline and character binding checks still apply',()=>{ const problems=storyboardSegmentProblems({shot_number:1,duration:12,video_prompt:'0-9秒:@高天明说:「血红文字。」'},characters) assert.ok(problems.some(p=>p.includes('时间轴')))