import ffmpeg import os from faster_whisper import WhisperModel def extract_audio(video_path: str) -> str: """Extract mono 16kHz WAV audio from a video file.""" audio_path = os.path.splitext(video_path)[0] + "_audio.wav" ( ffmpeg .input(video_path) .output(audio_path, acodec="pcm_s16le", ac=1, ar="16000") .overwrite_output() .run(quiet=True) ) return audio_path def transcribe(video_path: str, model_size: str = "base") -> dict: """ Transcribe video audio using faster-whisper. Returns a dict with text, segments (with word timestamps), and language. """ audio_path = extract_audio(video_path) # CPU with int8 quantization — fast, no GPU needed model = WhisperModel(model_size, device="cpu", compute_type="int8") segments_iter, info = model.transcribe( audio_path, word_timestamps=True, vad_filter=True, # skip silence automatically ) # Convert to standard format segments = [] full_text = [] for seg in segments_iter: words = [] if seg.words: for w in seg.words: words.append({ "word": w.word, "start": w.start, "end": w.end, "probability": w.probability, }) segments.append({ "id": seg.id, "start": seg.start, "end": seg.end, "text": seg.text.strip(), "words": words, }) full_text.append(seg.text.strip()) # Clean up audio file to save disk space try: os.remove(audio_path) except Exception: pass return { "text": " ".join(full_text), "segments": segments, "language": info.language, }