@oh-story/dsh 0.1.9 → 0.1.11
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 +14 -14
- package/lib/client.js +209 -73
- package/lib/client.js.map +3 -3
- package/lib/drama/manifest.json +248 -168
- package/lib/drama/skills/short-drama/SKILL.md +16 -4
- 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/creator_markdown_check.py +14 -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/character-and-look.md +10 -0
- package/lib/drama/skills/short-drama-assets/references/continuity-lock.md +6 -9
- 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-assets/references/voice-direction.md +28 -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 +65 -44
- 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 +6 -4
- package/lib/drama/skills/short-drama-edit/references/cut-craft.md +26 -67
- package/lib/drama/skills/short-drama-edit/references/delivery-verify.md +31 -56
- package/lib/drama/skills/short-drama-edit/references/generated-footage.md +42 -78
- package/lib/drama/skills/short-drama-edit/references/sound-and-subtitles.md +44 -92
- package/lib/drama/skills/short-drama-edit/references/stage-contract.md +14 -16
- package/lib/drama/skills/short-drama-edit/scripts/edit_tool.py +1272 -125
- package/lib/drama/skills/short-drama-edit/scripts/selftest.py +113 -9
- package/lib/drama/skills/short-drama-image-prompts/SKILL.md +2 -0
- package/lib/drama/skills/short-drama-image-prompts/references/common-recipe.md +11 -0
- 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-produce/SKILL.md +5 -1
- package/lib/drama/skills/short-drama-produce/references/adapter-contract.md +14 -20
- package/lib/drama/skills/short-drama-produce/references/providers/minimax-h3-video.md +8 -26
- package/lib/drama/skills/short-drama-produce/references/providers/minimax-speech.md +41 -0
- package/lib/drama/skills/short-drama-produce/scripts/provider_adapters.py +142 -1
- package/lib/drama/skills/short-drama-review/SKILL.md +4 -5
- package/lib/drama/skills/short-drama-review/references/production-quality-gates.md +6 -19
- 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 +24 -35
- package/lib/drama/skills/short-drama-review/references/stage-contract.md +3 -0
- package/lib/drama/skills/short-drama-storyboard/SKILL.md +23 -11
- package/lib/drama/skills/short-drama-storyboard/references/blocking-playbooks.md +1 -1
- package/lib/drama/skills/short-drama-storyboard/references/lighting-craft.md +39 -0
- 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 +139 -34
- package/lib/drama/skills/short-drama-storyboard/references/stage-contract.md +5 -3
- package/lib/drama/skills/short-drama-video-prompts/SKILL.md +15 -12
- package/lib/drama/skills/short-drama-video-prompts/references/camera-audio-continuity.md +29 -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 +52 -39
- package/lib/drama/skills/short-drama-video-prompts/references/motion-recipe.md +24 -21
- package/lib/drama/skills/short-drama-video-prompts/references/performance-action-timing.md +9 -23
- package/lib/drama/skills/short-drama-video-prompts/references/production-prompt-grammar.md +14 -26
- package/lib/drama/skills/short-drama-video-prompts/references/review-and-fixtures.md +1 -1
- package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.0.md +2 -3
- package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.5.md +34 -9
- package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +3 -2
- 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 +10 -7
- 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 +346 -98
- package/lib/index.js.map +4 -4
- package/lib/novel-to-game/README.md +299 -59
- package/lib/novel-to-game/README_ZH.md +299 -56
- package/lib/novel-to-game/VERSION +1 -1
- package/lib/novel-to-game/examples/jin-ping-mei/build/BUILD_BRIEF.md +3 -1
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/RUN.md +11 -3
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/new-guofeng.css +397 -8
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/style.css +0 -31
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/data.js +71 -73
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/engine.js +78 -89
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/main.js +37 -14
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/text.js +5 -5
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/package.json +2 -1
- package/lib/novel-to-game/examples/jin-ping-mei/qa/README.md +11 -16
- package/lib/novel-to-game/examples/jin-ping-mei/qa/verification.json +11 -11
- package/lib/novel-to-game/examples/jin-ping-mei/qa/verify_playable_model.mjs +23 -0
- package/lib/novel-to-game/manifest.json +77 -87
- package/lib/novel-to-game/skills/game-art-direction/SKILL.md +7 -12
- package/lib/novel-to-game/skills/game-art-direction/references/art-direction-method.md +27 -106
- package/lib/novel-to-game/skills/game-build/SKILL.md +13 -14
- package/lib/novel-to-game/skills/game-build/references/blender-asset-workflow.md +24 -0
- package/lib/novel-to-game/skills/game-build/references/build-brief-contract.md +45 -82
- package/lib/novel-to-game/skills/game-build/references/generative-media-pipeline.md +14 -45
- package/lib/novel-to-game/skills/game-build/references/playable-model-contract.md +30 -65
- package/lib/novel-to-game/skills/game-build/references/tts-production-contract.md +13 -27
- package/lib/novel-to-game/skills/game-concept/SKILL.md +13 -15
- package/lib/novel-to-game/skills/game-concept/references/concept-method.md +28 -75
- package/lib/novel-to-game/skills/game-qa/SKILL.md +6 -7
- package/lib/novel-to-game/skills/game-qa/references/test-design-method.md +9 -5
- package/lib/novel-to-game/skills/game-world-design/SKILL.md +12 -16
- package/lib/novel-to-game/skills/game-world-design/references/narrative-design-method.md +23 -72
- package/lib/novel-to-game/skills/game-world-design/references/numeric-design-method.md +14 -48
- package/lib/novel-to-game/skills/game-world-design/references/world-design-method.md +36 -103
- package/lib/novel-to-game/skills/novel-game-analyze/SKILL.md +4 -10
- package/lib/novel-to-game/skills/novel-game-analyze/references/gameability-protocol.md +4 -4
- package/lib/novel-to-game/skills/novel-to-game/SKILL.md +9 -21
- package/lib/novel-to-game/skills/novel-to-game/references/intake-method.md +5 -4
- package/lib/novel-to-game/skills/novel-to-game/references/pipeline-contract.md +5 -8
- package/lib/oh-story/manifest.json +607 -327
- package/lib/oh-story/roles/chapter-extractor.md +177 -237
- package/lib/oh-story/roles/character-designer.md +1 -2
- package/lib/oh-story/roles/consistency-checker.md +15 -13
- package/lib/oh-story/roles/narrative-writer.md +36 -38
- 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 +15 -9
- 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 +46 -94
- package/lib/oh-story/skills/story/scripts/author_memory_commit.py +934 -170
- package/lib/oh-story/skills/story-cover/SKILL.md +10 -1
- package/lib/oh-story/skills/story-deslop/SKILL.md +59 -73
- 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 +12 -11
- 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 +46 -94
- package/lib/oh-story/skills/story-deslop/references/banned-words.md +2 -2
- package/lib/oh-story/skills/story-deslop/references/deslop-gates.md +22 -5
- 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 +934 -170
- package/lib/oh-story/skills/story-deslop/scripts/check-ai-patterns.js +155 -8
- package/lib/oh-story/skills/story-import/SKILL.md +64 -584
- package/lib/oh-story/skills/story-import/references/character-state-reverse.md +1 -1
- 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/state-tracking.md +4 -69
- package/lib/oh-story/skills/story-import/references/structure-mapping-long.md +98 -92
- 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 +15 -11
- 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 +132 -27
- package/lib/oh-story/skills/story-import/scripts/tracking_commit.py +478 -15
- package/lib/oh-story/skills/story-import/scripts/wordcount_core.py +182 -23
- package/lib/oh-story/skills/story-long-analyze/SKILL.md +81 -270
- package/lib/oh-story/skills/story-long-analyze/references/author-facing.md +252 -0
- package/lib/oh-story/skills/story-long-analyze/references/deconstruction-notes.md +3 -3
- 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/inspiration-library.md +105 -0
- package/lib/oh-story/skills/story-long-analyze/references/pipeline-ops.md +138 -64
- package/lib/oh-story/skills/story-long-analyze/references/semantic-acceptance-fixtures.md +84 -0
- 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 +55 -128
- package/lib/oh-story/skills/story-long-analyze/references/style-profile-protocol.md +6 -6
- package/lib/oh-story/skills/story-long-analyze/references/synthesis-inputs.md +39 -0
- package/lib/oh-story/skills/story-long-analyze/scripts/build_chapter_index.py +466 -0
- package/lib/oh-story/skills/story-long-analyze/scripts/inspect_existing_assets.py +702 -0
- package/lib/oh-story/skills/story-long-analyze/scripts/inspiration_index.py +864 -0
- package/lib/oh-story/skills/story-long-analyze/scripts/manage_analysis_run.py +1145 -0
- package/lib/oh-story/skills/story-long-analyze/scripts/render_relation_chart.py +425 -0
- package/lib/oh-story/skills/story-long-scan/SKILL.md +45 -194
- 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 +49 -81
- 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 +12 -11
- package/lib/oh-story/skills/story-long-write/references/artifact-protocols.md +24 -202
- 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 +46 -94
- 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 +7 -11
- package/lib/oh-story/skills/story-long-write/references/character-relations.md +49 -1
- package/lib/oh-story/skills/story-long-write/references/cross-book-recall.md +26 -0
- package/lib/oh-story/skills/story-long-write/references/deslop-gates.md +171 -0
- package/lib/oh-story/skills/story-long-write/references/dialogue-mastery.md +4 -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/emotional-methods.md +2 -2
- 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 +7 -15
- 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 +19 -13
- package/lib/oh-story/skills/story-long-write/references/reader-contract-and-progression.md +13 -5
- package/lib/oh-story/skills/story-long-write/references/reference-index.md +5 -6
- 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 +15 -11
- package/lib/oh-story/skills/story-long-write/references/workflow-chapter.md +81 -121
- package/lib/oh-story/skills/story-long-write/references/workflow-daily.md +41 -139
- 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 +57 -67
- package/lib/oh-story/skills/story-long-write/references/workflow-setup.md +112 -253
- 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 +6 -4
- package/lib/oh-story/skills/story-long-write/references/writing-craft.md +19 -65
- package/lib/oh-story/skills/story-long-write/scripts/author_memory_commit.py +934 -170
- 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 +226 -25
- 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 +132 -27
- 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 +7 -4
- package/lib/oh-story/skills/story-long-write/scripts/storyctl.py +304 -46
- package/lib/oh-story/skills/story-long-write/scripts/tracking_commit.py +478 -15
- package/lib/oh-story/skills/story-long-write/scripts/wordcount_core.py +182 -23
- package/lib/oh-story/skills/story-review/SKILL.md +31 -302
- 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 +12 -11
- 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 +46 -94
- 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/dialogue-mastery.md +4 -0
- package/lib/oh-story/skills/story-review/references/review-quality.md +6 -11
- 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 +15 -11
- package/lib/oh-story/skills/story-review/scripts/author_memory_commit.py +934 -170
- 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 +478 -15
- package/lib/oh-story/skills/story-review/scripts/wordcount_core.py +182 -23
- package/lib/oh-story/skills/story-setup/SKILL.md +71 -452
- 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 +12 -11
- 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 +22 -5
- package/lib/oh-story/skills/story-setup/references/agent-references/dialogue-mastery.md +4 -0
- 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-emotional-methods.md +2 -2
- 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 +19 -65
- package/lib/oh-story/skills/story-setup/references/diagnostics.md +4 -4
- package/lib/oh-story/skills/story-short-analyze/SKILL.md +56 -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/stage4-6-reversal-summary.md +611 -0
- package/lib/oh-story/skills/story-short-scan/SKILL.md +35 -65
- 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 -175
- 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 +46 -94
- 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/dialogue-mastery.md +4 -0
- 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 -47
- 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 +21 -13
- package/lib/oh-story/skills/story-short-write/references/workflow-draft.md +116 -0
- package/lib/oh-story/skills/story-short-write/references/workflow-revision.md +99 -0
- 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 +934 -170
- 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/drama-production-view.d.ts.map +1 -1
- package/lib/types/client/file-activity.d.ts +19 -1
- package/lib/types/client/file-activity.d.ts.map +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/production-prompts.d.ts +7 -0
- package/lib/types/client/production-prompts.d.ts.map +1 -1
- package/lib/types/client/production-runtime.d.ts +16 -0
- package/lib/types/client/production-runtime.d.ts.map +1 -1
- package/lib/types/client/video-studio.d.ts.map +1 -1
- package/lib/types/drama-adapters.d.ts +5 -3
- package/lib/types/drama-adapters.d.ts.map +1 -1
- package/lib/types/native-hooks.d.ts +53 -1
- package/lib/types/native-hooks.d.ts.map +1 -1
- package/lib/types/role-identity.d.ts +17 -0
- package/lib/types/role-identity.d.ts.map +1 -0
- 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-script/scripts/agent_brief.py → video-understanding/scripts/briefing/builder.py} +38 -35
- package/lib/video-recap/skills/video-understanding/scripts/{brief_context.py → 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-script/scripts/brief_timeline.py → video-understanding/scripts/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 +45 -45
- package/lib/novel-to-game/skills/game-world-design/references/dialogue-design-method.md +0 -58
- package/lib/novel-to-game/skills/game-world-design/references/game-writing-craft.md +0 -53
- package/lib/novel-to-game/skills/novel-to-game/references/intake-benchmark-reference.md +0 -38
- package/lib/oh-story/skills/story-long-analyze/references/material-decomposition.md +0 -530
- package/lib/oh-story/skills/story-long-analyze/references/output-templates.md +0 -559
- package/lib/oh-story/skills/story-long-scan/references/scan-output-format.md +0 -207
- package/lib/oh-story/skills/story-long-write/references/state-tracking.md +0 -108
- package/lib/oh-story/skills/story-short-analyze/references/material-decomposition.md +0 -678
- 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/brief_context.py +0 -348
- package/lib/video-recap/skills/video-script/scripts/narration.py +0 -12
- package/lib/video-recap/skills/video-understanding/scripts/agent_brief.py +0 -399
- package/lib/video-recap/skills/video-understanding/scripts/brief_inputs.py +0 -290
- package/lib/video-recap/skills/video-understanding/scripts/brief_timeline.py +0 -327
- /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
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
"""Validate optional ASR, MiMo, and stage-status inputs for the brief."""
|
|
2
|
-
|
|
3
|
-
import hashlib
|
|
4
|
-
import json
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
|
|
7
|
-
from lib import CONFIG, file_fingerprint, stable_hash
|
|
8
|
-
from brief_context import _clean_asr_prompt_fingerprint, _consolidation_model
|
|
9
|
-
|
|
10
|
-
# Shared with consolidate.py, which this byte-identical copy cannot import (the sibling
|
|
11
|
-
# skill ships no consolidate.py). Keep both literals in sync.
|
|
12
|
-
_ASR_SPAN_TOL = 0.05
|
|
13
|
-
|
|
14
|
-
_MIMO_REJECTION_MARKERS = (
|
|
15
|
-
"request was rejected",
|
|
16
|
-
"considered high risk",
|
|
17
|
-
"high risk",
|
|
18
|
-
"content policy",
|
|
19
|
-
"cannot process",
|
|
20
|
-
"无法处理",
|
|
21
|
-
"内容审核",
|
|
22
|
-
"违规",
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def _load_clean_asr(work_dir, asr_result):
|
|
27
|
-
"""Return consolidate.py's cleaned ASR segments, or None to fall back to raw asr_result.
|
|
28
|
-
|
|
29
|
-
Accepted only when the file is at least as fresh as asr_result.json, its provenance
|
|
30
|
-
(source_md5 / model / prompt_md5) matches, and every segment keeps its original span
|
|
31
|
-
within _ASR_SPAN_TOL."""
|
|
32
|
-
if not asr_result:
|
|
33
|
-
return None
|
|
34
|
-
work_dir = Path(work_dir)
|
|
35
|
-
clean_path = work_dir / "asr_clean.json"
|
|
36
|
-
src_path = work_dir / "asr_result.json"
|
|
37
|
-
try:
|
|
38
|
-
fresh = (
|
|
39
|
-
clean_path.exists()
|
|
40
|
-
and clean_path.stat().st_mtime >= src_path.stat().st_mtime
|
|
41
|
-
)
|
|
42
|
-
except OSError:
|
|
43
|
-
return None
|
|
44
|
-
if not fresh:
|
|
45
|
-
return None
|
|
46
|
-
try:
|
|
47
|
-
payload = json.loads(clean_path.read_text(encoding="utf-8"))
|
|
48
|
-
source_md5 = hashlib.md5(src_path.read_bytes()).hexdigest()
|
|
49
|
-
except (OSError, json.JSONDecodeError):
|
|
50
|
-
return None
|
|
51
|
-
if not isinstance(payload, dict):
|
|
52
|
-
return None
|
|
53
|
-
provenance = {
|
|
54
|
-
"source_md5": source_md5,
|
|
55
|
-
"model": _consolidation_model(),
|
|
56
|
-
"prompt_md5": _clean_asr_prompt_fingerprint(),
|
|
57
|
-
}
|
|
58
|
-
if not payload.items() >= provenance.items():
|
|
59
|
-
return None
|
|
60
|
-
segments = payload.get("segments")
|
|
61
|
-
if not isinstance(segments, list) or len(segments) != len(asr_result):
|
|
62
|
-
return None
|
|
63
|
-
for orig, clean in zip(asr_result, segments):
|
|
64
|
-
if (
|
|
65
|
-
not isinstance(clean, dict)
|
|
66
|
-
or not isinstance(clean.get("start"), (int, float))
|
|
67
|
-
or not isinstance(clean.get("end"), (int, float))
|
|
68
|
-
):
|
|
69
|
-
return None
|
|
70
|
-
if (
|
|
71
|
-
abs(clean["start"] - orig["start"]) > _ASR_SPAN_TOL
|
|
72
|
-
or abs(clean["end"] - orig["end"]) > _ASR_SPAN_TOL
|
|
73
|
-
):
|
|
74
|
-
return None
|
|
75
|
-
return segments
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def _is_mimo_chunk_usable(content):
|
|
79
|
-
"""A chunk is usable only if MiMo returned real analysis (not empty / a moderation refusal)."""
|
|
80
|
-
text = (content or "").strip()
|
|
81
|
-
if not text:
|
|
82
|
-
return False
|
|
83
|
-
low = text.lower()
|
|
84
|
-
return not any(marker in low for marker in _MIMO_REJECTION_MARKERS)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def _mimo_video_settings_fingerprint():
|
|
88
|
-
"""Non-secret MiMo video-overview settings that affect generated content."""
|
|
89
|
-
return {
|
|
90
|
-
"model": CONFIG["mimo_video_model"],
|
|
91
|
-
"mimo_video_api_url": CONFIG["mimo_video_api_url"],
|
|
92
|
-
"mimo_video_fps": CONFIG["mimo_video_fps"],
|
|
93
|
-
"mimo_media_resolution": CONFIG["mimo_media_resolution"],
|
|
94
|
-
"mimo_video_chunk_max_seconds": CONFIG["mimo_video_chunk_max_seconds"],
|
|
95
|
-
"mimo_video_chunk_min_seconds": CONFIG["mimo_video_chunk_min_seconds"],
|
|
96
|
-
"mimo_video_base64_max_mb": CONFIG["mimo_video_base64_max_mb"],
|
|
97
|
-
"mimo_video_prompt": CONFIG["mimo_video_prompt"],
|
|
98
|
-
"mimo_disable_thinking": CONFIG["mimo_disable_thinking"],
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def _mimo_chunk_cache_key(chunk):
|
|
103
|
-
"""Stable identifier for a MiMo chunk (index + scene span) for partial-cache reuse."""
|
|
104
|
-
return f"{chunk['chunk_id']}|{chunk['scene_id']}|{chunk['start']:.3f}-{chunk['end']:.3f}"
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def _mimo_cached_chunks_fingerprint(done):
|
|
108
|
-
return stable_hash(done)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def _mimo_overview_payload_fingerprint(overview):
|
|
112
|
-
payload = dict(overview)
|
|
113
|
-
payload.pop("overview_fingerprint", None)
|
|
114
|
-
return stable_hash(payload)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
def _mimo_video_chunks(scenes):
|
|
118
|
-
"""Split scene spans into MiMo video chunks. scenes.json rows carry no scene_id, so the
|
|
119
|
-
row index stands in for it there."""
|
|
120
|
-
max_seconds = CONFIG["mimo_video_chunk_max_seconds"]
|
|
121
|
-
min_seconds = CONFIG["mimo_video_chunk_min_seconds"]
|
|
122
|
-
chunks = []
|
|
123
|
-
for scene_index, scene in enumerate(scenes):
|
|
124
|
-
start, end = scene["start"], scene["end"]
|
|
125
|
-
scene_id = scene.get("scene_id", scene_index)
|
|
126
|
-
cursor = start
|
|
127
|
-
while cursor < end:
|
|
128
|
-
chunk_end = min(end, cursor + max_seconds)
|
|
129
|
-
if end - chunk_end < min_seconds and chunk_end < end:
|
|
130
|
-
chunk_end = end
|
|
131
|
-
chunks.append(
|
|
132
|
-
{
|
|
133
|
-
"chunk_id": len(chunks),
|
|
134
|
-
"scene_id": scene_id,
|
|
135
|
-
"start": round(cursor, 3),
|
|
136
|
-
"end": round(chunk_end, 3),
|
|
137
|
-
}
|
|
138
|
-
)
|
|
139
|
-
cursor = chunk_end
|
|
140
|
-
return chunks
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
def _mimo_overview_matches_current_inputs(overview, scenes, video_path=None):
|
|
144
|
-
"""True only when mimo_video_overview.json was produced from the current settings,
|
|
145
|
-
source video and scene plan, and none of its chunks was moderation-rejected.
|
|
146
|
-
Provenance keys are read with .get: a stale or partial file simply does not match."""
|
|
147
|
-
if not isinstance(overview, dict) or overview.get("input") != "scene_chunks":
|
|
148
|
-
return False
|
|
149
|
-
settings = _mimo_video_settings_fingerprint()
|
|
150
|
-
expected_keys = [
|
|
151
|
-
_mimo_chunk_cache_key(chunk) for chunk in _mimo_video_chunks(scenes)
|
|
152
|
-
]
|
|
153
|
-
chunks = overview.get("chunks")
|
|
154
|
-
if not isinstance(chunks, list) or not all(
|
|
155
|
-
isinstance(chunk, dict)
|
|
156
|
-
and isinstance(chunk.get("content"), str)
|
|
157
|
-
and _is_mimo_chunk_usable(chunk["content"])
|
|
158
|
-
for chunk in chunks
|
|
159
|
-
):
|
|
160
|
-
return False
|
|
161
|
-
if video_path is not None:
|
|
162
|
-
try:
|
|
163
|
-
if overview.get("source_video_fingerprint") != file_fingerprint(video_path):
|
|
164
|
-
return False
|
|
165
|
-
except OSError:
|
|
166
|
-
return False
|
|
167
|
-
try:
|
|
168
|
-
cached_keys = [_mimo_chunk_cache_key(chunk) for chunk in chunks]
|
|
169
|
-
except (KeyError, TypeError, ValueError):
|
|
170
|
-
return False
|
|
171
|
-
return (
|
|
172
|
-
overview.get("settings") == settings
|
|
173
|
-
and overview.get("overview_fingerprint")
|
|
174
|
-
== _mimo_overview_payload_fingerprint(overview)
|
|
175
|
-
and overview.get("chunks_fingerprint")
|
|
176
|
-
== _mimo_cached_chunks_fingerprint(chunks)
|
|
177
|
-
and cached_keys == expected_keys
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
def _load_mimo_overview_for_brief(work_dir, scenes, enabled=None, video_path=None):
|
|
182
|
-
"""The current MiMo overview for the brief, or None when disabled, absent or stale."""
|
|
183
|
-
if not (CONFIG["mimo_video_overview"] if enabled is None else enabled):
|
|
184
|
-
return None
|
|
185
|
-
path = Path(work_dir) / "mimo_video_overview.json"
|
|
186
|
-
if not path.exists():
|
|
187
|
-
return None
|
|
188
|
-
try:
|
|
189
|
-
overview = json.loads(path.read_text(encoding="utf-8"))
|
|
190
|
-
except (OSError, json.JSONDecodeError):
|
|
191
|
-
return None
|
|
192
|
-
if not _mimo_overview_matches_current_inputs(
|
|
193
|
-
overview, scenes, video_path=video_path
|
|
194
|
-
):
|
|
195
|
-
return None
|
|
196
|
-
return overview
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
def _load_optional_stage_status(work_dir, filename):
|
|
200
|
-
"""Optional-stage status sidecar, or None when the stage never ran."""
|
|
201
|
-
path = Path(work_dir) / filename
|
|
202
|
-
if not path.exists():
|
|
203
|
-
return None
|
|
204
|
-
try:
|
|
205
|
-
status = json.loads(path.read_text(encoding="utf-8"))
|
|
206
|
-
except (OSError, json.JSONDecodeError):
|
|
207
|
-
return None
|
|
208
|
-
if not (
|
|
209
|
-
isinstance(status, dict)
|
|
210
|
-
and isinstance(status.get("enabled"), bool)
|
|
211
|
-
and isinstance(status.get("status"), str)
|
|
212
|
-
and isinstance(status.get("message"), str)
|
|
213
|
-
):
|
|
214
|
-
return None
|
|
215
|
-
return status
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
def _optional_stage_warning(stage, status, message):
|
|
219
|
-
line = f"- {stage}: {status}"
|
|
220
|
-
return f"{line} — {message[:180]}" if message else line
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
def _format_optional_stage_warnings(
|
|
224
|
-
work_dir,
|
|
225
|
-
*,
|
|
226
|
-
mimo_overview_enabled=None,
|
|
227
|
-
mimo_overview=None,
|
|
228
|
-
consolidation_index=None,
|
|
229
|
-
):
|
|
230
|
-
"""Surface fail-open optional-stage loss near the top of the brief."""
|
|
231
|
-
work_dir = Path(work_dir)
|
|
232
|
-
warnings = []
|
|
233
|
-
|
|
234
|
-
overview_enabled = (
|
|
235
|
-
CONFIG["mimo_video_overview"]
|
|
236
|
-
if mimo_overview_enabled is None
|
|
237
|
-
else mimo_overview_enabled
|
|
238
|
-
)
|
|
239
|
-
overview_status = _load_optional_stage_status(
|
|
240
|
-
work_dir, "mimo_video_overview.status.json"
|
|
241
|
-
)
|
|
242
|
-
if (
|
|
243
|
-
overview_status is not None
|
|
244
|
-
and overview_status["enabled"]
|
|
245
|
-
and overview_status["status"] in {"failed", "skipped_no_key"}
|
|
246
|
-
):
|
|
247
|
-
warnings.append(
|
|
248
|
-
_optional_stage_warning(
|
|
249
|
-
"mimo_video_overview",
|
|
250
|
-
overview_status["status"],
|
|
251
|
-
overview_status["message"],
|
|
252
|
-
)
|
|
253
|
-
)
|
|
254
|
-
elif overview_enabled and not mimo_overview:
|
|
255
|
-
warnings.append(
|
|
256
|
-
_optional_stage_warning(
|
|
257
|
-
"mimo_video_overview",
|
|
258
|
-
"missing_artifact",
|
|
259
|
-
"enabled but no valid mimo_video_overview.json is available to this brief",
|
|
260
|
-
)
|
|
261
|
-
)
|
|
262
|
-
|
|
263
|
-
consolidation_status = _load_optional_stage_status(
|
|
264
|
-
work_dir, "consolidation.status.json"
|
|
265
|
-
)
|
|
266
|
-
if consolidation_status is not None and consolidation_status["enabled"]:
|
|
267
|
-
if consolidation_status["status"] == "failed":
|
|
268
|
-
warnings.append(
|
|
269
|
-
_optional_stage_warning(
|
|
270
|
-
"consolidation", "failed", consolidation_status["message"]
|
|
271
|
-
)
|
|
272
|
-
)
|
|
273
|
-
elif consolidation_status.get("do_index") is True and not consolidation_index:
|
|
274
|
-
warnings.append(
|
|
275
|
-
_optional_stage_warning(
|
|
276
|
-
"consolidation",
|
|
277
|
-
"missing_index",
|
|
278
|
-
"enabled but no valid understanding_index.json is available to this brief",
|
|
279
|
-
)
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
if not warnings:
|
|
283
|
-
return []
|
|
284
|
-
return [
|
|
285
|
-
"## Optional stage warnings",
|
|
286
|
-
"",
|
|
287
|
-
"These stages are fail-open; continue, but do not assume their missing context exists.",
|
|
288
|
-
*warnings,
|
|
289
|
-
"",
|
|
290
|
-
]
|
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
"""Remap cut evidence and format output-timeline brief directives."""
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
import math
|
|
5
|
-
import re
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
|
|
8
|
-
from lib import CONFIG, stable_hash
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def _parse_target_seconds(value):
|
|
12
|
-
"""Parse a cut-mode target duration ("30m" / "600" / "1h5m" / "00:30:00") to seconds.
|
|
13
|
-
|
|
14
|
-
None or blank means the knob is unset (None). Any other value that does not parse to
|
|
15
|
-
a positive duration is a typo in user input and raises ValueError.
|
|
16
|
-
"""
|
|
17
|
-
if value is None:
|
|
18
|
-
return None
|
|
19
|
-
if isinstance(value, (int, float)):
|
|
20
|
-
seconds = float(value)
|
|
21
|
-
else:
|
|
22
|
-
text = str(value).strip().lower()
|
|
23
|
-
if not text:
|
|
24
|
-
return None
|
|
25
|
-
if ":" in text:
|
|
26
|
-
parts = [float(p) for p in text.split(":")]
|
|
27
|
-
if len(parts) == 2:
|
|
28
|
-
seconds = parts[0] * 60 + parts[1]
|
|
29
|
-
elif len(parts) == 3:
|
|
30
|
-
seconds = parts[0] * 3600 + parts[1] * 60 + parts[2]
|
|
31
|
-
else:
|
|
32
|
-
raise ValueError(f"unparseable target duration: {value!r}")
|
|
33
|
-
if any(p < 0 for p in parts):
|
|
34
|
-
raise ValueError(f"unparseable target duration: {value!r}")
|
|
35
|
-
else:
|
|
36
|
-
factors = {"ms": 0.001, "s": 1, "m": 60, "h": 3600}
|
|
37
|
-
seconds = 0.0
|
|
38
|
-
pos = 0
|
|
39
|
-
for m in re.finditer(r"([0-9]+(?:\.[0-9]+)?)(ms|s|m|h)?", text):
|
|
40
|
-
if m.start() != pos:
|
|
41
|
-
break
|
|
42
|
-
pos = m.end()
|
|
43
|
-
seconds += float(m.group(1)) * factors[m.group(2) or "s"]
|
|
44
|
-
if pos == 0 or pos != len(text):
|
|
45
|
-
raise ValueError(f"unparseable target duration: {value!r}")
|
|
46
|
-
if not seconds > 0:
|
|
47
|
-
raise ValueError(f"target duration must be positive: {value!r}")
|
|
48
|
-
return seconds
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def _format_research_directive(work_dir, substrate):
|
|
52
|
-
"""A loud, actionable research-first directive — but ONLY when the substrate is too thin
|
|
53
|
-
for real commentary (no dialogue/story spine) and no background_research.json exists yet.
|
|
54
|
-
|
|
55
|
-
The narration's quality ceiling is how much story context the agent has: with only frame
|
|
56
|
-
descriptions it can only narrate pixels, so research the title FIRST (see
|
|
57
|
-
references/research-guide.md). Fires only for thin/empty substrate — NOT merely because a
|
|
58
|
-
title was given — so a dialogue-rich titled run is never nagged.
|
|
59
|
-
"""
|
|
60
|
-
if (Path(work_dir) / "background_research.json").exists():
|
|
61
|
-
return [] # already researched; _format_background_research surfaces it
|
|
62
|
-
if substrate["level"] not in ("thin", "empty"):
|
|
63
|
-
return [] # rich enough to write from dialogue/spine; do not nag
|
|
64
|
-
context = CONFIG["context_info"].strip()
|
|
65
|
-
return [
|
|
66
|
-
"## ⚑ Research the story FIRST (do this before writing narration)",
|
|
67
|
-
"",
|
|
68
|
-
"Reason: the understanding substrate is thin — no dialogue/story spine, only frame",
|
|
69
|
-
"descriptions, so without research the narration can only describe pixels.",
|
|
70
|
-
"1. Pull the title/keywords from `--context`, the filename, or the user's description"
|
|
71
|
-
+ (f" (context: {context})." if context else "."),
|
|
72
|
-
"2. Use any available web-search/browser tool to look up synopsis, characters, and",
|
|
73
|
-
" relationships (see `references/research-guide.md`).",
|
|
74
|
-
"3. Write `work_dir/background_research.json`, then re-read this brief and write narration",
|
|
75
|
-
" that names people and reads the picture through the plot.",
|
|
76
|
-
"4. If no tool/network or nothing found: skip — keep beats sparse and strictly grounded in",
|
|
77
|
-
" the visible ASR/frame evidence rather than inventing drama.",
|
|
78
|
-
"",
|
|
79
|
-
]
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def _load_cut_output_spans_for_brief(work_dir, *, required=False):
|
|
83
|
-
"""Load fresh source→output spans for cut pass 2 brief evidence.
|
|
84
|
-
|
|
85
|
-
Pass 2 narration is authored against edited_source.mp4's OUTPUT timeline, so
|
|
86
|
-
ASR chunks and timeline_fusion must use the same OUTPUT clock. Before pass 2
|
|
87
|
-
(no edited_source.mp4 yet), callers may fall back to source-time evidence; once
|
|
88
|
-
pass 2 exists, missing/stale validated spans are a hard contract failure.
|
|
89
|
-
"""
|
|
90
|
-
|
|
91
|
-
def fail(reason):
|
|
92
|
-
if required:
|
|
93
|
-
raise SystemExit(
|
|
94
|
-
"cut pass2 brief requires fresh clip_plan_validated.json with explicit "
|
|
95
|
-
f"source/output spans ({reason})"
|
|
96
|
-
)
|
|
97
|
-
return None
|
|
98
|
-
|
|
99
|
-
work_dir = Path(work_dir)
|
|
100
|
-
if not (work_dir / "edited_source.mp4").exists():
|
|
101
|
-
return None
|
|
102
|
-
validated_path = work_dir / "clip_plan_validated.json"
|
|
103
|
-
if not validated_path.exists():
|
|
104
|
-
return fail("missing clip_plan_validated.json")
|
|
105
|
-
plan = json.loads(validated_path.read_text(encoding="utf-8"))
|
|
106
|
-
raw_path = work_dir / "clip_plan.json"
|
|
107
|
-
if raw_path.exists() and plan["raw_plan_fingerprint"] != stable_hash(
|
|
108
|
-
json.loads(raw_path.read_text(encoding="utf-8"))
|
|
109
|
-
):
|
|
110
|
-
return fail("stale clip_plan_validated.json")
|
|
111
|
-
spans = []
|
|
112
|
-
for clip in plan["clips"]:
|
|
113
|
-
span = {
|
|
114
|
-
key: clip[key]
|
|
115
|
-
for key in ("source_start", "source_end", "output_start", "output_end")
|
|
116
|
-
}
|
|
117
|
-
if not all(math.isfinite(value) for value in span.values()):
|
|
118
|
-
return fail("non-finite clip span")
|
|
119
|
-
if span["source_end"] <= span["source_start"] or span["output_end"] <= span["output_start"]:
|
|
120
|
-
return fail("non-positive clip span")
|
|
121
|
-
spans.append(span)
|
|
122
|
-
return spans or fail("no clips")
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def _source_output_overlaps_for_brief(start, end, spans):
|
|
126
|
-
overlaps = []
|
|
127
|
-
for span in spans:
|
|
128
|
-
source_start = max(start, span["source_start"])
|
|
129
|
-
source_end = min(end, span["source_end"])
|
|
130
|
-
if source_end <= source_start:
|
|
131
|
-
continue
|
|
132
|
-
output_start = span["output_start"] + (source_start - span["source_start"])
|
|
133
|
-
output_end = span["output_start"] + (source_end - span["source_start"])
|
|
134
|
-
overlaps.append(
|
|
135
|
-
{
|
|
136
|
-
"source_start": source_start,
|
|
137
|
-
"source_end": source_end,
|
|
138
|
-
"output_start": output_start,
|
|
139
|
-
"output_end": output_end,
|
|
140
|
-
}
|
|
141
|
-
)
|
|
142
|
-
return overlaps
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
def _remap_frame_facts_for_brief(frame_facts, overlap):
|
|
146
|
-
out = {}
|
|
147
|
-
for raw_ts, vals in frame_facts.items():
|
|
148
|
-
ts = float(raw_ts)
|
|
149
|
-
if not (overlap["source_start"] <= ts <= overlap["source_end"]):
|
|
150
|
-
continue
|
|
151
|
-
out_ts = overlap["output_start"] + (ts - overlap["source_start"])
|
|
152
|
-
out[f"{out_ts:.3f}"] = vals
|
|
153
|
-
return out
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
def _remap_scenes_to_output_for_brief(scenes, spans):
|
|
157
|
-
out = []
|
|
158
|
-
for scene in scenes:
|
|
159
|
-
overlaps = _source_output_overlaps_for_brief(scene["start"], scene["end"], spans)
|
|
160
|
-
for part_idx, overlap in enumerate(overlaps):
|
|
161
|
-
item = dict(scene)
|
|
162
|
-
item["start"] = round(overlap["output_start"], 3)
|
|
163
|
-
item["end"] = round(overlap["output_end"], 3)
|
|
164
|
-
item["frame_facts"] = _remap_frame_facts_for_brief(
|
|
165
|
-
scene.get("frame_facts", {}), overlap
|
|
166
|
-
)
|
|
167
|
-
if len(overlaps) > 1:
|
|
168
|
-
item["scene_id"] = f"{scene['scene_id']}.{part_idx}"
|
|
169
|
-
out.append(item)
|
|
170
|
-
out.sort(key=lambda x: (x["start"], x["end"]))
|
|
171
|
-
return out
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
def _remap_segments_to_output_for_brief(segments, spans):
|
|
175
|
-
out = []
|
|
176
|
-
for seg in segments:
|
|
177
|
-
for overlap in _source_output_overlaps_for_brief(seg["start"], seg["end"], spans):
|
|
178
|
-
item = dict(seg)
|
|
179
|
-
item["start"] = round(overlap["output_start"], 3)
|
|
180
|
-
item["end"] = round(overlap["output_end"], 3)
|
|
181
|
-
if "duration" in item:
|
|
182
|
-
item["duration"] = round(item["end"] - item["start"], 3)
|
|
183
|
-
out.append(item)
|
|
184
|
-
out.sort(key=lambda x: (x["start"], x["end"]))
|
|
185
|
-
return out
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
def _remap_brief_evidence_to_output_timeline(
|
|
189
|
-
work_dir, scenes_analysis, asr_result, silence_periods, *, required=False
|
|
190
|
-
):
|
|
191
|
-
spans = _load_cut_output_spans_for_brief(work_dir, required=required)
|
|
192
|
-
if not spans:
|
|
193
|
-
return scenes_analysis, asr_result, silence_periods
|
|
194
|
-
return (
|
|
195
|
-
_remap_scenes_to_output_for_brief(scenes_analysis, spans),
|
|
196
|
-
_remap_segments_to_output_for_brief(asr_result, spans),
|
|
197
|
-
_remap_segments_to_output_for_brief(silence_periods, spans),
|
|
198
|
-
)
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
def _read_json(path, default):
|
|
202
|
-
"""JSON artifact, or `default` when the optional file was never written."""
|
|
203
|
-
return json.loads(path.read_text(encoding="utf-8")) if path.exists() else default
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
def _sentence_entry_anchors_for_brief(work_dir, edit_mode):
|
|
207
|
-
"""Load sentence anchors and remap them to cut OUTPUT time when needed."""
|
|
208
|
-
work_dir = Path(work_dir)
|
|
209
|
-
anchors = [
|
|
210
|
-
dict(item)
|
|
211
|
-
for item in _read_json(
|
|
212
|
-
work_dir / "speech_boundary_anchors.json", {"sentence_anchors": []}
|
|
213
|
-
)["sentence_anchors"]
|
|
214
|
-
]
|
|
215
|
-
if edit_mode != "cut" or not (work_dir / "edited_source.mp4").exists():
|
|
216
|
-
return anchors
|
|
217
|
-
|
|
218
|
-
spans = _load_cut_output_spans_for_brief(work_dir, required=True)
|
|
219
|
-
remapped = []
|
|
220
|
-
for anchor in anchors:
|
|
221
|
-
source_time = anchor["time"]
|
|
222
|
-
for span in spans:
|
|
223
|
-
if span["source_start"] - 0.05 <= source_time <= span["source_end"] + 0.05:
|
|
224
|
-
item = dict(anchor)
|
|
225
|
-
item["source_time"] = round(source_time, 3)
|
|
226
|
-
item["time"] = round(
|
|
227
|
-
span["output_start"] + source_time - span["source_start"], 3
|
|
228
|
-
)
|
|
229
|
-
# Preserve the measured safe pause in OUTPUT time too, so cut-mode lint
|
|
230
|
-
# compares one clock.
|
|
231
|
-
source_pause_start = max(
|
|
232
|
-
span["source_start"], min(anchor.get("pause_start", source_time - 0.12), source_time)
|
|
233
|
-
)
|
|
234
|
-
item["source_pause_start"] = round(source_pause_start, 3)
|
|
235
|
-
item["pause_start"] = round(
|
|
236
|
-
span["output_start"] + source_pause_start - span["source_start"], 3
|
|
237
|
-
)
|
|
238
|
-
remapped.append(item)
|
|
239
|
-
|
|
240
|
-
speech_rows = [
|
|
241
|
-
row for row in _read_json(work_dir / "asr_result.json", []) if row["text"]
|
|
242
|
-
]
|
|
243
|
-
quiet_rows = [
|
|
244
|
-
row
|
|
245
|
-
for row in _read_json(work_dir / "silence_periods.json", [])
|
|
246
|
-
if not row["has_speech"]
|
|
247
|
-
]
|
|
248
|
-
out_payload = {
|
|
249
|
-
"schema_version": 2,
|
|
250
|
-
"artifact": "speech_boundary_anchors_output.json",
|
|
251
|
-
"timeline": "cut_output",
|
|
252
|
-
"source_artifact": "speech_boundary_anchors.json",
|
|
253
|
-
"clip_plan_fingerprint": stable_hash(
|
|
254
|
-
json.loads((work_dir / "clip_plan_validated.json").read_text(encoding="utf-8"))
|
|
255
|
-
),
|
|
256
|
-
"sentence_anchors": sorted(remapped, key=lambda item: item["time"]),
|
|
257
|
-
"speech_spans": _remap_segments_to_output_for_brief(speech_rows, spans),
|
|
258
|
-
"quiet_windows": _remap_segments_to_output_for_brief(quiet_rows, spans),
|
|
259
|
-
}
|
|
260
|
-
(work_dir / "speech_boundary_anchors_output.json").write_text(
|
|
261
|
-
json.dumps(out_payload, ensure_ascii=False, indent=2), encoding="utf-8"
|
|
262
|
-
)
|
|
263
|
-
return out_payload["sentence_anchors"]
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
def _format_sentence_entry_anchors_for_brief(work_dir, edit_mode):
|
|
267
|
-
anchors = [
|
|
268
|
-
anchor
|
|
269
|
-
for anchor in _sentence_entry_anchors_for_brief(work_dir, edit_mode)
|
|
270
|
-
if anchor["confidence"] in {"high", "medium"}
|
|
271
|
-
]
|
|
272
|
-
if not anchors:
|
|
273
|
-
return []
|
|
274
|
-
lines = [
|
|
275
|
-
"## 原声句末安全切入点",
|
|
276
|
-
"",
|
|
277
|
-
"这些时间是 ASR 句末标点与短声学停顿对齐后的旁白安全入口。旁白在原声已开始后切入时,"
|
|
278
|
-
"必须从其中一个点开始;否则会在 TTS 前被 `interrupts_source_sentence` 硬阻断。",
|
|
279
|
-
"- 调整方式:优先把 `start` 移到建议锚点;放不下时缩短文本、移动整块或删除该旁白,不能让脚本静默挪音频。",
|
|
280
|
-
'- 原声句子完整性是硬约束:切入块写 `"source_entry_policy": "sentence_boundary"`;'
|
|
281
|
-
"不存在 `intentional_interrupt` 绕过方式。没有后续可靠句末锚点时,移动、缩短或删除旁白块。",
|
|
282
|
-
]
|
|
283
|
-
for anchor in anchors:
|
|
284
|
-
source_suffix = (
|
|
285
|
-
f" (SOURCE {anchor['source_time']:.2f}s)" if "source_time" in anchor else ""
|
|
286
|
-
)
|
|
287
|
-
text_tail = str(anchor.get("text_tail", "")).strip()
|
|
288
|
-
lines.append(
|
|
289
|
-
f"- {anchor['time']:.2f}s [{anchor['confidence']}]{source_suffix} {text_tail}".rstrip()
|
|
290
|
-
)
|
|
291
|
-
lines.append("")
|
|
292
|
-
return lines
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
def _format_output_clip_list(work_dir):
|
|
296
|
-
"""List the kept clips on the OUTPUT timeline (cut-first/narrate-second pass 2), so the
|
|
297
|
-
agent narrates against the real rendered cut instead of the source timeline."""
|
|
298
|
-
path = Path(work_dir) / "clip_plan_validated.json"
|
|
299
|
-
if not path.exists():
|
|
300
|
-
return []
|
|
301
|
-
plan = json.loads(path.read_text(encoding="utf-8"))
|
|
302
|
-
out = ["## Kept clips on the OUTPUT timeline", ""]
|
|
303
|
-
for c in plan["clips"]:
|
|
304
|
-
reason = c.get("reason", "")
|
|
305
|
-
out.append(
|
|
306
|
-
f"- OUTPUT {c['output_start']:.1f}–{c['output_end']:.1f}s ← SOURCE[{c.get('source_id', '0')}] "
|
|
307
|
-
f"{c['source_start']:.1f}–{c['source_end']:.1f}s (clip_id={c.get('clip_id', '?')})"
|
|
308
|
-
+ (f" — {reason}" if reason else "")
|
|
309
|
-
)
|
|
310
|
-
out.append("")
|
|
311
|
-
return out if len(out) > 2 else []
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
def _write_deslop_qc_requirements(work_dir):
|
|
315
|
-
"""Write the stable deslop QC contract consumed by deslop_qc.py.
|
|
316
|
-
|
|
317
|
-
style_card_required defaults to False (advisory): a missing style_card.json is a
|
|
318
|
-
warning, not a render-blocking error. A future opt-in run can set it True to make
|
|
319
|
-
style_card.json a hard requirement — deslop_qc.py reads that field.
|
|
320
|
-
"""
|
|
321
|
-
payload = {
|
|
322
|
-
"schema_version": 1,
|
|
323
|
-
"style_card_required": False,
|
|
324
|
-
}
|
|
325
|
-
path = Path(work_dir) / "deslop_qc_requirements.json"
|
|
326
|
-
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
327
|
-
return path
|
/package/lib/video-recap/skills/video-assemble/scripts/{jianying_tracks.py → jianying/tracks.py}
RENAMED
|
File without changes
|
/package/lib/video-recap/skills/video-recap/scripts/{mimo_qc_contract.py → qc/mimo_contract.py}
RENAMED
|
File without changes
|
/package/lib/video-recap/skills/video-voiceover/scripts/{fish_audio.py → providers/fish_audio.py}
RENAMED
|
File without changes
|