ГлавнаяБлог → Как расшифровать запись, которая не влезает в один запрос

Как расшифровать запись, которая не влезает в один запрос

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

Запись конференции на четыре часа, суточный дамп с диктофона, вебинар с записью экрана — всё это не помещается в один запрос. Задача решается в три шага: сжать, разрезать по паузам, собрать текст обратно. Ниже готовая схема с кодом.

Сначала сжатие, потом нарезка

Прежде чем резать, попробуйте сжать: часто этого достаточно. Час речи в opus весит около 11 МБ, то есть двухчасовая запись укладывается в лимит целиком:

ffmpeg -i conference.wav -vn -ac 1 -ar 16000 -c:a libopus -b:a 24k conference.ogg

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

Где резать, чтобы не разорвать фразу

Нарезка равными интервалами проста, но рано или поздно разрежет слово пополам, и на стыке появится мусор. Надёжнее резать по тишине. Сначала находим паузы:

ffmpeg -i long.ogg -af silencedetect=noise=-35dB:d=1 -f null - 2>&1 | grep silence_end

Затем выбираем ближайшую к желаемой длине паузу и режем по ней:

ffmpeg -i long.ogg -ss 0 -to 912.4 -c copy part001.ogg

Практичный компромисс — куски по 10–15 минут: их удобно отправлять параллельно, и потеря на стыке при неудачном разрезе минимальна.

Параллельная обработка

Куски не зависят друг от друга, поэтому их отправляют одновременно. Порядок сохраняем по имени файла:

import concurrent.futures as cf, pathlib
from openai import OpenAI

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

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

parts = sorted(pathlib.Path(".").glob("part*.ogg"))
with cf.ThreadPoolExecutor(max_workers=4) as pool:
    result = dict(pool.map(one, parts))

full = "\n".join(result[p.name] for p in parts)
pathlib.Path("conference.txt").write_text(full, encoding="utf-8")

Число потоков подбирайте под лимит запросов в секунду вашего тарифа: если упрётесь, придёт отказ 429, и часть кусков придётся повторить.

Сквозные тайм-коды

Если нужен не просто текст, а навигация по записи, запрашивайте формат с сегментами и прибавляйте к времени смещение куска:

offset = 0.0
for path in parts:
    with path.open("rb") as f:
        r = client.audio.transcriptions.create(
            model="whisper-1", file=f, response_format="verbose_json")
    for seg in r.segments:
        print(round(seg["start"] + offset, 1), seg["text"].strip())
    offset += r.duration

Так тайм-коды остаются привязанными к исходной записи, и по ним можно перематывать оригинальное видео.

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

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

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

Какой предельный размер файла?

25 МБ на один запрос. В opus это примерно два часа речи, поэтому чаще всего достаточно сжатия без всякой нарезки.

Что означает ошибка 413?

Файл больше допустимого размера. Сожмите его в opus или mp3 с низким битрейтом либо разрежьте на части.

Теряется ли смысл на стыке кусков?

Если резать по паузам — нет. При нарезке равными интервалами на границе может пропасть слово, поэтому лучше искать тишину.

Можно ли обрабатывать куски одновременно?

Да, они независимы. Ограничение только одно — количество запросов в секунду по вашему тарифу.

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