From 7302d6ef6266e5386625774fb2a20a8f348a66aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Sat, 23 May 2026 14:34:32 +0400 Subject: [PATCH] =?UTF-8?q?doc:=20=D0=BF=D0=BE=D0=BB=D0=BD=D0=B0=D1=8F=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20Whisper=20API=20(ProxyAPI.ru)=20=E2=80=94=20?= =?UTF-8?q?=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D1=8B,=20?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D1=8B,=20verbose=5Fjson,?= =?UTF-8?q?=20word=20timestamps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/whisper-api.md | 271 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 doc/whisper-api.md diff --git a/doc/whisper-api.md b/doc/whisper-api.md new file mode 100644 index 0000000..75f9ba4 --- /dev/null +++ b/doc/whisper-api.md @@ -0,0 +1,271 @@ +# Whisper API — Распознавание речи (ProxyAPI.ru) + +> Источники: +> - [ProxyAPI.ru — Распознавание речи OpenAI API](https://proxyapi.ru/docs/openai-speech-to-text) +> - Тестирование через `curl` с реальными запросами (2026-05-23) +> - [OpenAI Speech-to-Text Guide](https://platform.openai.com/docs/guides/speech-to-text) (официальный, заблокирован из РФ) + +--- + +## 1. Endpoint + +``` +POST https://api.proxyapi.ru/openai/v1/audio/transcriptions +``` + +Авторизация: `Authorization: Bearer ` + +Второй endpoint — перевод в английский: +``` +POST https://api.proxyapi.ru/openai/v1/audio/translations +``` + +--- + +## 2. Модели + +| Модель | Форматы ответа | Временные метки | Поток | +|---|---|---|---| +| `whisper-1` | json, text, srt, verbose_json, vtt | ✅ word + segment | ❌ | +| `gpt-4o-transcribe` | json, text | ❌ | ✅ | +| `gpt-4o-mini-transcribe` | json, text | ❌ | ✅ | + +**Вывод:** для максимальной детализации (сегменты, слова,置信度) — только `whisper-1`. + +--- + +## 3. Параметры запроса + +| Параметр | Тип | Обязательный | Описание | +|---|---|---|---| +| `file` | file | ✅ | Аудиофайл (mp3, mp4, mpeg, mpga, m4a, wav, webm). Макс 25 МБ | +| `model` | string | ✅ | `whisper-1`, `gpt-4o-transcribe`, `gpt-4o-mini-transcribe` | +| `language` | string | ❌ | ISO-639-1 код (`it`, `en`, `ru`, ...). Без него — автоопределение | +| `prompt` | string | ❌ | Текст-подсказка: термины, имена, аббревиатуры для улучшения точности | +| `temperature` | float | ❌ | 0–1. По умолчанию 0. Выше = разнообразнее, но больше ошибок | +| `response_format` | string | ❌ | `json` (по умолч.), `text`, `srt`, `verbose_json`, `vtt` | +| `timestamp_granularities` | string[] | ❌ | `["word"]`, `["segment"]`, `["word","segment"]`. Только для `whisper-1` | + +### ⚠️ Важный нюанс (webm) + +ProxyAPI.ru **заявляет** поддержку `webm`, но по факту ffmpeg на их стороне **не может определить длительность** webm/opus файлов из Chrome. Ошибка: +```json +{"detail": "Cannot extract audio duration. Invalid file or format."} +``` + +**Решение:** конвертировать webm → WAV (16kHz, mono) в браузере через Web Audio API перед отправкой. + +--- + +## 4. Форматы ответа + +### 4.1 `json` (по умолчанию) + +```json +{ + "text": "распознанный текст" +} +``` +С `usage` (зависит от модели): +```json +{ + "text": "Sottotitoli e revisione a cura di QTSS", + "usage": { + "type": "duration", + "seconds": 2 + } +} +``` + +### 4.2 `text` + +Чистый текст, без JSON: +``` +Sottotitoli e revisione a cura di QTSS +``` + +### 4.3 `verbose_json` + +```json +{ + "task": "transcribe", + "language": "italian", + "duration": 2.0, + "text": "Sottotitoli e revisione a cura di QTSS", + "segments": [ + { + "id": 0, + "seek": 0, + "start": 0.0, + "end": 2.0, + "text": " Sottotitoli e revisione a cura di QTSS", + "tokens": [50364, 318, 1521, 310, 270, 9384, 308, 34218, 68, 257, 1262, 64, 1026, 1249, 7327, 50, 50464], + "temperature": 0.0, + "avg_logprob": -0.2574056088924408, + "compression_ratio": 0.8260869383811951, + "no_speech_prob": 0.8321689367294312 + } + ], + "usage": { + "type": "duration", + "seconds": 2 + } +} +``` + +#### Поля сегмента: + +| Поле | Описание | +|---|---| +| `id` | Номер сегмента (с 0) | +| `seek` | Смещение в секундах от начала файла | +| `start` | Начало сегмента (сек) | +| `end` | Конец сегмента (сек) | +| `text` | Текст сегмента | +| `tokens` | Идентификаторы токенов Whisper | +| `temperature` | Использованная температура | +| `avg_logprob` | Средняя лог-вероятность токенов (выше = увереннее). Можно использовать для оценки качества | +| `compression_ratio` | Степень сжатия текста относительно аудио | +| `no_speech_prob` | **Вероятность отсутствия речи** (0–1). Значения > 0.5 = вероятно тишина/шум | + +### 4.4 `verbose_json` + `timestamp_granularities=["word"]` + +```json +{ + "task": "transcribe", + "language": "italian", + "duration": 2.0, + "text": "Sottotitoli e revisione a cura di QTSS", + "words": [ + { "word": "Sottotitoli", "start": 0.0, "end": 0.48 }, + { "word": "e", "start": 0.48, "end": 0.56 }, + { "word": "revisione", "start": 0.56, "end": 1.12 }, + { "word": "a", "start": 1.12, "end": 1.20 }, + { "word": "cura", "start": 1.20, "end": 1.44 }, + { "word": "di", "start": 1.44, "end": 1.52 }, + { "word": "QTSS", "start": 1.52, "end": 2.0 } + ], + "usage": { "type": "duration", "seconds": 2 } +} +``` + +⚠️ При запросе `words`, поле `segments` **не возвращается** (взаимоисключающие). + +### 4.5 `srt` / `vtt` + +Форматы субтитров с таймкодами. Пример SRT: +``` +1 +00:00:00,000 --> 00:00:02,000 + Sottotitoli e revisione a cura di QTSS +``` + +--- + +## 5. Поддерживаемые языки + +Полный список (из официальных доков): + +Африкаанс, арабский, армянский, азербайджанский, белорусский, боснийский, болгарский, +каталанский, китайский, хорватский, чешский, датский, голландский, **английский**, +эстонский, финский, французский, галисийский, немецкий, греческий, иврит, хинди, +венгерский, исландский, индонезийский, **итальянский**, японский, каннада, казахский, +корейский, латышский, литовский, македонский, малайский, маратхи, маори, непальский, +норвежский, персидский, польский, португальский, румынский, **русский**, сербский, +словацкий, словенский, испанский, суахили, шведский, тагальский, тамильский, тайский, +турецкий, украинский, урду, вьетнамский, валлийский. + +Коды ISO-639-1: `it` (итальянский), `en` (английский), `ru` (русский), `fr` (французский), etc. + +--- + +## 6. Prompt — улучшение распознавания + +Параметр `prompt` помогает Whisper правильно распознать специфические термины, +имена, аббревиатуры. Работает как контекстная подсказка. + +```json +{ + "model": "whisper-1", + "file": "@audio.wav", + "language": "it", + "prompt": "amore, cuore, spaghetti, Ferrari, Lamborghini, ciao, buongiorno" +} +``` + +**Рекомендация:** передавать ожидаемое слово/фразу как prompt для повышения точности. + +--- + +## 7. Полезные поля для оценки качества + +### `avg_logprob` (средняя лог-вероятность) +- Диапазон: примерно от -2.0 (плохо) до 0 (идеально) +- Можно использовать как confidence score +- Порог ~ -0.5 для приемлемого качества + +### `no_speech_prob` (вероятность тишины) +- 0 = точно речь +- 1 = точно тишина/шум +- Порог > 0.5 = вероятно, сказать нечего + +### `compression_ratio` +- Отношение длины текста к длине аудио +- Аномальные значения могут указывать на галлюцинации + +--- + +## 8. Ограничения + +- Макс. размер файла: **25 МБ** +- Перевод (`/translations`) — **только на английский** +- Временные метки — **только `whisper-1`** +- Поток (`stream=true`) — **недоступен для `whisper-1`** +- `webm` заявлен но **не работает** с ProxyAPI.ru (нужна конвертация в WAV/MP3) + +--- + +## 9. Цены (ProxyAPI.ru, май 2026) + +| Модель | Цена за минуту | +|---|---| +| `whisper-1` | ~0.006 $ | +| `gpt-4o-transcribe` | ~0.006 $ | +| `gpt-4o-mini-transcribe` | ~0.003 $ | + +--- + +## 10. Пример использования в Lyngvo + +```javascript +// transcribe.js — актуальная версия (v103) +async function blobToWav(blob) { + const ab = await blob.arrayBuffer(); + const ctx = new AudioContext({ sampleRate: 16000 }); + const buf = await ctx.decodeAudioData(ab); + await ctx.close(); + // ... конвертация в WAV 16kHz mono ... + return new Blob([wavBuf], { type: 'audio/wav' }); +} + +async function transcribe(blob) { + const wavBlob = await blobToWav(blob); + const fd = new FormData(); + fd.append('file', wavBlob, 'audio.wav'); + fd.append('model', 'whisper-1'); + fd.append('language', 'it'); + // По желанию — prompt для улучшения точности + // fd.append('prompt', 'amore, ciao, buongiorno'); + + const r = await fetch( + 'https://api.proxyapi.ru/openai/v1/audio/transcriptions', + { + method: 'POST', + headers: { 'Authorization': `Bearer ${API_KEY}` }, + body: fd + } + ); + return await r.json(); + // → { text: "...", usage: { type: "duration", seconds: N } } +} +```