Реализация распознавания речи из видеофайлов
Извлечение аудиодорожки из видео и её транскрибация — стандартная задача при создании субтитров, индексировании видеоархивов, аналитике вебинаров. Ключевой момент: качество исходной аудиодорожки определяет WER больше, чем выбор модели.
Pipeline извлечения и транскрибации
import subprocess
import tempfile
from pathlib import Path
from faster_whisper import WhisperModel
def extract_audio_from_video(video_path: str) -> str:
"""Извлекаем аудио из видео через FFmpeg"""
output_path = tempfile.mktemp(suffix='.wav')
cmd = [
'ffmpeg', '-i', video_path,
'-vn', # отключаем видео
'-ar', '16000', # 16kHz для ASR
'-ac', '1', # моно
'-acodec', 'pcm_s16le', # PCM 16-bit
'-af', 'loudnorm', # нормализация громкости
output_path,
'-y', '-loglevel', 'error'
]
subprocess.run(cmd, check=True)
return output_path
def transcribe_video(video_path: str, model: WhisperModel) -> dict:
audio_path = extract_audio_from_video(video_path)
try:
segments, info = model.transcribe(
audio_path,
vad_filter=True,
word_timestamps=True,
language="ru"
)
return {
"language": info.language,
"segments": [
{
"start": seg.start,
"end": seg.end,
"text": seg.text
}
for seg in segments
]
}
finally:
Path(audio_path).unlink(missing_ok=True)
Форматы видео
FFmpeg поддерживает всё: MP4, MKV, AVI, MOV, WebM, FLV. При записях вебинаров (Zoom, Teams) часто встречается низкий bitrate аудио — применяем loudnorm фильтр и опционально highpass=f=200 для удаления низкочастотного шума.
Обработка многодорожечного видео
В видеоконференциях каждый участник может быть на отдельной аудиодорожке:
# Получаем информацию о дорожках
probe = ffmpeg.probe(video_path)
audio_streams = [s for s in probe['streams'] if s['codec_type'] == 'audio']
# Обрабатываем каждую дорожку отдельно для диаризации
Генерация субтитров
Из результата транскрибации автоматически генерируем SRT/VTT:
def to_srt(segments) -> str:
lines = []
for i, seg in enumerate(segments, 1):
start = format_timestamp(seg['start'])
end = format_timestamp(seg['end'])
lines.append(f"{i}\n{start} --> {end}\n{seg['text'].strip()}\n")
return "\n".join(lines)
Сроки: базовый скрипт — 1 день, batch-система с очередью — 3–4 дня.







