/video-subtitle – Video-Untertitel-Werkzeug
Transkribiere Video-Audio in SRT-Untertitel mit einem lokalen Whisper-Modell und brenne sie dann in das Video ein.
Benutzeraufruf
Wenn der Benutzer /video-subtitle eingibt, führe dieses Skill aus.
Voraussetzungen
Dieses Skill benötigt zwei Werkzeuge. Überprüfe die Verfügbarkeit, bevor du fortfährst:
1. mlx-whisper (Apple Silicon) oder openai-whisper
Erkenne, welches verfügbar ist:
which mlx_whisper whisper 2>/dev/null
Falls keines gefunden wird, leite den Benutzer zur Installation an:
- Apple Silicon Mac (empfohlen):
pip install mlx-whisper - Beliebige Plattform:
pip install openai-whisper
2. ffmpeg mit libass
Überprüfe auf libass-Unterstützung:
ffmpeg -filters 2>&1 | grep subtitles
Wenn keine Ausgabe erfolgt (libass fehlt), ist der subtitles-Filter nicht verfügbar:
- macOS:
brew install ffmpeg-full(keg-only,/opt/homebrew/opt/ffmpeg-full/bin/ffmpegverwenden) - Linux:
sudo apt install ffmpeg(enthält normalerweise libass) - Fallback: Wenn der Benutzer normales ffmpeg ohne libass hat, bette die SRT als Untertitelspur ein (Soft-Embedding) anstatt sie einzubrennen.
Whisper-Modellauswahl
Erkenne zwischengespeicherte Modelle:
ls ~/.cache/huggingface/hub/ 2>/dev/null | grep whisper
Bevorzuge das größte verfügbare Modell. Wenn keines zwischengespeichert ist, verwende:
- mlx-whisper:
mlx-community/whisper-large-v3-mlx - openai-whisper:
large-v3
Modi
/video-subtitle pfad/zum/video.mov→ Vollständige Pipeline (transkribieren + korrigieren + einbrennen)/video-subtitle srt pfad/zum/video.mov→ Nur SRT (transkribieren, ohne einbrennen)/video-subtitle burn pfad/zum/video.mov pfad/zum/sub.srt→ Nur einbrennen (vorhandene SRT verwenden)/video-subtitle(keine Argumente) → Interaktiv, nach Videopfad fragen
Vollständige Pipeline
Schritt 1: Video überprüfen
Wenn kein Pfad angegeben wurde, frage mit AskUserQuestion nach. Bestätige, dass die Datei existiert, und lese Metadaten aus:
ffmpeg -i "<video_path>" 2>&1 | grep -E "Duration|Stream.*(Video|Audio)"
Melde dem Benutzer Dauer, Auflösung und Dateigröße.
Schritt 2: Audio extrahieren
ffmpeg -i "<video_path>" -vn -acodec pcm_s16le -ar 16000 -ac 1 "<output_dir>/<basename>_audio.wav" -y
16 kHz Mono WAV ist das optimale Eingabeformat für Whisper.
Schritt 3: Sprache bestätigen
Frage den Benutzer mit AskUserQuestion. Übliche Optionen:
| Sprache | Flag |
|---|---|
| Chinesisch | --language zh |
| Englisch | --language en |
| Japanisch | --language ja |
| Automatisch | --language weglassen |
Schritt 4: Transkribieren
mlx-whisper:
mlx_whisper --model "<model>" --language <lang> --output-format srt --output-dir "<output_dir>" "<audio_wav>"
openai-whisper:
whisper "<audio_wav>" --model large-v3 --language <lang> --output_format srt --output_dir "<output_dir>"
Sage dem Benutzer: „Transkribiere, bitte warten …“
Schritt 5: SRT bereinigen
Lese die generierte SRT und korrigiere:
- Halluzinationen entfernen: Lösche Einträge mit Zeitstempeln der Dauer null (z. B.
00:00:57,640 --> 00:00:57,640) oder leeren Texten - Eigennamen korrigieren: Whisper erkennt Markennamen und Fachbegriffe häufig falsch – nutze den Gesprächskontext zur Korrektur
- Fragmente zusammenführen: Fasse Einträge kürzer als 0,5 s, die semantisch zusammenhängen
- Neu nummerieren: Führe dieses Python-Snippet aus, um alle Einträge neu zu nummerieren:
python3 -c "
import re
with open('<srt_path>', 'r') as f:
content = f.read()
blocks = re.split(r'\n\n+', content.strip())
out = []
for i, block in enumerate(blocks, 1):
lines = block.strip().split('\n')
if len(lines) >= 2:
lines[0] = str(i)
out.append('\n'.join(lines))
with open('<srt_path>', 'w') as f:
f.write('\n\n'.join(out) + '\n')
"
Zeige dem Benutzer die korrigierte SRT und frage, ob weitere Bearbeitungen vor dem Einbrennen nötig sind.
Schritt 6: Untertitel einbrennen
Ermittle das richtige ffmpeg-Binary (bevorzuge ffmpeg-full, wenn normales ffmpeg libass fehlt):
FFMPEG="ffmpeg"
if ! ffmpeg -filters 2>&1 | grep -q subtitles; then
if [ -x /opt/homebrew/opt/ffmpeg-full/bin/ffmpeg ]; then
FFMPEG="/opt/homebrew/opt/ffmpeg-full/bin/ffmpeg"
fi
fi
Dann einbrennen:
$FFMPEG \
-i "<video_path>" \
-vf "subtitles=<srt_path>:force_style='FontSize=24,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,Outline=2,MarginV=30'" \
-c:v libx264 -preset medium -crf 23 \
-c:a aac -b:a 128k \
-pix_fmt yuv420p \
"<output_dir>/<basename>_subtitled.mp4" -y
force_style-Optionen:
| Parameter | Standard | Beschreibung |
|---|---|---|
| FontSize | 24 | Schriftgröße |
| PrimaryColour | &H00FFFFFF | Weißer Text |
| OutlineColour | &H00000000 | Schwarze Kontur |
| Outline | 2 | Konturstärke |
| MarginV | 30 | Unterer Rand |
Wichtig: Der SRT-Dateipfad darf keine Sonderzeichen enthalten, die den ffmpeg-Filterparser stören. Verwende bei Bedarf relative Pfade oder Symlinks.
Schritt 7: Fertig
Melde den Ausgabedateipfad und die -größe. Schlage vor, open <pfad> zur Vorschau zu verwenden. Erinnere den Benutzer daran, dass die Zwischendatei _audio.wav gelöscht werden kann.
Fehlerbehebung
| Problem | Ursache | Lösung |
|---|---|---|
No such filter: 'subtitles' | ffmpeg fehlt libass | ffmpeg-full verwenden oder libass installieren |
No such filter: 'drawtext' | ffmpeg fehlt libfreetype | ffmpeg-full verwenden |
| Doppelte/leere SRT-Einträge | Whisper-Halluzination | Bereinigen in Schritt 5 |
| Chinesische Zeichen als Kästchen | Fehlende CJK-Schriftart | macOS: automatischer Fallback auf PingFang. Linux: apt install fonts-noto-cjk |
Error parsing filterchain | Sonderzeichen im SRT-Pfad | Relativen Pfad verwenden, Leerzeichen vermeiden |
Qualitätsregeln
- Getreue Transkription: Transkribiere nur, was tatsächlich gesagt wurde – füge keine Bedeutung hinzu oder schreibe sie um
- Eigennamen-Korrektur: Korrigiere häufige Whisper-Fehler, aber bestätige mit dem Benutzer
- Untertitel-Rhythmus: Maximal zwei Zeilen pro Eintrag, maximal ~20 CJK-Zeichen pro Zeile
- Aufräumen: Erinnere den Benutzer daran, die Zwischendateien (
_audio.wav) nach Abschluss zu löschen