@oh-story/dsh 0.1.10 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -11
- package/lib/client.js +7 -3
- package/lib/client.js.map +2 -2
- package/lib/drama/manifest.json +212 -142
- package/lib/drama/skills/short-drama/SKILL.md +14 -2
- package/lib/drama/skills/short-drama/assets/project-template/short-drama.json +3 -0
- package/lib/drama/skills/short-drama/references/creator-documents.md +3 -0
- package/lib/drama/skills/short-drama/references/knowhow-index.md +15 -0
- package/lib/drama/skills/short-drama/scripts/project_tool.py +131 -0
- package/lib/drama/skills/short-drama-assets/SKILL.md +2 -1
- package/lib/drama/skills/short-drama-assets/references/asset-review-checklist.md +2 -0
- package/lib/drama/skills/short-drama-assets/references/era-anchors.md +37 -0
- package/lib/drama/skills/short-drama-assets/references/stage-contract.md +2 -0
- package/lib/drama/skills/short-drama-develop/SKILL.md +10 -4
- package/lib/drama/skills/short-drama-develop/assets/adaptation-map.example.jsonl +1 -1
- package/lib/drama/skills/short-drama-develop/assets/creative-brief.md +8 -0
- package/lib/drama/skills/short-drama-develop/references/adaptation-craft.md +80 -13
- package/lib/drama/skills/short-drama-develop/references/episode-design.md +95 -12
- package/lib/drama/skills/short-drama-develop/references/genre-and-hook-playbook.md +9 -5
- package/lib/drama/skills/short-drama-develop/references/genre-cards//345/244/215/344/273/207/346/211/223/350/204/270.md +1 -1
- package/lib/drama/skills/short-drama-develop/references/genre-cards//347/263/273/347/273/237/346/265/201.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//351/200/206/350/242/255.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards//351/207/215/347/224/237/347/251/277/350/266/212.md +51 -0
- package/lib/drama/skills/short-drama-develop/references/genre-cards.md +10 -7
- package/lib/drama/skills/short-drama-develop/references/premise-devices.md +15 -9
- package/lib/drama/skills/short-drama-develop/references/serial-character-and-memory.md +3 -2
- package/lib/drama/skills/short-drama-develop/references/stage-contract.md +14 -7
- package/lib/drama/skills/short-drama-develop/references/story-craft.md +7 -3
- package/lib/drama/skills/short-drama-edit/SKILL.md +43 -20
- package/lib/drama/skills/short-drama-edit/assets/remotion/README.md +49 -13
- package/lib/drama/skills/short-drama-edit/assets/remotion/package.json +4 -2
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/Overlay.tsx +31 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/Root.tsx +5 -5
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/Subtitles.tsx +68 -69
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/font.ts +39 -29
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/rules.mjs +188 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/schema.ts +26 -13
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/Card.tsx +72 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/CornerChip.tsx +39 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/ScreenText.tsx +36 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/SystemPanel.tsx +44 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/TaskPanel.tsx +100 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/chrome.tsx +197 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/screen/tokens.ts +62 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/tsconfig.json +1 -0
- package/lib/drama/skills/short-drama-edit/assets//345/211/252/350/276/221/345/215/225.md +4 -2
- package/lib/drama/skills/short-drama-edit/references/cut-craft.md +3 -1
- package/lib/drama/skills/short-drama-edit/references/delivery-verify.md +6 -2
- package/lib/drama/skills/short-drama-edit/references/generated-footage.md +12 -6
- package/lib/drama/skills/short-drama-edit/references/sound-and-subtitles.md +13 -8
- package/lib/drama/skills/short-drama-edit/references/stage-contract.md +2 -0
- package/lib/drama/skills/short-drama-edit/scripts/edit_tool.py +1153 -121
- package/lib/drama/skills/short-drama-edit/scripts/selftest.py +49 -9
- package/lib/drama/skills/short-drama-novel-analyze/SKILL.md +3 -3
- package/lib/drama/skills/short-drama-novel-analyze/assets/episode-candidate.example.jsonl +2 -2
- package/lib/drama/skills/short-drama-novel-analyze/references/adaptation-triage.md +8 -4
- package/lib/drama/skills/short-drama-novel-analyze/references/adaptation-value.md +10 -3
- package/lib/drama/skills/short-drama-novel-analyze/references/aggregation-and-entities.md +25 -1
- package/lib/drama/skills/short-drama-novel-analyze/references/stage-contract.md +1 -0
- package/lib/drama/skills/short-drama-review/SKILL.md +2 -2
- package/lib/drama/skills/short-drama-review/references/review-method.md +6 -1
- package/lib/drama/skills/short-drama-review/references/rubric-assets-prompts.md +11 -0
- package/lib/drama/skills/short-drama-review/references/rubric-story-script.md +77 -3
- package/lib/drama/skills/short-drama-review/references/rubric-visual-motion.md +15 -0
- package/lib/drama/skills/short-drama-review/references/stage-contract.md +3 -0
- package/lib/drama/skills/short-drama-storyboard/SKILL.md +13 -5
- package/lib/drama/skills/short-drama-storyboard/references/blocking-playbooks.md +1 -1
- package/lib/drama/skills/short-drama-storyboard/references/production-shot-grammar.md +2 -2
- package/lib/drama/skills/short-drama-storyboard/references/shot-craft.md +82 -14
- package/lib/drama/skills/short-drama-storyboard/references/stage-contract.md +4 -2
- package/lib/drama/skills/short-drama-video-prompts/SKILL.md +5 -3
- package/lib/drama/skills/short-drama-video-prompts/references/camera-audio-continuity.md +12 -0
- package/lib/drama/skills/short-drama-video-prompts/references/delivery-profile.md +4 -5
- package/lib/drama/skills/short-drama-video-prompts/references/generability.md +4 -2
- package/lib/drama/skills/short-drama-video-prompts/references/minimax-h3.md +40 -1
- package/lib/drama/skills/short-drama-video-prompts/references/motion-recipe.md +20 -14
- package/lib/drama/skills/short-drama-video-prompts/references/performance-action-timing.md +1 -1
- package/lib/drama/skills/short-drama-video-prompts/references/production-prompt-grammar.md +8 -7
- package/lib/drama/skills/short-drama-video-prompts/references/review-and-fixtures.md +1 -1
- package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +1 -0
- package/lib/drama/skills/short-drama-video-prompts/references/target-model-profile.md +8 -1
- package/lib/drama/skills/short-drama-video-prompts/references/wan-3.0.md +103 -0
- package/lib/drama/skills/short-drama-video-prompts/scripts/motion_timing_check.py +8 -7
- package/lib/drama/skills/short-drama-write/SKILL.md +8 -3
- package/lib/drama/skills/short-drama-write/references/dialogue-craft.md +1 -1
- package/lib/drama/skills/short-drama-write/references/script-craft.md +56 -3
- package/lib/drama/skills/short-drama-write/references/stage-contract.md +4 -0
- package/lib/drama/skills/short-drama-write/scripts/duration_estimate.py +48 -2
- package/lib/index.js +71 -21
- package/lib/index.js.map +3 -3
- package/lib/oh-story/manifest.json +545 -310
- package/lib/oh-story/roles/chapter-extractor.md +11 -11
- package/lib/oh-story/roles/character-designer.md +1 -2
- package/lib/oh-story/roles/consistency-checker.md +11 -9
- package/lib/oh-story/roles/narrative-writer.md +24 -25
- package/lib/oh-story/roles/story-architect.md +9 -61
- package/lib/oh-story/roles/story-explorer.md +20 -125
- package/lib/oh-story/roles/story-researcher.md +0 -1
- package/lib/oh-story/skills/story/SKILL.md +6 -6
- package/lib/oh-story/skills/story/VERSION +1 -1
- package/lib/oh-story/skills/story/references/author-memory-maintenance.md +75 -0
- package/lib/oh-story/skills/story/references/author-memory.md +40 -118
- package/lib/oh-story/skills/story/scripts/author_memory_commit.py +3 -3
- package/lib/oh-story/skills/story-deslop/SKILL.md +24 -25
- package/lib/oh-story/skills/story-deslop/references/agent-calls.md +5 -0
- package/lib/oh-story/skills/story-deslop/references/anti-ai-writing.md +1 -1
- package/lib/oh-story/skills/story-deslop/references/author-memory-maintenance.md +75 -0
- package/lib/oh-story/skills/story-deslop/references/author-memory.md +40 -118
- package/lib/oh-story/skills/story-deslop/references/banned-words.md +2 -2
- package/lib/oh-story/skills/story-deslop/references/deslop-gates.md +21 -4
- package/lib/oh-story/skills/story-deslop/references/style-resolution.md +4 -4
- package/lib/oh-story/skills/story-deslop/scripts/author_memory_commit.py +3 -3
- package/lib/oh-story/skills/story-deslop/scripts/check-ai-patterns.js +155 -8
- package/lib/oh-story/skills/story-import/SKILL.md +63 -579
- package/lib/oh-story/skills/story-import/references/deep-analysis.md +47 -0
- package/lib/oh-story/skills/story-import/references/format-and-structure.md +1 -1
- package/lib/oh-story/skills/story-import/references/import-report.md +64 -0
- package/lib/oh-story/skills/story-import/references/import-special-cases.md +34 -0
- package/lib/oh-story/skills/story-import/references/import-tracking.md +95 -0
- package/lib/oh-story/skills/story-import/references/length-routing.md +1 -1
- package/lib/oh-story/skills/story-import/references/outline-reverse-rules.md +79 -0
- package/lib/oh-story/skills/story-import/references/outline-reverse.md +24 -0
- package/lib/oh-story/skills/story-import/references/structure-mapping-long.md +95 -91
- package/lib/oh-story/skills/story-import/references/structure-mapping-short.md +24 -12
- package/lib/oh-story/skills/story-import/references/tracking-initialization.md +1 -1
- package/lib/oh-story/skills/story-import/references/tracking-transaction.md +11 -9
- package/lib/oh-story/skills/story-import/scripts/build_outline_brief.py +332 -0
- package/lib/oh-story/skills/story-import/scripts/check-outline-contract.js +101 -14
- package/lib/oh-story/skills/story-import/scripts/tracking_commit.py +278 -23
- package/lib/oh-story/skills/story-import/scripts/wordcount_core.py +179 -23
- package/lib/oh-story/skills/story-long-analyze/SKILL.md +28 -50
- package/lib/oh-story/skills/story-long-analyze/references/author-facing.md +12 -5
- package/lib/oh-story/skills/story-long-analyze/references/deconstruction-notes.md +1 -1
- package/lib/oh-story/skills/story-long-analyze/references/final-checks.md +19 -0
- package/lib/oh-story/skills/story-long-analyze/references/index-rebuild.md +11 -0
- package/lib/oh-story/skills/story-long-analyze/references/pipeline-ops.md +21 -55
- package/lib/oh-story/skills/story-long-analyze/references/stage1-golden-chapters.md +128 -0
- package/lib/oh-story/skills/story-long-analyze/references/stage2-extraction.md +229 -0
- package/lib/oh-story/skills/story-long-analyze/references/stage3-plot-rhythm.md +480 -0
- package/lib/oh-story/skills/story-long-analyze/references/stage4-characters-settings.md +195 -0
- package/lib/oh-story/skills/story-long-analyze/references/stage5-report.md +33 -0
- package/lib/oh-story/skills/story-long-analyze/references/style-profile-generator.md +17 -0
- package/lib/oh-story/skills/story-long-analyze/references/style-profile-protocol.md +1 -1
- package/lib/oh-story/skills/story-long-analyze/references/synthesis-inputs.md +39 -0
- package/lib/oh-story/skills/story-long-analyze/scripts/manage_analysis_run.py +47 -8
- package/lib/oh-story/skills/story-long-scan/SKILL.md +41 -193
- package/lib/oh-story/skills/story-long-scan/references/platform-ciweimao.md +19 -0
- package/lib/oh-story/skills/story-long-scan/references/platform-fanqie.md +45 -0
- package/lib/oh-story/skills/story-long-scan/references/platform-jjwxc.md +28 -0
- package/lib/oh-story/skills/story-long-scan/references/platform-qidian.md +35 -0
- package/lib/oh-story/skills/story-long-scan/references/platform-qimao.md +27 -0
- package/lib/oh-story/skills/story-long-scan/references/topic-decision.md +6 -2
- package/lib/oh-story/skills/story-long-write/SKILL.md +32 -73
- package/lib/oh-story/skills/story-long-write/references/agent-calls.md +47 -0
- package/lib/oh-story/skills/story-long-write/references/anti-ai-writing.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/artifact-protocols.md +18 -201
- package/lib/oh-story/skills/story-long-write/references/author-memory-maintenance.md +75 -0
- package/lib/oh-story/skills/story-long-write/references/author-memory.md +40 -118
- package/lib/oh-story/skills/story-long-write/references/banned-words.md +2 -2
- package/lib/oh-story/skills/story-long-write/references/benchmark-recall.md +6 -10
- package/lib/oh-story/skills/story-long-write/references/character-relations.md +49 -1
- package/lib/oh-story/skills/story-long-write/references/deslop-gates.md +171 -0
- package/lib/oh-story/skills/story-long-write/references/emotion-on-page.md +116 -0
- package/lib/oh-story/skills/story-long-write/references/emotional-arc-design.md +1 -114
- package/lib/oh-story/skills/story-long-write/references/genre-prose-cards.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/long-chapter-quality.md +3 -2
- package/lib/oh-story/skills/story-long-write/references/long-format.md +0 -8
- package/lib/oh-story/skills/story-long-write/references/long-genre-catalog.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/long-genre-mechanics.md +3 -3
- package/lib/oh-story/skills/story-long-write/references/opening-design.md +2 -2
- package/lib/oh-story/skills/story-long-write/references/outline-conflict.md +4 -4
- package/lib/oh-story/skills/story-long-write/references/outline-methods.md +7 -7
- package/lib/oh-story/skills/story-long-write/references/outline-rhythm.md +3 -3
- package/lib/oh-story/skills/story-long-write/references/outline-structure-theory.md +14 -69
- package/lib/oh-story/skills/story-long-write/references/plot-frameworks.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/plot-special-topics.md +2 -2
- package/lib/oh-story/skills/story-long-write/references/project-files.md +10 -6
- package/lib/oh-story/skills/story-long-write/references/reader-contract-and-progression.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/reference-index.md +4 -4
- package/lib/oh-story/skills/story-long-write/references/stop-and-fix.md +9 -0
- package/lib/oh-story/skills/story-long-write/references/style-combat-face.md +1 -58
- package/lib/oh-story/skills/story-long-write/references/style-genre-modules.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/style-resolution.md +4 -4
- package/lib/oh-story/skills/story-long-write/references/tracking-initialization.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/tracking-transaction.md +11 -9
- package/lib/oh-story/skills/story-long-write/references/workflow-chapter.md +33 -44
- package/lib/oh-story/skills/story-long-write/references/workflow-daily.md +18 -51
- package/lib/oh-story/skills/story-long-write/references/workflow-outline.md +157 -0
- package/lib/oh-story/skills/story-long-write/references/workflow-revision.md +53 -67
- package/lib/oh-story/skills/story-long-write/references/workflow-setup.md +112 -251
- package/lib/oh-story/skills/story-long-write/references/workflow-volume.md +142 -0
- package/lib/oh-story/skills/story-long-write/references/writer-prompt-fallback.md +5 -3
- package/lib/oh-story/skills/story-long-write/references/writing-craft.md +18 -56
- package/lib/oh-story/skills/story-long-write/scripts/author_memory_commit.py +3 -3
- package/lib/oh-story/skills/story-long-write/scripts/build_architect_brief.py +260 -0
- package/lib/oh-story/skills/story-long-write/scripts/build_writer_prompt.py +96 -16
- package/lib/oh-story/skills/story-long-write/scripts/check-ai-patterns.js +155 -8
- package/lib/oh-story/skills/story-long-write/scripts/check-outline-contract.js +101 -14
- package/lib/oh-story/skills/story-long-write/scripts/check-outline-copy.js +7 -2
- package/lib/oh-story/skills/story-long-write/scripts/outline_view.py +2 -1
- package/lib/oh-story/skills/story-long-write/scripts/storyctl.py +250 -50
- package/lib/oh-story/skills/story-long-write/scripts/tracking_commit.py +278 -23
- package/lib/oh-story/skills/story-long-write/scripts/wordcount_core.py +179 -23
- package/lib/oh-story/skills/story-review/SKILL.md +19 -273
- package/lib/oh-story/skills/story-review/references/agent-prompts.md +184 -0
- package/lib/oh-story/skills/story-review/references/anti-ai-writing.md +1 -1
- package/lib/oh-story/skills/story-review/references/author-memory-maintenance.md +75 -0
- package/lib/oh-story/skills/story-review/references/author-memory.md +40 -118
- package/lib/oh-story/skills/story-review/references/banned-words.md +2 -2
- package/lib/oh-story/skills/story-review/references/batch-review.md +19 -0
- package/lib/oh-story/skills/story-review/references/character-relations.md +49 -1
- package/lib/oh-story/skills/story-review/references/review-quality.md +2 -1
- package/lib/oh-story/skills/story-review/references/review-tracking.md +10 -0
- package/lib/oh-story/skills/story-review/references/solo.md +52 -0
- package/lib/oh-story/skills/story-review/references/style-resolution.md +4 -4
- package/lib/oh-story/skills/story-review/references/tracking-initialization.md +1 -1
- package/lib/oh-story/skills/story-review/references/tracking-transaction.md +11 -9
- package/lib/oh-story/skills/story-review/scripts/author_memory_commit.py +3 -3
- package/lib/oh-story/skills/story-review/scripts/check-ai-patterns.js +155 -8
- package/lib/oh-story/skills/story-review/scripts/tracking_commit.py +278 -23
- package/lib/oh-story/skills/story-review/scripts/wordcount_core.py +179 -23
- package/lib/oh-story/skills/story-setup/SKILL.md +69 -458
- package/lib/oh-story/skills/story-setup/references/agent-references/agent-quality.md +4 -4
- package/lib/oh-story/skills/story-setup/references/agent-references/anti-ai-writing.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/banned-words.md +2 -2
- package/lib/oh-story/skills/story-setup/references/agent-references/benchmark-style-load.md +107 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/character-relations.md +49 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/deslop-gates.md +21 -4
- package/lib/oh-story/skills/story-setup/references/agent-references/emotion-on-page.md +116 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/emotional-arc-design.md +1 -114
- package/lib/oh-story/skills/story-setup/references/agent-references/format-and-structure.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/genre-prose-cards.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/long-genre-catalog.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/long-genre-mechanics.md +3 -3
- package/lib/oh-story/skills/story-setup/references/agent-references/long-quality.md +7 -5
- package/lib/oh-story/skills/story-setup/references/agent-references/opening-design.md +2 -2
- package/lib/oh-story/skills/story-setup/references/agent-references/outline-conflict.md +4 -4
- package/lib/oh-story/skills/story-setup/references/agent-references/outline-methods.md +7 -7
- package/lib/oh-story/skills/story-setup/references/agent-references/outline-rhythm.md +3 -3
- package/lib/oh-story/skills/story-setup/references/agent-references/short-emotional-methods.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/short-genre-formulas.md +0 -15
- package/lib/oh-story/skills/story-setup/references/agent-references/short-reversal.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/style-combat-face.md +1 -58
- package/lib/oh-story/skills/story-setup/references/agent-references/style-genre-modules.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/style-resolution.md +4 -4
- package/lib/oh-story/skills/story-setup/references/agent-references/writing-craft.md +18 -56
- package/lib/oh-story/skills/story-setup/references/diagnostics.md +3 -3
- package/lib/oh-story/skills/story-short-analyze/SKILL.md +37 -110
- package/lib/oh-story/skills/story-short-analyze/references/analysis-character-relations.md +1 -1
- package/lib/oh-story/skills/story-short-analyze/references/analysis-method.md +42 -0
- package/lib/oh-story/skills/story-short-analyze/references/optional-modules.md +97 -0
- package/lib/oh-story/skills/story-short-analyze/references/output-contract.md +9 -47
- package/lib/oh-story/skills/story-short-analyze/references/quality-checklist.md +80 -0
- package/lib/oh-story/skills/story-short-analyze/references/source-story-quality.md +4 -4
- package/lib/oh-story/skills/story-short-analyze/references/stage2-3-structure-emotion.md +308 -0
- package/lib/oh-story/skills/story-short-analyze/references/{material-decomposition.md → stage4-6-reversal-summary.md} +303 -374
- package/lib/oh-story/skills/story-short-scan/SKILL.md +30 -64
- package/lib/oh-story/skills/story-short-scan/references/manual-rank-input.md +36 -0
- package/lib/oh-story/skills/story-short-scan/references/platform-dianzhong.md +24 -0
- package/lib/oh-story/skills/story-short-scan/references/platform-heiyan.md +21 -0
- package/lib/oh-story/skills/story-short-scan/references/topic-match.md +38 -0
- package/lib/oh-story/skills/story-short-write/SKILL.md +23 -34
- package/lib/oh-story/skills/story-short-write/references/agent-calls.md +13 -0
- package/lib/oh-story/skills/story-short-write/references/author-memory-maintenance.md +75 -0
- package/lib/oh-story/skills/story-short-write/references/author-memory.md +40 -118
- package/lib/oh-story/skills/story-short-write/references/banned-words.md +2 -2
- package/lib/oh-story/skills/story-short-write/references/benchmark-recall.md +1 -21
- package/lib/oh-story/skills/story-short-write/references/emotional-methods.md +1 -1
- package/lib/oh-story/skills/story-short-write/references/genre-writing-formulas.md +0 -15
- package/lib/oh-story/skills/story-short-write/references/output-contract.md +9 -47
- package/lib/oh-story/skills/story-short-write/references/reference-index.md +17 -49
- package/lib/oh-story/skills/story-short-write/references/scene-craft.md +40 -0
- package/lib/oh-story/skills/story-short-write/references/short-craft.md +7 -43
- package/lib/oh-story/skills/story-short-write/references/short-format.md +3 -3
- package/lib/oh-story/skills/story-short-write/references/short-prose-quality.md +2 -1
- package/lib/oh-story/skills/story-short-write/references/short-reversal.md +1 -1
- package/lib/oh-story/skills/story-short-write/references/style-resolution.md +4 -4
- package/lib/oh-story/skills/story-short-write/references/submission-craft.md +1 -1
- package/lib/oh-story/skills/story-short-write/references/villain-and-reveal.md +5 -10
- package/lib/oh-story/skills/story-short-write/references/workflow-design.md +19 -12
- package/lib/oh-story/skills/story-short-write/references/workflow-draft.md +22 -32
- package/lib/oh-story/skills/story-short-write/references/workflow-revision.md +84 -17
- package/lib/oh-story/skills/story-short-write/references/writing-workflow.md +7 -119
- package/lib/oh-story/skills/story-short-write/scripts/author_memory_commit.py +3 -3
- package/lib/oh-story/skills/story-short-write/scripts/check-ai-patterns.js +155 -8
- package/lib/oh-story/skills/story-short-write/scripts/check-outline-copy.js +7 -2
- package/lib/types/client/video-studio.d.ts.map +1 -1
- package/lib/types/native-hooks.d.ts +2 -2
- package/lib/types/native-hooks.d.ts.map +1 -1
- package/lib/types/role-tool.d.ts.map +1 -1
- package/lib/types/skill-provider.d.ts.map +1 -1
- package/lib/types/video-project.d.ts.map +1 -1
- package/lib/types/workspace-route.d.ts.map +1 -1
- package/lib/video-recap/CHANGELOG.md +60 -1
- package/lib/video-recap/README.en.md +348 -137
- package/lib/video-recap/README.md +340 -136
- package/lib/video-recap/manifest.json +406 -251
- package/lib/video-recap/skills/video-assemble/SKILL.md +30 -15
- package/lib/video-recap/skills/video-assemble/references/audio-modes.md +63 -0
- package/lib/video-recap/skills/video-assemble/references/explicit-audio-mix.md +75 -0
- package/lib/video-recap/skills/video-assemble/references/foreground-compose.md +118 -0
- package/lib/video-recap/skills/video-assemble/references/narration-adoption.md +103 -0
- package/lib/video-recap/skills/video-assemble/references/packaging.md +45 -0
- package/lib/video-recap/skills/video-assemble/references/pair-media.md +74 -0
- package/lib/video-recap/skills/video-assemble/references/source-score.md +147 -0
- package/lib/video-recap/skills/video-assemble/references/subtitle-track.md +202 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/__init__.py +1 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/audio_mix_binding.py +279 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/frozen_audio.py +187 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/narration_binding.py +323 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/strict_inputs.py +109 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/strict_publish.py +130 -0
- package/lib/video-recap/skills/video-assemble/scripts/artifacts.py +10 -46
- package/lib/video-recap/skills/video-assemble/scripts/assemble.py +378 -119
- package/lib/video-recap/skills/video-assemble/scripts/assemble_constants.py +29 -12
- package/lib/video-recap/skills/video-assemble/scripts/assembly_contract.py +95 -44
- package/lib/video-recap/skills/video-assemble/scripts/assembly_settings.py +75 -32
- package/lib/video-recap/skills/video-assemble/scripts/audio_mix.py +11 -11
- package/lib/video-recap/skills/video-assemble/scripts/compose_foreground.py +293 -0
- package/lib/video-recap/skills/video-assemble/scripts/export_jianying.py +71 -78
- package/lib/video-recap/skills/video-assemble/scripts/jianying/__init__.py +1 -0
- package/lib/video-recap/skills/video-assemble/scripts/{jianying_builders.py → jianying/builders.py} +39 -67
- package/lib/video-recap/skills/video-assemble/scripts/{jianying_model.py → jianying/model.py} +3 -11
- package/lib/video-recap/skills/video-assemble/scripts/{jianying_optional.py → jianying/optional.py} +1 -1
- package/lib/video-recap/skills/video-assemble/scripts/jianying/schema.py +53 -0
- package/lib/video-recap/skills/video-assemble/scripts/{jianying_templates.py → jianying/templates.py} +1 -1
- package/lib/video-recap/skills/video-assemble/scripts/{jianying_timeline_contract.py → jianying/timeline_contract.py} +34 -13
- package/lib/video-recap/skills/video-assemble/scripts/{jianying_writer.py → jianying/writer.py} +7 -17
- package/lib/video-recap/skills/video-assemble/scripts/lib.py +37 -4
- package/lib/video-recap/skills/video-assemble/scripts/media.py +12 -21
- package/lib/video-recap/skills/video-assemble/scripts/narration_audio.py +64 -34
- package/lib/video-recap/skills/video-assemble/scripts/packaging.py +122 -0
- package/lib/video-recap/skills/video-assemble/scripts/pair_media.py +216 -0
- package/lib/video-recap/skills/video-assemble/scripts/render_preflight.py +1 -3
- package/lib/video-recap/skills/video-assemble/scripts/source_score.py +469 -0
- package/lib/video-recap/skills/video-assemble/scripts/source_subtitles.py +25 -9
- package/lib/video-recap/skills/video-assemble/scripts/subtitles/__init__.py +1 -0
- package/lib/video-recap/skills/video-assemble/scripts/{subtitle_core.py → subtitles/core.py} +13 -6
- package/lib/video-recap/skills/video-assemble/scripts/{subtitle_render.py → subtitles/render.py} +5 -4
- package/lib/video-recap/skills/video-assemble/scripts/subtitles/track.py +324 -0
- package/lib/video-recap/skills/video-assemble/scripts/subtitles/track_binding.py +200 -0
- package/lib/video-recap/skills/video-assemble/scripts/timeline.py +30 -46
- package/lib/video-recap/skills/video-assemble/scripts/timeline_emit.py +91 -7
- package/lib/video-recap/skills/video-assemble/scripts/visual_render.py +22 -8
- package/lib/video-recap/skills/video-cut/SKILL.md +34 -16
- package/lib/video-recap/skills/video-cut/references/shot-review.md +50 -0
- package/lib/video-recap/skills/video-cut/scripts/cut.py +2 -28
- package/lib/video-recap/skills/video-cut/scripts/cut_cli.py +58 -62
- package/lib/video-recap/skills/video-cut/scripts/cut_contract.py +21 -106
- package/lib/video-recap/skills/video-cut/scripts/cut_render.py +14 -9
- package/lib/video-recap/skills/video-cut/scripts/lib.py +39 -0
- package/lib/video-recap/skills/video-cut/scripts/narration_mapping.py +2 -155
- package/lib/video-recap/skills/video-cut/scripts/narrative_selection.py +244 -0
- package/lib/video-recap/skills/video-cut/scripts/shot_review.py +357 -0
- package/lib/video-recap/skills/video-recap/SKILL.md +86 -42
- package/lib/video-recap/skills/video-recap/references/audio-routing.md +126 -0
- package/lib/video-recap/skills/video-recap/references/config-playbook.md +12 -8
- package/lib/video-recap/skills/video-recap/references/data-schema.md +44 -33
- package/lib/video-recap/skills/video-recap/references/resource-library.md +151 -0
- package/lib/video-recap/skills/video-recap/references/shift-left-qc-schema.md +1 -1
- package/lib/video-recap/skills/video-recap/scripts/doctor.py +123 -30
- package/lib/video-recap/skills/video-recap/scripts/final_qc.py +22 -75
- package/lib/video-recap/skills/video-recap/scripts/lib.py +3 -3
- package/lib/video-recap/skills/video-recap/scripts/library.py +509 -0
- package/lib/video-recap/skills/video-recap/scripts/materials.py +63 -91
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc.py +8 -70
- package/lib/video-recap/skills/video-recap/scripts/project_binding.py +286 -0
- package/lib/video-recap/skills/video-recap/scripts/qc/__init__.py +1 -0
- package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_client.py → qc/mimo_client.py} +1 -1
- package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_evidence.py → qc/mimo_evidence.py} +33 -66
- package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_observations.py → qc/mimo_observations.py} +3 -11
- package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_payload.py → qc/mimo_payload.py} +4 -7
- package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_report.py → qc/mimo_report.py} +17 -28
- package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_runner.py → qc/mimo_runner.py} +2 -2
- package/lib/video-recap/skills/video-recap/scripts/qc_contract.py +0 -19
- package/lib/video-recap/skills/video-recap/scripts/recap_cli.py +119 -50
- package/lib/video-recap/skills/video-recap/scripts/recap_inspect.py +32 -114
- package/lib/video-recap/skills/video-recap/scripts/recap_review.py +9 -23
- package/lib/video-recap/skills/video-recap/scripts/recap_runner.py +387 -334
- package/lib/video-recap/skills/video-recap/scripts/recap_runtime.py +23 -23
- package/lib/video-recap/skills/video-recap/scripts/recap_source.py +278 -0
- package/lib/video-recap/skills/video-recap/scripts/recap_stage_qc.py +25 -12
- package/lib/video-recap/skills/video-recap/scripts/recap_timeline.py +59 -52
- package/lib/video-recap/skills/video-recap/scripts/resource_lock.py +162 -0
- package/lib/video-recap/skills/video-script/SKILL.md +16 -13
- package/lib/video-recap/skills/video-script/references/creative-editing-playbook.md +9 -5
- package/lib/video-recap/skills/video-script/references/promotional-copy.md +68 -0
- package/lib/video-recap/skills/video-script/references/research-guide.md +1 -1
- package/lib/video-recap/skills/video-script/scripts/evidence_bundle.py +24 -76
- package/lib/video-recap/skills/video-script/scripts/lib.py +10 -87
- package/lib/video-recap/skills/video-script/scripts/narration_lint.py +63 -39
- package/lib/video-recap/skills/video-script/scripts/review.py +0 -2
- package/lib/video-recap/skills/video-script/scripts/review_grounding.py +35 -59
- package/lib/video-recap/skills/video-script/scripts/review_response.py +66 -128
- package/lib/video-recap/skills/video-script/scripts/review_runner.py +12 -20
- package/lib/video-recap/skills/video-script/scripts/speech_ownership.py +4 -4
- package/lib/video-recap/skills/video-script/scripts/validate.py +53 -42
- package/lib/video-recap/skills/video-understanding/SKILL.md +6 -4
- package/lib/video-recap/skills/video-understanding/references/data-schema.md +50 -156
- package/lib/video-recap/skills/video-understanding/references/research-guide.md +4 -4
- package/lib/video-recap/skills/video-understanding/scripts/asr.py +85 -65
- package/lib/video-recap/skills/video-understanding/scripts/asr_timing_evidence.py +270 -0
- package/lib/video-recap/skills/video-understanding/scripts/brief.py +2 -5
- package/lib/video-recap/skills/video-understanding/scripts/briefing/__init__.py +1 -0
- package/lib/video-recap/skills/video-understanding/scripts/{agent_brief.py → briefing/builder.py} +38 -35
- package/lib/video-recap/skills/{video-script/scripts/brief_context.py → video-understanding/scripts/briefing/context.py} +4 -35
- package/lib/video-recap/skills/{video-script/scripts/brief_inputs.py → video-understanding/scripts/briefing/inputs.py} +9 -31
- package/lib/video-recap/skills/video-understanding/scripts/{brief_timeline.py → briefing/timeline.py} +5 -6
- package/lib/video-recap/skills/video-understanding/scripts/consolidate.py +65 -116
- package/lib/video-recap/skills/video-understanding/scripts/detect.py +31 -40
- package/lib/video-recap/skills/video-understanding/scripts/lib.py +30 -86
- package/lib/video-recap/skills/video-understanding/scripts/narration_lint.py +63 -39
- package/lib/video-recap/skills/video-understanding/scripts/speech_ownership.py +4 -4
- package/lib/video-recap/skills/video-understanding/scripts/storyboard.py +17 -79
- package/lib/video-recap/skills/video-understanding/scripts/understanding_brief.py +14 -40
- package/lib/video-recap/skills/video-understanding/scripts/understanding_cache.py +64 -46
- package/lib/video-recap/skills/video-understanding/scripts/understanding_runner.py +31 -11
- package/lib/video-recap/skills/video-understanding/scripts/understanding_storyboard.py +19 -14
- package/lib/video-recap/skills/video-understanding/scripts/vlm.py +80 -108
- package/lib/video-recap/skills/video-voiceover/SKILL.md +29 -19
- package/lib/video-recap/skills/video-voiceover/references/index-tts.md +31 -0
- package/lib/video-recap/skills/video-voiceover/scripts/approved_text_policy.py +123 -0
- package/lib/video-recap/skills/video-voiceover/scripts/dub.py +51 -59
- package/lib/video-recap/skills/video-voiceover/scripts/lib.py +8 -44
- package/lib/video-recap/skills/video-voiceover/scripts/providers/__init__.py +1 -0
- package/lib/video-recap/skills/video-voiceover/scripts/providers/index_tts.py +184 -0
- package/lib/video-recap/skills/video-voiceover/scripts/voiceover.py +212 -134
- package/package.json +41 -41
- package/lib/oh-story/skills/story-long-analyze/references/material-decomposition.md +0 -538
- package/lib/oh-story/skills/story-long-analyze/references/output-templates.md +0 -603
- package/lib/oh-story/skills/story-long-scan/references/scan-output-format.md +0 -207
- package/lib/oh-story/skills/story-short-analyze/references/output-templates.md +0 -561
- package/lib/video-recap/skills/video-assemble/scripts/jianying_schema.py +0 -98
- package/lib/video-recap/skills/video-recap/references/creative-editing-playbook.md +0 -225
- package/lib/video-recap/skills/video-recap/references/research-guide.md +0 -74
- package/lib/video-recap/skills/video-recap/references/timeline-and-jianying.md +0 -250
- package/lib/video-recap/skills/video-script/scripts/agent_brief.py +0 -399
- package/lib/video-recap/skills/video-script/scripts/brief_timeline.py +0 -327
- package/lib/video-recap/skills/video-script/scripts/narration.py +0 -12
- package/lib/video-recap/skills/video-understanding/scripts/brief_context.py +0 -348
- package/lib/video-recap/skills/video-understanding/scripts/brief_inputs.py +0 -290
- /package/lib/video-recap/skills/video-assemble/scripts/{jianying_tracks.py → jianying/tracks.py} +0 -0
- /package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_contract.py → qc/mimo_contract.py} +0 -0
- /package/lib/video-recap/skills/video-voiceover/scripts/{fish_audio.py → providers/fish_audio.py} +0 -0
|
@@ -4,7 +4,8 @@ import json
|
|
|
4
4
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
-
from lib import CONFIG, log
|
|
7
|
+
from lib import CONFIG, log, load_background_research
|
|
8
|
+
from asr_timing_evidence import asr_evidence_summary_for_brief
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
from detect import detect_speech_boundary_anchors
|
|
@@ -35,14 +36,8 @@ def _research_context(work_dir):
|
|
|
35
36
|
and read scenes with plot knowledge instead of labelling everyone "黑衣男子".
|
|
36
37
|
Returns "" when no usable research file is present, so behaviour is unchanged.
|
|
37
38
|
"""
|
|
38
|
-
|
|
39
|
-
if not
|
|
40
|
-
return ""
|
|
41
|
-
try:
|
|
42
|
-
data = json.loads(path.read_text(encoding="utf-8"))
|
|
43
|
-
except (json.JSONDecodeError, OSError):
|
|
44
|
-
return ""
|
|
45
|
-
if not isinstance(data, dict):
|
|
39
|
+
data = load_background_research(work_dir)
|
|
40
|
+
if not data:
|
|
46
41
|
return ""
|
|
47
42
|
parts = []
|
|
48
43
|
for key in ("synopsis", "episode_context", "worldbuilding"):
|
|
@@ -124,38 +119,16 @@ def _load_understanding_artifacts_for_brief(work_dir):
|
|
|
124
119
|
Material-library restores are allowed to reuse expensive analysis artifacts,
|
|
125
120
|
but cut pass 2 must still rebuild `agent_narration_brief.md` against the
|
|
126
121
|
rendered OUTPUT timeline. This helper deliberately performs no extraction,
|
|
127
|
-
ASR, VLM, or external API calls; it only reads already-present JSON.
|
|
122
|
+
ASR, VLM, or external API calls; it only reads already-present JSON. An absent
|
|
123
|
+
artifact contributes [] (the brief documents the thin substrate); a corrupt one raises.
|
|
128
124
|
"""
|
|
129
125
|
work_dir = Path(work_dir)
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
|
|
127
|
+
def _own(name):
|
|
132
128
|
path = work_dir / name
|
|
133
|
-
if
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
data = _load_json(path)
|
|
137
|
-
except (OSError, ValueError, TypeError):
|
|
138
|
-
continue
|
|
139
|
-
if isinstance(data, list):
|
|
140
|
-
scenes = data
|
|
141
|
-
break
|
|
142
|
-
asr_result = []
|
|
143
|
-
if (work_dir / "asr_result.json").exists():
|
|
144
|
-
try:
|
|
145
|
-
data = _load_json(work_dir / "asr_result.json")
|
|
146
|
-
except (OSError, ValueError, TypeError):
|
|
147
|
-
data = []
|
|
148
|
-
if isinstance(data, list):
|
|
149
|
-
asr_result = data
|
|
150
|
-
silence_periods = []
|
|
151
|
-
if (work_dir / "silence_periods.json").exists():
|
|
152
|
-
try:
|
|
153
|
-
data = _load_json(work_dir / "silence_periods.json")
|
|
154
|
-
except (OSError, ValueError, TypeError):
|
|
155
|
-
data = []
|
|
156
|
-
if isinstance(data, list):
|
|
157
|
-
silence_periods = data
|
|
158
|
-
return scenes, asr_result, silence_periods
|
|
129
|
+
return _load_json(path) if path.exists() else []
|
|
130
|
+
|
|
131
|
+
return _own("vlm_analysis.json"), _own("asr_result.json"), _own("silence_periods.json")
|
|
159
132
|
|
|
160
133
|
|
|
161
134
|
def _write_brief_from_existing_artifacts(video, work_dir, args, video_duration):
|
|
@@ -166,7 +139,7 @@ def _write_brief_from_existing_artifacts(video, work_dir, args, video_duration):
|
|
|
166
139
|
if not (Path(work_dir) / "speech_boundary_anchors.json").exists():
|
|
167
140
|
detect_speech_boundary_anchors(work_dir, asr_result)
|
|
168
141
|
overview_path = Path(work_dir) / "mimo_video_overview.json"
|
|
169
|
-
if CONFIG
|
|
142
|
+
if CONFIG["mimo_video_overview"]:
|
|
170
143
|
scenes = _merge_overview_into_scenes(scenes, overview_path)
|
|
171
144
|
|
|
172
145
|
source_storyboard = None
|
|
@@ -193,8 +166,9 @@ def _write_brief_from_existing_artifacts(video, work_dir, args, video_duration):
|
|
|
193
166
|
video_duration,
|
|
194
167
|
work_dir,
|
|
195
168
|
args.style,
|
|
196
|
-
mimo_overview_enabled=CONFIG
|
|
169
|
+
mimo_overview_enabled=CONFIG["mimo_video_overview"],
|
|
197
170
|
mimo_overview_video_path=video,
|
|
171
|
+
asr_evidence=asr_evidence_summary_for_brief(work_dir, video),
|
|
198
172
|
)
|
|
199
173
|
_prepend_storyboard_brief_header(
|
|
200
174
|
brief_path, source_storyboard, edited_storyboard, cut_mode=cut_mode
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
"""Own understanding-stage cache keys, provenance, and statuses."""
|
|
2
2
|
|
|
3
|
-
import hashlib
|
|
4
|
-
|
|
5
3
|
import json
|
|
6
4
|
|
|
7
5
|
from pathlib import Path
|
|
8
6
|
|
|
7
|
+
from asr_timing_evidence import EVIDENCE_FILENAME, validate_asr_timing_evidence
|
|
9
8
|
from extract import FRAME_TIME_CONVENTION_VERSION
|
|
10
|
-
from lib import CONFIG, log,
|
|
9
|
+
from lib import CONFIG, log, file_identity, load_prompt
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
from vlm import (
|
|
@@ -34,14 +33,23 @@ def _load_json(path):
|
|
|
34
33
|
return json.loads(Path(path).read_text(encoding="utf-8"))
|
|
35
34
|
|
|
36
35
|
|
|
37
|
-
def
|
|
36
|
+
def _video_input(video_path):
|
|
37
|
+
"""The source video as a cache input: resolved path plus {size, mtime_ns}, so two
|
|
38
|
+
different files written in the same timestamp tick never share a stage output."""
|
|
39
|
+
return {"path": str(Path(video_path).resolve()), **file_identity(video_path)}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _artifact_identity(path):
|
|
43
|
+
"""{size, mtime_ns} of an input artifact, or None when it does not exist."""
|
|
38
44
|
path = Path(path)
|
|
39
|
-
return
|
|
45
|
+
return file_identity(path) if path.exists() else None
|
|
40
46
|
|
|
41
47
|
|
|
42
48
|
def _stage_cache_valid(artifact_path, expected_meta):
|
|
49
|
+
"""A stage output is reusable when it exists, is non-empty, its sidecar equals the
|
|
50
|
+
expected inputs/settings dict, and the output itself is the one the sidecar recorded."""
|
|
43
51
|
artifact_path = Path(artifact_path)
|
|
44
|
-
if not artifact_path.exists():
|
|
52
|
+
if not artifact_path.exists() or artifact_path.stat().st_size == 0:
|
|
45
53
|
return False
|
|
46
54
|
meta_path = _artifact_meta_path(artifact_path)
|
|
47
55
|
if not meta_path.exists():
|
|
@@ -50,18 +58,17 @@ def _stage_cache_valid(artifact_path, expected_meta):
|
|
|
50
58
|
meta = _load_json(meta_path)
|
|
51
59
|
except (OSError, ValueError, TypeError):
|
|
52
60
|
return False
|
|
53
|
-
|
|
54
|
-
if not recorded or recorded != _artifact_fingerprint(artifact_path):
|
|
61
|
+
if not isinstance(meta, dict) or meta.get("artifact") != file_identity(artifact_path):
|
|
55
62
|
return False
|
|
56
63
|
expected = dict(expected_meta)
|
|
57
|
-
expected["
|
|
64
|
+
expected["artifact"] = meta["artifact"]
|
|
58
65
|
return meta == expected
|
|
59
66
|
|
|
60
67
|
|
|
61
68
|
def _write_stage_meta(artifact_path, meta):
|
|
62
69
|
meta_path = _artifact_meta_path(artifact_path)
|
|
63
70
|
payload = dict(meta)
|
|
64
|
-
payload["
|
|
71
|
+
payload["artifact"] = _artifact_identity(artifact_path)
|
|
65
72
|
meta_path.write_text(
|
|
66
73
|
json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8"
|
|
67
74
|
)
|
|
@@ -93,7 +100,7 @@ def _write_mimo_overview_status(
|
|
|
93
100
|
"mimo_video_overview.status.json",
|
|
94
101
|
{
|
|
95
102
|
"stage": "mimo_video_overview",
|
|
96
|
-
"enabled": bool(CONFIG
|
|
103
|
+
"enabled": bool(CONFIG["mimo_video_overview"])
|
|
97
104
|
if enabled is None
|
|
98
105
|
else bool(enabled),
|
|
99
106
|
"status": status,
|
|
@@ -116,23 +123,19 @@ def _merge_overview_into_scenes(scenes, overview_path):
|
|
|
116
123
|
`frame_facts` is untouched, `assess_understanding_substrate` (which grades on frame_facts +
|
|
117
124
|
ASR) cannot regress; richer descriptions can only help.
|
|
118
125
|
"""
|
|
119
|
-
|
|
120
|
-
if not isinstance(overview, dict):
|
|
126
|
+
if not Path(overview_path).exists():
|
|
121
127
|
return scenes
|
|
128
|
+
overview = _load_json(overview_path)
|
|
122
129
|
by_scene = {}
|
|
123
|
-
for chunk in overview
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if content and _is_mimo_chunk_usable(content):
|
|
128
|
-
by_scene.setdefault(chunk.get("scene_id"), []).append(content)
|
|
130
|
+
for chunk in overview["chunks"]:
|
|
131
|
+
content = chunk["content"].strip()
|
|
132
|
+
if _is_mimo_chunk_usable(content):
|
|
133
|
+
by_scene.setdefault(chunk["scene_id"], []).append(content)
|
|
129
134
|
if not by_scene:
|
|
130
135
|
return scenes
|
|
131
136
|
enriched = 0
|
|
132
|
-
for scene in scenes
|
|
133
|
-
|
|
134
|
-
continue
|
|
135
|
-
contents = by_scene.get(scene.get("scene_id"))
|
|
137
|
+
for scene in scenes:
|
|
138
|
+
contents = by_scene.get(scene["scene_id"])
|
|
136
139
|
if not contents:
|
|
137
140
|
continue
|
|
138
141
|
scene.setdefault("frame_description", scene.get("description", ""))
|
|
@@ -184,7 +187,7 @@ def _scene_cache_payload(video_path):
|
|
|
184
187
|
return {
|
|
185
188
|
"schema_version": 1,
|
|
186
189
|
"stage": "scenes",
|
|
187
|
-
"
|
|
190
|
+
"inputs": {"video": _video_input(video_path)},
|
|
188
191
|
"settings": {
|
|
189
192
|
"scene_threshold": CONFIG.get("scene_threshold"),
|
|
190
193
|
"scene_junk_filter": CONFIG.get("scene_junk_filter"),
|
|
@@ -200,7 +203,7 @@ def _asr_cache_payload(video_path, *, skip_asr=False):
|
|
|
200
203
|
return {
|
|
201
204
|
"schema_version": 1,
|
|
202
205
|
"stage": "asr",
|
|
203
|
-
"
|
|
206
|
+
"inputs": {"video": _video_input(video_path)},
|
|
204
207
|
"settings": {
|
|
205
208
|
"skip_asr": bool(skip_asr),
|
|
206
209
|
"mimo_asr_api_key_present": bool(CONFIG.get("mimo_asr_api_key")),
|
|
@@ -213,12 +216,34 @@ def _asr_cache_payload(video_path, *, skip_asr=False):
|
|
|
213
216
|
}
|
|
214
217
|
|
|
215
218
|
|
|
219
|
+
def _asr_cache_state(artifact_path, expected_meta, video_path):
|
|
220
|
+
"""Classify an ASR cache without upgrading stale evidence into new authority."""
|
|
221
|
+
artifact_path = Path(artifact_path)
|
|
222
|
+
if not _stage_cache_valid(artifact_path, expected_meta):
|
|
223
|
+
return "MISS"
|
|
224
|
+
evidence_path = artifact_path.parent / EVIDENCE_FILENAME
|
|
225
|
+
if not evidence_path.exists():
|
|
226
|
+
return "LEGACY_UNVERIFIED"
|
|
227
|
+
if validate_asr_timing_evidence(evidence_path, video_path, artifact_path):
|
|
228
|
+
evidence = _load_json(evidence_path)
|
|
229
|
+
if evidence.get("status") == "LEGACY_UNVERIFIED":
|
|
230
|
+
return "LEGACY_UNVERIFIED"
|
|
231
|
+
# An all-empty transcription is an unexplained outcome, not proven silence; treating it
|
|
232
|
+
# as fresh would make one bad run a permanent cache hit.
|
|
233
|
+
if evidence.get("status") in {"UNAVAILABLE_NO_DURATION", "EMPTY_UNKNOWN"}:
|
|
234
|
+
return "MISS"
|
|
235
|
+
return "FRESH"
|
|
236
|
+
return "MISS"
|
|
237
|
+
|
|
238
|
+
|
|
216
239
|
def _silence_cache_payload(video_path, asr_json):
|
|
217
240
|
return {
|
|
218
241
|
"schema_version": 1,
|
|
219
242
|
"stage": "silence",
|
|
220
|
-
"
|
|
221
|
-
|
|
243
|
+
"inputs": {
|
|
244
|
+
"video": _video_input(video_path),
|
|
245
|
+
"asr_result": _artifact_identity(asr_json),
|
|
246
|
+
},
|
|
222
247
|
"asr_meta": _load_json(_artifact_meta_path(asr_json))
|
|
223
248
|
if _artifact_meta_path(asr_json).exists()
|
|
224
249
|
else None,
|
|
@@ -238,7 +263,8 @@ def _silence_cache_payload(video_path, asr_json):
|
|
|
238
263
|
}
|
|
239
264
|
|
|
240
265
|
|
|
241
|
-
def
|
|
266
|
+
def _vlm_prompt_payload():
|
|
267
|
+
"""The exact prompt/context text the VLM stage sends; compared by equality."""
|
|
242
268
|
prompt = load_prompt("VLM_DEPTH_PROMPT")
|
|
243
269
|
if not prompt:
|
|
244
270
|
prompt = (
|
|
@@ -249,33 +275,28 @@ def _vlm_prompt_fingerprint():
|
|
|
249
275
|
context = CONFIG.get("context_info", "")
|
|
250
276
|
if context:
|
|
251
277
|
prompt = f"已知信息:{context}\n\n{prompt}"
|
|
252
|
-
return {
|
|
253
|
-
"prompt_text_fingerprint": _text_fingerprint(prompt),
|
|
254
|
-
"context_info_fingerprint": _text_fingerprint(context),
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
def _text_fingerprint(value):
|
|
259
|
-
return hashlib.md5(str(value or "").encode("utf-8")).hexdigest()
|
|
278
|
+
return {"prompt_text": prompt, "context_info": context}
|
|
260
279
|
|
|
261
280
|
|
|
262
281
|
def _vlm_cache_payload(video_path, work_dir, scenes_json, frames):
|
|
263
282
|
return {
|
|
264
283
|
"schema_version": 1,
|
|
265
284
|
"stage": "vlm",
|
|
266
|
-
"
|
|
267
|
-
|
|
285
|
+
"inputs": {
|
|
286
|
+
"video": _video_input(video_path),
|
|
287
|
+
"scenes": _artifact_identity(scenes_json),
|
|
288
|
+
"background_research": _artifact_identity(
|
|
289
|
+
Path(work_dir) / "background_research.json"
|
|
290
|
+
),
|
|
291
|
+
},
|
|
268
292
|
"frames": _frame_cache_payload(video_path, CONFIG.get("fps"), frames),
|
|
269
|
-
"prompt":
|
|
293
|
+
"prompt": _vlm_prompt_payload(),
|
|
270
294
|
"settings": {
|
|
271
295
|
"fps": CONFIG.get("fps"),
|
|
272
296
|
"vlm_model": CONFIG.get("vlm_model"),
|
|
273
297
|
"api_url": CONFIG.get("api_url"),
|
|
274
298
|
"mimo_disable_thinking": CONFIG.get("mimo_disable_thinking", True),
|
|
275
299
|
"mimo_media_resolution": CONFIG.get("mimo_media_resolution"),
|
|
276
|
-
"background_research_fingerprint": _artifact_fingerprint(
|
|
277
|
-
Path(work_dir) / "background_research.json"
|
|
278
|
-
),
|
|
279
300
|
},
|
|
280
301
|
}
|
|
281
302
|
|
|
@@ -290,13 +311,10 @@ def _frame_cache_payload(video_path, fps, frames):
|
|
|
290
311
|
# v2: frame number→time is (n-1)/fps, not n/fps. Bumping invalidates frames/VLM
|
|
291
312
|
# artifacts produced under the old off-by-one so they are recomputed, not reused.
|
|
292
313
|
"schema_version": FRAME_TIME_CONVENTION_VERSION,
|
|
293
|
-
"
|
|
314
|
+
"inputs": {"video": _video_input(video_path)},
|
|
294
315
|
"fps": float(fps),
|
|
295
316
|
"frame_count": len(frames),
|
|
296
317
|
"frames": frame_names,
|
|
297
|
-
"frame_fingerprints": {
|
|
298
|
-
name: file_fingerprint(frame) for name, frame in zip(frame_names, frames)
|
|
299
|
-
},
|
|
300
318
|
}
|
|
301
319
|
|
|
302
320
|
|
|
@@ -14,6 +14,7 @@ from extract import extract_frames
|
|
|
14
14
|
from detect import detect_scenes, detect_silence_periods, detect_speech_boundary_anchors
|
|
15
15
|
|
|
16
16
|
from asr import transcribe_audio
|
|
17
|
+
from asr_timing_evidence import write_asr_timing_evidence, asr_evidence_summary_for_brief
|
|
17
18
|
|
|
18
19
|
from vlm import (
|
|
19
20
|
analyze_scenes,
|
|
@@ -27,6 +28,7 @@ from brief import build_agent_brief, assess_understanding_substrate
|
|
|
27
28
|
from understanding_brief import _research_context, _write_brief_from_existing_artifacts
|
|
28
29
|
from understanding_cache import (
|
|
29
30
|
_asr_cache_payload,
|
|
31
|
+
_asr_cache_state,
|
|
30
32
|
_frames_cache_valid,
|
|
31
33
|
_load_json,
|
|
32
34
|
_merge_overview_into_scenes,
|
|
@@ -112,7 +114,6 @@ def main():
|
|
|
112
114
|
CONFIG["target_duration"] = args.target_duration
|
|
113
115
|
if args.mimo_video_overview:
|
|
114
116
|
CONFIG["mimo_video_overview"] = True
|
|
115
|
-
scene_threshold = CONFIG.get("scene_threshold")
|
|
116
117
|
|
|
117
118
|
video_duration = get_video_duration(video)
|
|
118
119
|
if CONFIG["fps"] <= 0:
|
|
@@ -145,21 +146,39 @@ def main():
|
|
|
145
146
|
scenes = _load_json(scenes_json)
|
|
146
147
|
log(f"跳过场景检测(已存在 {len(scenes)} 个场景)")
|
|
147
148
|
else:
|
|
148
|
-
scenes = detect_scenes(video, work_dir, scene_threshold)
|
|
149
|
+
scenes = detect_scenes(video, work_dir, CONFIG["scene_threshold"])
|
|
149
150
|
_write_stage_meta(scenes_json, scenes_meta)
|
|
150
151
|
|
|
151
152
|
# Step 3: ASR
|
|
152
153
|
asr_meta = _asr_cache_payload(video, skip_asr=args.skip_asr)
|
|
154
|
+
cache_state = None
|
|
155
|
+
if not args.skip_asr and not args.force:
|
|
156
|
+
cache_state = _asr_cache_state(asr_json, asr_meta, video)
|
|
153
157
|
if args.skip_asr:
|
|
154
158
|
asr_result = []
|
|
155
159
|
asr_json.write_text(
|
|
156
160
|
json.dumps(asr_result, ensure_ascii=False, indent=2), encoding="utf-8"
|
|
157
161
|
)
|
|
158
162
|
_write_stage_meta(asr_json, asr_meta)
|
|
163
|
+
write_asr_timing_evidence(
|
|
164
|
+
work_dir, video, "EXPLICITLY_SKIPPED", final_segments=asr_result
|
|
165
|
+
)
|
|
159
166
|
log("跳过 ASR(--skip-asr)")
|
|
160
|
-
elif
|
|
167
|
+
elif cache_state in {
|
|
168
|
+
"FRESH",
|
|
169
|
+
"LEGACY_UNVERIFIED",
|
|
170
|
+
}:
|
|
161
171
|
asr_result = _load_json(asr_json)
|
|
162
|
-
|
|
172
|
+
if cache_state == "LEGACY_UNVERIFIED":
|
|
173
|
+
write_asr_timing_evidence(
|
|
174
|
+
work_dir,
|
|
175
|
+
video,
|
|
176
|
+
"LEGACY_UNVERIFIED",
|
|
177
|
+
final_segments=asr_result,
|
|
178
|
+
)
|
|
179
|
+
log(f"复用旧 ASR({len(asr_result)} 段;时间/声学证据未经验证)")
|
|
180
|
+
else:
|
|
181
|
+
log(f"跳过 ASR(证据匹配,已存在 {len(asr_result)} 段)")
|
|
163
182
|
else:
|
|
164
183
|
try:
|
|
165
184
|
asr_result = transcribe_audio(video, work_dir)
|
|
@@ -188,13 +207,13 @@ def main():
|
|
|
188
207
|
vlm_analysis = _load_json(vlm_json)
|
|
189
208
|
log(f"跳过 VLM 分析(已存在 {len(vlm_analysis)} 个场景)")
|
|
190
209
|
else:
|
|
191
|
-
if not CONFIG
|
|
192
|
-
key_name = CONFIG
|
|
210
|
+
if not CONFIG["api_key"]:
|
|
211
|
+
key_name = CONFIG["api_env_var"]
|
|
193
212
|
raise SystemExit(f"请设置 {key_name} 环境变量(VLM 画面分析需要)")
|
|
194
213
|
log("VLM API 连通性预检...")
|
|
195
214
|
api_call(
|
|
196
215
|
{
|
|
197
|
-
"model": CONFIG
|
|
216
|
+
"model": CONFIG["vlm_model"],
|
|
198
217
|
"messages": [{"role": "user", "content": "hi"}],
|
|
199
218
|
"max_tokens": 5,
|
|
200
219
|
}
|
|
@@ -204,8 +223,8 @@ def main():
|
|
|
204
223
|
|
|
205
224
|
# Step 4.1: optional MiMo scene-chunk video understanding
|
|
206
225
|
overview_path = work_dir / "mimo_video_overview.json"
|
|
207
|
-
if CONFIG
|
|
208
|
-
if not CONFIG
|
|
226
|
+
if CONFIG["mimo_video_overview"]:
|
|
227
|
+
if not CONFIG["mimo_video_api_key"]:
|
|
209
228
|
log("跳过 MiMo 分片视频概览:未设置 MIMO_API_KEY")
|
|
210
229
|
overview_path.unlink(missing_ok=True)
|
|
211
230
|
_write_mimo_overview_status(
|
|
@@ -227,7 +246,7 @@ def main():
|
|
|
227
246
|
log(f"MiMo 分片视频概览失败(忽略): {e}")
|
|
228
247
|
_write_mimo_overview_status(work_dir, "failed", e, None)
|
|
229
248
|
else:
|
|
230
|
-
if
|
|
249
|
+
if overview:
|
|
231
250
|
_write_mimo_overview_status(
|
|
232
251
|
work_dir, "ok", "MiMo 分片视频概览完成", overview_path.name
|
|
233
252
|
)
|
|
@@ -341,8 +360,9 @@ def main():
|
|
|
341
360
|
video_duration,
|
|
342
361
|
work_dir,
|
|
343
362
|
args.style,
|
|
344
|
-
mimo_overview_enabled=CONFIG
|
|
363
|
+
mimo_overview_enabled=CONFIG["mimo_video_overview"],
|
|
345
364
|
mimo_overview_video_path=video,
|
|
365
|
+
asr_evidence=asr_evidence_summary_for_brief(work_dir, video),
|
|
346
366
|
)
|
|
347
367
|
# C1: post-process the RETURNED brief FILE (not brief.py) so the brief⇄narration twin stays
|
|
348
368
|
# byte-identical. Prepends a storyboard header pointing the agent at the sheet(s).
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
|
-
from lib import CONFIG, log
|
|
5
|
+
from lib import CONFIG, log
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
from storyboard import build_source_storyboard, build_edited_storyboard
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
from understanding_cache import (
|
|
12
|
-
|
|
12
|
+
_artifact_identity,
|
|
13
|
+
_video_input,
|
|
13
14
|
_frames_manifest_path,
|
|
14
15
|
_load_json,
|
|
15
16
|
_stage_cache_valid,
|
|
@@ -19,8 +20,8 @@ from understanding_cache import (
|
|
|
19
20
|
|
|
20
21
|
def _storyboard_sample_policy():
|
|
21
22
|
return {
|
|
22
|
-
"max_tiles": CONFIG
|
|
23
|
-
"columns": CONFIG
|
|
23
|
+
"max_tiles": CONFIG["storyboard_max_tiles"],
|
|
24
|
+
"columns": CONFIG["storyboard_columns"],
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
|
|
@@ -31,9 +32,11 @@ def _edited_storyboard_meta(clip_plan_validated_json, frames_manifest_path):
|
|
|
31
32
|
return {
|
|
32
33
|
"schema_version": 1,
|
|
33
34
|
"stage": "edited_storyboard",
|
|
34
|
-
"
|
|
35
|
+
"inputs": {
|
|
36
|
+
"clip_plan_validated": _artifact_identity(clip_plan_validated_json),
|
|
37
|
+
"frames_manifest": _artifact_identity(frames_manifest_path),
|
|
38
|
+
},
|
|
35
39
|
"fps": float(CONFIG.get("fps") or 0),
|
|
36
|
-
"frames_manifest_fp": _artifact_fingerprint(frames_manifest_path),
|
|
37
40
|
"sample_policy": _storyboard_sample_policy(),
|
|
38
41
|
}
|
|
39
42
|
|
|
@@ -44,10 +47,10 @@ def _generate_source_storyboard(
|
|
|
44
47
|
"""Generate (or reuse cached) the source storyboard. Advisory: returns dict|None, never raises.
|
|
45
48
|
|
|
46
49
|
Cached via _write_stage_meta/_stage_cache_valid on storyboard/source_storyboard.json; the
|
|
47
|
-
meta includes fps + the frames-manifest
|
|
50
|
+
meta includes fps + the frames-manifest identity so an fps-change resume rebuilds (Principle 5).
|
|
48
51
|
If frames/ is absent (cache hit skipped extraction / cleaned) → skip + log; pipeline continues.
|
|
49
52
|
"""
|
|
50
|
-
if not CONFIG
|
|
53
|
+
if not CONFIG["storyboard"]:
|
|
51
54
|
return None
|
|
52
55
|
frames_dir = Path(work_dir) / "frames"
|
|
53
56
|
if not frames_dir.is_dir() or not any(frames_dir.glob("frame_*.jpg")):
|
|
@@ -57,10 +60,12 @@ def _generate_source_storyboard(
|
|
|
57
60
|
meta = {
|
|
58
61
|
"schema_version": 1,
|
|
59
62
|
"stage": "source_storyboard",
|
|
60
|
-
"
|
|
63
|
+
"inputs": {
|
|
64
|
+
"video": _video_input(video_path),
|
|
65
|
+
"scenes": _artifact_identity(scenes_json),
|
|
66
|
+
"frames_manifest": _artifact_identity(_frames_manifest_path(work_dir)),
|
|
67
|
+
},
|
|
61
68
|
"fps": float(CONFIG.get("fps") or 0),
|
|
62
|
-
"scenes_fp": _artifact_fingerprint(scenes_json),
|
|
63
|
-
"frames_manifest_fp": _artifact_fingerprint(_frames_manifest_path(work_dir)),
|
|
64
69
|
"sample_policy": _storyboard_sample_policy(),
|
|
65
70
|
}
|
|
66
71
|
if not force and _stage_cache_valid(json_path, meta):
|
|
@@ -73,7 +78,7 @@ def _generate_source_storyboard(
|
|
|
73
78
|
else:
|
|
74
79
|
log("storyboard 跳过 source(缓存匹配)")
|
|
75
80
|
return cached
|
|
76
|
-
result = build_source_storyboard(work_dir, video_path, scenes, CONFIG
|
|
81
|
+
result = build_source_storyboard(work_dir, video_path, scenes, CONFIG["fps"])
|
|
77
82
|
if result is not None and json_path.exists():
|
|
78
83
|
_write_stage_meta(json_path, meta)
|
|
79
84
|
return result
|
|
@@ -84,7 +89,7 @@ def _generate_edited_storyboard(work_dir, source_video_path, *, force=False):
|
|
|
84
89
|
file-presence (NOT on edit_mode — recap.py forwards --edit-mode cut in BOTH passes, so the
|
|
85
90
|
validated plan presence is the only reliable pass2 signal). Advisory: returns dict|None.
|
|
86
91
|
"""
|
|
87
|
-
if not CONFIG
|
|
92
|
+
if not CONFIG["storyboard"]:
|
|
88
93
|
return None
|
|
89
94
|
clip_plan_validated_json = Path(work_dir) / "clip_plan_validated.json"
|
|
90
95
|
if not clip_plan_validated_json.exists():
|
|
@@ -113,7 +118,7 @@ def _generate_edited_storyboard(work_dir, source_video_path, *, force=False):
|
|
|
113
118
|
log("storyboard 跳过 edited:clip_plan_validated.json 无法解析")
|
|
114
119
|
return None
|
|
115
120
|
result = build_edited_storyboard(
|
|
116
|
-
work_dir, source_video_path, clip_plan_validated, CONFIG
|
|
121
|
+
work_dir, source_video_path, clip_plan_validated, CONFIG["fps"]
|
|
117
122
|
)
|
|
118
123
|
if result is not None and json_path.exists():
|
|
119
124
|
_write_stage_meta(json_path, meta)
|