# Преобразование речи в текст

> Расшифровывайте аудио в текст через выделенный эндпоинт RouterAI API.

RouterAI поддерживает преобразование речи в текст (STT, speech-to-text) через выделенный эндпоинт `/api/v1/audio/transcriptions`. Эндпоинт принимает запрос в двух форматах — на выбор:

1. **multipart/form-data** (OpenAI-совместимый): аудиофайл в поле `file`, как в официальном OpenAI SDK (`client.audio.transcriptions.create`) и `curl -F`
2. **JSON**: аудио в кодировке base64 в поле `input_audio`

В ответ придёт JSON с распознанным текстом и статистикой использования. Оба формата делят общий лимит тела запроса 32 МБ.

**Примечание**: В JSON-формате аудио передаётся как **строка base64** (сырые байты, не data URI). Расшифровку выполняют только модели с поддержкой транскрибации.

## Поиск моделей

Модели с поддержкой STT можно найти на нашей [странице моделей](https://routerai.ru/models?output_modalities[]=transcription), отфильтровав по модальности аудио. Примеры моделей: `openai/whisper-large-v3`, `openai/whisper-1`.

## OpenAI SDK и multipart/form-data

Эндпоинт совместим с официальным OpenAI SDK — достаточно указать `base_url`:

```python
from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://routerai.ru/api/v1",
)

with open("audio.mp3", "rb") as f:
    transcription = client.audio.transcriptions.create(
        model="openai/whisper-large-v3",
        file=f,
        language="ru",
    )

print(transcription.text)
```

```typescript
import fs from 'fs';
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: 'YOUR_API_KEY',
  baseURL: 'https://routerai.ru/api/v1',
});

const transcription = await client.audio.transcriptions.create({
  model: 'openai/whisper-large-v3',
  file: fs.createReadStream('audio.mp3'),
  language: 'ru',
});

console.log(transcription.text);
```

То же самое через `curl` (заголовок `Content-Type` руками не ставьте — его с boundary сформирует сам curl):

```bash
curl -X POST https://routerai.ru/api/v1/audio/transcriptions \
  -H "Authorization: Bearer $ROUTERAI_API_KEY" \
  -F "file=@audio.mp3" \
  -F "model=openai/whisper-large-v3" \
  -F "language=ru"
```

Формат аудио определяется по расширению имени файла, фолбэк — Content-Type части `file`. Если расширение нераспознано (например, файл называется `blob`), переименуйте файл или передайте у части корректный MIME-тип (`audio/mpeg`, `audio/wav`, …). Поле `stream` игнорируется — эндпоинт нестриминговый. Лимит размера файла — 25 МБ.

## Использование API (JSON)

Отправьте `POST` запрос на [`/api/v1/audio/transcriptions`](https://routerai.ru/docs/reference#tag/transcription) с JSON-телом, содержащим аудио в base64. В ответ придёт JSON с распознанным текстом и статистикой использования.

### Структура запроса

1. `model` — идентификатор STT-модели (например, `openai/whisper-large-v3`)
2. `input_audio.data` — содержимое аудиофайла в кодировке base64
3. `input_audio.format` — формат файла (`mp3`, `wav`, `flac`, `m4a`, `ogg`, `webm`, `aac`)

### Пример запроса cURL

```bash
# Кодируем аудиофайл в base64
BASE64_AUDIO=$(base64 -w 0 ./audio.wav)

curl -X POST https://routerai.ru/api/v1/audio/transcriptions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ROUTERAI_API_KEY" \
  -d @- << EOF
{
  "model": "openai/whisper-large-v3",
  "input_audio": {
    "data": "$BASE64_AUDIO",
    "format": "wav"
  }
}
EOF
```

### Пример на Python

```python
import requests
import base64

with open("audio.wav", "rb") as f:
    base64_audio = base64.b64encode(f.read()).decode("utf-8")

response = requests.post(
    url="https://routerai.ru/api/v1/audio/transcriptions",
    headers={
        "Authorization": "Bearer $ROUTERAI_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "model": "openai/whisper-large-v3",
        "input_audio": {
            "data": base64_audio,
            "format": "wav",
        },
    },
)

result = response.json()
print(result["text"])
```

### Пример на TypeScript (fetch)

```typescript
import fs from 'fs';

const audioBuffer = await fs.promises.readFile('audio.wav');
const base64Audio = audioBuffer.toString('base64');

const response = await fetch('https://routerai.ru/api/v1/audio/transcriptions', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.ROUTERAI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'openai/whisper-large-v3',
    input_audio: {
      data: base64Audio,
      format: 'wav',
    },
  }),
});

const result = await response.json();
console.log(result.text);
```

### Параметры запроса

| Параметр             | Тип    | Обязательный | Описание                                                                          |
| -------------------- | ------ | ------------ | --------------------------------------------------------------------------------- |
| `model`              | string | Да           | STT-модель для запроса (например, `openai/whisper-large-v3`)                       |
| `input_audio`        | object | Да (JSON)    | Аудио для расшифровки (только JSON-формат)                                         |
| `input_audio.data`   | string | Да (JSON)    | Аудио в кодировке base64 (сырые байты, не data URI)                                |
| `input_audio.format` | string | Да (JSON)    | Формат аудио (`mp3`, `wav`, `flac`, `m4a`, `ogg`, `webm`, `aac`)                   |
| `file`               | file   | Да (multipart) | Аудиофайл (только multipart/form-data); формат — по расширению или MIME-типу части |
| `language`           | string | Нет          | Язык в формате ISO-639-1 (например, `"ru"`, `"en"`). По умолчанию определяется автоматически |
| `temperature`        | number | Нет          | Температура семплирования. Меньшие значения дают более детерминированный результат |
| `response_format`    | string | Нет          | `json` (по умолчанию) — `{text, usage}`; `verbose_json` — дополнительно `task`, `language`, `duration` и таймстампы (см. ниже) |
| `timestamp_granularities` | array | Нет      | `word` и/или `segment` — гранулярность таймстампов, только с `response_format=verbose_json` (в multipart — повторяющееся поле `timestamp_granularities[]`) |
| `provider`           | object | Нет          | Настройки маршрутизации провайдера (порядок, исключения), только в JSON-формате — передаются провайдеру-агрегатору как есть |

## Формат ответа

Эндпоинт возвращает JSON-ответ с распознанным текстом:

```json
{
  "text": "Привет, это тест преобразования речи в текст.",
  "usage": {
    "seconds": 9.2,
    "total_tokens": 113,
    "input_tokens": 83,
    "output_tokens": 30,
    "cost": 0.19
  }
}
```

### Поля ответа

| Поле                  | Тип    | Описание                                            |
| --------------------- | ------ | --------------------------------------------------- |
| `text`                | string | Распознанный текст                                  |
| `usage.seconds`       | number | Длительность входного аудио в секундах              |
| `usage.total_tokens`  | number | Всего использовано токенов (вход + выход)            |
| `usage.input_tokens`  | number | Количество тарифицированных входных токенов          |
| `usage.output_tokens` | number | Количество сгенерированных выходных токенов          |
| `usage.cost`          | number | Стоимость запроса в рублях (тарификация RouterAI)    |

Та же стоимость доступна и постфактум через `GET /api/v1/generation?id=<X-Generation-Id>` (поле `total_cost`, в рублях) — идентификатор генерации приходит в заголовке ответа `X-Generation-Id`.

### Подробный ответ (verbose_json)

С `response_format: "verbose_json"` ответ дополнительно содержит метаданные расшифровки и таймстампы:

```json
{
  "text": "Привет, это тест преобразования речи в текст.",
  "task": "transcribe",
  "language": "russian",
  "duration": 9.2,
  "segments": [
    {
      "id": 0,
      "start": 0.0,
      "end": 4.5,
      "text": "Привет, это тест",
      "avg_logprob": -0.21,
      "no_speech_prob": 0.01
    }
  ],
  "words": [
    { "word": "Привет", "start": 0.0, "end": 0.6 }
  ],
  "usage": { "seconds": 9.2, "cost": 0.19 }
}
```

| Поле       | Тип    | Описание                                                                  |
| ---------- | ------ | ------------------------------------------------------------------------- |
| `task`     | string | Выполненная задача (`transcribe`)                                          |
| `language` | string | Определённый или заданный язык аудио                                       |
| `duration` | number | Длительность входного аудио в секундах                                     |
| `segments` | array  | Посегментные таймстампы (с `timestamp_granularities: ["segment"]`)         |
| `words`    | array  | Пословные таймстампы (с `timestamp_granularities: ["word"]`), если провайдер их возвращает |

**Примечание:** verbose_json и таймстампы поддерживаются не всеми моделями и провайдерами.

### Заголовки ответа

| Заголовок         | Описание                                                               |
| ----------------- | ---------------------------------------------------------------------- |
| `X-Generation-Id` | Уникальный ID генерации для запроса — полезен для отслеживания и отладки |

## Поддерживаемые форматы аудио

Поддерживаемые форматы зависят от провайдера. Распространённые форматы:

| Формат | MIME-тип     | Описание                                |
| ------ | ------------ | --------------------------------------- |
| `wav`  | `audio/wav`  | Несжатое аудио, наивысшее качество       |
| `mp3`  | `audio/mpeg` | Сжатое аудио, широкая совместимость      |
| `flac` | `audio/flac` | Сжатие без потерь                        |
| `m4a`  | `audio/mp4`  | Аудио MPEG-4                             |
| `ogg`  | `audio/ogg`  | Аудио Ogg Vorbis                         |
| `webm` | `audio/webm` | Аудио WebM, частое для записей в браузере |
| `aac`  | `audio/aac`  | Advanced Audio Coding                   |

**Примечание:** Проверьте документацию вашей модели, чтобы подтвердить поддерживаемые форматы. Не все модели поддерживают все форматы.

## Тарификация

STT-модели используют разные схемы тарификации в зависимости от провайдера:

- **По длительности** (например, OpenAI Whisper): оплата за секунду входного аудио
- **По токенам** (например, новые модели OpenAI): оплата за входные/выходные токены, как у текстовых моделей

Стоимость каждой модели можно посмотреть на [странице моделей](https://routerai.ru/models?output_modalities[]=transcription). Фактическая стоимость выполненного запроса (в рублях) возвращается в поле `usage.cost` ответа, а также доступна через `GET /api/v1/generation?id=<X-Generation-Id>` — поле `total_cost`.

## Отличия от аудио входных данных

RouterAI предлагает два способа обработки аудио:

1. **Преобразование речи в текст** (эта страница): выделенный эндпоинт `/api/v1/audio/transcriptions`, оптимизированный под транскрибацию. Возвращает структурированный JSON с текстом и статистикой использования. Лучший выбор для перевода аудио в текст.

2. **Аудио во входных данных чата** ([Аудио входные данные](/docs/guides/overview/multimodal/audio)): аудио передаётся в составе запроса `/api/v1/chat/completions` через тип контента `input_audio`. Модель обрабатывает аудио вместе с текстом и отвечает в диалоговом формате. Лучший выбор для анализа аудио, ответов на вопросы по содержанию и комбинирования модальностей.

## Лучшие практики

- **Выбор формата**: WAV даёт лучшее качество для транскрибации. MP3 и другие сжатые форматы работают хорошо, но могут немного снижать точность на пограничном аудио
- **Размер файла**: Очень длинные записи разбивайте на сегменты покороче. Максимальный размер тела запроса — 32 МБ
- **Кодирование base64**: Аудио передаётся как строка base64 (сырые байты, не data URI). В большинстве языков есть встроенные средства base64-кодирования
- **Указание языка**: Если язык известен заранее, передайте `language` в формате ISO-639-1 — это повышает точность и скорость

## Устранение неполадок

**Пустая или неверная расшифровка?**

- Убедитесь, что формат аудио совпадает с полем `format` в запросе
- Проверьте, что качество аудио достаточно для распознавания
- При необходимости укажите параметр `language`

**Запрос завершается с ошибкой размера?**

- Тело запроса не должно превышать 32 МБ. Разбейте длинные записи на сегменты покороче
- Сжатые форматы (MP3, AAC) дают меньший размер и передаются быстрее

**Модель не найдена?**

- Найдите доступные STT-модели на [странице моделей](https://routerai.ru/models?output_modalities[]=transcription)
- Проверьте корректность идентификатора модели (например, `openai/whisper-large-v3`, а не `whisper-large-v3`)

**Ошибка аутентификации?**

- Убедитесь, что используете действительный API-ключ из [вашего дашборда](https://routerai.ru/settings/keys)
- Эндпоинт STT использует ту же аутентификацию, что и Chat Completions API
