A Command-Line Pipeline That Turns Historical Stories into Vertical Videos
This pipeline demonstrates that AI-generated vertical video is now a fully scriptable, repeatable workflow, cutting production time from hours to minutes. It also exposes the regulatory reality of mandatory AI watermarks in China and shows a practical local workaround for self-use, while still requiring the declaration on public posts.
The pipeline replaces video editing GUIs with code. One storyboard.json holds the script, style suffix, and scene prompts; gen_assets.py calls MOSS's OpenAI-compatible image and TTS APIs to create visuals and voiceovers, then uses OpenCV inpaint to strip the mandatory "AI-generated" watermark. build_subs.py computes the timeline from measured audio durations and renders ASS subtitles, while assemble.py applies Ken Burns motion, mixes audio, and burns in the subtitles.
A single `speed` parameter raised the narration rate from 4.2 to 4.9 characters per second without changing the voice. The whole run takes about three minutes for asset generation and produces an 84.6-second 1080×1920 H.264 video. The system is reusable: swap the storyboard JSON and rerun the scripts to get a new video in about fifteen minutes, as demonstrated with two Edison-themed versions.
The watermark removal sidesteps a legal requirement; the article itself insists on declaring AI generation when publishing, so the practical workaround is only for internal review, not for circumventing compliance.
The timing heuristic of splitting by character count works because Chinese speech is uniform; for tonal or variable-rate languages it would likely drift and need per-word timestamps.
The entire pipeline is a testament to moving from GUI to code: reproducibility and reuse, but it is still tied to the specific MOSS API and its rate limits.
We got burned on the three-frame sampling step: the export showed success, but a segment of Chinese subtitles was entirely blank. The reason: Chinese text without spaces was measured with a too-short line height, so not a single line fit, and the sampled frames happened to dodge it. Later we changed to sampling one frame at the midpoint of each Dialogue, counting the pixels in the subtitle band, and erroring out when it's near zero, which caught it before delivery. (AI-assisted writing)
Which model do you use?