@oh-story/dsh 0.1.11 → 0.1.13
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 +17 -11
- package/lib/client.js +85 -35
- package/lib/client.js.map +3 -3
- package/lib/drama/manifest.json +41 -36
- package/lib/drama/skills/short-drama/scripts/creator_markdown_check.py +340 -13
- package/lib/drama/skills/short-drama-assets/references/voice-direction.md +4 -2
- package/lib/drama/skills/short-drama-edit/SKILL.md +32 -12
- package/lib/drama/skills/short-drama-edit/references/still-cuts.md +90 -0
- package/lib/drama/skills/short-drama-edit/scripts/edit_tool.py +1035 -145
- package/lib/drama/skills/short-drama-edit/scripts/selftest.py +48 -0
- package/lib/drama/skills/short-drama-produce/SKILL.md +6 -1
- package/lib/drama/skills/short-drama-produce/references/adapter-contract.md +12 -0
- package/lib/drama/skills/short-drama-produce/scripts/production_tool.py +138 -9
- package/lib/drama/skills/short-drama-produce/scripts/provider_adapters.py +6 -0
- package/lib/drama/skills/short-drama-storyboard/SKILL.md +2 -0
- package/lib/drama/skills/short-drama-storyboard/references/production-shot-grammar.md +3 -1
- package/lib/drama/skills/short-drama-video-prompts/SKILL.md +7 -0
- package/lib/drama/skills/short-drama-video-prompts/references/performance-action-timing.md +14 -0
- package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.5.md +19 -6
- package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +1 -0
- package/lib/drama/skills/short-drama-video-prompts/references/target-model-profile.md +5 -0
- package/lib/drama/skills/short-drama-video-prompts/references/wan-3.0.md +4 -1
- package/lib/index.js +16 -7
- package/lib/index.js.map +2 -2
- package/lib/novel-to-game/README.md +98 -44
- package/lib/novel-to-game/README_ZH.md +100 -46
- package/lib/novel-to-game/VERSION +1 -1
- package/lib/novel-to-game/examples/jin-ping-mei/build/BUILD_BRIEF.md +27 -202
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/RUN.md +23 -115
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/chamber.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/court_night.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/court_rain.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/garden.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/hall.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/kitchen.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/street.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/street_dawn.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/temple.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/yue/moon.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/angry.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/blush.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/neutral.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/sad.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/smile.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/surprised.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/angry.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/blush.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/neutral.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/sad.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/smile.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/surprised.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/angry.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/blush.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/neutral.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/sad.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/smile.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/surprised.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/angry.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/blush.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/neutral.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/sad.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/smile.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/surprised.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/angry.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/blush.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/neutral.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/sad.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/smile.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/surprised.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/style.css +326 -2503
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/index.html +71 -4
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/adv.js +221 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/audio.js +113 -257
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/main.js +511 -3026
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/menus.js +277 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/petals.js +67 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/stage.js +180 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/store.js +70 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/common.js +198 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/common2.js +204 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/common3.js +198 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/dates.js +186 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/index.js +122 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/meng.js +190 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/pan.js +212 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/pinger.js +198 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/xuee.js +199 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/yue.js +214 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/package.json +2 -2
- package/lib/novel-to-game/examples/jin-ping-mei/build/art/generated-art.json +182 -45
- package/lib/novel-to-game/examples/jin-ping-mei/qa/README.md +7 -17
- package/lib/novel-to-game/examples/jin-ping-mei/qa/verification.json +9 -9
- package/lib/novel-to-game/manifest.json +303 -78
- package/lib/novel-to-game/skills/game-art-direction/references/art-direction-method.md +7 -2
- package/lib/novel-to-game/skills/game-concept/references/concept-method.md +2 -0
- package/lib/novel-to-game/skills/game-world-design/references/narrative-design-method.md +2 -0
- package/lib/novel-to-game/skills/game-world-design/references/world-design-method.md +9 -0
- package/lib/types/client/drama-production-view.d.ts +11 -0
- package/lib/types/client/drama-production-view.d.ts.map +1 -1
- package/lib/types/client/file-activity.d.ts +1 -1
- package/lib/types/client/file-activity.d.ts.map +1 -1
- package/lib/types/client/production-prompts.d.ts +7 -1
- package/lib/types/client/production-prompts.d.ts.map +1 -1
- package/lib/types/client/production-runtime.d.ts +7 -2
- package/lib/types/client/production-runtime.d.ts.map +1 -1
- package/lib/types/drama-adapters.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/video-recap/CHANGELOG.md +108 -1
- package/lib/video-recap/README.en.md +18 -14
- package/lib/video-recap/README.md +18 -14
- package/lib/video-recap/manifest.json +297 -321
- package/lib/video-recap/skills/video-assemble/SKILL.md +18 -16
- package/lib/video-recap/skills/video-assemble/references/explicit-audio-mix.md +3 -1
- package/lib/video-recap/skills/video-assemble/references/jianying/SOURCE.md +5 -5
- package/lib/video-recap/skills/video-assemble/references/packaging.md +4 -4
- package/lib/video-recap/skills/video-assemble/references/subtitle-track.md +10 -10
- package/lib/video-recap/skills/video-assemble/scripts/adoption/audio_mix_binding.py +13 -2
- package/lib/video-recap/skills/video-assemble/scripts/adoption/av_clock.py +109 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/strict_publish.py +4 -1
- package/lib/video-recap/skills/video-assemble/scripts/artifacts.py +2 -9
- package/lib/video-recap/skills/video-assemble/scripts/assemble.py +188 -51
- package/lib/video-recap/skills/video-assemble/scripts/assemble_constants.py +0 -1
- package/lib/video-recap/skills/video-assemble/scripts/assembly_contract.py +32 -75
- package/lib/video-recap/skills/video-assemble/scripts/assembly_settings.py +8 -15
- package/lib/video-recap/skills/video-assemble/scripts/audio_mix.py +202 -161
- package/lib/video-recap/skills/video-assemble/scripts/codec_peak.py +112 -0
- package/lib/video-recap/skills/video-assemble/scripts/export_jianying.py +10 -101
- package/lib/video-recap/skills/video-assemble/scripts/jianying/builders.py +44 -475
- package/lib/video-recap/skills/video-assemble/scripts/jianying/model.py +1 -22
- package/lib/video-recap/skills/video-assemble/scripts/jianying/templates.py +0 -3
- package/lib/video-recap/skills/video-assemble/scripts/jianying/timeline_contract.py +36 -103
- package/lib/video-recap/skills/video-assemble/scripts/jianying/tracks.py +0 -8
- package/lib/video-recap/skills/video-assemble/scripts/jianying/writer.py +28 -203
- package/lib/video-recap/skills/video-assemble/scripts/lib.py +20 -34
- package/lib/video-recap/skills/video-assemble/scripts/loudness.py +332 -0
- package/lib/video-recap/skills/video-assemble/scripts/media.py +158 -38
- package/lib/video-recap/skills/video-assemble/scripts/narration_audio.py +30 -16
- package/lib/video-recap/skills/video-assemble/scripts/render_preflight.py +49 -8
- package/lib/video-recap/skills/video-assemble/scripts/source_subtitles.py +17 -6
- package/lib/video-recap/skills/video-assemble/scripts/subtitles/core.py +24 -2
- package/lib/video-recap/skills/video-assemble/scripts/subtitles/track.py +2 -5
- package/lib/video-recap/skills/video-assemble/scripts/subtitles/track_binding.py +2 -9
- package/lib/video-recap/skills/video-assemble/scripts/timeline.py +12 -34
- package/lib/video-recap/skills/video-assemble/scripts/timeline_emit.py +3 -4
- package/lib/video-recap/skills/video-assemble/scripts/visual_render.py +28 -2
- package/lib/video-recap/skills/video-cut/SKILL.md +37 -11
- package/lib/video-recap/skills/video-cut/references/shot-review.md +1 -1
- package/lib/video-recap/skills/video-cut/scripts/cut.py +2 -34
- package/lib/video-recap/skills/video-cut/scripts/cut_cli.py +96 -124
- package/lib/video-recap/skills/video-cut/scripts/cut_contract.py +97 -182
- package/lib/video-recap/skills/video-cut/scripts/cut_render.py +177 -166
- package/lib/video-recap/skills/video-cut/scripts/frame_grid.py +249 -0
- package/lib/video-recap/skills/video-cut/scripts/lib.py +0 -3
- package/lib/video-recap/skills/video-cut/scripts/media_geometry.py +173 -7
- package/lib/video-recap/skills/video-cut/scripts/sentence_boundaries.py +234 -151
- package/lib/video-recap/skills/video-cut/scripts/sentence_gate.py +189 -0
- package/lib/video-recap/skills/video-cut/scripts/shot_review.py +2 -6
- package/lib/video-recap/skills/video-recap/SKILL.md +24 -27
- package/lib/video-recap/skills/video-recap/references/audio-routing.md +8 -6
- package/lib/video-recap/skills/video-recap/references/config-playbook.md +8 -11
- package/lib/video-recap/skills/video-recap/references/data-schema.md +131 -74
- package/lib/video-recap/skills/video-recap/references/resource-library.md +17 -1
- package/lib/video-recap/skills/video-recap/scripts/doctor.py +51 -268
- package/lib/video-recap/skills/video-recap/scripts/final_qc.py +89 -254
- package/lib/video-recap/skills/video-recap/scripts/lib.py +81 -70
- package/lib/video-recap/skills/video-recap/scripts/library.py +40 -4
- package/lib/video-recap/skills/video-recap/scripts/materials.py +13 -80
- package/lib/video-recap/skills/video-recap/scripts/recap_cli.py +49 -17
- package/lib/video-recap/skills/video-recap/scripts/recap_inspect.py +1 -3
- package/lib/video-recap/skills/video-recap/scripts/recap_runner.py +86 -116
- package/lib/video-recap/skills/video-recap/scripts/recap_runtime.py +87 -23
- package/lib/video-recap/skills/video-recap/scripts/recap_source.py +0 -39
- package/lib/video-recap/skills/video-recap/scripts/recap_stage_qc.py +37 -135
- package/lib/video-recap/skills/video-recap/scripts/recap_timeline.py +118 -127
- package/lib/video-recap/skills/video-recap/scripts/resources/__init__.py +4 -0
- package/lib/video-recap/skills/video-recap/scripts/{resource_lock.py → resources/lock.py} +1 -1
- package/lib/video-recap/skills/video-recap/scripts/{project_binding.py → resources/project_binding.py} +78 -17
- package/lib/video-recap/skills/video-reference/SKILL.md +108 -0
- package/lib/video-recap/skills/video-reference/references/reference-schema.md +139 -0
- package/lib/video-recap/skills/video-reference/scripts/lib.py +85 -0
- package/lib/video-recap/skills/video-reference/scripts/reference.py +96 -0
- package/lib/video-recap/skills/video-reference/scripts/reference_check.py +553 -0
- package/lib/video-recap/skills/video-reference/scripts/reference_frames.py +122 -0
- package/lib/video-recap/skills/video-reference/scripts/reference_measure.py +253 -0
- package/lib/video-recap/skills/video-reference/scripts/reference_profile.py +271 -0
- package/lib/video-recap/skills/video-script/SKILL.md +9 -7
- package/lib/video-recap/skills/video-script/scripts/agent_text.py +18 -267
- package/lib/video-recap/skills/video-script/scripts/deslop_qc.py +12 -30
- package/lib/video-recap/skills/video-script/scripts/entry_suggestion.py +125 -0
- package/lib/video-recap/skills/video-script/scripts/evidence_bundle.py +2 -26
- package/lib/video-recap/skills/video-script/scripts/lib.py +5 -15
- package/lib/video-recap/skills/video-script/scripts/lint_summary.py +184 -0
- package/lib/video-recap/skills/video-script/scripts/narration_lint.py +120 -100
- package/lib/video-recap/skills/video-script/scripts/review.py +3 -34
- package/lib/video-recap/skills/video-script/scripts/review_grounding.py +20 -46
- package/lib/video-recap/skills/video-script/scripts/review_response.py +120 -258
- package/lib/video-recap/skills/video-script/scripts/review_runner.py +2 -10
- package/lib/video-recap/skills/video-script/scripts/speech_ownership.py +89 -5
- package/lib/video-recap/skills/video-script/scripts/validate.py +26 -34
- package/lib/video-recap/skills/video-understanding/SKILL.md +29 -4
- package/lib/video-recap/skills/video-understanding/references/data-schema.md +5 -22
- package/lib/video-recap/skills/video-understanding/scripts/agent_text.py +24 -121
- package/lib/video-recap/skills/video-understanding/scripts/asr.py +11 -5
- package/lib/video-recap/skills/video-understanding/scripts/asr_timing_evidence.py +15 -24
- package/lib/video-recap/skills/video-understanding/scripts/briefing/builder.py +59 -25
- package/lib/video-recap/skills/video-understanding/scripts/briefing/context.py +39 -3
- package/lib/video-recap/skills/video-understanding/scripts/briefing/inputs.py +15 -27
- package/lib/video-recap/skills/video-understanding/scripts/briefing/timeline.py +136 -37
- package/lib/video-recap/skills/video-understanding/scripts/consolidate.py +121 -37
- package/lib/video-recap/skills/video-understanding/scripts/detect.py +118 -16
- package/lib/video-recap/skills/video-understanding/scripts/index_normalize.py +359 -0
- package/lib/video-recap/skills/video-understanding/scripts/lib.py +62 -21
- package/lib/video-recap/skills/video-understanding/scripts/storyboard.py +181 -51
- package/lib/video-recap/skills/video-understanding/scripts/timeline_fusion.py +0 -26
- package/lib/video-recap/skills/video-understanding/scripts/understanding_brief.py +37 -14
- package/lib/video-recap/skills/video-understanding/scripts/understanding_cache.py +40 -32
- package/lib/video-recap/skills/video-understanding/scripts/understanding_runner.py +100 -127
- package/lib/video-recap/skills/video-understanding/scripts/understanding_storyboard.py +182 -30
- package/lib/video-recap/skills/video-understanding/scripts/vlm.py +30 -27
- package/lib/video-recap/skills/video-voiceover/SKILL.md +19 -12
- package/lib/video-recap/skills/video-voiceover/references/index-tts.md +3 -3
- package/lib/video-recap/skills/video-voiceover/scripts/approved_text_policy.py +3 -1
- package/lib/video-recap/skills/video-voiceover/scripts/dub.py +60 -135
- package/lib/video-recap/skills/video-voiceover/scripts/lib.py +9 -34
- package/lib/video-recap/skills/video-voiceover/scripts/providers/fish_audio.py +6 -1
- package/lib/video-recap/skills/video-voiceover/scripts/tts_audio.py +64 -1
- package/lib/video-recap/skills/video-voiceover/scripts/tts_cache.py +99 -0
- package/lib/video-recap/skills/video-voiceover/scripts/voiceover.py +177 -200
- package/package.json +45 -45
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/inner_court_accord_five.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/public_day15.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/household/li_jiaoer.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/new-guofeng.css +0 -1494
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/assets.js +0 -147
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/data.js +0 -7470
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/engine.js +0 -13066
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/text.js +0 -32
- package/lib/novel-to-game/examples/jin-ping-mei/qa/playable-model.json +0 -99
- package/lib/novel-to-game/examples/jin-ping-mei/qa/verify_playable_model.mjs +0 -152
- package/lib/video-recap/skills/video-assemble/references/foreground-compose.md +0 -118
- package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_combination_segment.json +0 -84
- package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_combination_video_material.json +0 -98
- package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_draft.json +0 -204
- package/lib/video-recap/skills/video-assemble/references/pair-media.md +0 -74
- package/lib/video-recap/skills/video-assemble/scripts/compose_foreground.py +0 -293
- package/lib/video-recap/skills/video-assemble/scripts/pair_media.py +0 -216
- package/lib/video-recap/skills/video-recap/references/shift-left-qc-schema.md +0 -23
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc.py +0 -33
- package/lib/video-recap/skills/video-recap/scripts/qc/__init__.py +0 -1
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_client.py +0 -13
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_contract.py +0 -9
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_evidence.py +0 -287
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_observations.py +0 -175
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_payload.py +0 -206
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_report.py +0 -318
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_runner.py +0 -130
- package/lib/video-recap/skills/video-recap/scripts/qc_contract.py +0 -320
- package/lib/video-recap/skills/video-script/scripts/timeline_fusion.py +0 -108
- package/lib/video-recap/skills/video-understanding/scripts/brief.py +0 -9
- package/lib/video-recap/skills/video-understanding/scripts/deslop_qc.py +0 -211
- package/lib/video-recap/skills/video-understanding/scripts/narration_lint.py +0 -707
- package/lib/video-recap/skills/video-understanding/scripts/speech_ownership.py +0 -143
- /package/lib/video-recap/skills/video-cut/scripts/{narration_mapping.py → cut_qc.py} +0 -0
|
@@ -10,57 +10,25 @@ import argparse
|
|
|
10
10
|
import json
|
|
11
11
|
import os
|
|
12
12
|
import shutil
|
|
13
|
-
import subprocess
|
|
14
13
|
import sys
|
|
15
14
|
import urllib.parse
|
|
16
15
|
from pathlib import Path
|
|
17
16
|
|
|
18
|
-
from lib import CONFIG
|
|
17
|
+
from lib import CONFIG, TTS_PROVIDERS, env_bool, ffmpeg_filters
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
# index-tts is checked as hard failures below; these providers only need a key.
|
|
22
|
+
TTS_KEY_HINTS = {
|
|
23
|
+
"mimo-tts": "MIMO_TTS_API_KEY or MIMO_API_KEY",
|
|
24
|
+
"fish-audio": "FISH_API_KEY",
|
|
25
|
+
}
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
def _command_path(name: str) -> str | None:
|
|
27
29
|
return shutil.which(name)
|
|
28
30
|
|
|
29
31
|
|
|
30
|
-
def _ffmpeg_filters() -> set[str]:
|
|
31
|
-
"""Filters the installed ffmpeg lists; empty when ffmpeg is absent.
|
|
32
|
-
|
|
33
|
-
A present ffmpeg whose `-filters` fails or hangs is an environment fault and raises,
|
|
34
|
-
so it is never misreported downstream as "filter absent"."""
|
|
35
|
-
ffmpeg = _command_path("ffmpeg")
|
|
36
|
-
if not ffmpeg:
|
|
37
|
-
return set()
|
|
38
|
-
try:
|
|
39
|
-
result = subprocess.run(
|
|
40
|
-
[ffmpeg, "-hide_banner", "-filters"], text=True, capture_output=True, timeout=20
|
|
41
|
-
)
|
|
42
|
-
except (OSError, subprocess.SubprocessError) as exc:
|
|
43
|
-
raise RuntimeError(f"`ffmpeg -filters` failed or hung: {exc}") from exc
|
|
44
|
-
if result.returncode != 0:
|
|
45
|
-
detail = (result.stderr or result.stdout or "").strip()[:300]
|
|
46
|
-
raise RuntimeError(f"`ffmpeg -filters` failed (exit {result.returncode}): {detail}")
|
|
47
|
-
filters = set()
|
|
48
|
-
for line in result.stdout.splitlines():
|
|
49
|
-
parts = line.split()
|
|
50
|
-
if len(parts) >= 2 and parts[0] and parts[0][0] in ".TSCAPN|":
|
|
51
|
-
filters.add(parts[1])
|
|
52
|
-
return filters
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def ffmpeg_has_subtitles_filter() -> bool:
|
|
56
|
-
"""True when this ffmpeg can burn subtitles — its filter list includes the libass
|
|
57
|
-
`subtitles` filter. The render burns even the .ass file through `subtitles=` (see
|
|
58
|
-
video-assemble assemble.py:_subtitle_burn_filter), so this — not the `ass` filter — is
|
|
59
|
-
the exact capability `--burn-subtitles` needs. Reused by the orchestrator preflight
|
|
60
|
-
(recap.py) to fail fast before any API spend."""
|
|
61
|
-
return "subtitles" in _ffmpeg_filters()
|
|
62
|
-
|
|
63
|
-
|
|
64
32
|
def _asr_status() -> dict[str, object]:
|
|
65
33
|
configured = bool(CONFIG["mimo_asr_api_key"])
|
|
66
34
|
return {
|
|
@@ -108,218 +76,8 @@ def _index_tts_status() -> dict[str, object]:
|
|
|
108
76
|
}
|
|
109
77
|
|
|
110
78
|
|
|
111
|
-
def _capability(name: str, summary: str, *, detail: str = "", action: str = "") -> dict[str, str]:
|
|
112
|
-
item = {"name": name, "summary": summary}
|
|
113
|
-
if detail:
|
|
114
|
-
item["detail"] = detail
|
|
115
|
-
if action:
|
|
116
|
-
item["action"] = action
|
|
117
|
-
return item
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def _build_capability_menu(checks: dict) -> dict[str, list[dict[str, str]]]:
|
|
121
|
-
"""Human-ready preflight summary grouped by what can run, what blocks, and what degrades.
|
|
122
|
-
|
|
123
|
-
This is intentionally a small rollup over the existing `checks` tree. It does not replace
|
|
124
|
-
the raw machine checks, install anything, or introduce provider ranking.
|
|
125
|
-
"""
|
|
126
|
-
system = checks["system_tools"]
|
|
127
|
-
api = checks["api_config"]
|
|
128
|
-
asr = checks["asr"]
|
|
129
|
-
tts = checks["tts"]
|
|
130
|
-
|
|
131
|
-
menu: dict[str, list[dict[str, str]]] = {
|
|
132
|
-
"ready": [],
|
|
133
|
-
"blocked": [],
|
|
134
|
-
DEGRADED_GROUP: [],
|
|
135
|
-
"optional_upgrades": [],
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
ffmpeg_ready = system["ffmpeg"]
|
|
139
|
-
ffprobe_ready = system["ffprobe"]
|
|
140
|
-
subtitles_ready = system["burn_subtitles_ready"]
|
|
141
|
-
api_key_set = api["api_key_set"]
|
|
142
|
-
asr_ready = asr["available"]
|
|
143
|
-
tts_ready = tts["available"]
|
|
144
|
-
vlm_ready = api["mimo_video_configured"]
|
|
145
|
-
normal_core_ready = ffmpeg_ready and ffprobe_ready and api_key_set and vlm_ready and tts_ready
|
|
146
|
-
|
|
147
|
-
if ffmpeg_ready and ffprobe_ready:
|
|
148
|
-
menu["ready"].append(
|
|
149
|
-
_capability(
|
|
150
|
-
"core_media_tools",
|
|
151
|
-
"ffmpeg and ffprobe are available",
|
|
152
|
-
detail="Local probing, cutting, rendering, and duration checks can run.",
|
|
153
|
-
)
|
|
154
|
-
)
|
|
155
|
-
else:
|
|
156
|
-
if not ffmpeg_ready:
|
|
157
|
-
menu["blocked"].append(
|
|
158
|
-
_capability("ffmpeg", "Missing ffmpeg", action="Install ffmpeg before running the recap pipeline.")
|
|
159
|
-
)
|
|
160
|
-
if not ffprobe_ready:
|
|
161
|
-
menu["blocked"].append(
|
|
162
|
-
_capability("ffprobe", "Missing ffprobe", action="Install ffprobe before running media probing/export.")
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
if api_key_set:
|
|
166
|
-
menu["ready"].append(
|
|
167
|
-
_capability(
|
|
168
|
-
"mimo_credentials",
|
|
169
|
-
"MiMo API key is configured",
|
|
170
|
-
detail=f"Source: {api['api_env_var']}",
|
|
171
|
-
)
|
|
172
|
-
)
|
|
173
|
-
else:
|
|
174
|
-
menu["blocked"].append(
|
|
175
|
-
_capability(
|
|
176
|
-
"mimo_credentials",
|
|
177
|
-
"Missing MIMO_API_KEY",
|
|
178
|
-
action="Set MIMO_API_KEY; the default ASR / VLM / TTS path depends on it.",
|
|
179
|
-
)
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
if vlm_ready:
|
|
183
|
-
menu["ready"].append(
|
|
184
|
-
_capability(
|
|
185
|
-
"mimo_vlm",
|
|
186
|
-
"MiMo VLM/video understanding is configured",
|
|
187
|
-
detail=f"Model: {api['vlm_model']}",
|
|
188
|
-
)
|
|
189
|
-
)
|
|
190
|
-
elif api_key_set:
|
|
191
|
-
menu["blocked"].append(
|
|
192
|
-
_capability(
|
|
193
|
-
"mimo_vlm",
|
|
194
|
-
"MiMo VLM/video understanding is not configured",
|
|
195
|
-
action="Set MIMO_VIDEO_API_KEY or the shared MIMO_API_KEY before video understanding.",
|
|
196
|
-
)
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
tts_provider = tts["provider"]
|
|
200
|
-
if tts_provider == "index-tts":
|
|
201
|
-
capability_name = "index_tts_configuration"
|
|
202
|
-
action = "Set valid INDEX_TTS_ENDPOINT and INDEX_TTS_VOICE values before voiceover."
|
|
203
|
-
elif tts_provider == "fish-audio":
|
|
204
|
-
capability_name = "fish_audio_tts"
|
|
205
|
-
action = "Set FISH_API_KEY before voiceover."
|
|
206
|
-
else:
|
|
207
|
-
capability_name = "mimo_tts"
|
|
208
|
-
action = "Set MIMO_TTS_API_KEY or the shared MIMO_API_KEY before voiceover."
|
|
209
|
-
if tts_ready:
|
|
210
|
-
menu["ready"].append(
|
|
211
|
-
_capability(
|
|
212
|
-
capability_name,
|
|
213
|
-
(
|
|
214
|
-
"index-tts configuration is present"
|
|
215
|
-
if tts_provider == "index-tts"
|
|
216
|
-
else f"{tts_provider} is configured"
|
|
217
|
-
),
|
|
218
|
-
detail=(
|
|
219
|
-
tts["validation_scope"]
|
|
220
|
-
if tts_provider == "index-tts"
|
|
221
|
-
else f"Model: {tts['model']}"
|
|
222
|
-
),
|
|
223
|
-
)
|
|
224
|
-
)
|
|
225
|
-
elif api_key_set:
|
|
226
|
-
menu["blocked"].append(
|
|
227
|
-
_capability(
|
|
228
|
-
capability_name,
|
|
229
|
-
f"{tts_provider} is not configured",
|
|
230
|
-
action=action,
|
|
231
|
-
)
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
if asr_ready:
|
|
235
|
-
menu["ready"].append(
|
|
236
|
-
_capability(
|
|
237
|
-
"mimo_asr",
|
|
238
|
-
"MiMo ASR is configured",
|
|
239
|
-
detail=f"Language: {asr['mimo_asr_language']}; model: {asr['mimo_asr_model']}",
|
|
240
|
-
)
|
|
241
|
-
)
|
|
242
|
-
else:
|
|
243
|
-
menu[DEGRADED_GROUP].append(
|
|
244
|
-
_capability(
|
|
245
|
-
"mimo_asr",
|
|
246
|
-
"ASR is unavailable; run only with --skip-asr",
|
|
247
|
-
action=asr["note"],
|
|
248
|
-
)
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
if subtitles_ready:
|
|
252
|
-
menu["ready"].append(
|
|
253
|
-
_capability("subtitle_burn", "Subtitle burn-in is available", detail="ffmpeg has the subtitles/libass filter.")
|
|
254
|
-
)
|
|
255
|
-
elif ffmpeg_ready:
|
|
256
|
-
menu[DEGRADED_GROUP].append(
|
|
257
|
-
_capability(
|
|
258
|
-
"subtitle_burn",
|
|
259
|
-
"Subtitle burn-in is unavailable",
|
|
260
|
-
action="Use --no-burn-subtitles or install an ffmpeg build with the subtitles/libass filter.",
|
|
261
|
-
)
|
|
262
|
-
)
|
|
263
|
-
|
|
264
|
-
if not normal_core_ready:
|
|
265
|
-
menu["blocked"].append(
|
|
266
|
-
_capability(
|
|
267
|
-
"default_recap_pipeline",
|
|
268
|
-
"Default recap run is blocked",
|
|
269
|
-
detail="Resolve the blocking items above before a normal run.",
|
|
270
|
-
)
|
|
271
|
-
)
|
|
272
|
-
elif asr_ready and subtitles_ready:
|
|
273
|
-
menu["ready"].append(
|
|
274
|
-
_capability(
|
|
275
|
-
"default_recap_pipeline",
|
|
276
|
-
(
|
|
277
|
-
"Recap prerequisites are configured"
|
|
278
|
-
if tts_provider == "index-tts"
|
|
279
|
-
else "Default recap run is ready"
|
|
280
|
-
),
|
|
281
|
-
detail=(
|
|
282
|
-
"ASR, VLM, and media tools are configured; Index TTS passed offline configuration checks only."
|
|
283
|
-
if tts_provider == "index-tts"
|
|
284
|
-
else "ASR, VLM, TTS, and media tools are configured."
|
|
285
|
-
),
|
|
286
|
-
)
|
|
287
|
-
)
|
|
288
|
-
else:
|
|
289
|
-
actions = []
|
|
290
|
-
if not asr_ready:
|
|
291
|
-
actions.append("run with --skip-asr")
|
|
292
|
-
if not subtitles_ready:
|
|
293
|
-
actions.append("run with --no-burn-subtitles")
|
|
294
|
-
menu[DEGRADED_GROUP].append(
|
|
295
|
-
_capability(
|
|
296
|
-
"recap_degraded_mode",
|
|
297
|
-
"Recap can run only in an explicit degraded mode",
|
|
298
|
-
detail="; ".join(actions),
|
|
299
|
-
)
|
|
300
|
-
)
|
|
301
|
-
|
|
302
|
-
menu["optional_upgrades"].append(
|
|
303
|
-
_capability(
|
|
304
|
-
"jianying_export",
|
|
305
|
-
"Editable JianYing draft export can be requested with --export-jianying",
|
|
306
|
-
detail="No JianYing install is required to write the draft; ffprobe improves media metadata.",
|
|
307
|
-
)
|
|
308
|
-
)
|
|
309
|
-
if subtitles_ready:
|
|
310
|
-
menu["optional_upgrades"].append(
|
|
311
|
-
_capability(
|
|
312
|
-
"burned_subtitles",
|
|
313
|
-
"Burned subtitles are available and enabled by default",
|
|
314
|
-
action="Use --no-burn-subtitles if you prefer external subtitle files.",
|
|
315
|
-
)
|
|
316
|
-
)
|
|
317
|
-
|
|
318
|
-
return menu
|
|
319
|
-
|
|
320
|
-
|
|
321
79
|
def build_report(*, tts_provider: str | None = None) -> dict[str, object]:
|
|
322
|
-
filters =
|
|
80
|
+
filters = ffmpeg_filters()
|
|
323
81
|
ffmpeg_path = _command_path("ffmpeg") or ""
|
|
324
82
|
ffprobe_path = _command_path("ffprobe") or ""
|
|
325
83
|
mimo_video_configured = bool(CONFIG["mimo_video_api_key"])
|
|
@@ -345,6 +103,15 @@ def build_report(*, tts_provider: str | None = None) -> dict[str, object]:
|
|
|
345
103
|
else:
|
|
346
104
|
tts_model = CONFIG["mimo_tts_model"]
|
|
347
105
|
subtitle_filter = "subtitles" in filters
|
|
106
|
+
drawtext_filter = "drawtext" in filters
|
|
107
|
+
burn_explicit = "BURN_SUBTITLES" in os.environ and env_bool("BURN_SUBTITLES", True)
|
|
108
|
+
if not ffmpeg_path:
|
|
109
|
+
subtitle_delivery = "unavailable"
|
|
110
|
+
elif subtitle_filter:
|
|
111
|
+
subtitle_delivery = "burned"
|
|
112
|
+
else:
|
|
113
|
+
# The default burn degrades to the .srt sidecar; an explicit request fails fast.
|
|
114
|
+
subtitle_delivery = "fails_explicit_burn" if burn_explicit else "sidecar_srt"
|
|
348
115
|
checks = {
|
|
349
116
|
"system_tools": {
|
|
350
117
|
"ffmpeg": bool(ffmpeg_path),
|
|
@@ -354,6 +121,9 @@ def build_report(*, tts_provider: str | None = None) -> dict[str, object]:
|
|
|
354
121
|
"ffmpeg_subtitles_filter": subtitle_filter,
|
|
355
122
|
"ffmpeg_ass_filter": "ass" in filters,
|
|
356
123
|
"burn_subtitles_ready": bool(ffmpeg_path and subtitle_filter),
|
|
124
|
+
"subtitle_delivery": subtitle_delivery,
|
|
125
|
+
"ffmpeg_drawtext_filter": drawtext_filter,
|
|
126
|
+
"visual_overlays_ready": bool(ffmpeg_path and drawtext_filter),
|
|
357
127
|
},
|
|
358
128
|
"tts": {
|
|
359
129
|
"provider": effective_tts_provider,
|
|
@@ -414,17 +184,40 @@ def build_report(*, tts_provider: str | None = None) -> dict[str, object]:
|
|
|
414
184
|
)
|
|
415
185
|
if not index_tts["index_tts_voice_set"]:
|
|
416
186
|
failures.append("INDEX_TTS_VOICE is not set")
|
|
417
|
-
if
|
|
418
|
-
warnings.append(
|
|
187
|
+
if subtitle_delivery == "sidecar_srt":
|
|
188
|
+
warnings.append(
|
|
189
|
+
"ffmpeg lacks subtitles/libass filter; the default run will not burn subtitles and "
|
|
190
|
+
"delivers a .srt sidecar instead (explicit --burn-subtitles fails): "
|
|
191
|
+
"install an ffmpeg build with libass to burn them"
|
|
192
|
+
)
|
|
193
|
+
elif subtitle_delivery == "fails_explicit_burn":
|
|
194
|
+
warnings.append(
|
|
195
|
+
"ffmpeg lacks subtitles/libass filter and BURN_SUBTITLES asks for burn-in, so runs "
|
|
196
|
+
"will stop at preflight: unset BURN_SUBTITLES to get a .srt sidecar, pass "
|
|
197
|
+
"--no-burn-subtitles, or install an ffmpeg build with libass"
|
|
198
|
+
)
|
|
199
|
+
if tools["ffmpeg"] and not drawtext_filter:
|
|
200
|
+
warnings.append(
|
|
201
|
+
"ffmpeg lacks the drawtext filter (libfreetype); narration visual_overlays will stop "
|
|
202
|
+
"the run before TTS: remove them or install an ffmpeg build with drawtext"
|
|
203
|
+
)
|
|
419
204
|
if not checks["api_config"]["api_key_set"]:
|
|
420
205
|
failures.append("MIMO_API_KEY is not set; the default ASR / VLM path requires MiMo")
|
|
206
|
+
if not mimo_video_configured:
|
|
207
|
+
warnings.append(
|
|
208
|
+
"MiMo VLM not configured: set MIMO_VIDEO_API_KEY or MIMO_API_KEY before video understanding"
|
|
209
|
+
)
|
|
210
|
+
if not tts_configured and effective_tts_provider in TTS_KEY_HINTS:
|
|
211
|
+
warnings.append(
|
|
212
|
+
f"TTS provider {effective_tts_provider} not configured: "
|
|
213
|
+
f"set {TTS_KEY_HINTS[effective_tts_provider]} before voiceover"
|
|
214
|
+
)
|
|
421
215
|
if not checks["asr"]["available"]:
|
|
422
216
|
warnings.append("ASR not configured (MIMO_API_KEY); pipeline can run with --skip-asr")
|
|
423
217
|
return {
|
|
424
218
|
"ok": not failures,
|
|
425
219
|
"repo_root": str(SCRIPT_DIR.parents[2]),
|
|
426
220
|
"checks": checks,
|
|
427
|
-
"capability_menu": _build_capability_menu(checks),
|
|
428
221
|
"failures": failures,
|
|
429
222
|
"warnings": warnings,
|
|
430
223
|
}
|
|
@@ -449,6 +242,12 @@ def _print_human(report: dict) -> None:
|
|
|
449
242
|
f"{_status_icon(system['ffmpeg_subtitles_filter'], warning=True)} "
|
|
450
243
|
f"ffmpeg subtitles/libass filter: "
|
|
451
244
|
f"{'available' if system['ffmpeg_subtitles_filter'] else 'missing'}"
|
|
245
|
+
f" (subtitles: {system['subtitle_delivery']})"
|
|
246
|
+
)
|
|
247
|
+
print(
|
|
248
|
+
f"{_status_icon(system['ffmpeg_drawtext_filter'], warning=True)} "
|
|
249
|
+
f"ffmpeg drawtext filter (visual_overlays): "
|
|
250
|
+
f"{'available' if system['ffmpeg_drawtext_filter'] else 'missing'}"
|
|
452
251
|
)
|
|
453
252
|
|
|
454
253
|
api = checks["api_config"]
|
|
@@ -504,22 +303,6 @@ def _print_human(report: dict) -> None:
|
|
|
504
303
|
print(f"✓ TTS voice: {tts['mimo_tts_voice']} (source: {tts['mimo_tts_voice_source']})")
|
|
505
304
|
print(f"✓ TTS API URL: {tts['mimo_tts_api_url']} (source: {tts['mimo_tts_api_url_source']})")
|
|
506
305
|
|
|
507
|
-
menu = report["capability_menu"]
|
|
508
|
-
print("\n[capability menu]")
|
|
509
|
-
for group in ("ready", "blocked", DEGRADED_GROUP, "optional_upgrades"):
|
|
510
|
-
print(f"{group}:")
|
|
511
|
-
items = menu[group]
|
|
512
|
-
if not items:
|
|
513
|
-
print(" - none")
|
|
514
|
-
continue
|
|
515
|
-
for item in items:
|
|
516
|
-
line = f" - {item['name']}: {item['summary']}"
|
|
517
|
-
if "detail" in item:
|
|
518
|
-
line += f" ({item['detail']})"
|
|
519
|
-
print(line)
|
|
520
|
-
if "action" in item:
|
|
521
|
-
print(f" action: {item['action']}")
|
|
522
|
-
|
|
523
306
|
if report["warnings"]:
|
|
524
307
|
print("\nWarnings:")
|
|
525
308
|
for warning in report["warnings"]:
|