ГлавнаяБлог → Распознавание речи на Python: от одного файла до рабочего скрипта

Распознавание речи на Python: от одного файла до рабочего скрипта

Опубликовано 2026-08-18 · 6 мин чтения

Распознавание речи на Python — это четыре строки кода. Всё остальное в этом руководстве — про неочевидное: какой формат ответа запрашивать, что делать со слишком большим файлом и почему ваш первый скрипт будет работать медленнее, чем мог бы.

Установка и первый запрос

Зависимость одна — официальный SDK OpenAI. API совместим по протоколу, отдельный клиент не нужен:

pip install openai
from openai import OpenAI

client = OpenAI(base_url="https://voicesscribe.com/v1", api_key="ваш ключ")

with open("audio.mp3", "rb") as f:
    result = client.audio.transcriptions.create(model="whisper-1", file=f)

print(result.text)

Это всё. Ключ держите в переменной окружения, а не в исходниках:

import os
client = OpenAI(base_url="https://voicesscribe.com/v1", api_key=os.environ["VS_KEY"])

Выбор формата ответа

По умолчанию возвращается объект с полем text. Ещё три формата имеют смысл:

ФорматЧто возвращаетсяКогда брать
jsonОбъект с .textПо умолчанию; нужны только слова
verbose_jsonСегменты, таймкоды, определённый языкТаймкоды, главы, контроль качества
srt / vttГотовый файл субтитров строкойСубтитры для видео
textЧистая строка без обёрткиПередача в следующий инструмент

С verbose_json в ответе есть ещё определённый язык и его вероятность — самый дешёвый сигнал качества из доступных:

r = client.audio.transcriptions.create(
    model="whisper-1", file=f, response_format="verbose_json",
)

for s in r.segments:
    print(f"[{s.start:6.1f}] {s.text.strip()}")

if r.language_probability < 0.6:
    print("подозрительная запись — стоит проверить руками")

Как правильно обрабатывать ошибки

SDK бросает типизированные исключения, поэтому обработка выходит короткой. Важно различать: часть ошибок имеет смысл повторить, часть будет падать одинаково всегда.

from openai import APIStatusError, APIConnectionError

try:
    r = client.audio.transcriptions.create(model="whisper-1", file=f)
except APIConnectionError:
    ...                      # сеть — повтор оправдан
except APIStatusError as e:
    if e.status_code == 401:
        raise RuntimeError("неверный ключ доступа")
    if e.status_code == 413:
        raise RuntimeError("файл больше 25 МБ — пережать или разрезать")
    if e.status_code == 429:
        ...                  # лимит или закончились минуты — подождать
    raise

Ошибка 400 обычно означает пустой или битый файл. Убедитесь, что он открывается плеером, прежде чем винить API.

Файлы больше 25 МБ

Лимит запроса — 25 МБ. Два пути в порядке предпочтения.

Сначала пережать. Большинство переростков велики потому, что это wav или стерео на высоком битрейте. Моно 16 кГц — то, что модель использует внутри в любом случае:

ffmpeg -i input.wav -ac 1 -ar 16000 -b:a 48k output.mp3

После такой конвертации час звука превращается примерно в 25 МБ, и большинству файлов резка перестаёт быть нужна.

Потом резать, если всё ещё нужно. Режьте по паузам, а не по фиксированным минутам, чтобы предложения оставались целыми:

ffmpeg -i long.mp3 -f segment -segment_time 1800 -c copy part%03d.mp3

Как ускорить скрипт

Первый скрипт, который пишут все, обрабатывает файлы по одному и почти всё время висит на ожидании сети. Расшифровка упирается в ввод-вывод, поэтому дело решают потоки:

from concurrent.futures import ThreadPoolExecutor

def transcribe(path):
    with open(path, "rb") as f:
        return client.audio.transcriptions.create(model="whisper-1", file=f).text

with ThreadPoolExecutor(max_workers=4) as pool:
    texts = list(pool.map(transcribe, paths))

Значение max_workers берите из лимита запросов в секунду на вашем тарифе, а не из числа ядер процессора. Шире лимита — и успешные запросы превращаются в 429.

Точность на собственной лексике

Самый недооценённый параметр — prompt. Он не появляется в выводе, а смещает распознавание в сторону перечисленных слов:

r = client.audio.transcriptions.create(
    model="whisper-1", file=f,
    prompt="Продукты: Кестрел, Хокнест. Говорят: Дуарте, Иванова.",
    language="ru",
)

Хорошо работают двадцать-сорок терминов, реально встречающихся в вашем аудио; абзац общего описания не даёт ничего. Добавленный language для одноязычного потока снимает ошибки определения языка на коротких записях.

Ошибки, стоящие больше всего времени

Попробуйте на своих записях. Регистрация занимает минуту, бесплатных минут хватает, чтобы оценить качество.

Получить ключ бесплатно

Частые вопросы

Нужна ли специальная библиотека для Python?

Нет, официальный пакет openai работает как есть — API совместим по протоколу. От настроек OpenAI отличаются только базовый адрес и ключ.

Нужно ли готовить формат аудио средствами Python?

Специально — нет: ogg, opus, mp3, wav, m4a и webm принимаются как есть. Перевод в моно 16 кГц mp3 нужен только чтобы уложиться в лимит запроса в 25 МБ.

Как получить таймкоды в Python?

Запросите response_format=verbose_json — в ответе будут сегменты с временем начала и конца, а также определённый язык и его вероятность.

Можно ли расшифровывать несколько файлов параллельно?

Да, через ThreadPoolExecutor. Расшифровка ждёт сеть, поэтому потоки здесь правильный инструмент; размер пула ставьте ниже лимита запросов в секунду на тарифе.

Что делать с файлами больше 25 МБ?

Сначала пережать в моно 16 кГц — этого достаточно в большинстве случаев. Если файл всё ещё велик, разрежьте его по паузам и склейте результаты.

Читайте также