@oh-story/dsh 0.1.8 → 0.1.9
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 +35 -14
- package/lib/client.js.map +2 -2
- package/lib/drama/manifest.json +165 -69
- package/lib/drama/skills/short-drama/SKILL.md +5 -1
- package/lib/drama/skills/short-drama/scripts/creator_markdown_check.py +126 -9
- package/lib/drama/skills/short-drama/scripts/project_tool.py +11 -0
- package/lib/drama/skills/short-drama-assets/references/character-and-look.md +18 -0
- package/lib/drama/skills/short-drama-assets/references/continuity-lock.md +10 -1
- package/lib/drama/skills/short-drama-edit/SKILL.md +148 -0
- package/lib/drama/skills/short-drama-edit/agents/openai.yaml +4 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/README.md +60 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/package.json +15 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/remotion.config.ts +6 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/Root.tsx +26 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/Subtitles.tsx +88 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/font.ts +46 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/index.ts +4 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/src/schema.ts +32 -0
- package/lib/drama/skills/short-drama-edit/assets/remotion/tsconfig.json +13 -0
- package/lib/drama/skills/short-drama-edit/assets//345/211/252/350/276/221/345/215/225.md +43 -0
- package/lib/drama/skills/short-drama-edit/references/cut-craft.md +81 -0
- package/lib/drama/skills/short-drama-edit/references/delivery-verify.md +58 -0
- package/lib/drama/skills/short-drama-edit/references/generated-footage.md +96 -0
- package/lib/drama/skills/short-drama-edit/references/sound-and-subtitles.md +113 -0
- package/lib/drama/skills/short-drama-edit/references/stage-contract.md +55 -0
- package/lib/drama/skills/short-drama-edit/scripts/edit_tool.py +1041 -0
- package/lib/drama/skills/short-drama-edit/scripts/selftest.py +456 -0
- package/lib/drama/skills/short-drama-image-prompts/assets/image-prompts.md +5 -0
- package/lib/drama/skills/short-drama-image-prompts/assets/lookdev-prompts.md +3 -0
- package/lib/drama/skills/short-drama-novel-analyze/references/aggregation-and-entities.md +2 -2
- package/lib/drama/skills/short-drama-novel-analyze/references/chapter-extraction.md +4 -1
- package/lib/drama/skills/short-drama-produce/SKILL.md +24 -3
- package/lib/drama/skills/short-drama-produce/references/adapter-contract.md +28 -0
- package/lib/drama/skills/short-drama-produce/references/providers/minimax-h3-video.md +24 -5
- package/lib/drama/skills/short-drama-produce/references/providers/seedance.md +7 -0
- package/lib/drama/skills/short-drama-produce/scripts/fixture_adapter.py +18 -1
- package/lib/drama/skills/short-drama-produce/scripts/production_tool.py +181 -2
- package/lib/drama/skills/short-drama-produce/scripts/provider_adapters.py +57 -2
- package/lib/drama/skills/short-drama-review/SKILL.md +3 -0
- package/lib/drama/skills/short-drama-review/references/production-quality-gates.md +20 -0
- package/lib/drama/skills/short-drama-review/references/rubric-visual-motion.md +36 -0
- package/lib/drama/skills/short-drama-storyboard/SKILL.md +7 -0
- package/lib/drama/skills/short-drama-storyboard/assets/keyframe-prompts.md +4 -0
- package/lib/drama/skills/short-drama-storyboard/references/shot-craft.md +39 -0
- package/lib/drama/skills/short-drama-storyboard/references/stage-contract.md +2 -0
- package/lib/drama/skills/short-drama-video-prompts/SKILL.md +7 -1
- package/lib/drama/skills/short-drama-video-prompts/references/minimax-h3.md +101 -6
- package/lib/drama/skills/short-drama-video-prompts/references/motion-recipe.md +7 -1
- package/lib/drama/skills/short-drama-video-prompts/references/performance-action-timing.md +35 -0
- package/lib/drama/skills/short-drama-video-prompts/references/production-prompt-grammar.md +3 -1
- package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.0.md +13 -3
- package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.5.md +35 -4
- package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +1 -1
- package/lib/drama/skills/short-drama-write/SKILL.md +13 -2
- package/lib/drama/skills/short-drama-write/references/screenplay-format.md +6 -0
- package/lib/drama/skills/short-drama-write/references/stage-contract.md +1 -0
- package/lib/index.js +4 -2
- package/lib/index.js.map +2 -2
- package/lib/novel-to-game/VERSION +1 -1
- package/lib/novel-to-game/manifest.json +28 -28
- package/lib/novel-to-game/skills/game-art-direction/SKILL.md +6 -27
- package/lib/novel-to-game/skills/game-build/SKILL.md +12 -29
- package/lib/novel-to-game/skills/game-concept/SKILL.md +10 -26
- package/lib/novel-to-game/skills/game-qa/SKILL.md +5 -15
- package/lib/novel-to-game/skills/game-qa/references/test-design-method.md +1 -1
- package/lib/novel-to-game/skills/game-world-design/SKILL.md +19 -28
- package/lib/novel-to-game/skills/game-world-design/references/dialogue-design-method.md +1 -2
- package/lib/novel-to-game/skills/novel-game-analyze/SKILL.md +6 -9
- package/lib/novel-to-game/skills/novel-to-game/SKILL.md +6 -11
- package/lib/novel-to-game/skills/novel-to-game/references/intake-benchmark-reference.md +0 -4
- package/lib/novel-to-game/skills/novel-to-game/references/intake-method.md +1 -3
- package/lib/novel-to-game/skills/novel-to-game/references/pipeline-contract.md +3 -5
- package/lib/oh-story/manifest.json +292 -172
- package/lib/oh-story/roles/character-designer.md +1 -1
- package/lib/oh-story/roles/narrative-writer.md +56 -242
- package/lib/oh-story/roles/story-architect.md +1 -1
- package/lib/oh-story/skills/story/SKILL.md +1 -1
- package/lib/oh-story/skills/story/VERSION +1 -1
- package/lib/oh-story/skills/story/references/author-memory.md +10 -8
- package/lib/oh-story/skills/story-deslop/SKILL.md +20 -182
- package/lib/oh-story/skills/story-deslop/references/anti-ai-writing.md +19 -47
- package/lib/oh-story/skills/story-deslop/references/author-memory.md +10 -8
- package/lib/oh-story/skills/story-deslop/references/banned-words.md +3 -1
- package/lib/oh-story/skills/story-deslop/references/deslop-gates.md +154 -0
- package/lib/oh-story/skills/story-deslop/references/style-resolution.md +27 -0
- package/lib/oh-story/skills/story-deslop/scripts/check-ai-patterns.js +6 -1
- package/lib/oh-story/skills/story-deslop/scripts/check-degeneration.js +39 -20
- package/lib/oh-story/skills/story-deslop/scripts/normalize-punctuation.js +10 -5
- package/lib/oh-story/skills/story-deslop/scripts/style-whitelist.js +39 -0
- package/lib/oh-story/skills/story-import/SKILL.md +2 -2
- package/lib/oh-story/skills/story-import/references/format-and-structure.md +2 -2
- package/lib/oh-story/skills/story-import/references/tracking-initialization.md +31 -0
- package/lib/oh-story/skills/story-import/references/tracking-transaction.md +2 -29
- package/lib/oh-story/skills/story-import/scripts/check-outline-contract.js +176 -12
- package/lib/oh-story/skills/story-long-analyze/SKILL.md +1 -1
- package/lib/oh-story/skills/story-long-write/SKILL.md +20 -193
- package/lib/oh-story/skills/story-long-write/references/anti-ai-writing.md +19 -47
- package/lib/oh-story/skills/story-long-write/references/artifact-protocols.md +62 -7
- package/lib/oh-story/skills/story-long-write/references/author-memory.md +10 -8
- package/lib/oh-story/skills/story-long-write/references/banned-words.md +3 -1
- package/lib/oh-story/skills/story-long-write/references/benchmark-recall.md +20 -0
- package/lib/oh-story/skills/story-long-write/references/dialogue-mastery.md +6 -4
- package/lib/oh-story/skills/story-long-write/references/long-chapter-quality.md +2 -2
- package/lib/oh-story/skills/story-long-write/references/long-format.md +2 -0
- package/lib/oh-story/skills/story-long-write/references/outline-structure-theory.md +2 -0
- package/lib/oh-story/skills/story-long-write/references/project-files.md +108 -0
- package/lib/oh-story/skills/story-long-write/references/reference-index.md +87 -0
- package/lib/oh-story/skills/story-long-write/references/style-combat-face.md +1 -1
- package/lib/oh-story/skills/story-long-write/references/style-craft.md +9 -29
- 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 +27 -0
- package/lib/oh-story/skills/story-long-write/references/tracking-initialization.md +31 -0
- package/lib/oh-story/skills/story-long-write/references/tracking-transaction.md +2 -29
- package/lib/oh-story/skills/story-long-write/references/workflow-chapter.md +51 -52
- package/lib/oh-story/skills/story-long-write/references/workflow-daily.md +8 -7
- package/lib/oh-story/skills/story-long-write/references/workflow-setup.md +36 -15
- package/lib/oh-story/skills/story-long-write/references/writer-prompt-fallback.md +22 -0
- package/lib/oh-story/skills/story-long-write/references/writing-craft.md +69 -2
- package/lib/oh-story/skills/story-long-write/scripts/build_writer_prompt.py +410 -0
- package/lib/oh-story/skills/story-long-write/scripts/check-ai-patterns.js +6 -1
- package/lib/oh-story/skills/story-long-write/scripts/check-degeneration.js +39 -20
- package/lib/oh-story/skills/story-long-write/scripts/check-outline-contract.js +176 -12
- package/lib/oh-story/skills/story-long-write/scripts/check-outline-copy.js +90 -23
- package/lib/oh-story/skills/story-long-write/scripts/normalize-punctuation.js +10 -5
- package/lib/oh-story/skills/story-long-write/scripts/outline_view.py +283 -0
- package/lib/oh-story/skills/story-long-write/scripts/style-whitelist.js +39 -0
- package/lib/oh-story/skills/story-review/SKILL.md +13 -3
- package/lib/oh-story/skills/story-review/references/anti-ai-writing.md +19 -47
- package/lib/oh-story/skills/story-review/references/author-memory.md +10 -8
- package/lib/oh-story/skills/story-review/references/banned-words.md +3 -1
- package/lib/oh-story/skills/story-review/references/dialogue-mastery.md +6 -4
- package/lib/oh-story/skills/story-review/references/review-quality.md +2 -2
- package/lib/oh-story/skills/story-review/references/style-resolution.md +27 -0
- package/lib/oh-story/skills/story-review/references/tracking-initialization.md +31 -0
- package/lib/oh-story/skills/story-review/references/tracking-transaction.md +2 -29
- package/lib/oh-story/skills/story-review/scripts/check-ai-patterns.js +6 -1
- package/lib/oh-story/skills/story-review/scripts/check-degeneration.js +39 -20
- package/lib/oh-story/skills/story-review/scripts/normalize-punctuation.js +10 -5
- package/lib/oh-story/skills/story-review/scripts/style-whitelist.js +39 -0
- package/lib/oh-story/skills/story-setup/SKILL.md +17 -10
- package/lib/oh-story/skills/story-setup/references/agent-references/anti-ai-writing.md +19 -47
- package/lib/oh-story/skills/story-setup/references/agent-references/banned-words.md +3 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/deslop-gates.md +154 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/dialogue-mastery.md +6 -4
- package/lib/oh-story/skills/story-setup/references/agent-references/format-and-structure.md +2 -2
- package/lib/oh-story/skills/story-setup/references/agent-references/short-genre-formulas.md +1 -1
- package/lib/oh-story/skills/story-setup/references/agent-references/style-combat-face.md +1 -1
- 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 +27 -0
- package/lib/oh-story/skills/story-setup/references/agent-references/writing-craft.md +69 -2
- package/lib/oh-story/skills/story-setup/references/diagnostics.md +38 -0
- package/lib/oh-story/skills/story-short-analyze/references/analysis-writing-techniques.md +1 -1
- package/lib/oh-story/skills/story-short-analyze/references/source-story-quality.md +2 -2
- package/lib/oh-story/skills/story-short-write/SKILL.md +18 -186
- package/lib/oh-story/skills/story-short-write/references/author-memory.md +10 -8
- package/lib/oh-story/skills/story-short-write/references/banned-words.md +3 -1
- package/lib/oh-story/skills/story-short-write/references/benchmark-recall.md +60 -0
- package/lib/oh-story/skills/story-short-write/references/dialogue-mastery.md +6 -4
- package/lib/oh-story/skills/story-short-write/references/genre-styles//344/270/226/346/203/205/346/211/223/350/204/270.md +2 -2
- package/lib/oh-story/skills/story-short-write/references/genre-styles//345/217/214/347/224/267/344/270/273.md +1 -1
- package/lib/oh-story/skills/story-short-write/references/genre-styles//345/244/215/344/273/207/346/211/223/350/204/270.md +3 -3
- package/lib/oh-story/skills/story-short-write/references/genre-styles//345/256/205/346/226/227/345/256/253/346/226/227.md +3 -3
- package/lib/oh-story/skills/story-short-write/references/genre-styles//346/200/273/350/243/201/350/261/252/351/227/250.md +3 -3
- package/lib/oh-story/skills/story-short-write/references/genre-styles//346/202/254/347/226/221.md +5 -5
- package/lib/oh-story/skills/story-short-write/references/genre-styles//346/260/221/344/277/227/346/200/252/350/260/210.md +4 -4
- package/lib/oh-story/skills/story-short-write/references/genre-styles//347/224/234/345/256/240.md +5 -5
- package/lib/oh-story/skills/story-short-write/references/genre-styles//350/277/275/345/246/273/347/201/253/350/221/254/345/234/272.md +3 -3
- package/lib/oh-story/skills/story-short-write/references/genre-writing-formulas.md +1 -1
- package/lib/oh-story/skills/story-short-write/references/genre-writing-techniques.md +1 -1
- package/lib/oh-story/skills/story-short-write/references/reference-index.md +53 -0
- package/lib/oh-story/skills/story-short-write/references/short-craft.md +12 -14
- package/lib/oh-story/skills/story-short-write/references/short-deslop.md +10 -10
- package/lib/oh-story/skills/story-short-write/references/short-format.md +3 -1
- package/lib/oh-story/skills/story-short-write/references/short-prose-quality.md +2 -2
- package/lib/oh-story/skills/story-short-write/references/style-resolution.md +27 -0
- package/lib/oh-story/skills/story-short-write/references/workflow-design.md +77 -0
- package/lib/oh-story/skills/story-short-write/references/writing-workflow.md +5 -5
- package/lib/oh-story/skills/story-short-write/scripts/check-ai-patterns.js +6 -1
- package/lib/oh-story/skills/story-short-write/scripts/check-degeneration.js +39 -20
- package/lib/oh-story/skills/story-short-write/scripts/check-delivery-contract.js +34 -5
- package/lib/oh-story/skills/story-short-write/scripts/check-outline-copy.js +90 -23
- package/lib/oh-story/skills/story-short-write/scripts/normalize-punctuation.js +10 -5
- package/lib/oh-story/skills/story-short-write/scripts/style-whitelist.js +39 -0
- package/lib/types/client/drama-production-view.d.ts.map +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/production-prompts.d.ts.map +1 -1
- package/lib/types/client/production-runtime.d.ts +17 -0
- package/lib/types/client/production-runtime.d.ts.map +1 -1
- package/lib/types/skill-provider.d.ts.map +1 -1
- package/lib/video-recap/CHANGELOG.md +31 -1
- package/lib/video-recap/manifest.json +162 -162
- package/lib/video-recap/skills/video-assemble/scripts/artifacts.py +4 -9
- package/lib/video-recap/skills/video-assemble/scripts/assemble.py +47 -60
- package/lib/video-recap/skills/video-assemble/scripts/assembly_contract.py +77 -115
- package/lib/video-recap/skills/video-assemble/scripts/assembly_settings.py +41 -40
- package/lib/video-recap/skills/video-assemble/scripts/audio_automation.py +22 -32
- package/lib/video-recap/skills/video-assemble/scripts/audio_mix.py +102 -192
- package/lib/video-recap/skills/video-assemble/scripts/jianying_builders.py +14 -35
- package/lib/video-recap/skills/video-assemble/scripts/jianying_model.py +14 -12
- package/lib/video-recap/skills/video-assemble/scripts/jianying_optional.py +8 -9
- package/lib/video-recap/skills/video-assemble/scripts/jianying_schema.py +3 -14
- package/lib/video-recap/skills/video-assemble/scripts/jianying_timeline_contract.py +23 -12
- package/lib/video-recap/skills/video-assemble/scripts/jianying_tracks.py +1 -4
- package/lib/video-recap/skills/video-assemble/scripts/jianying_writer.py +24 -25
- package/lib/video-recap/skills/video-assemble/scripts/lib.py +31 -85
- package/lib/video-recap/skills/video-assemble/scripts/media.py +100 -144
- package/lib/video-recap/skills/video-assemble/scripts/narration_audio.py +101 -195
- package/lib/video-recap/skills/video-assemble/scripts/render_preflight.py +10 -21
- package/lib/video-recap/skills/video-assemble/scripts/source_subtitles.py +90 -169
- package/lib/video-recap/skills/video-assemble/scripts/subtitle_core.py +69 -122
- package/lib/video-recap/skills/video-assemble/scripts/subtitle_render.py +10 -17
- package/lib/video-recap/skills/video-assemble/scripts/timeline.py +33 -48
- package/lib/video-recap/skills/video-assemble/scripts/timeline_emit.py +14 -20
- package/lib/video-recap/skills/video-assemble/scripts/visual_render.py +135 -213
- package/lib/video-recap/skills/video-cut/scripts/cut_cli.py +49 -57
- package/lib/video-recap/skills/video-cut/scripts/cut_contract.py +38 -74
- package/lib/video-recap/skills/video-cut/scripts/cut_render.py +46 -95
- package/lib/video-recap/skills/video-cut/scripts/lib.py +23 -25
- package/lib/video-recap/skills/video-cut/scripts/media_geometry.py +70 -173
- package/lib/video-recap/skills/video-cut/scripts/narration_mapping.py +28 -53
- package/lib/video-recap/skills/video-cut/scripts/sentence_boundaries.py +162 -322
- package/lib/video-recap/skills/video-recap/references/timeline-and-jianying.md +6 -7
- package/lib/video-recap/skills/video-recap/scripts/doctor.py +104 -124
- package/lib/video-recap/skills/video-recap/scripts/final_qc.py +255 -412
- package/lib/video-recap/skills/video-recap/scripts/lib.py +30 -52
- package/lib/video-recap/skills/video-recap/scripts/materials.py +97 -120
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc_client.py +7 -12
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc_evidence.py +46 -97
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc_observations.py +18 -36
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc_payload.py +29 -47
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc_report.py +43 -76
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc_runner.py +2 -1
- package/lib/video-recap/skills/video-recap/scripts/qc_contract.py +2 -1
- package/lib/video-recap/skills/video-recap/scripts/recap_cli.py +2 -2
- package/lib/video-recap/skills/video-recap/scripts/recap_inspect.py +129 -145
- package/lib/video-recap/skills/video-recap/scripts/recap_review.py +27 -20
- package/lib/video-recap/skills/video-recap/scripts/recap_runner.py +20 -31
- package/lib/video-recap/skills/video-recap/scripts/recap_runtime.py +31 -106
- package/lib/video-recap/skills/video-recap/scripts/recap_stage_qc.py +43 -113
- package/lib/video-recap/skills/video-recap/scripts/recap_timeline.py +196 -377
- package/lib/video-recap/skills/video-script/scripts/agent_brief.py +1 -1
- package/lib/video-recap/skills/video-script/scripts/agent_text.py +63 -172
- package/lib/video-recap/skills/video-script/scripts/brief_context.py +80 -135
- package/lib/video-recap/skills/video-script/scripts/brief_inputs.py +125 -167
- package/lib/video-recap/skills/video-script/scripts/brief_timeline.py +93 -208
- package/lib/video-recap/skills/video-script/scripts/deslop_qc.py +20 -46
- package/lib/video-recap/skills/video-script/scripts/lib.py +30 -26
- package/lib/video-recap/skills/video-script/scripts/narration_lint.py +145 -140
- package/lib/video-recap/skills/video-script/scripts/review_response.py +12 -42
- package/lib/video-recap/skills/video-script/scripts/review_runner.py +0 -6
- package/lib/video-recap/skills/video-script/scripts/speech_ownership.py +39 -100
- package/lib/video-recap/skills/video-script/scripts/timeline_fusion.py +33 -124
- package/lib/video-recap/skills/video-understanding/scripts/agent_brief.py +1 -1
- package/lib/video-recap/skills/video-understanding/scripts/agent_text.py +63 -172
- package/lib/video-recap/skills/video-understanding/scripts/asr.py +1 -2
- package/lib/video-recap/skills/video-understanding/scripts/brief_context.py +80 -135
- package/lib/video-recap/skills/video-understanding/scripts/brief_inputs.py +125 -167
- package/lib/video-recap/skills/video-understanding/scripts/brief_timeline.py +93 -208
- package/lib/video-recap/skills/video-understanding/scripts/consolidate.py +1 -1
- package/lib/video-recap/skills/video-understanding/scripts/deslop_qc.py +20 -46
- package/lib/video-recap/skills/video-understanding/scripts/lib.py +31 -26
- package/lib/video-recap/skills/video-understanding/scripts/narration_lint.py +145 -140
- package/lib/video-recap/skills/video-understanding/scripts/speech_ownership.py +39 -100
- package/lib/video-recap/skills/video-understanding/scripts/timeline_fusion.py +33 -124
- package/lib/video-recap/skills/video-understanding/scripts/vlm.py +1 -4
- package/lib/video-recap/skills/video-voiceover/scripts/dub.py +7 -13
- package/lib/video-recap/skills/video-voiceover/scripts/fish_audio.py +12 -30
- package/lib/video-recap/skills/video-voiceover/scripts/lib.py +98 -131
- package/lib/video-recap/skills/video-voiceover/scripts/tts_audio.py +17 -28
- package/lib/video-recap/skills/video-voiceover/scripts/voiceover.py +151 -240
- package/package.json +41 -41
|
@@ -1,30 +1,10 @@
|
|
|
1
1
|
"""Normalize, split, budget, and de-duplicate narration text."""
|
|
2
2
|
|
|
3
|
-
import importlib.util
|
|
4
|
-
|
|
5
3
|
import copy
|
|
6
|
-
|
|
7
|
-
|
|
8
4
|
import re
|
|
9
5
|
|
|
10
|
-
from
|
|
11
|
-
|
|
12
|
-
from lib import CONFIG
|
|
13
|
-
|
|
14
|
-
from lib import log
|
|
15
|
-
|
|
16
|
-
try:
|
|
17
|
-
from deslop_qc import analyze_deslop_qc
|
|
18
|
-
except ModuleNotFoundError:
|
|
19
|
-
_deslop_qc_path = Path(__file__).with_name("deslop_qc.py")
|
|
20
|
-
_deslop_qc_spec = importlib.util.spec_from_file_location(
|
|
21
|
-
"deslop_qc", _deslop_qc_path
|
|
22
|
-
)
|
|
23
|
-
if _deslop_qc_spec is None or _deslop_qc_spec.loader is None:
|
|
24
|
-
raise
|
|
25
|
-
_deslop_qc_module = importlib.util.module_from_spec(_deslop_qc_spec)
|
|
26
|
-
_deslop_qc_spec.loader.exec_module(_deslop_qc_module)
|
|
27
|
-
analyze_deslop_qc = _deslop_qc_module.analyze_deslop_qc
|
|
6
|
+
from lib import CONFIG, log
|
|
7
|
+
from deslop_qc import _sentence_pieces, _text_units
|
|
28
8
|
|
|
29
9
|
|
|
30
10
|
def _format_frame_facts(scene):
|
|
@@ -32,10 +12,7 @@ def _format_frame_facts(scene):
|
|
|
32
12
|
facts = scene.get("frame_facts", {})
|
|
33
13
|
if not facts:
|
|
34
14
|
return ""
|
|
35
|
-
lines = []
|
|
36
|
-
for ts in sorted(facts.keys(), key=lambda x: float(x)):
|
|
37
|
-
actions = facts[ts]
|
|
38
|
-
lines.append(f" {ts}s: {'; '.join(actions)}")
|
|
15
|
+
lines = [f" {ts}s: {'; '.join(facts[ts])}" for ts in sorted(facts, key=float)]
|
|
39
16
|
return "\n 帧动作:\n" + "\n".join(lines)
|
|
40
17
|
|
|
41
18
|
|
|
@@ -45,50 +22,23 @@ def _text_char_count(text):
|
|
|
45
22
|
re.sub(
|
|
46
23
|
r'[,。!?、;:…“”‘’《》〈〉\s"\'「」『』()()【】\[\]—~·,.!?;:\\-]',
|
|
47
24
|
"",
|
|
48
|
-
text
|
|
25
|
+
text,
|
|
49
26
|
)
|
|
50
27
|
)
|
|
51
28
|
|
|
52
29
|
|
|
53
|
-
def _contains_cjk(text):
|
|
54
|
-
return bool(re.search(r"[\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff]", text or ""))
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def _writing_text_units(text):
|
|
58
|
-
"""Length unit used for ASR writing chunks: CJK chars, otherwise words."""
|
|
59
|
-
text = str(text or "")
|
|
60
|
-
if _contains_cjk(text):
|
|
61
|
-
return len(re.sub(r"\s+", "", text))
|
|
62
|
-
return len(re.findall(r"\b\w+\b", text))
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def _sentence_pieces(text):
|
|
66
|
-
"""Split text into sentence-like pieces while keeping terminal punctuation."""
|
|
67
|
-
text = re.sub(r"\s+", " ", str(text or "")).strip()
|
|
68
|
-
if not text:
|
|
69
|
-
return []
|
|
70
|
-
parts = re.split(r"([。!?!?;;.])", text)
|
|
71
|
-
cleaned = []
|
|
72
|
-
for idx in range(0, len(parts), 2):
|
|
73
|
-
body = parts[idx].strip()
|
|
74
|
-
punct = parts[idx + 1] if idx + 1 < len(parts) else ""
|
|
75
|
-
if body or punct:
|
|
76
|
-
cleaned.append((body + punct).strip())
|
|
77
|
-
return cleaned or [text]
|
|
78
|
-
|
|
79
|
-
|
|
80
30
|
def _split_text_by_sentence_windows(text, min_chars=500, max_chars=800):
|
|
81
31
|
"""Clipto-style three-tier sentence boundary splitting for long ASR text."""
|
|
82
|
-
text = re.sub(r"\s+", " ",
|
|
32
|
+
text = re.sub(r"\s+", " ", text).strip()
|
|
83
33
|
if not text:
|
|
84
34
|
return []
|
|
85
|
-
if
|
|
35
|
+
if _text_units(text) <= max_chars:
|
|
86
36
|
return _sentence_pieces(text)
|
|
87
37
|
|
|
88
38
|
result = []
|
|
89
39
|
rest = text
|
|
90
40
|
sentence_marks = "。!?!?;;."
|
|
91
|
-
while
|
|
41
|
+
while _text_units(rest) > max_chars:
|
|
92
42
|
# The min/max thresholds are unit-based but punctuation is char-indexed.
|
|
93
43
|
# For Chinese (the dominant recap target) these are nearly identical; for
|
|
94
44
|
# non-CJK this remains a safe sentence-boundary heuristic around words.
|
|
@@ -102,10 +52,7 @@ def _split_text_by_sentence_windows(text, min_chars=500, max_chars=800):
|
|
|
102
52
|
if ch in sentence_marks:
|
|
103
53
|
outside = i
|
|
104
54
|
break
|
|
105
|
-
if outside >= 0 and outside + 1 <= len(rest)
|
|
106
|
-
cut = outside
|
|
107
|
-
else:
|
|
108
|
-
cut = char_max - 1
|
|
55
|
+
cut = outside if outside >= 0 and outside + 1 <= len(rest) else char_max - 1
|
|
109
56
|
piece = rest[: cut + 1].strip()
|
|
110
57
|
if not piece:
|
|
111
58
|
piece = rest[:char_max].strip()
|
|
@@ -119,19 +66,13 @@ def _split_text_by_sentence_windows(text, min_chars=500, max_chars=800):
|
|
|
119
66
|
|
|
120
67
|
def _timed_sentence_pieces(seg, min_chars, max_chars):
|
|
121
68
|
"""Split one ASR segment into timed sentence pieces with approximate spans."""
|
|
122
|
-
text =
|
|
69
|
+
text = seg["text"].strip()
|
|
123
70
|
if not text:
|
|
124
71
|
return []
|
|
125
|
-
|
|
126
|
-
start = float(seg.get("start", 0))
|
|
127
|
-
end = float(seg.get("end", start))
|
|
128
|
-
except (TypeError, ValueError):
|
|
129
|
-
start = end = 0.0
|
|
130
|
-
if end < start:
|
|
131
|
-
end = start
|
|
72
|
+
start, end = seg["start"], seg["end"]
|
|
132
73
|
pieces = []
|
|
133
74
|
for sentence in _sentence_pieces(text):
|
|
134
|
-
if
|
|
75
|
+
if _text_units(sentence) > max_chars:
|
|
135
76
|
pieces.extend(
|
|
136
77
|
_split_text_by_sentence_windows(
|
|
137
78
|
sentence, min_chars=min_chars, max_chars=max_chars
|
|
@@ -139,20 +80,19 @@ def _timed_sentence_pieces(seg, min_chars, max_chars):
|
|
|
139
80
|
)
|
|
140
81
|
else:
|
|
141
82
|
pieces.append(sentence)
|
|
142
|
-
total_units = sum(max(1,
|
|
143
|
-
duration =
|
|
83
|
+
total_units = sum(max(1, _text_units(piece)) for piece in pieces)
|
|
84
|
+
duration = end - start
|
|
144
85
|
cursor = start
|
|
145
86
|
timed = []
|
|
146
87
|
for idx, piece in enumerate(pieces):
|
|
147
|
-
units = max(1,
|
|
148
|
-
|
|
149
|
-
piece_end = end if idx == len(pieces) - 1 else cursor + piece_duration
|
|
88
|
+
units = max(1, _text_units(piece))
|
|
89
|
+
piece_end = end if idx == len(pieces) - 1 else cursor + duration * units / total_units
|
|
150
90
|
timed.append(
|
|
151
91
|
{
|
|
152
92
|
"start": round(cursor, 2),
|
|
153
93
|
"end": round(piece_end, 2),
|
|
154
94
|
"text": piece,
|
|
155
|
-
"char_count":
|
|
95
|
+
"char_count": _text_units(piece),
|
|
156
96
|
}
|
|
157
97
|
)
|
|
158
98
|
cursor = piece_end
|
|
@@ -160,25 +100,18 @@ def _timed_sentence_pieces(seg, min_chars, max_chars):
|
|
|
160
100
|
|
|
161
101
|
|
|
162
102
|
def _scene_ids_for_range(scenes, start, end):
|
|
103
|
+
duration = max(0.001, end - start)
|
|
163
104
|
scene_ids = []
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
try:
|
|
167
|
-
s_start = float(scene.get("start", 0))
|
|
168
|
-
s_end = float(scene.get("end", s_start))
|
|
169
|
-
except (TypeError, ValueError):
|
|
170
|
-
continue
|
|
171
|
-
overlap = _overlap_seconds(start, end, s_start, s_end)
|
|
105
|
+
for scene in scenes:
|
|
106
|
+
overlap = _overlap_seconds(start, end, scene["start"], scene["end"])
|
|
172
107
|
# Ignore tiny boundary tails from approximate ASR sentence timing. A
|
|
173
108
|
# scene id should mean the chunk materially belongs to that scene.
|
|
174
109
|
if overlap and (overlap >= duration * 0.2 or overlap >= 3.0):
|
|
175
|
-
scene_ids.append(scene
|
|
176
|
-
return
|
|
110
|
+
scene_ids.append(scene["scene_id"])
|
|
111
|
+
return scene_ids
|
|
177
112
|
|
|
178
113
|
|
|
179
|
-
def _chunk_asr_for_writing(
|
|
180
|
-
segments, scenes_analysis=None, min_chars=None, max_chars=None
|
|
181
|
-
):
|
|
114
|
+
def _chunk_asr_for_writing(segments, scenes_analysis, min_chars=None, max_chars=None):
|
|
182
115
|
"""Chunk ASR into semantic windows before an agent writes long-dialogue recaps.
|
|
183
116
|
|
|
184
117
|
The strategy mirrors Clipto's segment splitter: accumulate a window, prefer
|
|
@@ -186,15 +119,13 @@ def _chunk_asr_for_writing(
|
|
|
186
119
|
boundary outside the window, and fall back to the remaining text. CJK text is
|
|
187
120
|
measured by characters; non-CJK text is measured by words.
|
|
188
121
|
"""
|
|
189
|
-
min_chars =
|
|
190
|
-
max_chars =
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if isinstance(seg, dict):
|
|
197
|
-
pieces.extend(_timed_sentence_pieces(seg, min_chars, max_chars))
|
|
122
|
+
min_chars = CONFIG["asr_chunk_min_chars"] if min_chars is None else min_chars
|
|
123
|
+
max_chars = CONFIG["asr_chunk_max_chars"] if max_chars is None else max_chars
|
|
124
|
+
pieces = [
|
|
125
|
+
piece
|
|
126
|
+
for seg in segments
|
|
127
|
+
for piece in _timed_sentence_pieces(seg, min_chars, max_chars)
|
|
128
|
+
]
|
|
198
129
|
|
|
199
130
|
chunks = []
|
|
200
131
|
current = []
|
|
@@ -208,8 +139,8 @@ def _chunk_asr_for_writing(
|
|
|
208
139
|
chunks.append(
|
|
209
140
|
{
|
|
210
141
|
"chunk_id": len(chunks),
|
|
211
|
-
"start":
|
|
212
|
-
"end":
|
|
142
|
+
"start": current[0]["start"],
|
|
143
|
+
"end": current[-1]["end"],
|
|
213
144
|
"scene_ids": sorted(
|
|
214
145
|
current_scene_ids, key=lambda sid: (isinstance(sid, str), sid)
|
|
215
146
|
),
|
|
@@ -223,9 +154,7 @@ def _chunk_asr_for_writing(
|
|
|
223
154
|
current_scene_ids = set()
|
|
224
155
|
|
|
225
156
|
for piece in pieces:
|
|
226
|
-
units = max(
|
|
227
|
-
1, int(piece.get("char_count", _writing_text_units(piece.get("text", ""))))
|
|
228
|
-
)
|
|
157
|
+
units = max(1, piece["char_count"])
|
|
229
158
|
piece_scene_ids = set(
|
|
230
159
|
_scene_ids_for_range(scenes_analysis, piece["start"], piece["end"])
|
|
231
160
|
)
|
|
@@ -279,12 +208,6 @@ def _post_dedup_narration(narration):
|
|
|
279
208
|
result = [narration[0]]
|
|
280
209
|
for seg in narration[1:]:
|
|
281
210
|
prev = result[-1]
|
|
282
|
-
if (
|
|
283
|
-
not prev.get("narration", "").strip()
|
|
284
|
-
or not seg.get("narration", "").strip()
|
|
285
|
-
):
|
|
286
|
-
result.append(seg)
|
|
287
|
-
continue
|
|
288
211
|
set_a, set_b = _char_bigrams(prev["narration"]), _char_bigrams(seg["narration"])
|
|
289
212
|
if not set_a or not set_b:
|
|
290
213
|
result.append(seg)
|
|
@@ -294,20 +217,15 @@ def _post_dedup_narration(narration):
|
|
|
294
217
|
# bigrams by chance, so a low threshold collapses intentional parallel beats
|
|
295
218
|
# ("他不再试探" / "他直接赌上全力") and silently drops density below target.
|
|
296
219
|
if overlap > 0.6:
|
|
297
|
-
# Validation is also the handoff boundary for renderer metadata
|
|
298
|
-
#
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
raw_overlays = candidate.get("visual_overlays")
|
|
303
|
-
if isinstance(raw_overlays, list):
|
|
304
|
-
merged_overlays.extend(copy.deepcopy(raw_overlays))
|
|
220
|
+
# Validation is also the handoff boundary for renderer metadata: keep the
|
|
221
|
+
# overlays authored on either merged beat.
|
|
222
|
+
merged_overlays = copy.deepcopy(
|
|
223
|
+
prev.get("visual_overlays", []) + seg.get("visual_overlays", [])
|
|
224
|
+
)
|
|
305
225
|
if len(seg["narration"]) > len(prev["narration"]):
|
|
306
226
|
prev["narration"] = seg["narration"]
|
|
307
227
|
prev["end"] = seg["end"]
|
|
308
|
-
prev["pause_after_ms"] = seg
|
|
309
|
-
"pause_after_ms", prev.get("pause_after_ms", 600)
|
|
310
|
-
)
|
|
228
|
+
prev["pause_after_ms"] = seg["pause_after_ms"]
|
|
311
229
|
if merged_overlays:
|
|
312
230
|
prev["visual_overlays"] = merged_overlays
|
|
313
231
|
log(f" 去重合并: {prev['start']:.0f}-{prev['end']:.0f}s")
|
|
@@ -319,56 +237,39 @@ def _post_dedup_narration(narration):
|
|
|
319
237
|
return result
|
|
320
238
|
|
|
321
239
|
|
|
322
|
-
def _scene_available_seconds(start, end
|
|
323
|
-
|
|
324
|
-
tail_pad = max(0.0, float(CONFIG.get("narration_tail_pad_seconds", 0.1) or 0.0))
|
|
325
|
-
return max(0.0, float(end) - float(start) - tail_pad)
|
|
240
|
+
def _scene_available_seconds(start, end):
|
|
241
|
+
return max(0.0, end - start - CONFIG["narration_tail_pad_seconds"])
|
|
326
242
|
|
|
327
243
|
|
|
328
|
-
def _recommended_char_budget(start, end
|
|
244
|
+
def _recommended_char_budget(start, end):
|
|
329
245
|
# account for the global narration atempo (CONFIG['narration_speed']) so a beat's text
|
|
330
246
|
# is budgeted against the FINAL sped-up audio, not the raw TTS rate — otherwise windows
|
|
331
247
|
# are over-sized and the bed shows long silent gaps between sentences.
|
|
332
248
|
effective_rate = (
|
|
333
|
-
CONFIG["speech_rate"]
|
|
334
|
-
* CONFIG["speech_safety_margin"]
|
|
335
|
-
* float(CONFIG.get("narration_speed", 1.0) or 1.0)
|
|
249
|
+
CONFIG["speech_rate"] * CONFIG["speech_safety_margin"] * CONFIG["narration_speed"]
|
|
336
250
|
)
|
|
337
|
-
|
|
338
|
-
return max(0, int(available * effective_rate))
|
|
251
|
+
return int(_scene_available_seconds(start, end) * effective_rate)
|
|
339
252
|
|
|
340
253
|
|
|
341
254
|
def _find_scene_for_midpoint(scenes_analysis, start, end):
|
|
342
|
-
mid = (
|
|
255
|
+
mid = (start + end) / 2
|
|
343
256
|
for scene in scenes_analysis:
|
|
344
257
|
if scene["start"] <= mid <= scene["end"]:
|
|
345
258
|
return scene
|
|
346
259
|
return None
|
|
347
260
|
|
|
348
261
|
|
|
349
|
-
def _normalise_narration_segment(seg
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
except (TypeError, ValueError):
|
|
356
|
-
return None
|
|
357
|
-
if end <= start:
|
|
358
|
-
return None
|
|
359
|
-
text = str(seg.get("narration", "")).strip()
|
|
360
|
-
if not text:
|
|
361
|
-
return None
|
|
362
|
-
pause = seg.get("pause_after_ms", CONFIG.get("breath_ms", 250))
|
|
363
|
-
try:
|
|
364
|
-
pause = int(pause)
|
|
365
|
-
except (TypeError, ValueError):
|
|
366
|
-
pause = CONFIG.get("breath_ms", 250)
|
|
262
|
+
def _normalise_narration_segment(seg):
|
|
263
|
+
"""Normalize one lint-validated narration segment for the full-mode rewrite.
|
|
264
|
+
|
|
265
|
+
Authored timing is a delivery contract: scene boundaries are approximate
|
|
266
|
+
visual-analysis buckets, so start/end are never clamped here.
|
|
267
|
+
"""
|
|
367
268
|
item = {
|
|
368
|
-
"start": round(start, 2),
|
|
369
|
-
"end": round(end, 2),
|
|
370
|
-
"narration":
|
|
371
|
-
"pause_after_ms":
|
|
269
|
+
"start": round(seg["start"], 2),
|
|
270
|
+
"end": round(seg["end"], 2),
|
|
271
|
+
"narration": str(seg["narration"]).strip(),
|
|
272
|
+
"pause_after_ms": int(seg.get("pause_after_ms", CONFIG["breath_ms"])),
|
|
372
273
|
"overlaps_speech": bool(seg.get("overlaps_speech", True)),
|
|
373
274
|
}
|
|
374
275
|
for optional_key in (
|
|
@@ -381,30 +282,20 @@ def _normalise_narration_segment(seg, scenes_analysis=None):
|
|
|
381
282
|
if optional_key in seg:
|
|
382
283
|
item[optional_key] = seg[optional_key]
|
|
383
284
|
# carry the per-beat emotion/tone tag (MiMo TTS instruct) through lint untouched
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
#
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
visual_overlays = seg.get("visual_overlays")
|
|
391
|
-
if isinstance(visual_overlays, list):
|
|
392
|
-
item["visual_overlays"] = copy.deepcopy(visual_overlays)
|
|
393
|
-
# Authored timing is a delivery contract. Scene boundaries are approximate
|
|
394
|
-
# visual-analysis buckets, while source sentence anchors are measured audio
|
|
395
|
-
# handoff points. Lint may warn when a block crosses a scene, but validation
|
|
396
|
-
# must never silently clamp start/end and invalidate an audio-safe handoff.
|
|
285
|
+
if seg.get("emotion"):
|
|
286
|
+
item["emotion"] = seg["emotion"].strip()
|
|
287
|
+
# Renderer-owned metadata survives the validation rewrite; the recap orchestrator
|
|
288
|
+
# filters supported overlay kinds later.
|
|
289
|
+
if "visual_overlays" in seg:
|
|
290
|
+
item["visual_overlays"] = copy.deepcopy(seg["visual_overlays"])
|
|
397
291
|
return item
|
|
398
292
|
|
|
399
293
|
|
|
400
294
|
def _clean_narration_punctuation(text):
|
|
401
|
-
text = re.sub(r"\s+", " ", text
|
|
295
|
+
text = re.sub(r"\s+", " ", text).strip()
|
|
402
296
|
text = re.sub(r'[,:、;,]["\']?[。!?]', "。", text)
|
|
403
|
-
|
|
404
|
-
return text
|
|
297
|
+
return re.sub(r'["\']。$', "。", text)
|
|
405
298
|
|
|
406
299
|
|
|
407
300
|
def _overlap_seconds(start, end, other_start, other_end):
|
|
408
|
-
return max(
|
|
409
|
-
0.0, min(float(end), float(other_end)) - max(float(start), float(other_start))
|
|
410
|
-
)
|
|
301
|
+
return max(0.0, min(end, other_end) - max(start, other_start))
|
|
@@ -176,8 +176,7 @@ def _strip_reasoning_residue(text):
|
|
|
176
176
|
"""
|
|
177
177
|
text = re.sub(r"(?is)<think\b.*?</think\s*>", "", text) # full <think>…</think> block
|
|
178
178
|
text = re.sub(r"(?is)<think\b.*\Z", "", text) # unclosed/truncated <think tail
|
|
179
|
-
|
|
180
|
-
return text
|
|
179
|
+
return re.sub(r"(?i)^\s*<?/?think\s*>\s*", "", text) # leading orphan/residual think tag
|
|
181
180
|
|
|
182
181
|
|
|
183
182
|
def _run_asr(wav_path):
|