@oh-story/dsh 0.1.7 → 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 +30 -15
- package/lib/client.js +93 -16
- 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
|
@@ -2,40 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
import base64
|
|
7
|
-
|
|
8
6
|
import hashlib
|
|
9
|
-
|
|
10
7
|
import json
|
|
11
|
-
|
|
12
8
|
import math
|
|
13
|
-
|
|
14
9
|
import os
|
|
15
|
-
|
|
16
|
-
|
|
17
10
|
import subprocess
|
|
18
|
-
|
|
19
11
|
import tempfile
|
|
20
|
-
|
|
21
12
|
from pathlib import Path
|
|
22
|
-
|
|
23
|
-
from
|
|
13
|
+
from typing import Any
|
|
14
|
+
from collections.abc import Callable, Mapping, Sequence
|
|
24
15
|
|
|
25
16
|
import qc_contract
|
|
26
|
-
|
|
17
|
+
from mimo_qc_client import mimo_qc_api_call
|
|
27
18
|
from mimo_qc_evidence import (
|
|
28
19
|
_cache_evidence,
|
|
29
20
|
_effective_config,
|
|
30
21
|
_existing_final_output,
|
|
31
22
|
_fingerprint_value,
|
|
32
|
-
_redact,
|
|
33
23
|
collect_evidence,
|
|
34
24
|
safe_mimo_config,
|
|
35
25
|
)
|
|
36
26
|
from mimo_qc_observations import normalize_observations
|
|
37
27
|
from mimo_qc_payload import _request_payload, _validated_live_output, build_payload
|
|
38
|
-
from mimo_qc_client import mimo_qc_api_call
|
|
39
28
|
from mimo_qc_contract import (
|
|
40
29
|
ARTIFACT_NAME,
|
|
41
30
|
DEFAULT_STAGE,
|
|
@@ -52,6 +41,7 @@ FrameSampler = Callable[..., Sequence[Mapping[str, Any]]]
|
|
|
52
41
|
|
|
53
42
|
|
|
54
43
|
def _probe_duration(path: Path) -> float:
|
|
44
|
+
"""Media duration via ffprobe; 0.0 when ffprobe cannot read it (frame sampling is advisory)."""
|
|
55
45
|
result = subprocess.run(
|
|
56
46
|
[
|
|
57
47
|
"ffprobe",
|
|
@@ -72,7 +62,7 @@ def _probe_duration(path: Path) -> float:
|
|
|
72
62
|
return 0.0
|
|
73
63
|
try:
|
|
74
64
|
return max(0.0, float(json.loads(result.stdout)["format"]["duration"]))
|
|
75
|
-
except (KeyError,
|
|
65
|
+
except (KeyError, ValueError):
|
|
76
66
|
return 0.0
|
|
77
67
|
|
|
78
68
|
|
|
@@ -92,7 +82,7 @@ def sample_video_frames(
|
|
|
92
82
|
return []
|
|
93
83
|
if duration <= 0:
|
|
94
84
|
return []
|
|
95
|
-
count = min(
|
|
85
|
+
count = min(max_frames, max(1, math.ceil(duration / 15.0)))
|
|
96
86
|
samples = []
|
|
97
87
|
with tempfile.TemporaryDirectory(prefix="video-recap-mimo-qc-") as tmp:
|
|
98
88
|
for index in range(count):
|
|
@@ -113,10 +103,7 @@ def sample_video_frames(
|
|
|
113
103
|
"-frames:v",
|
|
114
104
|
"1",
|
|
115
105
|
"-vf",
|
|
116
|
-
|
|
117
|
-
f"scale={int(max_dimension)}:{int(max_dimension)}:"
|
|
118
|
-
"force_original_aspect_ratio=decrease"
|
|
119
|
-
),
|
|
106
|
+
f"scale={max_dimension}:{max_dimension}:force_original_aspect_ratio=decrease",
|
|
120
107
|
"-q:v",
|
|
121
108
|
"4",
|
|
122
109
|
str(destination),
|
|
@@ -138,21 +125,18 @@ def sample_video_frames(
|
|
|
138
125
|
"timestamp": round(timestamp, 3),
|
|
139
126
|
}
|
|
140
127
|
)
|
|
141
|
-
return samples
|
|
128
|
+
return samples
|
|
142
129
|
|
|
143
130
|
|
|
144
131
|
def _frame_metadata(samples: Sequence[Mapping[str, Any]]) -> dict[str, Any]:
|
|
145
132
|
return {
|
|
146
|
-
"count":
|
|
133
|
+
"count": len(samples),
|
|
147
134
|
"max_frames": MAX_FRAMES,
|
|
148
135
|
"max_dimension": MAX_FRAME_DIMENSION,
|
|
149
136
|
"sampler_version": FRAME_SAMPLER_VERSION,
|
|
150
137
|
"samples": [
|
|
151
|
-
{
|
|
152
|
-
|
|
153
|
-
"timestamp": sample.get("timestamp"),
|
|
154
|
-
}
|
|
155
|
-
for sample in list(samples)[:MAX_FRAMES]
|
|
138
|
+
{"sha256": sample["sha256"], "timestamp": sample["timestamp"]}
|
|
139
|
+
for sample in samples
|
|
156
140
|
],
|
|
157
141
|
}
|
|
158
142
|
|
|
@@ -165,8 +149,8 @@ def _cache_input(
|
|
|
165
149
|
) -> dict[str, Any]:
|
|
166
150
|
return {
|
|
167
151
|
"stage": stage,
|
|
168
|
-
"model": payload
|
|
169
|
-
"payload_fingerprint": payload
|
|
152
|
+
"model": payload["model"],
|
|
153
|
+
"payload_fingerprint": payload["payload_fingerprint"],
|
|
170
154
|
"evidence": _cache_evidence(evidence),
|
|
171
155
|
"frames": frames,
|
|
172
156
|
"contract": qc_contract.SCHEMA_VERSION,
|
|
@@ -174,29 +158,27 @@ def _cache_input(
|
|
|
174
158
|
|
|
175
159
|
|
|
176
160
|
def _stage_reports(path: Path) -> dict[str, dict[str, Any]]:
|
|
161
|
+
"""Per-stage reports from an existing aggregate mimo_qc.json, or {} before the first stage."""
|
|
177
162
|
if not path.is_file():
|
|
178
163
|
return {}
|
|
179
164
|
try:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
165
|
+
stages = json.loads(path.read_text(encoding="utf-8"))["metadata"]["stages"]
|
|
166
|
+
for report in stages.values():
|
|
167
|
+
qc_contract.validate_report(report)
|
|
168
|
+
return dict(stages)
|
|
169
|
+
except (
|
|
170
|
+
OSError,
|
|
171
|
+
ValueError,
|
|
172
|
+
TypeError,
|
|
173
|
+
KeyError,
|
|
174
|
+
AttributeError,
|
|
175
|
+
qc_contract.QCContractError,
|
|
176
|
+
):
|
|
183
177
|
return {}
|
|
184
|
-
stages = report.get("metadata", {}).get("stages")
|
|
185
|
-
if isinstance(stages, Mapping):
|
|
186
|
-
valid = {}
|
|
187
|
-
for stage, stage_report in stages.items():
|
|
188
|
-
try:
|
|
189
|
-
qc_contract.validate_report(stage_report)
|
|
190
|
-
except (TypeError, qc_contract.QCContractError):
|
|
191
|
-
continue
|
|
192
|
-
valid[str(stage)] = dict(stage_report)
|
|
193
|
-
return valid
|
|
194
|
-
return {str(report["stage"]): report}
|
|
195
178
|
|
|
196
179
|
|
|
197
180
|
def _error_name(exc: Exception) -> str:
|
|
198
|
-
|
|
199
|
-
return (text or type(exc).__name__)[:120]
|
|
181
|
+
return (str(exc).strip() or type(exc).__name__)[:120]
|
|
200
182
|
|
|
201
183
|
|
|
202
184
|
def build_report(
|
|
@@ -224,28 +206,20 @@ def build_report(
|
|
|
224
206
|
output = _existing_final_output(root, final_output)
|
|
225
207
|
if output is not None:
|
|
226
208
|
sampler = frame_sampler or sample_video_frames
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
output, max_frames=MAX_FRAMES, max_dimension=MAX_FRAME_DIMENSION
|
|
231
|
-
)
|
|
232
|
-
)[:MAX_FRAMES]
|
|
233
|
-
except Exception:
|
|
234
|
-
samples = []
|
|
209
|
+
samples = list(
|
|
210
|
+
sampler(output, max_frames=MAX_FRAMES, max_dimension=MAX_FRAME_DIMENSION)
|
|
211
|
+
)[:MAX_FRAMES]
|
|
235
212
|
frame_meta = _frame_metadata(samples)
|
|
236
213
|
cache_input = _cache_input(stage, payload, evidence, frame_meta)
|
|
237
214
|
cache_key = _fingerprint_value(cache_input)
|
|
238
215
|
|
|
239
216
|
if (
|
|
240
217
|
not refresh
|
|
241
|
-
and existing
|
|
218
|
+
and existing is not None
|
|
242
219
|
and existing.get("metadata", {}).get("cache_key") == cache_key
|
|
243
220
|
):
|
|
244
221
|
cached = json.loads(json.dumps(existing))
|
|
245
|
-
cached["metadata"]
|
|
246
|
-
cached["metadata"]["mode"] = "live_cache"
|
|
247
|
-
cached["metadata"]["request_count"] = 0
|
|
248
|
-
qc_contract.validate_report(cached)
|
|
222
|
+
cached["metadata"].update(status="cached", mode="live_cache", request_count=0)
|
|
249
223
|
return cached
|
|
250
224
|
|
|
251
225
|
status = "completed"
|
|
@@ -266,6 +240,8 @@ def build_report(
|
|
|
266
240
|
model_output = {"observations": []}
|
|
267
241
|
status, error = "unavailable", "missing_key"
|
|
268
242
|
else:
|
|
243
|
+
# Fail-open boundary for the third-party request: transport errors arrive as
|
|
244
|
+
# MiMoQCRequestError (a RuntimeError), malformed responses as ValueError.
|
|
269
245
|
try:
|
|
270
246
|
response = (api_call or mimo_qc_api_call)(
|
|
271
247
|
_request_payload(payload, samples),
|
|
@@ -273,7 +249,7 @@ def build_report(
|
|
|
273
249
|
timeout=60,
|
|
274
250
|
)
|
|
275
251
|
model_output = _validated_live_output(response)
|
|
276
|
-
except
|
|
252
|
+
except (RuntimeError, ValueError) as exc:
|
|
277
253
|
model_output = {"observations": []}
|
|
278
254
|
status, error = "failed", _error_name(exc)
|
|
279
255
|
else:
|
|
@@ -302,26 +278,23 @@ def build_report(
|
|
|
302
278
|
"payload": payload,
|
|
303
279
|
"config": cfg,
|
|
304
280
|
}
|
|
305
|
-
|
|
281
|
+
return qc_contract.build_report(
|
|
306
282
|
artifact=ARTIFACT_NAME,
|
|
307
283
|
stage=stage,
|
|
308
284
|
findings=findings,
|
|
309
285
|
metadata=metadata,
|
|
310
286
|
)
|
|
311
|
-
qc_contract.validate_report(report)
|
|
312
|
-
return _redact(report)
|
|
313
287
|
|
|
314
288
|
|
|
315
289
|
def _aggregate_reports(
|
|
316
290
|
stage_reports: Mapping[str, Mapping[str, Any]], current_stage: str
|
|
317
291
|
) -> dict[str, Any]:
|
|
318
|
-
current = stage_reports[current_stage]
|
|
319
292
|
findings = [
|
|
320
293
|
finding
|
|
321
294
|
for stage_report in stage_reports.values()
|
|
322
|
-
for finding in stage_report
|
|
295
|
+
for finding in stage_report["findings"]
|
|
323
296
|
]
|
|
324
|
-
metadata = dict(
|
|
297
|
+
metadata = dict(stage_reports[current_stage]["metadata"])
|
|
325
298
|
metadata["stages"] = {
|
|
326
299
|
stage: dict(report) for stage, report in stage_reports.items()
|
|
327
300
|
}
|
|
@@ -339,13 +312,10 @@ def write_report(
|
|
|
339
312
|
"""Atomically merge one stage into mimo_qc.json and return the aggregate."""
|
|
340
313
|
path = Path(output) if output else Path(work_dir) / ARTIFACT_NAME
|
|
341
314
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
342
|
-
safe_stage = _redact(dict(report))
|
|
343
|
-
qc_contract.validate_report(safe_stage)
|
|
344
315
|
stages = _stage_reports(path)
|
|
345
|
-
stages[
|
|
346
|
-
aggregate = _aggregate_reports(stages,
|
|
347
|
-
|
|
348
|
-
serialized = json.dumps(_redact(aggregate), ensure_ascii=False, indent=2) + "\n"
|
|
316
|
+
stages[report["stage"]] = dict(report)
|
|
317
|
+
aggregate = _aggregate_reports(stages, report["stage"])
|
|
318
|
+
serialized = json.dumps(aggregate, ensure_ascii=False, indent=2) + "\n"
|
|
349
319
|
descriptor, temp_name = tempfile.mkstemp(prefix=f".{path.name}.", dir=path.parent)
|
|
350
320
|
try:
|
|
351
321
|
with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
|
|
@@ -353,10 +323,7 @@ def write_report(
|
|
|
353
323
|
handle.flush()
|
|
354
324
|
os.fsync(handle.fileno())
|
|
355
325
|
os.replace(temp_name, path)
|
|
356
|
-
except
|
|
357
|
-
|
|
358
|
-
os.unlink(temp_name)
|
|
359
|
-
except OSError:
|
|
360
|
-
pass
|
|
326
|
+
except BaseException:
|
|
327
|
+
Path(temp_name).unlink(missing_ok=True)
|
|
361
328
|
raise
|
|
362
329
|
return path, aggregate
|
|
@@ -9,7 +9,8 @@ from __future__ import annotations
|
|
|
9
9
|
import hashlib
|
|
10
10
|
import re
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import Any
|
|
12
|
+
from typing import Any
|
|
13
|
+
from collections.abc import Mapping, Sequence
|
|
13
14
|
from urllib.parse import urlsplit, urlunsplit
|
|
14
15
|
|
|
15
16
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import argparse
|
|
4
4
|
import os
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from lib import env_bool
|
|
7
7
|
|
|
8
8
|
TTS_PROVIDERS = ("auto", "mimo-tts", "fish-audio")
|
|
9
9
|
|
|
@@ -46,7 +46,7 @@ def parse_args():
|
|
|
46
46
|
parser.add_argument(
|
|
47
47
|
"--mimo-qc-refresh",
|
|
48
48
|
action="store_true",
|
|
49
|
-
default=
|
|
49
|
+
default=env_bool("MIMO_QC_REFRESH", False),
|
|
50
50
|
help="ignore a matching MiMo QC stage cache",
|
|
51
51
|
)
|
|
52
52
|
parser.add_argument(
|