| name | adr |
| description | Execute the ADR (Automated Documentary Rendering) V8.1 pipeline. Trigger when user says "执行ADR", "跑ADR", "生成ADR", or asks to create a documentary video on any topic. |
ADR V8.1 — Automated Documentary Rendering
Input a topic, output a cinematic short video with voiceover, subtitles, BGM, and social media copy.
When to Use
Trigger when the user requests "执行ADR", "跑ADR", "生成ADR", "制作视频", or any documentary video generation.
Execution
Run as background process (never block the event loop):
cd /Users/wekoidubai/ADR && nohup /opt/homebrew/bin/python3 run_adr_v8.py "主题" > /tmp/adr_v8.log 2>&1 &
Required env: WERYAI_API_KEY, TG_BOT_TOKEN, TG_CHAT_ID (graceful error if missing).
Self-reports to Telegram. Do NOT monitor or tail logs.
10-Step Pipeline
- Script: Spielberg AI (Gemini 3.1 Flash Lite, 3x retry for 9 lines) + Historical consultant (Gemini 3.1 Flash, visual research) + Jiang Wen AI (Gemini 3.1 Flash, emotion + image prompts)
- Voice: AI selects optimal speaker from Chinese voices based on topic/emotion (Gemini 3.1 Flash)
- Audio: WeryAI Podcast single-track voiceover (text-fail auto-retry 5x)
- Timeline: Whisper ASR (base model, auto-download) → char_time_map → velocity-curve interpolation per sentence
- Media: 20-thread pool generates 9 images + 1 BGM (image retry 3x, global 5s POST throttle)
- Assembly: ffmpeg concat demuxer + ASS subtitles (Arial Unicode MS)
- Render: J-Cut via -itsoffset, VO volume 1.5 + BGM volume 0.25
- Timing: image -> +0.2s subtitle -> +0.5s audio (cinematic 3-layer perception)
- Delivery: Telegram video (3x upload retry) + AI social copy with one-click copy button
- Stats: per-step timing breakdown pushed to Telegram
Key Changes from V8.0
- Models unified to Gemini family (Flash Lite for script, Flash for everything else) — no more Claude dependency
- Whisper alignment: replaced greedy-merge with velocity-curve interpolation (char_time_map + binary search + linear interp)
- Script generation: 3x auto-retry if < 9 lines
- Env vars: graceful error with debug dump instead of raw KeyError
- Whisper model: auto-download via _ensure_whisper_model()
- BGM prompt: now generated by Gemini instead of Claude
Override Script Injection
Write 1~22 lines to /tmp/adr_script_override.txt before launching ADR to bypass LLM script generation:
0:00-0:42
地球上每一粒粮食都是从一座正在倒计时的矿山里借来的...
0:43-1:06
没有磷,化肥停产...
- Timecodes (
M:SS-M:SS or H:MM:SS-H:MM:SS) are recognized; matching TTS will pad silence between sections to honor target timing
- For ADSD mode use
角色:台词 prefix per line (up to 4 distinct speakers); plain lines default to monologue
- File is auto-renamed to
.used_{timestamp} after consumption (one-shot)
Flag Reference (Optional Modes)
| Flag | Env Var | Effect |
|---|
--adsd / --ads-dialogue | ADR_ADS_DIALOGUE=1 | ADSD mode (per-turn TTS + lip-sync, ensemble dialogue) |
--no-motion | — | Disable per-scene WERYDANCE motion (HADS/VADS default ON; falls back to HADR/VADR static segs) |
--grid-multiref-main | ADR_STORYBOARD_GRID_MULTIREF_MAIN=1 | HADS: grid-multiref as main video source (saves WERYDANCE calls vs per-scene) |
--storyboard-trailer-main | ADR_STORYBOARD_TRAILER_MAIN=1 | HADS: single WERYDANCE trailer with all panels |
--adsd-speaker-batch | ADR_ADSD_SPEAKER_BATCH=1 | ADSD: analyze consecutive-same-speaker grouping (analysis only; actual batching TBD) |
--skip-approval | — | Skip image preview/approval gate |
--bgm-only / --no-voice | — | Strip TTS, BGM-only output |
ADR_ADSD_DEFAULT_MALE_VOICE_ASSET | env | Override default male voice asset for ADSD audio-dub |
ADR_ADSD_DEFAULT_FEMALE_VOICE_ASSET | env | Override default female voice asset for ADSD audio-dub |
Voice Asset Smart Mapping (P3)
ADSD turns auto-pick voice asset based on speaker name keyword match (e.g., 工程师→黄仁勋, 老人→绫璟道人, 教授→许知远, 印尼→印尼华侨 B-only). Falls back to default male/female asset on miss. Registered assets live in voice_assets/voice_assets.json.
SSL False-Negative Protection (probe-gap)
step10 wraps TG video upload with sendMessage probe-gap detection: sends a silent text probe before and after upload; if message_id gap ≥ 2, video already landed in chat despite local SSLError, so retry is skipped (no duplicate). Same wrapper now applied to cover photo upload.