#!/usr/bin/env python3 """Word timestamps for takes, from a local Whisper — the cutdown cuts INSIDE lines, and the QA listener's timestamps drift too much for that. uv run --with faster-whisper python tools/trailer/words.py ... (take names in promo/trailer/clips) """ import os, subprocess, sys import numpy as np from faster_whisper import WhisperModel ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) m = WhisperModel('small.en', compute_type='int8') for name in sys.argv[1:]: # decode with ffmpeg ourselves: faster-whisper's PyAV path breaks on newer av releases src = name if os.path.exists(name) else os.path.join(ROOT, 'promo', 'trailer', 'clips', name + '.mp4') raw = subprocess.run(['ffmpeg', '-v', 'error', '-i', src, '-ac', '1', '-ar', '16000', '-f', 's16le', '-'], capture_output=True).stdout segs, _ = m.transcribe(np.frombuffer(raw, np.int16).astype(np.float32) / 32768, word_timestamps=True) print(name + ':', ' '.join(f'{w.word.strip()}[{w.start:.2f}-{w.end:.2f}]' for s in segs for w in s.words))