STT — справочник API
Назначение сервиса
STT-сервис принимает ссылку на аудиофайл и возвращает только транскрипцию.
Для новой интеграции активный сценарий такой:
- POST /transcribe/audio_url — если нужно обработать аудио;
- GET /result/{task_id} — чтобы получить статус и итог аудио-задачи.
Совместимые старые пути /classify/text, /classify/audio_url и /classify/batch сохранены только для ручных проверок и обратной совместимости. Путь /transcribe/text удалён из активного runtime-контракта.
Базовые адреса
| Среда | URL | Когда использовать |
|---|---|---|
| Промышленная | https://stt.techcon-ml.ru |
основной адрес для интеграции |
| Тестовая | https://stt.dev.techcon-ml.ru |
только после отдельной перепроверки |
| Локальная | http://localhost:8000 |
локальная разработка |
Актуальная оговорка: https://stt.dev.techcon-ml.ru/health при последней согласованной проверке возвращал 502 Bad Gateway, поэтому для интеграционных проверок опирайтесь на промышленный адрес.
OpenAPI JSON: <base_url>/openapi.json
Основная ReDoc-поверхность: <base_url>/docs
Вторичная Swagger UI-поверхность: <base_url>/swagger
Совместимый дополнительный ReDoc-путь: <base_url>/redoc
Иерархия источников истины
Если нужно быстро понять общий сценарий, используйте эту страницу.
Если нужен точный состав полей, кодов ошибок и примеров, сверяйтесь в таком порядке:
1. рабочее поведение промышленного сервиса;
2. openapi.json, live ReDoc на /docs, Swagger UI на /swagger и совместимый ReDoc-путь /redoc этого сервиса;
3. эта страница;
4. общее руководство по интеграции.
Этот портал публикует производную копию принятого сервисного контракта. Если текст на портале расходится с тем, что сейчас отвечает production или показывает live /docs / /swagger, ориентируйтесь на live сервис.
Практическая оговорка: на ReDoc-поверхностях /docs и /redoc сейчас видны и служебные пути /showcase/*. Они не входят во внешний интеграционный контракт и не нужны обычному интегратору.
Быстрый выбор пути
| Что нужно сделать | Эндпоинт | Режим |
|---|---|---|
| Поставить аудио-задачу | POST /transcribe/audio_url |
асинхронная постановка задачи |
| Узнать статус или получить результат аудио | GET /result/{task_id} |
опрос статуса |
| Получить справочную таксономию | GET /taxonomy |
вспомогательный путь |
| Передать уже готовый текст старому клиенту | POST /classify/text |
совместимый старый путь |
| Поддержать старого клиента | /classify/* |
совместимый старый путь |
| Проверить доступность сервиса | GET /health |
публичный путь |
| Забрать метрики Prometheus | GET /metrics |
публичный путь |
Общий формат ответов
Успех:
{"ok": true, "data": {...}}
Ошибка:
{"ok": false, "error": {"code": "UPPER_SNAKE_CODE", "message": "..."}}
Аутентификация
Основная схема доступа:
- BEARER_TOKENS — основной источник токенов доступа;
- BEARER_TOKEN — совместимый запасной вариант, если BEARER_TOKENS пуст.
Если обе переменные пусты, сервис работает без аутентификации только в открытом локальном режиме.
Формат заголовка:
Authorization: Bearer <token>
При включённой аутентификации токен нужен для:
- POST /transcribe/audio_url
- POST /classify/text
- POST /classify/audio_url
- POST /classify/batch
- GET /result/{task_id}
- GET /taxonomy
Без токена доступны:
- GET /health
- GET /metrics
- GET /docs
- GET /swagger
- GET /redoc
- GET /openapi.json
Ограничения по числу запросов
Что подтверждено текущим контрактом:
- ограничение применяется на токен;
- окно — 60 секунд;
- значение задаётся через RATE_LIMIT_PER_MINUTE;
- при превышении лимита сервис возвращает HTTP 429, RATE_LIMIT_EXCEEDED и Retry-After: 60.
Не считайте активным контрактом исторические значения лимита без подтверждения для вашей среды.
Карта эндпоинтов
| Метод | Путь | Назначение | Комментарий |
|---|---|---|---|
GET |
/health |
Проверка состояния | публичный |
GET |
/metrics |
Метрики Prometheus | публичный |
POST |
/transcribe/audio_url |
Основной путь для аудио | асинхронная постановка |
GET |
/result/{task_id} |
Статус и итог аудио-задачи | основной резервный путь |
GET |
/taxonomy |
Справочная таксономия | вспомогательный путь |
POST |
/classify/text |
Старый совместимый путь для текста | использовать только для старых клиентов |
POST |
/classify/audio_url |
Старый совместимый путь для аудио | использовать только для старых клиентов |
POST |
/classify/batch |
Пакетная транскрипция текстов | старый совместимый путь |
GET /health
Публичная проверка состояния сервиса.
Успех 200:
{
"ok": true,
"data": {
"status": "ok",
"worker_id": "tc-gpu-t4-01",
"model_loaded": true,
"version": "0.8.0",
"taxonomy_classes": 38
}
}
Если модель или таксономия ещё не готовы:
- HTTP 503
- error.code = "MODEL_NOT_LOADED"
Совместимый старый текстовый путь
POST /classify/text
Синхронный путь для уже готового текста. Его нужно использовать только для ручных проверок и старых клиентов после удаления POST /transcribe/text из активного runtime-контракта.
Тело запроса:
{"text": "трещина в стене"}
Правила:
- text обязателен;
- длина 1..2000;
- режим всегда transcription_only.
Ответ 200:
{
"ok": true,
"data": {
"status": "success",
"transcription": {
"raw_text": "трещина в стене",
"corrected_text": "трещина в стене",
"corrections_made": []
},
"classification": null,
"extracted_fields": null,
"processing_time_ms": 0.0,
"mode": "transcription_only"
}
}
Возможные ошибки:
- 401 UNAUTHORIZED
- 422 VALIDATION_ERROR
- 429 RATE_LIMIT_EXCEEDED
Аудио: постановка задачи, опрос и обратный вызов
Что важно для интегратора
POST /transcribe/audio_urlне возвращает транскрипцию сразу;- сервис ставит задачу в очередь и сразу отвечает
202; - если worker уже работает, ответ обычно несёт
estimated_wait_seconds=60; - если T4 ещё нужно поднять или её статус не подтверждён, сервис повышает ожидание до
estimated_wait_seconds=180; - результат нужно забирать через
GET /result/{task_id}; webhookможет ускорить получение итога, но не заменяет опрос статуса.- красный
GET /healthв первые минуты cold start сам по себе ещё не доказывает финальный outage, если задача принята и остаётся вqueued/processing.
Постановка задачи
Предпочтительный путь:
- POST /transcribe/audio_url
Совместимый старый путь:
- POST /classify/audio_url
Оба пути используют один и тот же контракт принятия задачи.
Тело запроса:
{
"url": "https://storage.yandexcloud.net/bucket/audio.wav",
"metadata": {
"report_defect_id": 123,
"defect_id": 42,
"defect_name": "трещина"
},
"webhook": {
"url": "https://integrator.example/api/stt-callback",
"secret": "shared-secret"
}
}
Правила:
- используйте именно поле url, а не audio_url;
- metadata опционален;
- webhook опционален;
- итог всё равно нужно уметь дочитывать через GET /result/{task_id};
- estimated_wait_seconds — это ориентир до первого полезного опроса, а не гарантия готовности.
Ответ 202:
{
"ok": true,
"data": {
"task_id": "stt-42e11f77f737",
"status": "queued",
"status_url": "/result/stt-42e11f77f737",
"estimated_wait_seconds": 180,
"metadata": {
"report_defect_id": 123,
"defect_id": 42,
"defect_name": "трещина"
},
"webhook": {
"configured": true,
"status": "pending"
}
}
}
Ошибки при постановке задачи:
- 401 UNAUTHORIZED
- 422 VALIDATION_ERROR
- 429 RATE_LIMIT_EXCEEDED
- 503 REDIS_UNAVAILABLE
- 500 INTERNAL_ERROR
Опрос статуса: GET /result/{task_id}
Для этого пути нужен тот же токен, что и для постановки задачи.
Когда задача ещё не завершилась, сервис отвечает 202:
{
"ok": true,
"data": {
"task_id": "stt-42e11f77f737",
"status": "processing",
"metadata": {
"report_defect_id": 123,
"defect_id": 42,
"defect_name": "трещина"
},
"webhook": {
"configured": true,
"status": "pending"
}
}
}
Когда задача завершилась успешно, сервис отвечает 200:
{
"ok": true,
"data": {
"task_id": "stt-42e11f77f737",
"status": "done",
"result": {
"transcription": "трещина на фасаде",
"service": "stt"
},
"processing_time_ms": 3500,
"completed_at": "1234567890",
"metadata": {
"report_defect_id": 123,
"defect_id": 42,
"defect_name": "трещина"
},
"webhook": {
"configured": true,
"status": "delivered",
"delivery_id": "stt-42e11f77f737:done:1234567890",
"delivered_at": "1234567891"
}
}
}
Когда задача завершилась ошибкой, сервис отвечает 200:
{
"ok": true,
"data": {
"task_id": "stt-42e11f77f737",
"status": "failed",
"error": "download timeout",
"failed_at": "1234567890"
}
}
Рекомендуемая тактика опроса:
- первый запрос к GET /result/{task_id} делать не раньше значения estimated_wait_seconds;
- если сервис всё ещё отвечает 202, продолжать опрос не чаще 60s;
- не считать первые минуты ожидания ошибкой слишком рано, если сервису пришлось поднимать T4 перед обработкой;
- до выхода за estimated_wait_seconds и без других признаков поломки не трактовать один только красный /health как доказательство окончательного отказа.
Ошибки при опросе:
- 401 UNAUTHORIZED
- 404 TASK_NOT_FOUND
- 503 REDIS_UNAVAILABLE
Обратный вызов webhook
Что можно считать активным контрактом:
- webhook относится только к аудио-задачам;
- обратный вызов включается только если при постановке задачи передан блок webhook;
- он приходит только для конечных статусов done и failed;
- один HTTP-вызов webhook ждёт до 60s;
- повторные попытки по умолчанию идут по схеме 5s, 10s, 20s, 40s и далее, но не чаще чем раз в 1h;
- опрос через GET /result/{task_id} остаётся обязательным резервным способом дочитать итог;
- при повторной доставке дедупликацию нужно делать по delivery_id.
Что не нужно поднимать в обязательную бизнес-логику без отдельного согласования: - точный график повторных попыток доставки; - полный перечень промежуточных служебных статусов доставки; - внутренние детали выполнения ретраев.
Пример заголовков обратного вызова:
- Content-Type: application/json
- X-Techcon-STT-Event: stt.task.done или stt.task.failed
- X-Techcon-STT-Delivery-Id: <delivery_id>
- X-Techcon-STT-Task-Id: <task_id>
- X-Techcon-STT-Signature: sha256=<hex> — если был передан webhook.secret
Пример тела webhook:
{
"ok": true,
"event": "stt.task.done",
"delivery_id": "stt-42e11f77f737:done:1234567890",
"data": {
"task_id": "stt-42e11f77f737",
"status": "done",
"result": {
"transcription": "трещина на фасаде",
"service": "stt"
},
"processing_time_ms": 3500,
"completed_at": "1234567890"
}
}
POST /classify/batch
Пакетная транскрипция текстов для старых клиентов.
Тело запроса:
{
"items": [
{"text": "трещина"},
{"text": "отслоение штукатурки"}
]
}
Ответ 200:
{
"ok": true,
"data": {
"results": [
{
"status": "success",
"transcription": {
"raw_text": "трещина",
"corrected_text": "трещина",
"corrections_made": []
},
"classification": null,
"extracted_fields": null,
"processing_time_ms": 0.0,
"mode": "transcription_only"
}
]
}
}
GET /taxonomy
Справочный эндпоинт с классами таксономии.
Ответ 200:
{
"ok": true,
"data": {
"classes": [
{
"id": "C01",
"name": "Трещины",
"group": "Конструктивные",
"description": "Описание"
}
]
}
}
Практические сценарии
Сценарий 1: аудио без webhook
- Отправьте
POST /transcribe/audio_url. - Сохраните
task_id. - Опрашивайте
GET /result/{task_id}доdoneилиfailed.
Сценарий 2: аудио с webhook
- Отправьте
POST /transcribe/audio_urlс блокомwebhook. - Сохраните
task_id. - Ждите обратный вызов, но не отключайте опрос статуса.
- Если обратный вызов пришёл повторно, используйте
delivery_idдля дедупликации.
Сценарий 3: старый совместимый текстовый путь
- Используйте
POST /classify/textтолько для ручной проверки или старого клиента, если текст уже получен вне STT. - Сразу возьмите результат из ответа
200.
Что сверять через live /docs
Через ReDoc на /docs удобно проверять:
- полный список эндпоинтов;
- схемы запросов и ответов;
- точные названия полей;
- встроенные примеры для runtime-контракта.
Для интегратора эта страница остаётся более удобным кратким объяснением сценариев, а live ReDoc на /docs — точной спецификацией полей и схем.