Синхронное распознавание — STT v1¶
Синхронное распознавание преобразует аудио- или видеофайл в текст в рамках одного HTTP-запроса: вы отправляете запись — сервис возвращает распознанный текст.
Способ подходит для сравнительно коротких записей, когда результат нужен сразу. Для длинных файлов используйте асинхронное распознавание или асинхронный вариант этого метода.
Поддерживаются моно- и стереозаписи. В стереорежиме каждый канал считается отдельным говорящим, а реплики возвращаются в хронологическом порядке (диаризация по каналам).
HTTP-запрос¶
Запрос отправляется в формате multipart/form-data и требует аутентификации — заголовок Authorization: Api-Key <ключ> (см. Аутентификация).
Параметры запроса¶
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
audio |
file | да | — | Аудио- или видеофайл с аудиодорожкой |
lang |
string | нет | ru-RU |
Язык распознавания: Playground предлагает ru-RU, en-US, kk-KZ, ky-KG, uz-UZ и tg-TJ; GigaAM принимает только ru-RU, kk-KZ, ky-KG, uz-UZ. Передача locale не выбирает модель автоматически |
topic |
string | нет | general |
Совместимое поле SpeechKit v1; сейчас принимается, но не влияет на маршрут или результат |
format |
string | нет | oggopus |
Совместимое поле: lpcm, oggopus, amr. Для контейнеров формат определяется по файлу; загрузка headerless PCM в HTTP v1 пока не поддерживается |
sampleRateHertz |
string | нет | 48000 |
Подсказка частоты: 8000, 16000, 48000; сама по себе не позволяет декодировать headerless PCM |
channelMode |
string | нет | stereo |
Режим каналов: stereo — распознавание каждого канала отдельно (для mono-файла будет один канал); mono — сведение каналов в один |
diarization |
boolean | нет | false |
Внешняя диаризация говорящих для mono. В stereo каналы уже считаются отдельными источниками, поэтому флаг не применяется; для ElevenLabs-Scribe-v2 отдельный внешний этап не запускается |
maxSpeakers |
int | нет | — | Максимальное число говорящих при кластеризации во время диаризации (от 1 до 20) |
llmCorrection |
boolean | нет | true |
LLM-коррекция распознанного текста. Включена по умолчанию — итоговый текст может отличаться от «сырого» результата ASR. Если LLM-бэкенд не настроен, возвращается исходный текст |
entityExtraction |
boolean | нет | false |
Best-effort извлечение именованных сущностей из уже исправленного текста. Добавляет entities и entity_extraction_status |
emotionAnalysis |
boolean | нет | false |
Параллельно с ASR запустить эмоциональную динамику DUSHA. Доступно только для русской речи |
emotionIncludeSegments |
boolean | нет | false |
При включённом emotionAnalysis вернуть сглаженные окна в emotion_analysis.windows; эпизоды и session-метрики возвращаются всегда |
emotionNegativeThreshold |
number | нет | серверный EMOTION_NEGATIVE_THRESHOLD, штатно 0.5 |
Порог 0..1 для сглаженной суммы P(angry) + P(sad) при выделении негативных эпизодов |
summarizationPreset |
string | нет | — | Структурированная саммаризация окончательного текста. Доступны четырнадцать серверных пресетов. Если параметр не передан, LLM для саммаризации не вызывается |
summarizationDetail |
string | нет | standard |
Подробность результата: brief, standard или detailed |
summarizationOutputLanguage |
string | нет | язык записи | BCP-47 tag языка сгенерированных полей саммаризации, например en-US. Не меняет транскрипт и учитывается только вместе с summarizationPreset |
model |
string | нет | SpeechExpert-STT |
Модель распознавания |
rawResults |
boolean | нет | false |
Запись чисел прописью (зарезервировано, пока не реализовано) |
Query или форма
Параметры lang, channelMode, diarization, maxSpeakers, llmCorrection, entityExtraction, emotionAnalysis, emotionIncludeSegments, emotionNegativeThreshold, summarizationPreset, summarizationDetail и summarizationOutputLanguage можно передавать как в query-строке, так и в теле формы (multipart). Если параметр передан обоими способами, приоритет имеет значение из формы. Для emotion-параметров принимаются также snake_case-имена emotion_analysis, emotion_include_segments, emotion_negative_threshold.
Значение channelMode по умолчанию — stereo. Если нужен компактный
mono-ответ с words/segments, передайте channelMode=mono явно, в том
числе для физически одноканального файла.
Stereo — это независимые физические каналы
Значение по умолчанию stereo рассчитано на звонок, где собеседники записаны
раздельно слева и справа. Если оба канала содержат один и тот же общий микс,
автоматического удаления дублей сейчас нет и текст может повториться. Для
обычной музыкальной, диктофонной или зеркальной стереозаписи передавайте
channelMode=mono.
Модели распознавания¶
| Идентификатор | Описание |
|---|---|
SpeechExpert-STT |
Рекомендуемая встроенная offline-модель SpeechExpert для телефонного качества |
T-one |
T-One через Triton; для WebSocket и gRPC работает как настоящая потоковая модель, в HTTP v1 распознаёт готовый файл |
GigaAM-v3-CTC |
Устаревший совместимый алиас GigaAM-Multilingual-Large-CTC; маршрутизация и тарификация явно используют multilingual replacement |
GigaAM-Multilingual-Large-CTC |
Локальная 600M-модель ai-sage/GigaAM-Multilingual, проверенный snapshot ревизии large_ctc; публичный профиль для русского, казахского, кыргызского и узбекского с обязательной локальной оценкой kk/ky/uz |
Whisper-Large-v3-Turbo |
Whisper Large v3 Turbo |
ElevenLabs-Scribe-v2 |
ElevenLabs-Scribe-v2 через /v1/speech-to-text; в UI доступна для ru-RU, en-US, kk-KZ, ky-KG, uz-UZ, tg-TJ, используется ключ ELEVENLABS_API_KEY |
Playground сначала предлагает выбрать язык, а затем показывает только совместимые модели. Та же матрица валидируется сервером для API: несовместимая пара отклоняется до распознавания, но API-клиент должен выбрать модель явно:
| Язык | Код | Совместимые модели API и Playground |
|---|---|---|
| Русский | ru-RU |
SpeechExpert-STT, T-One, Whisper, ElevenLabs, GigaAM Multilingual |
| Английский | en-US |
Whisper, ElevenLabs |
| Казахский | kk-KZ |
GigaAM Multilingual, ElevenLabs |
| Кыргызский | ky-KG |
GigaAM Multilingual, ElevenLabs |
| Узбекский | uz-UZ |
GigaAM Multilingual, ElevenLabs |
| Таджикский | tg-TJ |
ElevenLabs |
Английский декодер GigaAM существует, но в model card его качество обозначено
как умеренное, поэтому он не включён в публичный профиль. Казахский, кыргызский
и узбекский маршруты доступны, но требуют локальной оценки ASR и VAD на целевом
домене, акцентах и акустике до production-включения: checkpoint MarbleNet не
перечисляет kk, ky и uz среди языков обучения. Таджикский не добавлен в
GigaAM: для tg нет готового large_ctc декодера и опубликованной приемлемой
оценки. При этом официальный профиль ElevenLabs Scribe v2
поддерживает русский, английский, казахский, кыргызский, узбекский и таджикский;
в Playground tg-TJ поэтому показывает только совместимую модель ElevenLabs.
GigaAM выполняет синхронный GPU inference вне event loop в отдельном worker, а
MarbleNet вызывается асинхронно по gRPC в уже существующем tone-triton.
Конкурентность обоих этапов ограничивается независимыми семафорами API и GigaAM
worker.
Locale сохраняется в последующих шагах: LLM-коррекция и извлечение сущностей
получают выбранный код языка. Саммаризация по умолчанию формирует результат на
основном языке расшифровки, но summarizationOutputLanguage независимо задаёт
язык сгенерированных полей. Русские deterministic-нормализаторы чисел,
ненормативной лексики и телефонов не запускаются для kk, ky и uz;
русская модель восстановления пунктуации для multilingual-профиля отключена.
Миграция с Vosk
Vosk и его контейнеры удалены. Сохранённые идентификаторы Vosk 0.62, Vosk 0.56, Vosk 0.54, Zipformer2-RU, Vosk-Streaming-RU, Sherpa-Streaming-RU и SpeechExpert-STT-Streaming временно принимаются как устаревшие алиасы и маршрутизируются в T-One. Они также тарифицируются как T-one; отдельного тарифа Vosk больше нет, а исходное имя сохраняется только в истории ранее созданных записей и транзакций. Для новых интеграций указывайте T-one.
Сравнение моделей на телефонном датасете
Внутренний прогон моделей на датасете телефонного качества:
| Модель | WER | edits | RTFX |
|---|---|---|---|
| SpeechExpert-STT | 20.871 % | 7475 | 323.599 |
| ElevenLabs-Scribe-v2 | 33.832 % | 12117 | 8.108 |
WER и edits — чем меньше, тем лучше. RTFX — чем больше, тем быстрее.
Форматы аудио¶
| Формат | Расширение | Описание |
|---|---|---|
| WAV | .wav |
PCM 16 бит, любая частота дискретизации |
| Аудиоконтейнеры | .mp3, .m4a, .ogg, .oga, .opus, .webm, .flac, .aac, .amr, .wma |
Конвертируются через ffmpeg |
| Видеоконтейнеры | .mp4, .mov, .mkv, .avi, .mpeg, .mpg, .3gp, .3gpp, .webm |
Извлекается аудиодорожка и конвертируется через ffmpeg |
Автоопределение формата
Если вы отправляете обычный аудио- или видеофайл, формат определяется
автоматически и дополнительные параметры не нужны. Headerless PCM в HTTP
v1 сейчас не декодируется, даже если переданы format=lpcm и
sampleRateHertz; для сырого PCM используйте
WebSocket или gRPC, либо заверните данные в WAV.
Ответ¶
Режим mono¶
В ответе всегда есть поле result — распознанный текст целиком. Для моделей,
поддерживающих word offsets, дополнительно возвращаются words с нативными
таймстемпами модели и segments, сгруппированные для интерфейса и экспорта
SRT/VTT. Это относится и к Riva, и к GigaAM-Multilingual-Large-CTC:
{
"result": "добрый день",
"words": [
{"text": "добрый", "start_ms": 340, "end_ms": 720, "speaker": null},
{"text": "день", "start_ms": 760, "end_ms": 1080, "speaker": null}
],
"segments": [
{
"text": "добрый день",
"start_ms": 340,
"end_ms": 1080,
"speaker": null,
"timing_source": "riva",
"timing_estimated": false
}
],
"timing_source": "riva",
"timing_estimated": false
}
Если речь не распознана, result содержит пустую строку.
Время задаётся в миллисекундах от начала исходного аудио, до VAD, интервалом
[start_ms, end_ms). words остаются сырыми словами Riva; пунктуация и
LLM-коррекция применяются к тексту segments, не меняя их реальные границы.
Соседние слова объединяются в сегмент, пока пауза между ними не превышает 500 мс.
Для GigaAM Multilingual модель marblenet_vad в существующем tone-triton
сначала строит интервалы речи с разрешением 20 мс и ограничивает каждую реплику
24 секундами. Публичный Triton wrapper принимает сырое mono-аудио 16 кГц,
выполняет точный NeMo mel-препроцессинг и вызывает ONNX-core через BLS. Длинная
запись обрабатывается блоками по 300 секунд с 2-секундным контекстом; после
сшивания каждый исходный кадр присутствует ровно один раз. GigaAM возвращает
нативные CTC-границы слов внутри реплики, после чего API добавляет начало
VAD-интервала. Поэтому words[].start_ms/end_ms относятся к исходному файлу,
segments соответствуют распознанным VAD-репликам, а верхнеуровневый
timing_source равен gigaam-ctc+marblenet-vad и timing_estimated — false.
Смежные части одной реплики, появившиеся только из-за 24-секундного лимита,
распознаются общим GigaAM-запросом с внутренним overlap; нативные слова затем
назначаются исходным VAD-сегментам по midpoint ровно один раз. Интервалы,
разделённые реальной паузой, остаются отдельными запросами.
Успешный пустой ответ VAD означает строгую тишину: GigaAM не вызывается,
result остаётся пустым, а временная разметка не публикуется (words,
segments, timing_source и timing_estimated равны null). Если MarbleNet
недоступен, сервис по умолчанию распознаёт весь файл целиком и сохраняет
нативные CTC-таймкоды (timing_source=gigaam-ctc). При
MARBLENET_VAD_REQUIRED=true такой сбой завершает запрос ошибкой вместо
fallback.
Если выбранная модель не возвращает нативные offsets, поля words, segments,
timing_source и timing_estimated не заполняются (null) — в mono сервис не
подставляет искусственный диапазон 0..duration. Если Riva вернула полный текст,
но только часть word offsets, result сохраняется целиком, words остаются доступными, а
segments не публикуются, чтобы неполная разметка не обрезала текст и не включала
ошибочный экспорт субтитров.
При channelMode=mono&diarization=true внешний diarization-пайплайн вместо
words/segments возвращает utterances с кластерным номером speaker и
границами реплики. Верхнеуровневый result в этом режиме имеет вид
[0:00:03] Спикер 1: ...; maxSpeakers ограничивает число кластеров. Эти границы
относятся к репликам диаризации и не выдаются за нативные word offsets ASR.
Режим stereo¶
Используется для стереозаписей, где в каждом канале — отдельный говорящий. Реплики выделяются, распознаются по каналам и возвращаются в хронологическом порядке.
| Поле | Тип | Описание |
|---|---|---|
result |
string | Весь распознанный текст, склеенный в порядке реплик |
speakers |
array | Цельный текст каждого канала |
utterances |
array | Реплики каналов в хронологическом порядке |
timing_source |
string | riva, gigaam-ctc, marblenet-vad, gigaam-ctc+marblenet-vad, synthetic или mixed — источник границ реплик |
timing_estimated |
boolean | false только если все опубликованные границы нативные |
Каждый элемент массива utterances:
| Поле | Тип | Описание |
|---|---|---|
speaker |
int | Номер говорящего (канала): 0 — левый, 1 — правый |
start_ms |
int | Начало реплики в миллисекундах от начала файла |
end_ms |
int | Конец реплики в миллисекундах |
text |
string | Распознанный текст реплики |
Пример ответа для стереозаписи:
{
"result": "Привет Как дела Нормально",
"utterances": [
{ "speaker": 0, "start_ms": 0, "end_ms": 520, "text": "Привет" },
{ "speaker": 1, "start_ms": 600, "end_ms": 1200, "text": "Как дела" },
{ "speaker": 0, "start_ms": 1250, "end_ms": 2100, "text": "Нормально" }
]
}
Диаризация по каналам
При channelMode=stereo каждый канал распознаётся отдельно (моно тоже допускается — тогда будет один канал). Каналы нумеруются с 0; для стерео это левый канал 0 и правый канал 1. В speakers возвращается цельный текст каждого канала, а в utterances — цельные реплики с таймингами в хронологическом порядке.
Если модель вернула полное выравнивание слов, границы реплик нативные и
timing_source равен riva. Если выравнивания нет или оно неполное, для
сохранения стереоконтракта текст канала получает оценочный диапазон на всю
длительность канала (synthetic, timing_estimated: true). При сочетании
источников возвращается mixed.
Матрица временной разметки файлового STT v1:
| Маршрут | Mono без диаризации | Stereo |
|---|---|---|
SpeechExpert-STT |
Нативные words и производные segments, если Riva вернула полное выравнивание |
Нативные границы реплик при полном выравнивании каждого канала |
GigaAM-v3-CTC, GigaAM-Multilingual-Large-CTC |
Нативные CTC words; segments по MarbleNet VAD с абсолютными границами исходного файла |
utterances каждого канала получают абсолютные границы MarbleNet VAD; при недоступном VAD сохраняется совместимый диапазон канала |
T-one, Whisper-Large-v3-Turbo, ElevenLabs-Scribe-v2 |
Текст без word offsets | Реплики с оценочным диапазоном synthetic, если у маршрута нет выравнивания |
Любая модель с channelMode=mono&diarization=true |
utterances с границами diarization-пайплайна вместо word offsets |
Не применяется |
speakers[] содержит объекты {"channel": 0, "result": "..."}. Элементы
words[] имеют text, start_ms, end_ms и необязательный speaker, а
segments[] — те же текстовые и временные поля плюс timing_source и
timing_estimated. Пользовательские подписи спикеров могут храниться в
speaker_names; это поле не создаётся ASR и описано в разделе
«Переименование спикеров».
Эмоциональная динамика¶
При emotionAnalysis=true сервис использует тот же канонический WAV, запускает
DUSHA параллельно с ASR и возвращает слой аналитики рядом с транскриптом. Новая
загрузка в отдельный Emotion API не нужна. После BCP-47-нормализации функция
принимает только lang=ru и lang=ru-RU; например, сочетание
lang=kk-KZ&emotionAnalysis=true отклоняется до inference.
{
"result": "я уже третий раз объясняю одну и ту же проблему",
"utterances": [
{"speaker": 1, "start_ms": 814000, "end_ms": 823000, "text": "я уже третий раз объясняю одну и ту же проблему"}
],
"emotion_analysis_status": "ready",
"emotion_analysis": {
"model": "dusha_emotion_ensemble_wav2vec_conformer_calibrated",
"model_version": "1",
"calibration_version": "sha256:...",
"language": "ru-RU",
"validated_languages": ["ru-RU"],
"window_seconds": 3.0,
"hop_seconds": 1.0,
"negative_threshold": 0.5,
"ema_alpha": 0.2835,
"metadata": {
"episode_min_windows": 2,
"episode_min_duration_ms": 2000,
"episode_merge_gap_ms": 1500,
"uncertain_top1_threshold": 0.45,
"uncertain_margin_threshold": 0.1,
"positive_threshold": 0.4,
"trend_window_share": 0.2,
"trend_min_delta": 0.05
},
"session": {
"duration_ms": 1200000,
"window_count": 1198,
"negative_share": 0.087,
"positive_share": 0.14,
"uncertain_share": 0.09,
"mean_negative_score": 0.18,
"peak_negative_score": 0.84,
"peak_negative_raw_score": 0.89,
"peak_negative_ema": 0.84,
"peak_at_ms": 818000,
"final_negative_ema": 0.12,
"first_negative_mean": 0.43,
"last_negative_mean": 0.12,
"deescalation_score": 0.31,
"deescalation_trend": "improved",
"deescalated": true,
"episode_count": 3,
"probs": {
"angry": 0.16,
"neutral": 0.58,
"other": 0.08,
"positive": 0.09,
"sad": 0.09
}
},
"episodes": [
{
"label": "negative",
"start_ms": 814000,
"end_ms": 823000,
"duration_ms": 9000,
"peak_score": 0.84,
"peak_at_ms": 818000,
"mean_score": 0.72,
"negative_score": 0.84,
"confidence": 0.68,
"mean_confidence": 0.68,
"max_confidence": 0.76,
"prediction": "angry",
"window_count": 7,
"speaker": 1,
"utterance_indices": [0],
"segment_indices": [],
"transcript_excerpt": "я уже третий раз объясняю одну и ту же проблему",
"probs": {
"angry": 0.68,
"neutral": 0.05,
"other": 0.07,
"positive": 0.04,
"sad": 0.16
}
}
],
"windows": null
}
}
Числа в примере иллюстративны. windows заполняется только при
emotionIncludeSegments=true; каждое окно содержит исходную prediction,
confidence, все пять probabilities, raw и EMA negative-score, а также индексы
пересекающихся реплик/сегментов.
Эпизод возвращает как mean_confidence, так и max_confidence; поле
confidence остаётся alias среднего значения.
Оконный negative_score равен P(angry) + P(sad) и сглаживается EMA.
negative_share взвешивается по покрытию исходной временной шкалы.
peak_negative_score и его явный alias peak_negative_ema — максимум
сглаженного сигнала; несглаженный максимум хранится отдельно в
peak_negative_raw_score. peak_at_ms указывает позицию сглаженного пика.
positive_share и uncertain_share считаются как доля окон соответствующего
производного состояния.
deescalation_score — среднее сглаженное значение первых 20% окон минус среднее
последних 20%; положительное значение означает снижение негативного сигнала,
отрицательное — рост. Сервер объединяет короткие разрывы и отбрасывает
одиночные/слишком короткие события; точные правила возвращаются в metadata.
Для интерфейса пять raw классов сводятся к negative, neutral, positive и
uncertain. uncertain — производное состояние низкой уверенности или малого
отрыва top-1 от top-2, а не шестой класс модели. other означает только другую
или неопределённую акустическую окраску.
Связь со спикером публикуется лишь при однозначном пересечении с mono-
диаризацией. Для channelMode=stereo текущий интегрированный анализ выполняется
после downmix и намеренно не приписывается конкретному каналу; используйте
utterance_indices для контекста, а не для автоматической оценки собеседника.
Emotion-обработка best-effort: её сбой не отменяет распознавание. Тогда
emotion_analysis равен null, а emotion_analysis_status — failed или
unavailable. Результат вероятностный и предназначен для навигации к исходному
аудио и ручной проверки, а не для автоматического решения о человеке. Полные
ограничения и отдельный endpoint описаны в Emotion API.
Для ru-RU тот же флаг независимо запускает анализ слов финальной
транскрипции. Он возвращается в text_emotion_analysis со своим
text_emotion_analysis_status и не меняет акустические score, эпизоды или
ranking. Текстовый model_score — sigmoid score модели, не калиброванная
вероятность истины; provenance включает исходную цитату, clause, таймкоды,
speaker и индексы utterance/segment.
Извлечение именованных сущностей¶
При entityExtraction=true обработка выполняется в порядке ASR → опциональная
LLM-коррекция (если llmCorrection=true) → извлечение сущностей. Поэтому
mention и символьные offsets относятся к тому тексту, который фактически
возвращён клиенту, а не к сырому результату модели.
Сбой извлечения не отменяет успешную транскрибацию.
Поддерживаются типы person, organization, location, product, event,
date, time, money, phone, email, url, address, document и
identifier. Одинаковые упоминания группируются по типу и нормализованному
значению:
{
"result": "Анна позвонила в ACME",
"entities": [
{
"id": "person:1",
"type": "person",
"text": "Анна",
"normalized": "Анна",
"occurrences": [
{
"utterance_index": null,
"mention": "Анна",
"char_start": 0,
"char_end": 4,
"speaker": null,
"start_ms": null,
"end_ms": null
}
]
}
],
"entity_extraction_status": "ready"
}
Offsets используют полуоткрытый интервал [char_start, char_end).
utterance_index указывает индекс строки-источника: элемента utterances, если
они есть, иначе элемента segments; при извлечении непосредственно из
верхнеуровневого result он равен null. Временные поля в occurrence — это
грубые границы исходной реплики/сегмента, а не отдельного слова.
| Статус | Значение |
|---|---|
ready |
Все части текста обработаны, включая корректный пустой результат |
partial |
Часть чанков или элементов не удалось проверить; валидные сущности сохранены |
failed |
Извлечение завершилось ошибкой; транскрипт возвращён, entities пуст |
unavailable |
Извлечение запрошено, но LLM-ключ не настроен |
Если entityExtraction=false, оба поля сущностей не заполняются и равны null.
Коррекция использует модель из LLM_CORRECTION_MODEL (штатно
google/gemini-3.5-flash-minimal). Пустые LLM_ENTITY_EXTRACTION_* наследуют
endpoint, модель и ключ коррекции; при необходимости NER можно настроить отдельно.
Саммаризация по пресетам¶
summarizationPreset запускается после коррекции и извлечения сущностей. То
есть резюме, ссылки и цитаты относятся к окончательному тексту. Модель
контролируется сервером через LLM_SUMMARIZATION_MODEL; значение по умолчанию —
google/gemini-3.1-flash-lite.
Язык результата
Все сгенерированные человекочитаемые значения — заголовки, резюме, пункты,
вопросы, ответы, задачи и элементы готовых наборов — по умолчанию
возвращаются на преобладающем языке оригинальной речи. Язык определяется по
тексту транскрипции; lang/locale служит только вспомогательной подсказкой.
Явный summarizationOutputLanguage в распознавании или outputLanguage в
JSON-методах саммаризации переопределяет это правило только для
сгенерированных значений.
Технические поля (source_ref, таймкоды, спикеры и каналы), имена JSON-полей,
серверные sources[].quote, ссылки, имена, идентификаторы и дословные
фрагменты сохраняются в оригинале. Язык инструкции и англоязычная JSON Schema
не подменяют выбранный язык. Для полного перевода транскрипта используйте
отдельный POST /api/stt/v1:translate.
| Пресет | Назначение |
|---|---|
short |
Резюме в 2–4 предложениях и до пяти ключевых пунктов |
notes |
Тематический или хронологический конспект |
conversation |
Цель, позиции участников, ключевые факты и итог разговора |
action_items |
Решения, задачи, исполнители, сроки и открытые вопросы |
topics_timestamps |
Темы в хронологическом порядке с переходом к началу каждой темы |
lecture |
Учебный конспект: определения, аргументы, примеры и процедуры |
sales_crm |
Потребности, квалификация, возражения, сигналы покупки и следующие шаги |
contact_center |
Причина обращения, проблема, обработка, результат, эскалация и обещания |
interview |
Вопросы или темы, содержательные ответы, мнения и уточнения |
research_report |
Повторяющиеся темы, JTBD, возражения и доказательные выводы по одному или нескольким интервью |
podcast_chapters |
Обзор выпуска и хронологические главы с таймкодами |
voice_inbox |
Классификация голосовых мыслей на задачи, события, идеи, заметки и вопросы |
study_pack |
Конспект, карточки, проверочные вопросы и словарь |
creator_pack |
Тезисы, главы, фрагменты с таймкодами, полная статья, show notes и публикации |
Параметр summarizationDetail не меняет сценарий, а регулирует объём:
brief оставляет только самое важное, standard даёт сбалансированный результат,
detailed сохраняет существенные детали, примеры, возражения и контекст.
Для research_report специализированные результаты находятся в
summarization.workflow:
research_themes— повторяющиеся темы с названием, выводом и источниками;jobs_to_be_done— JTBD-формулировка и отдельно подтверждённые ситуация, мотивация и ожидаемый результат;objections— явно высказанные барьеры, сомнения и причины отказа;- доказательные выводы возвращаются в
structured.key_points.
Сервер удаляет исследовательский элемент без существующего источника. Для повторяющейся темы нужны минимум две независимые реплики; в дайджесте нескольких интервью источники должны относиться минимум к двум разным записям. Точная доля респондентов не рассчитывается: источники подтверждают повторяемость, но не заменяют статистический анализ всей выборки.
Доказательная структура результата¶
При успехе ответ содержит summarization_status: "ready". Поля
key_points, sections, decisions, action_items, open_questions и
risks остаются массивами строк для обратной совместимости. Дополнительное
поле structured содержит те же элементы со ссылками на исходный текст:
{
"summarization_status": "ready",
"summarization": {
"schema_version": "2.0",
"id": "4a518cc8-4f70-470d-b868-40e39420fba5",
"created_at": "2026-07-15T12:00:00+00:00",
"preset": "action_items",
"detail_level": "standard",
"output_language": "en-US",
"title": "Project launch",
"summary": "The team agreed on the launch.",
"key_points": ["The launch is scheduled for Friday"],
"sections": [],
"decisions": ["Launch the project on Friday"],
"action_items": ["Anna will prepare the release"],
"open_questions": [],
"risks": [],
"structured": {
"key_points": [],
"sections": [],
"decisions": [
{
"text": "Launch the project on Friday",
"confirmation": "confirmed",
"sources": [
{
"ref": "S0003",
"anchor_id": "c26f6b0ee94de908b7106e21",
"quote": "Да, запускаем в пятницу.",
"start_ms": 42100,
"end_ms": 43800,
"speaker": 1,
"speaker_name": "Руководитель",
"utterance_index": 2,
"segment_index": null,
"timing_estimated": false
}
]
}
],
"action_items": [
{
"text": "Anna will prepare the release",
"assignee": "Анна",
"due_date": "by Friday",
"sources": [
{
"ref": "S0004",
"quote": "Анна подготовит релиз до пятницы.",
"start_ms": 44000,
"end_ms": 45600,
"speaker": 1,
"utterance_index": 3,
"timing_estimated": false
}
]
}
],
"open_questions": [],
"risks": []
}
}
}
summarization.output_language содержит нормализованный явно запрошенный tag;
значение null означает автоматический выбор языка по транскрипции.
LLM возвращает только короткие source_ref, а сервер подставляет цитату,
таймкод, спикера и индекс из исходного STTResponse. Неизвестные ссылки
отбрасываются; утверждение или элемент workflow без хотя бы одного валидного
источника не публикуется. Поэтому клиенту нельзя вычислять время из текста ответа LLM.
Если у расшифровки нет utterances или segments, у источника остаётся цитата,
но временные поля равны null. timing_estimated=true означает, что исходные
границы были оценочными.
Для решений confirmation принимает confirmed, proposed, rejected или
unclear. Поля задачи assignee и due_date заполняются только при явном
упоминании. Отсутствующие данные представлены null, пустой строкой или
массивом; предположение не превращается в подтверждённое решение.
Сбой провайдера не отменяет готовую транскрибацию: статус будет failed, а при
отсутствующем LLM-ключе — unavailable; в обоих случаях summarization равен
null.
Новый результат без повторного распознавания¶
Для уже готового текста используется только LLM-постобработка:
Метод не читает аудиофайл, не запускает ASR и не списывает аудиоминуты. Нужно
передать ровно один источник: полный response ещё не сохранённого результата
или recordingId записи текущего пользователя. lang служит подсказкой о языке
исходной речи. Необязательный outputLanguage независимо задаёт язык
сгенерированных полей; без него используется преобладающий язык транскрипции. У
сохранённой записи locale дополнительно берётся из её метаданных.
curl -X POST "https://api.speech.example.com/api/stt/v1:summarize" \
-H "Authorization: Api-Key $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"preset": "topics_timestamps",
"detailLevel": "detailed",
"lang": "ru-RU",
"outputLanguage": "en-US",
"response": {
"result": "Готовый распознанный текст",
"segments": []
}
}'
Ответ содержит summarization, summarization_status, recordingId,
recording_updated, summaryVersion и activeSummaryVersionId. Для
сохранённой записи каждый успешный запуск создаёт неизменяемую версию и делает
её активной. Активная версия также проецируется в прежние поля
response.summarization и response.summarization_status, поэтому старые
клиенты продолжают видеть один текущий результат. Ошибка LLM не создаёт версию
и не удаляет предыдущую.
История результатов сохранённой записи¶
Методы /api/account/... в этом и следующих разделах требуют активную cookie-
сессию портала и пользователя-владельца записи. Один API-ключ без portal-cookie
для них недостаточен. Публичные методы /api/stt/... по-прежнему принимают
обычную API-аутентификацию.
| Метод | Назначение |
|---|---|
GET /api/account/recordings/{recording_id}/summaries |
Версии от новой к старой и activeSummaryVersionId |
POST /api/account/recordings/{recording_id}/summaries/{summary_id}:activate |
Сделать версию активной |
DELETE /api/account/recordings/{recording_id}/summaries/{summary_id} |
Удалить версию |
Элемент списка содержит снимок summarization, пресет, подробность, выбранный
output_language, модель, статус, время создания и is_active. Для результата,
созданного собственным шаблоном, сохраняются template_id, имя и номер ревизии. При первом чтении
истории старая запись с единственным response.summarization лениво получает
одну legacy-версию. Если удалить активную версию, активируется самая новая из
оставшихся; если версий больше нет, прежняя проекция очищается.
Собственные шаблоны¶
Шаблон задаёт дополнительный фокус, но не может отменить схему ответа, выбранный язык результата, сохранение исходных цитат, проверку источников и запрет на выдуманные факты:
| Метод | Назначение |
|---|---|
GET /api/account/summary-templates |
Список шаблонов пользователя |
POST /api/account/summary-templates |
Создать шаблон |
PATCH /api/account/summary-templates/{template_id} |
Изменить и увеличить revision |
DELETE /api/account/summary-templates/{template_id} |
Удалить шаблон |
{
"name": "Разбор исследования",
"description": "Гипотезы, ограничения и следующие эксперименты",
"instruction": "Отдельно перечисли подтверждения и опровержения гипотез.",
"base_preset": "lecture",
"default_detail": "detailed"
}
Чтобы применить шаблон, передайте templateId в POST /api/stt/v1:summarize.
preset и detailLevel можно указать явно; иначе используются
base_preset и default_detail шаблона. В готовой версии сохраняется снимок
имени, инструкции и ревизии, поэтому дальнейшее изменение шаблона не меняет
исторический результат.
Дайджест нескольких записей¶
Метод принимает от 2 до 20 разных сохранённых записей текущего пользователя:
{
"recordingIds": [
"7ae1ee00-4fb3-4c43-83c3-53568ef06b0b",
"4a518cc8-4f70-470d-b868-40e39420fba5"
],
"preset": "research_report",
"detailLevel": "detailed",
"outputLanguage": "en-US",
"title": "Исследование по 20 интервью"
}
В источниках структурированного результата дополнительно появляются
recording_id и recording_name; ссылки имеют вид R01S0001. Ответ содержит
digestId, summarization, статус и исходный список recordingIds. Успешный
результат сохраняется и доступен через:
| Метод | Назначение |
|---|---|
GET /api/account/summary-digests?offset=0&limit=50 |
Список дайджестов |
GET /api/account/summary-digests/{digest_id} |
Один дайджест |
DELETE /api/account/summary-digests/{digest_id} |
Удалить дайджест |
Вместо preset можно передать templateId. Все записи и шаблон проверяются по
владельцу; отсутствующий или чужой объект возвращается как 404. Для обычных
пресетов суммарный контекст ограничен 200 000 символов. research_report
при большем объёме автоматически переходит на доказательный map-reduce:
каждая запись анализируется отдельно, затем сервер сводит только отобранные
наблюдения и исходные реплики в общий отчёт. Общий лимит исследовательского
дайджеста — 1 500 000 символов, то есть при 20 записях доступно в среднем до
75 000 символов на интервью без обрезания принятой расшифровки. При превышении
соответствующего лимита возвращается 413.
Промежуточные выводы не получают синтетических ссылок: на обоих этапах
используются исходные RxxSxxxx, а финальный reducer принимает только ссылки,
которые реально попали в проверенный набор доказательств. Повторяющаяся тема
обязана ссылаться минимум на две разные записи. Ограниченный набор доказательств
не используется для заявлений о процентах, большинстве или частоте.
Без outputLanguage язык дайджеста определяется по преобладающему объёму речи
во всём объединённом контексте; locale отдельных записей и поле lang остаются
подсказками. Явный BCP-47 tag задаёт язык сгенерированных выводов, но цитаты в
источниках остаются на языках записей.
Готовые пользовательские наборы¶
Для сохранённой записи отдельный метод создаёт версионируемый результат без повторного ASR:
{
"recordingId": "7ae1ee00-4fb3-4c43-83c3-53568ef06b0b",
"kind": "study_pack",
"detailLevel": "standard",
"outputLanguage": "tg-TJ"
}
kind принимает voice_inbox, study_pack, action_center или
creator_pack. Результат использует ту же контролируемую сервером модель
(по умолчанию google/gemini-3.1-flash-lite) и те же проверенные сервером источники. В
summarization.workflow находятся специализированные поля:
inbox_items— задача, событие, идея, заметка или вопрос;flashcards,quiz,glossary— учебный набор;clips— кандидаты фрагментов; таймкод берётся из проверенного источника;content_drafts— полная статья, show notes, описание видео, рассылка и отдельные публикации для общего social-формата, Telegram и VK.
Creator Pack также заполняет доказательные тезисы в structured.key_points и
хронологические главы в structured.sections. Вид article_outline сохраняется
для совместимости, а полный материал имеет kind=article и сохраняет Markdown-
заголовки и абзацы. Для встроенного long-form сценария сервер отдельно создаёт
редакционный разбор, статью и набор публикаций, затем объединяет их и проверяет
содержательность каждого формата. Недостающие части запрашиваются ещё один раз;
неполный после повторной проверки long-form набор не получает статус ready.
Короткие записи до 4000 символов и пользовательские шаблоны сохраняют прежний
best-effort режим, чтобы полезный частичный результат не терялся.
SRT и VTT формируются отдельно из STT-таймингов: если исходная модель не вернула
временные границы, интерфейс не выдумывает их из ответа LLM.
Все сгенерированные текстовые поля workflow наследуют общий языковой контракт
саммаризации и учитывают необязательный outputLanguage.
Ответ содержит resultId, versionId, sourceFingerprint, статус и payload.
Повторный запуск добавляет неизменяемую версию к тому же логическому результату.
Чтение и переключение версий:
| Метод | Назначение |
|---|---|
GET /api/account/recordings/{recording_id}/derived-results |
Все виды и их активные версии |
GET /api/account/recordings/{recording_id}/derived-results/{result_id}/versions |
История одного набора |
POST /api/account/recordings/{recording_id}/derived-results/{result_id}/versions/{version_id}:select |
Сделать версию активной |
DELETE /api/account/recordings/{recording_id}/derived-results/{result_id}/versions/{version_id} |
Удалить версию |
DELETE /api/account/recordings/{recording_id}/derived-results/{result_id} |
Удалить логический результат со всеми версиями |
У списка derived-results есть необязательный query-фильтр kind. После
удаления активной версии сервер выбирает следующую доступную версию; если версий
не осталось, удаляется и пустой логический результат.
Центр поручений¶
Задачи, решения и требующие проверки элементы Voice Inbox копируются из неизменяемого результата в отдельную очередь. Пользователь может подтвердить, исправить или отклонить кандидат, не меняя исходный ответ модели:
| Метод | Назначение |
|---|---|
GET /api/account/recordings/{recording_id}/review-items |
Очередь подтверждения |
PATCH /api/account/recordings/{recording_id}/review-items/{item_id} |
Статус, исправленное значение или заметка |
Поддерживаются статусы pending, confirmed, corrected, dismissed и
UI-алиасы accepted, edited, rejected. Поле anchors содержит
серверные источники; sourceFingerprint связывает подтверждение с конкретной
версией транскрипта.
У GET доступны фильтры status и kind. Тело PATCH может содержать
status, replacement и note; исходный LLM-результат при этом не изменяется.
Перевод готового транскрипта¶
Полный перевод — отдельная LLM-обработка, которая не запускает ASR, не меняет исходный транскрипт и не заменяет текущую саммаризацию:
Нужно передать ровно один источник: полный response или recordingId
принадлежащей пользователю записи. targetLanguage обязателен, а
sourceLanguage — необязательная подсказка. Языки задаются нормализуемыми
BCP-47 tags:
При успехе возвращается status: "ready" и отдельный объект translation:
{
"status": "ready",
"translation": {
"schema_version": "1.0",
"id": "da962058-770c-4d50-a5bb-77b75ea5a929",
"created_at": "2026-07-16T12:00:00+00:00",
"source_language": "ru-RU",
"target_language": "en-US",
"text": "Yes, we are launching on Friday.",
"segments": [
{
"source_ref": "S0001",
"source_text": "Да, запускаем в пятницу.",
"text": "Yes, we are launching on Friday.",
"source": {
"ref": "S0001",
"quote": "Да, запускаем в пятницу.",
"start_ms": 42100,
"end_ms": 43800,
"segment_index": 0,
"timing_estimated": false
}
}
]
},
"recordingId": null,
"resultId": null,
"versionId": null,
"sourceFingerprint": "d3135a..."
}
Сервер переводит полные исходные фрагменты, проверяет сохранение всех
source_ref и затем восстанавливает их порядок и серверные источники. Поля
source_text, source.quote, таймкоды и спикеры относятся к оригиналу;
новые word-level таймкоды для переведённых слов не выдумываются. Верхнее поле
translation.text — соединённый по порядку текст переведённых фрагментов.
Для длинного текста сервер формирует пакеты не более 40 фрагментов и примерно
16 000 символов, запускает их асинхронно и пропускает запросы через общий
LLM-семафор и pacing. Сам HTTP-метод возвращает ответ после завершения всех
пакетов. Общий предел исходного текста — 500 000 символов; превышение даёт
413. Если LLM не настроена, возвращается status: "unavailable", при ошибке
обработки — status: "failed"; в обоих случаях translation равен null.
Для POST /api/stt/v1:translate действует отдельный sliding-window rate limit.
У аутентифицированного запроса лимит привязан к пользователю и общий для его
сессии и API-ключей; если пользователь не определён, используется IP-адрес.
По умолчанию разрешено 5 запросов за 60 секунд. Значения настраиваются через
STT_TRANSLATION_RATE_LIMIT_MAX_REQUESTS и
STT_TRANSLATION_RATE_LIMIT_WINDOW_SECONDS. При превышении сервер отвечает
429 Too Many Requests и передаёт число секунд до следующей попытки в заголовке
Retry-After. Счётчики хранятся в памяти процесса, поэтому для строгого общего
лимита при нескольких workers или replicas нужен дополнительный лимит на
reverse proxy/API gateway либо общее хранилище.
Успешный перевод по recordingId сохраняется как производный результат
kind=translation: отдельный целевой язык образует отдельный логический
результат, а повторный запуск добавляет версию. Ответ тогда также содержит
resultId, versionId и sourceFingerprint; перевод доступен через методы
derived-results, перечисленные выше. Исходные поля записи
и response.summarization при этом не изменяются. В интерфейсе Мои записи
доступны русский, английский, казахский, кыргызский, узбекский и таджикский
целевые языки; API принимает любой tag, прошедший BCP-47-валидацию.
Вопрос по архиву¶
{
"question": "О каких сроках договорились и кто отвечает?",
"recordingIds": [
"7ae1ee00-4fb3-4c43-83c3-53568ef06b0b",
"4a518cc8-4f70-470d-b868-40e39420fba5"
]
}
Можно передать 1–20 записей. Если recordingIds отсутствует, используются до
20 последних сохранённых расшифровок пользователя. Ответ строится только по
архиву: каждый тезис имеет источники с записью, цитатой и таймкодом. Если
подтверждений недостаточно, insufficient_evidence=true; внешние знания не
подмешиваются.
Ответ и тезисы формируются на преобладающем языке речи выбранных записей, даже если вопрос задан на другом языке. Имена, термины и подтверждающие цитаты сохраняются в оригинале.
Приватный режим¶
Асинхронный метод принимает два дополнительных флага:
curl -X POST \
"https://api.speech.example.com/api/stt/v1:recognizeAsync?privacyMode=true&externalAiConsent=false&llmCorrection=false&entityExtraction=false" \
-H "Authorization: Api-Key $API_KEY" \
-F "audio=@private.wav"
При privacyMode=true сервис:
- не создаёт запись для файла или видео по ссылке;
- не обновляет сохранённую запись при повторном распознавании;
- помечает результат операции как временный; после копирования результата клиент
должен вызвать
POST /api/operations/{operationId}:purge; - запускает страховочную серверную очистку по deadline, который считается от
момента запуска операции. По умолчанию это 15 минут
(
PRIVATE_OPERATION_TTL_MINUTES), а фоновая проверка выполняется раз в минуту.
Playground вызывает :purge автоматически после получения ответа. Обычный
API-клиент должен сделать это сам: чтение GET /api/operations/{id} не удаляет
содержимое. Если долгая задача завершилась уже после своего deadline,
страховочная очистка может сработать почти сразу после завершения.
Это приватная серверная обработка, а не локальный STT и не сквозное шифрование.
Без externalAiConsent=true блокируются LLM-коррекция, NER, саммаризация и
ElevenLabs. Поскольку llmCorrection=true является общим значением по
умолчанию, прямой приватный запрос без согласия должен явно передать
llmCorrection=false (а также не включать NER/саммаризацию и не выбирать
ElevenLabs), иначе сервер вернёт 400. Playground согласует эти переключатели
автоматически. Явное согласие разрешает передачу текста или аудио настроенному
внешнему провайдеру, но не включает постоянное хранение результата.
Хранение аудио отдельно от текста¶
У сохранённой записи доступны политики:
| Политика | Поведение |
|---|---|
keep |
Хранить аудио без заданного срока |
24h |
Назначить удаление через 24 часа от установки политики; worker выполняет его best-effort |
delete_after_processing |
Пометить аудио к удалению; текущий account API синхронно пытается удалить доступное медиа, итог нужно проверить по media_status |
Удаление медиа не удаляет транскрипт, источники, саммаризации, готовые наборы и подтверждения:
| Метод | Назначение |
|---|---|
PUT /api/account/recordings/{recording_id}/retention |
Установить audio_retention |
DELETE /api/account/recordings/{recording_id}/media |
Немедленно удалить только аудио |
DELETE /api/account/recordings/{recording_id} |
Удалить запись и прямо связанные версии/производные результаты; подробности и edge cases — в API записей |
media_status принимает available, purge_pending, purged или
purge_failed. После успешного удаления media_available=false; при любом
статусе кроме available метод GET .../media возвращает 410 Gone. Смена
политики не восстанавливает уже удалённый файл.
Живые субтитры¶
Playground использует существующий WS /api/stt/v1/ws: браузер отправляет
PCM16 mono 16 кГц, отображает partial/final-гипотезы крупным текстом и завершает
поток сообщением {"event":"eof"}. Сеанс не создаёт запись и операцию. В UI
есть изменение размера шрифта, контраст, автопрокрутка, копирование и локальное
скачивание текста. Playground авторизуется cookie портала и не добавляет API-ключ
в URL. Внешние клиенты могут использовать заголовок Authorization; legacy query
?api_key=... сохранён для совместимости. Перед началом потока проверяются
доступные кредиты, после завершения фактическая длительность PCM записывается в
usage и тарифицируется как STT.
Примеры использования¶
curl -X POST "https://api.speech.example.com/api/stt/v1" \
-H "Authorization: Api-Key $API_KEY" \
-F "audio=@stereo.wav" \
-F "lang=ru-RU" \
-F "channelMode=stereo"
В ответе будут поля result и utterances — реплики по говорящим в хронологическом порядке.
import requests
with open("audio.wav", "rb") as f:
response = requests.post(
"https://api.speech.example.com/api/stt/v1",
headers={"Authorization": "Api-Key <ваш-ключ>"},
files={"audio": ("audio.wav", f, "audio/wav")},
params={"lang": "ru-RU", "channelMode": "mono"},
)
print(response.json()["result"])
Асинхронный вариант¶
Для длинных записей у метода есть фоновый вариант:
Он сразу возвращает объект операции с полем id. Результат
забирается методом GET /api/operations/{id}. Базовая часть response
совпадает с синхронным STTResponse, но фоновые сценарии могут добавить
служебные поля сохранённой записи.
Нужно передать ровно один источник:
| Поле формы | Поведение в обычном режиме |
|---|---|
audio |
Временная загрузка; запись в Моих записях автоматически не создаётся |
videoUrl |
Скачивается одна аудиодорожка, после успеха создаётся сохранённая запись и в ответ добавляется recording_id |
recordingId |
Повторно используется медиа принадлежащей пользователю записи; её STT-ответ обновляется, а операция может вернуть recording_id или recording_deleted |
Метод поддерживает те же настройки распознавания. lang, channelMode,
diarization, maxSpeakers, llmCorrection, entityExtraction,
summarizationPreset, summarizationDetail, summarizationOutputLanguage, privacyMode и
externalAiConsent принимаются в query или форме; форма имеет приоритет.
model, topic, rawResults, format и sampleRateHertz передаются только в
query string. Значения по умолчанию: llmCorrection=true,
entityExtraction=false, саммаризация и приватный режим выключены.
При privacyMode=true ни один источник не создаёт и не обновляет запись; правила
согласия на внешние провайдеры и очистки операции описаны
выше.
Распознавание видео по ссылке¶
Для videoUrl сервис с помощью yt-dlp скачивает одну лучшую аудиодорожку без
плейлиста, после чего запускает обычный STT-пайплайн.
curl -X POST "https://api.speech.example.com/api/stt/v1:recognizeAsync?model=SpeechExpert-STT" \
-H "Authorization: Api-Key $API_KEY" \
-F "videoUrl=https://www.youtube.com/watch?v=VIDEO_ID" \
-F "lang=ru-RU" \
-F "channelMode=stereo"
Поддерживаются YouTube, VK Видео / VK Play, RuTube, Яндекс Видео, Дзен, Одноклассники, Vimeo, Dailymotion, Twitch, TikTok, SoundCloud и другие сайты с отдельным extractor в yt-dlp. Доступность зависит от конкретного ролика; некоторые ссылки требуют актуальных cookies или могут временно не работать из-за изменений на стороне площадки. Generic extractor отключён из соображений безопасности, прямые произвольные ссылки на файлы следует передавать через audio или STT v3 uri.
Размер скачанного аудио и длительность ролика ограничиваются настройками
STT_YTDLP_MAX_DOWNLOAD_BYTES и STT_YTDLP_MAX_DURATION_SECONDS (по умолчанию
200 МБ и 4 часа). Плейлисты и прямые трансляции не загружаются.
Ошибки¶
| Код | Когда возникает |
|---|---|
400 |
Пустой файл, неподдерживаемый формат, ошибка конвертации |
401 |
Не аутентифицирован (отсутствует или неверный API-ключ) |
402 |
Недостаточно кредитов для выбранной модели/длительности |
404 |
Сохранённая запись, шаблон или другой принадлежащий пользователю ресурс не найден |
413 |
Файл или транскрипт для LLM-перевода превышает допустимый размер |
409 |
Операция или версия находится в состоянии, несовместимом с действием |
422 |
Не прошли типы, диапазоны или взаимные ограничения параметров |
500 |
Внутренняя ошибка |
503 |
Сервис распознавания временно недоступен |
Для :recognizeAsync исходный POST может успешно вернуть операцию, а ошибка
загрузки, декодирования, ASR или LLM появится позже в Operation.error при
опросе. Поэтому клиент должен проверять не только HTTP-код создания задачи, но и
поля done, error и response завершённой операции.