Video per Code erstellen (mit Sprachausgabe)
Übersicht
Ein Video = Endgültiger Text → Zeilenweise TTS → Zeilenweise ASR-Prüfung → Zeitachse → HTML-Animation → Einzelbild-Screenshots → ffmpeg-Komposition.
Kernprinzip: Die Zeitachse kommt vom Audio. Zuerst jede Zeile vertonen und prüfen, die tatsächlichen Start-/Endzeiten jedes Untertitelabschnitts messen, dann alle Bild-Animationen an diese Zeitpunkte anhängen. Bilder haben keine festen Sekunden, wenn die Sprachausgabe geändert wird, wird die Zeitachse einfach neu berechnet. Das Rendering erstellt für jede Seite einen __seek(t)-Screenshot, das Ergebnis ist deterministisch und reproduzierbar.
Geeignet für: Erklärvideos/Tutorials (2–5 Min.), Produktpromo-Clips (20–40 Sek.), Wissensvideos mit Untertiteln und Kapitelleisten. Nicht geeignet für: Videos mit echten Personen, Videos mit realem Filmmaterial, reine Musik-MVs.
Ablauf
Jeder Schritt hat ein Qualitäts-Tor. Überspringe keinen Schritt, bevor das vorherige Tor nicht erfolgreich passiert wurde.
| # | Schritt | Ergebnis | Tor | Referenz |
|---|---|---|---|---|
| 0 | Initialisierung | Arbeitsverzeichnis | bash scripts/init.sh <dir> erfolgreich | siehe unten |
| 1 | Themenauswahl, Faktencheck, Text | script.md, audio/make_script.py | Fakten geprüft (Experimente zuerst ausführen); Benutzer stimmt Text explizit zu, bevor TTS gestartet wird | references/script.md |
| 2 | Sprachaufnahme (TTS) | audio/raw/NN.wav → audio/clips/NN.wav (1,3x) | Jede Zeile per ASR prüfen, fehlerhafte Zeilen neu aufnehmen | references/voice.md |
| 3 | Zeitachse | build/narration.wav, build/timeline.json | Untertitelabschnitte passen zur Sprache | references/timeline.md |
| 4 | Material | Echte Bildschirmfotos, echte Terminalausgaben | Stimmen mit dem gesprochenen Text überein, Beispiel-Domains verwenden example.com | references/capture.md |
| 5 | Komposition | comp/index.html | Einzelbild-Screenshots und Collagen einzeln durchgesehen | references/composition.md |
| 6 | Rendering | dist/video.mp4 | Dauer = Zeitachse, Lautstärke -14 LUFS | references/render.md |
| 7 | Cover, Veröffentlichungstext | dist/cover-bili.png, dist/cover-douyin.png, dist/copy.txt | Cover liegen im jeweiligen Plattform-Beschnittsicherheitsbereich | references/publish.md |
| 8 | Übergabe, Bereinigung | Video an Benutzer senden; Quelldateien archivieren | Benutzer bestätigt Speicherung, dann Bereinigung | siehe unten |
Initialisierung
bash scripts/init.sh ~/work/<Projekt>/video-<Folgenname> kopiert template/ in das Arbeitsverzeichnis, scripts/ nach tools/ und installiert playwright-core. Die Vorlage ist eine sofort lauffähige 30-Sekunden-Demo. Ersetze vor Arbeitsbeginn diese Beispielinhalte:
script.md,audio/make_script.py: Text dieser Folge; Kapitel werden nur einmal inCHAPTERSvonmake_script.pydefiniert, Pausen zwischen Kapiteln, Kapitelleisten und Kapitelzeitstempel werden daraus abgeleitet.audio/direction.txt: TTS-Regieanweisungen [Szene].asr-prompt.txt: Fachbegriffe dieser Folge (korrekte Schreibweise, ggf. mit Aussprachehinweis).- Szenen und Animationen in
comp/index.html, Cover-Inhalte incomp/cover-*.html.
Häufige Befehle
Ausführung im Arbeitsverzeichnis:
| Befehl | Funktion |
|---|---|
python3 audio/make_script.py | Erzeugt audio/script.json und audio/lines.json |
python3 tools/tts.py audio/lines.json audio/raw | Zeilenweise Sprachausgabe; verwendet vorhandene Audiodateien bei gleichem Text, nach Textänderung einfach neu ausführen |
bash tools/speed.sh audio/raw audio/clips 1.3 | Geschwindigkeit ändern ohne Tonhöhenänderung |
python3 tools/asr.py audio/clips --en | Zeilenweise Erkennung: plain / Fachbegriffe / Englisch-Modus |
python3 tools/takes.py 3,7 3 | Zeilen 3 und 7 jeweils 3 Takes aufnehmen und bewerten |
python3 tools/takes.py audio/var.json 2 | Verschiedene Umschreibungen derselben Zeile jeweils 2 Takes |
python3 tools/tts.py audio/lines.json audio/raw --adopt 3 audio/takes/03-0-1.raw.wav | Einen bestimmten Take übernehmen |
python3 tools/build_audio.py audio/clips build audio/script.json | Sprachdateien zusammenfügen, Zeitachse erzeugen |
python3 tools/align_chunks.py audio/clips build/timeline.json audio/script.json | Untertitelabschnitte an tatsächliche Aussprache anpassen |
node tools/render.mjs --timeline=build/timeline.json --stills=2,8.5,20 | Einzelbilder extrahieren nach build/stills (vorher immer leeren) |
bash tools/contact.sh build/stills build/sheets | 2x2 Collage erstellen, mit Read betrachten |
bash tools/render-par.sh build/timeline.json build/narration.wav dist/video.mp4 8 | Paralleles Rendern des gesamten Videos mit 8 Prozessen und Audiomischung |
node tools/render.mjs --html=comp/cover-4x3.html --width=1440 --height=1080 --png=dist/cover-bili.png | Cover erstellen |
python3 tools/bili_kw.py "nginx ssl Zertifikat konfigurieren" "Baota https" | Themenfindung: Top 6 Bilibili-Keywords nach Aufrufen |
Abhängigkeiten: ffmpeg, Node 18+, lokaler Google Chrome, Python 3 + requests + openai-whisper (small-Modell). TTS verwendet MiMo von Xiaomi, API-Key aus Umgebungsvariable MIMO_API_KEY oder Datei, auf die MIMO_ENV_FILE verweist, sonst beim Benutzer erfragen; Austausch gegen anderen TTS ist möglich, solange jede Zeile eine einzelne WAV-Datei bleibt.
Häufigste Fehlerquellen
- TTS ohne Genehmigung starten. Text zuerst an Benutzer senden; "Weiter"/"Start"/"OK" gilt als Zustimmung. Wurde der Text für die Aussprache geändert, bei Übergabe jede Änderung einzeln auflisten.
- Untertitel und Sprachausgabe in einer Datei. Untertitel sind für den Zuschauer (
Nginx,443,1.3), Sprachausgabe für TTS (Engine X,vier vier drei,eins Komma drei). Inmake_script.pymitP(Untertitel, Aussprache)getrennt schreiben, die Ausspracheabschnitte müssen zusammengesetzt den gesamten TTS-Text ergeben. - Nur die gesamte Mischung anhören. Die Erkennung des gesamten Audios verwechselt englische Fachbegriffe; daher muss jede Zeile einzeln erkannt werden. Bei der Auswahl eines Takes nur den plain-Score und das
--en-Ergebnis betrachten; ein mit Fachbegriffen gepimptes priming „korrigiert“ auch falsch ausgesprochene Wörter – Bewertungsregeln siehe voice.md. - Sekundenzahlen fest in Animationen codieren. Animationen nach dem Start der ersten Zeile immer mit
T(Zeile, Abschnitt)schreiben; nach Geschwindigkeitsänderung oder Neuaufnahme ändern sich die Zeiten. - Seitenanfang bleibt leer. Wenn die erste Karte 2–3 Sekunden lang noch nicht erscheint, wirkt das Video wie eingefroren; Inhalt muss im ersten Untertitelabschnitt des Kapitels sichtbar sein.
- Mehrere
fill: both-Animationen auf demselben Element, doppelte IDs. WAAPI gibt keinen Fehler aus, das Element kann vollständig verschwinden oder im falschen Zustand bleiben – siehe composition.md. - Seite mit
file://öffnen. CSS-Mask etc. funktionieren nicht;render.mjsenthält einen lokalen HTTP-Server. - Cover wird von der Plattform beschnitten. Bilibili schneidet ein Bild gleichzeitig auf 4:3 und 16:9 zu, Douyin 9:16 wird auf 3:4 beschnitten – Inhalt nur im Sicherheitsbereich platzieren.
- Verstoß gegen Weiterleitungsregeln. Keine echten Website-URLs, QR-Codes, Kontaktdaten in Bildern, Cover oder Text platzieren; keine Aufforderungen wie „schau mal nach“ / „suche mal“;
example.comund ähnliche reservierte Beispieldomains sind in Demos und Terminalausgaben erlaubt. Plattformübergreifende Videos verwenden keine bestimmte Content-Plattform als Beispiel; Werbevideos erwähnen keine Preise. - Erfolg melden, bevor das Ergebnis angesehen wird. Fortschrittsmeldungen erst senden, nachdem der Befehl vollständig ausgeführt wurde und die Ausgabe sichtbar ist.
Übergabe und Bereinigung
- Übergabe: Fertiges Video, Bilibili 4:3-Cover, Douyin 9:16-Cover,
dist/copy.txt(Titel, Tags, Beschreibung, Kapitelzeitstempel). Das Bilibili-Video wird standardmäßig auch auf Douyin etc. veröffentlicht, daher werden das Hochkant-Cover und der Douyin-Text zusammen ausgegeben; wenn der Benutzer nur eine Plattform angibt, nur diese eine Ausgabe. Liste aller aus Aussprachegründen geänderten Textstellen sowie aller unsicheren Zeitpunkte, um die der Benutzer gebeten wird, sie anzuhören. - Wenn die Datei die Chat-Größenbeschränkung überschreitet (häufig 30 MB), zuerst eine Preview mit
crf 22senden und den Speicherort der HD-Version angeben. Bei Zeitüberschreitung beim Senden großer Dateien nach erneutem Senden darauf hinweisen, dass der Benutzer möglicherweise zwei Kopien erhält. - Nachdem der Benutzer bestätigt hat, dass die Materialien gespeichert wurden: Wiederverwendbare Quelldateien (
comp/und verwendete Materialien,audio/make_script.py, Varianten-Spezifikation,script.md,copy.txt,direction.txt,asr-prompt.txt, Screenshot-Skripte,lab/) in die Benutzer-Vorlagenbibliothek archivieren (falls nicht vereinbart, beim Benutzer nachfragen, z.B.~/work/<Projekt>/video-template/<Folgenname>/), mitdiff -reinzeln auf Übereinstimmung prüfen, dann Arbeitsverzeichnis, temporäres Browser-Profil, Container, Entwicklungsserver (per PID töten, vorher Befehl prüfen) und nur für Screenshots installierte Frontend-Abhängigkeiten löschen. Whisper-Modell-Cache und Docker-Images bleiben erhalten.