272 lines
10 KiB
Markdown
272 lines
10 KiB
Markdown
# 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 <API_KEY>`
|
||
|
||
Второй 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 } }
|
||
}
|
||
```
|