Skip to content

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

  1. Отправьте POST /transcribe/audio_url.
  2. Сохраните task_id.
  3. Опрашивайте GET /result/{task_id} до done или failed.

Сценарий 2: аудио с webhook

  1. Отправьте POST /transcribe/audio_url с блоком webhook.
  2. Сохраните task_id.
  3. Ждите обратный вызов, но не отключайте опрос статуса.
  4. Если обратный вызов пришёл повторно, используйте delivery_id для дедупликации.

Сценарий 3: старый совместимый текстовый путь

  1. Используйте POST /classify/text только для ручной проверки или старого клиента, если текст уже получен вне STT.
  2. Сразу возьмите результат из ответа 200.

Что сверять через live /docs

Через ReDoc на /docs удобно проверять: - полный список эндпоинтов; - схемы запросов и ответов; - точные названия полей; - встроенные примеры для runtime-контракта.

Для интегратора эта страница остаётся более удобным кратким объяснением сценариев, а live ReDoc на /docs — точной спецификацией полей и схем.