Skip to content

Руководство по интеграции — TechCon ML Platform

Аудитория: интеграторы и внешние разработчики. Версия: 2.0.8 | Дата: 2026-06-03 Портал: docs.techcon-ml.ru

⚠️ Что важно для новой интеграции — v2.0.8 (2026-06-03)

Для STT канонический путь — /transcribe/audio_url, а GET /result/{task_id} остаётся обязательным резервным путём даже при включённом webhook.

  1. POST /transcribe/text удалён из активного runtime-контракта; если текст уже готов, используйте только старый совместимый путь POST /classify/text.
  2. POST /transcribe/audio_url возвращает только 202 {task_id}.
  3. Для STT старые пути /classify/text и /classify/audio_url сохранены только для обратной совместимости.
  4. В теле STT-аудио-запроса используется поле url и вложенный объект webhook, а не audio_url или webhook_url.
  5. После 202 первый запрос к GET /result/{task_id} делайте не раньше estimated_wait_seconds: обычно 60s при уже запущенном worker и 180s, если сервису ещё нужно поднять T4.
  6. Если сервис всё ещё отвечает 202, продолжайте опрос не чаще 60s.
  7. Красный GET /health в первые минуты cold start сам по себе ещё не доказывает финальный outage, если задача принята и остаётся в queued / processing.
  8. Адрес https://stt.dev.techcon-ml.ru нельзя считать обычной готовой средой без отдельной перепроверки.

Почему это важно: руководство должно помогать собрать рабочую интеграцию, а не смешивать внешний контракт с внутренними эксплуатационными деталями. Что делать интегратору: строить STT-интеграцию по шаблону из раздела 6.2 и проверять спорные детали по /stt/API/, openapi.json, live ReDoc на /docs и Swagger UI на /swagger.


1. Обзор платформы

TechCon ML Platform — это 4 независимых API-сервиса для автоматизации технической инспекции зданий. Ниже — краткая карта того, какой сервис за что отвечает и как их обычно используют вместе.

Сервис Назначение Версия
Дефектоскопия Классификация дефектов на фотографиях (223 класса) v0.2.0
STT (Speech-to-Text) Транскрибация аудиозаписей по голосовым описаниям v0.8.0
Техпаспорта Извлечение данных из сканов технических паспортов v1.0.0
Техпланы (Поиск) Гибридный поиск по базе ~6000 технических планов v1.0.0

Как сервисы используются вместе

Инспектор осматривает здание
    │
    ├── Фотографирует дефект → Дефектоскопия API → класс дефекта + поверхность
    ├── Записывает голосовое описание → STT API → текстовая расшифровка
    ├── Сканирует техпаспорт → Техпаспорта API → структурированные данные
    └── Ищет нормативы → Техпланы API → релевантные документы

Обычно данные приходят пакетами: один дефект = 1 фото (обязательно) + 0–1 аудио (опционально). Отдельный аудиофайл без соответствующего фото в этом контуре не предполагается.


2. Адреса сервисов

Production

Сервис URL Основная docs UI Дополнительная docs UI
Дефектоскопия https://defects.techcon-ml.ru /docs (ReDoc) /swagger (Swagger UI), /redoc (совместимый ReDoc-путь)
STT https://stt.techcon-ml.ru /docs (ReDoc) /swagger (Swagger UI), /redoc (совместимый ReDoc-путь)
Техпаспорта https://passports.techcon-ml.ru /docs (Swagger UI) /redoc (ReDoc)
Техпланы https://techplans.techcon-ml.ru /docs (Swagger UI) /redoc (ReDoc)

Не выводите тип документации только из имени пути: для STT и defectoscopy основная человекочитаемая спецификация теперь живёт на /docs, а не на /redoc.

Тестовая среда

Сервис URL
Дефектоскопия https://defects.dev.techcon-ml.ru
STT https://stt.dev.techcon-ml.ru
Техпаспорта https://passports.dev.techcon-ml.ru
Техпланы https://techplans.techcon-ml.ru (только production)

Перед интеграционными проверками всегда смотрите GET /health нужного сервиса. Для https://stt.dev.techcon-ml.ru сохраняется отдельная оговорка: этот адрес нельзя считать обычной готовой средой без новой перепроверки; при последней согласованной проверке GET /health там возвращал 502 Bad Gateway.

Файл OpenAPI для импорта в Postman или Insomnia: <base_url>/openapi.json


3. Общий формат ответов

Во всех сервисах, кроме оговорённых исключений, используется формат ok/data.

Успешный ответ

{
  "ok": true,
  "data": { ... }
}

Ответ с ошибкой

{
  "ok": false,
  "error": {
    "code": "UPPER_SNAKE_CASE",
    "message": "Человекочитаемое описание"
  }
}

Когда обёртки нет

Не используют ok/data: - HTML-страницы - Server-Sent Events (SSE) - бинарные файлы (PDF, CSV) - HTTP 204 No Content

Стандартные коды ошибок

Код HTTP Описание
VALIDATION_ERROR 422 Неверные входные данные
NOT_FOUND 404 Ресурс не найден (task_id истёк или не существует)
UNAUTHORIZED 401 Токен отсутствует или недействителен
RATE_LIMIT_EXCEEDED 429 Превышено допустимое число запросов. Проверяйте Retry-After и договорённость по конкретному сервису
INTERNAL_ERROR 500 Непредвиденная ошибка сервера
SERVICE_NOT_READY 503 Сервис запускается или ещё не готов
MODEL_NOT_LOADED 503 ML-модель не инициализирована
REDIS_UNAVAILABLE 503 Очередь задач недоступна
GPU_STARTING 503 GPU запускается — повторите запрос позже или дождитесь обработки уже принятой задачи
TASK_NOT_FOUND 404 task_id не найден

Каждый сервис может добавлять свои коды ошибок. Подробности смотрите в его отдельном справочнике API.


4. Аутентификация

Сервис Метод Как получить токен
Дефектоскопия Bearer token DEFECTOSCOPY_BEARER_TOKENS или DEFECTOSCOPY_BEARER_TOKEN
STT Bearer token BEARER_TOKENS — основной путь, BEARER_TOKEN — только обратная совместимость
Техпаспорта Bearer token или JWT Статический: от администратора. JWT: POST /auth/token (24ч)
Техпланы Bearer token Только для /reports (admin). Основные эндпоинты публичны

Формат заголовка

Authorization: Bearer <токен>

Публичные эндпоинты (без токена)

Во всех сервисах: - GET /health — проверка состояния - GET /metrics — метрики Prometheus (дефектоскопия, STT, техпаспорта — публичный; техпланы — требует Bearer)


5. Проверка готовности сервиса

У всех сервисов есть единый GET /health.

curl -sf https://<service>.techcon-ml.ru/health | jq

Ответ, когда сервис готов:

{
  "ok": true,
  "data": { ... }
}

Поле data различается по сервисам: - Дефектоскопия: {"model_loaded": true, "gpu": {...}} - STT: {"status": "ok", "model_loaded": true, "version": "0.8.0", ...} - Техпаспорта: {"database": "ok", "workers_online": 1, "version": "1.0.0"} - Техпланы: {"status": "ok", "total_records": 6231}

Ответ, когда сервис не готов:

{
  "ok": false,
  "error": {
    "code": "MODEL_NOT_LOADED",
    "message": "Taxonomy or pipeline not initialized"
  }
}

Как трактовать ответ: - HTTP 200 + ok == true → сервис готов принимать запросы; - HTTP 503 + ok == false → сервис ещё не готов или временно недоступен; - поле data содержит сервисные подробности: например, version, model_loaded или счётчики.


6. Ключевые эндпоинты

6.1 Дефектоскопия

Эндпоинт Метод Описание Токен
/predict POST Поставить задачу классификации фото в очередь Да
/result/{task_id} GET Получить результат классификации Да
/health GET Состояние сервиса Нет
/metrics GET Prometheus-метрики Нет

Шаг 1 — Отправить задачу:

export DEFECTOSCOPY_TOKEN='<токен из внешнего секрет-хранилища>'

curl -X POST https://defects.techcon-ml.ru/predict \
  -H "Authorization: Bearer $DEFECTOSCOPY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "image_url": "https://storage.yandexcloud.net/techconimg/zT1RP8i7vfpj",
    "webhook_url": "https://integrator.example.com/hooks/defectoscopy"
  }'

Ответ 202 (задача принята):

{
  "ok": true,
  "data": {
    "task_id": "def-a1b2c3d4e5f6",
    "status": "queued",
    "status_url": "/result/def-a1b2c3d4e5f6",
    "estimated_wait_seconds": 90
  }
}

estimated_wait_seconds=90 — это только ориентир для первого повторного запроса. Это не гарантированное время готовности и не таймер обратного вызова.

Шаг 2 — Повторно запросить результат:

curl https://defects.techcon-ml.ru/result/def-a1b2c3d4e5f6 \
  -H "Authorization: Bearer $DEFECTOSCOPY_TOKEN"

Ответ 202 (ещё обрабатывается):

{
  "ok": true,
  "data": {
    "task_id": "def-a1b2c3d4e5f6",
    "status": "processing",
    "message": "Задача обрабатывается",
    "webhook": {
      "configured": true,
      "state": "pending",
      "attempts": 0
    }
  }
}

Поле message предназначено для человека. Для машинной логики опирайтесь на status, HTTP-код и итоговые поля, а не на формулировку этого текста.

Ответ 200 (готово, обратный вызов доставлен):

{
  "ok": true,
  "data": {
    "task_id": "def-a1b2c3d4e5f6",
    "status": "done",
    "result": { "surface": "...", "masters": [...], "defects": [...] },
    "processing_time_ms": 432,
    "completed_at": "1745271700",
    "webhook": {
      "configured": true,
      "state": "delivered",
      "attempts": 1,
      "delivery_id": "1b00b33fbad3496eb17ab0fd800d55a7",
      "last_attempt_at": "1745271700",
      "delivered_at": "1745271700",
      "response_status_code": 200
    }
  }
}

Обратный вызов у defectoscopy: - включается полем webhook_url; - отправляется только после done или failed; - использует заголовки X-Techcon-Event, X-Techcon-Task-ID, X-Techcon-Delivery-ID; - не переводит успешную задачу из done в failed; - не имеет отдельного секрета или HMAC-подписи, в отличие от STT.

Не поднимайте в обязательный бизнес-контракт без отдельного согласования точный бюджет повторов, полное расписание задержек или все промежуточные состояния доставки.

Рекомендуемый интервал повторных запросов: первый GET /result/{task_id} делать не раньше estimated_wait_seconds, затем повторять опрос с паузой порядка 30–60 секунд на задачу. TTL результата: 24 часа. Даже при включённом обратном вызове итог нужно дочитывать через GET /result/{task_id}.

6.2 STT (Транскрибация аудио)

Точный STT-контракт читайте в двух слоях: - https://docs.techcon-ml.ru/stt/API/ — канонический человекочитаемый справочник на портале; - https://stt.techcon-ml.ru/openapi.json, https://stt.techcon-ml.ru/docs и https://stt.techcon-ml.ru/swagger — рабочее описание API на стороне сервиса.

Эндпоинт Метод Описание Токен
/transcribe/audio_url POST Поставить задачу транскрибации аудио в очередь Да
/result/{task_id} GET Получить статус и результат аудио-задачи Да
/taxonomy GET Вспомогательная таксономия Да
/classify/text POST Старый совместимый путь для уже готового текста Да
/health GET Состояние Нет

Старые пути /classify/text и /classify/audio_url сохранены только для обратной совместимости. Путь /transcribe/text удалён из активного runtime-контракта.

Если текст уже получен вне STT, старый совместимый путь POST /classify/text оставляйте только как fallback для старого клиента или ручной проверки; основной production-flow для новой интеграции всё равно строится вокруг аудио-ветки ниже.

Шаг 1 — Отправить аудио на обработку:

curl -X POST https://stt.techcon-ml.ru/transcribe/audio_url \
  -H "Authorization: Bearer $STT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://storage.yandexcloud.net/bucket/audio.wav",
    "webhook": {
      "url": "https://integrator.example/api/stt-callback"
    }
  }'

Важно для интегратора: - в теле запроса используется поле url, а не audio_url; - блок webhook опционален и использует вложенный объект с полями url и secret; - estimated_wait_seconds — это ориентир до первого полезного опроса, а не гарантия готовности; - webhook дополняет опрос статуса, но не заменяет его.

Ответ 202 (задача принята):

{
  "ok": true,
  "data": {
    "task_id": "stt-a1b2c3d4e5f6",
    "status": "queued",
    "status_url": "/result/stt-a1b2c3d4e5f6",
    "estimated_wait_seconds": 180,
    "webhook": {
      "configured": true,
      "status": "pending"
    }
  }
}

Шаг 2 — Повторно запрашивать статус:

Рекомендуемая тактика опроса для STT: - первый запрос к GET /result/{task_id} делать не раньше значения estimated_wait_seconds; - если сервис всё ещё отвечает 202, продолжать опрос не чаще 60s; - webhook не заменяет опрос статуса; - не считать первые минуты ожидания ошибкой слишком рано, если сервису пришлось поднимать T4 перед обработкой; - до выхода за estimated_wait_seconds и без других признаков поломки не трактовать один только красный /health как доказательство окончательного отказа; - Конечный результат хранится 24 часа после done или failed.

curl https://stt.techcon-ml.ru/result/stt-a1b2c3d4e5f6 \
  -H "Authorization: Bearer $STT_TOKEN"

Ответ 202 (ещё обрабатывается):

{
  "ok": true,
  "data": {
    "task_id": "stt-a1b2c3d4e5f6",
    "status": "processing",
    "webhook": {
      "configured": true,
      "status": "pending"
    }
  }
}

Ответ 200 (готово):

{
  "ok": true,
  "data": {
    "task_id": "stt-a1b2c3d4e5f6",
    "status": "done",
    "result": { "transcription": "трещина в несущей стене", "service": "stt" },
    "processing_time_ms": 334,
    "webhook": {
      "configured": true,
      "status": "delivered",
      "delivery_id": "stt-a1b2c3d4e5f6:done:1234567890"
    }
  }
}

Если задача завершилась ошибкой, сервис возвращает 200 и статус failed. При включённом webhook считайте delivery_id ключом дедупликации. Если для новой интеграции нужна точная матрица кодов ошибок, терминальных статусов и ограничений STT, используйте страницу /stt/API/ как основной человекочитаемый справочник.

6.3 Техпаспорта

Эндпоинт Метод Описание Токен
/upload POST Загрузка скана паспорта Да
/api/tasks GET Список задач обработки Да
/api/task/{id}/status GET Статус задачи Да
/api/task/{id}/result GET Результат извлечения Да
/api/v1/create-pdf POST Генерация PDF из данных Да
/health GET Состояние (включая workers) Нет

Полный цикл:

import httpx

client = httpx.Client(
    base_url="https://passports.techcon-ml.ru",
    headers={"Authorization": f"Bearer {TOKEN}"}
)

# 1. Загрузить скан
r = client.post("/upload", files={"file": open("scan.pdf", "rb")})
task_id = r.json()["data"]["task_id"]

# 2. Ожидать завершения
import time
while True:
    r = client.get(f"/api/task/{task_id}/status")
    status = r.json()["data"]["status"]
    if status in ("completed", "failed"):
        break
    time.sleep(2)

# 3. Получить результат
r = client.get(f"/api/task/{task_id}/result")
extracted_data = r.json()["data"]

6.4 Техпланы (Поиск)

Эндпоинт Метод Описание Токен
/search POST Гибридный поиск по техпланам Нет
/detail/{uid} GET Детали документа Нет
/export GET Экспорт результатов Нет
/health GET Состояние Нет

Запрос /search:

curl -X POST https://techplans.techcon-ml.ru/search \
  -H "Content-Type: application/json" \
  -d '{"query": "нормативы по трещинам в стенах", "limit": 10}'

7. Сквозной пример интеграции

Полный цикл обработки одного дефекта (v2.0, асинхронные фото и аудио):

import httpx
import time

# --- Конфигурация ---
DEFECTO_URL = "https://defects.techcon-ml.ru"
STT_URL = "https://stt.techcon-ml.ru"
TECHPLANS_URL = "https://techplans.techcon-ml.ru"
TOKEN = "ваш-токен"
HEADERS = {"Authorization": f"Bearer {TOKEN}"}
POLL_INTERVAL = 5   # секунд
POLL_TIMEOUT = 300  # максимум 5 минут ожидания


def poll_result(client: httpx.Client, url: str, task_id: str) -> dict:
    """Опрос до получения результата."""
    deadline = time.time() + POLL_TIMEOUT
    while time.time() < deadline:
        r = client.get(f"{url}/result/{task_id}", headers=HEADERS)
        data = r.json()["data"]
        if data["status"] == "done":
            return data["result"]
        if data["status"] == "failed":
            raise RuntimeError(f"Задача завершилась ошибкой: {data.get('error')}")
        time.sleep(POLL_INTERVAL)
    raise TimeoutError(f"Задача {task_id} не завершилась за {POLL_TIMEOUT}с")


with httpx.Client() as client:
    # --- 1. Отправить фото дефекта в очередь ---
    r = client.post(
        f"{DEFECTO_URL}/predict",
        json={"image_url": "https://storage.example.com/photo_001.jpg"},
        headers=HEADERS,
    )
    assert r.status_code == 202
    defecto_task_id = r.json()["data"]["task_id"]

    # --- 2. Отправить аудио в очередь, если оно есть ---
    r = client.post(
        f"{STT_URL}/transcribe/audio_url",
        json={"url": "https://storage.example.com/audio_001.wav"},
        headers=HEADERS,
    )
    assert r.status_code == 202
    stt_task_id = r.json()["data"]["task_id"]

    # --- 3. Дождаться результатов ---
    # Для простоты пример опрашивает задачи по очереди.
    defect = poll_result(client, DEFECTO_URL, defecto_task_id)
    audio = poll_result(client, STT_URL, stt_task_id)

    print(f"Дефект: {defect['surface']} / {defect['defects']}")
    print(f"Транскрипция: {audio['transcription']}")

    # --- 4. Найти подходящие нормативы ---
    r = client.post(
        f"{TECHPLANS_URL}/search",
        json={"query": f"{defect.get('defects', [''])[0]}", "limit": 5},
    )
    results = r.json()["data"]
    print(f"Найдено нормативов: {len(results)}")

8. Техническая диагностика

Все сервисы отдают метрики в формате Prometheus:

curl -sf https://<service>.techcon-ml.ru/metrics | head -10

Стандартные метрики: - http_requests_total — количество запросов по handler / method / status - http_request_duration_seconds — длительность запросов (histogram) - python_gc_* — метрики сборщика мусора

Панели Grafana: grafana.techcon-ml.ru Проверка доступности: gatus.techcon-ml.ru


9. Ограничения и рекомендации

Ограничения по числу запросов

Сервис Ограничение
Дефектоскопия Проверяйте документацию сервиса и Retry-After
STT Значение зависит от среды; проверяйте Retry-After и локальный контракт сервиса
Техпаспорта Проверяйте документацию сервиса
Техпланы Для основных путей ограничение не зафиксировано в этом руководстве

Рекомендации интегратору

  1. Ставьте таймауты: 30с для асинхронной постановки задач, 10с для /health
  2. Проверяйте поле ok: не полагайтесь только на HTTP-код
  3. Повторяйте запрос при 503: сервис может перезапускаться
  4. Используйте пакетную обработку там, где она есть: STT /classify/batch — до 100 элементов за запрос
  5. Проверяйте готовность сервиса перед нагрузкой: GET /healthok == true

Ожидаемый профиль нагрузки

  • До 10 000 фото + аудио за партию (50 домов × 200 дефектов)
  • Данные поступают пакетами, а не в реальном времени
  • Задержка в часы допустима

10. Детальные справочники

Полные справочники API каждого сервиса (все эндпоинты, параметры, примеры ответов):


11. Контакты

Вопрос Куда обращаться
API интеграция techcon_hub (этот документ)
Инфраструктура techcon_infra_yac
Мониторинг techcon_infra_monitoring
Баги в конкретном сервисе GitHub Issues соответствующего репозитория

Документ обновляется при изменении API сервисов. Актуальная версия: docs.techcon-ml.ru