Техническая карта · as-built

py_faster_whisper
мост ASR, файловый WebUI и диаризация

Репозиторий принимает живой PCM-поток или аудио/видео файл, вызывает внешние модели распознавания речи и разделения по говорящим, затем возвращает текст через NATS или HTTP/WebUI.

ВходPCM16 по NATSили файл в WebUI Оркестрацияstt_whisper_to_natsVAD · chunks · state · mergeaiohttp WebUI / APIs ASR backendsHTTP / NATS worker DiarizationPOST /diarize Результаттекст / speakersevents / artifacts
VERIFIED code + tests + runtimeINFERRED вывод из нескольких источниковUNKNOWN причина решения
Sources: src/stt_whisper_to_nats.py · src/webui/server.py · src/webui/file_mode.py · stack/stack.drs

Deployment · 04.10.2026 · проверенная поставка

Chat-agent и voice поставляются отдельно

chat-agent.gis-master.ru

Стэк web-rtc-komaroff: Frontend, Core, Agent, LLM, workflow runtimes, PostgreSQL и общий NATS. Каталог документации остаётся здесь.

voice.gis-master.ru

Стэк py_faster_whisper: один live ASR bridge, пять file UI, диагностика, lock, пять H100 requesters и три CPU sidecars.

Оба host используют OAuth2 для UI, API и WebSocket. Voice подключён к общему NATS. Live ASR: streaming через NATS/H100 worker. Файловый ASR: LinTO HTTP. Subjects, H100, Ollama и TURN сохраняются.

Postgres volume сохраняется; benchmark и summary используют прежний whisper_bench_jobs на gis-master.ru. Сначала поставляется chat, затем voice после освобождения file lock.

Deployment runbook · Проверка всех 29 сервисов · source/CI/runtime/live проверяются отдельно. Следующие датированные измерения описывают прежние запуски.

Границы

Система связывает интерфейсы с моделями. Сами модели — отдельные сервисы

BOUNDARY: THIS REPOSITORY Stream bridgeVAD → phrases → events File WebUIupload → jobs → artifacts Voice UIadjacent repo Operatorbrowser NATSbroker / WS ASRLinTO / H100 worker Diarizerspeaker model

Инициаторы

Voice-chat передаёт живой аудиопоток; оператор загружает файл через WebUI.

Внешнее владение

Voice владеет своим public ingress и requesters. Общий NATS принадлежит chat; H100 модели и receivers находятся снаружи.

VERIFIED

Внутри репозитория нет LLM, agent workflow, собственной БД или WebRTC media server.

UNKNOWN

Историческая причина разделения ownership по репозиториям из исходников не устанавливается.

Sources: src/stt_whisper_to_nats.py · src/webui/server.py · stack/stack.drs · ../webrtc-komaroff/DOCS/ARCHITECTURE.md
Запуск

Один entry point включает два независимых runtime-контура

Stream bridge

ASR_MODE=streaming

PCM по NATS → CPU VAD → H100 worker → partial/final/rejected/error. LinTO HTTP остаётся в batch и файловом пути.

python -m src.stt_whisper_to_nats

WebUI + file runner

WEBUI_ENABLED

aiohttp страницы, upload API, автоматические и staged jobs, diagnostics, snapshots и downloads.

Хотя бы один контур должен быть включён.

Page modeНазначениеГлавный результат
diarize / transcribe_onlyАвтоматическая обработка одного файлаPlain text; при healthy backend — speaker transcript
stagedРаздельно запускать ASR, diarization и combineПовторно используемые cached artifacts и timings
bench / solution / caseСравнивать сохранённые конфигурации и прогоныresults.jsonl, timing/RTF/quality proxies
summary / diagnosticsСводка прогонов и health/smoke checksНаблюдаемое состояние зависимостей
Sources: src/stt_whisper_to_nats.py · src/webui/server.py · src/webui/static/app.js · src/webui/static/staged_app.js
Навигация

Код организован вокруг orchestration, WebUI и трёх sidecar-моделей

src/stt_whisper_to_nats.pyentry point, NATS stream bridge, automatic file worker
src/webui/server.pyaiohttp routing, upload/download, lock, page selection
src/webui/file_mode.pymedia normalization, chunks, LinTO calls, transcript merge
src/webui/staged_jobs.pyfilesystem artifacts и независимые этапы staged pipeline
src/{diarization,diarization_syntax}.pyHTTP contract, word attribution, speaker turns, optional syntax pass
src/*_diarization_server.pypyannote, sherpa-onnx, NeMo Sortformer HTTP sidecars
src/webui/static/single-page clients, NATS WebSocket client, styles
stack/ · docker/ · .gitlab-ci.ymlimages, Dry Stack deployment, CI/CD
tests/file/diarization flows, transports, health и diagnostics contracts

Hotspot: несколько orchestration-файлов превышают тысячу строк. Это подтверждает широкую область изменений, но не объясняет, почему границы выбраны именно так.

Sources: src/ · src/webui/ · tests/ · stack/
Компоненты

Файлы и batch связывают HTTP-модели с событиями NATS

Voice producerwire PCM16 Browsermultipart + WS Batch bridgebuffers · VAD · temp WAVper subject/session WebUI + workerjob store · chunks · mergelock client · snapshotsbench / diagnostics LinTO ASRHTTP multipart DiarizationHTTP multipart JSON Job lockinternal HTTP NATSstream input/outputfile progress/resultsbrowser WebSocketproxy transport
сплошная — HTTPпунктир — NATS / eventsDB: отсутствует
Sources: src/stt_whisper_to_nats.py · src/webui/server.py · src/model_transport.py · src/webui/job_lock.py
Runtime flow A

Живой поток: PCM16 превращается в короткие фразы

CoreNATSStream bridgeH100 workerConsumer webrtc.komaroff.asr.stream.*PCM16 frameto.inference.webrtc.asr.audio.*from.inference.webrtc.asr.events.*partial / final / rejected / errorwebrtc.komaroff.asr.text.* resample 16 kHz → Silero VADsilence / max-duration flush

State

Буферы в памяти на output subject/session. После restart не восстанавливаются.

Transport

Live streaming передаёт речь H100 worker по NATS. LinTO CONNECT используется отдельно для файлов и batch.

Ошибки

Sequence gaps и ошибки активного stream дают события; session/stream ID отсекают устаревшие результаты.

Sources: src/stt_whisper_to_nats.py · src/streaming_asr/{bridge,vad,worker,protocol}.py · DOCS/STREAMING_ASR.md
Runtime flow B

Файл: ASR и разделение по говорящим сходятся по timestamps

1

Upload и normalize

Файл сохраняется в job directory; ffmpeg создаёт mono 16 kHz WAV и audio-only artifact.

2

ASR chunks

По умолчанию 300 s, overlap 15 s, последовательно, с двумя повторами; нужны word timestamps.

3

Diarization параллельно

После healthy preflight backend получает тот же звук. При недоступности остаётся plain transcript.

4

Combine

Слово относится к speaker по midpoint/overlap; соседние слова становятся speaker turns.

Один active automatic job на процесс. Новый job отменяет прежний; внешний lock добавляет межпроцессную сериализацию.

Реальный результат Whisper Diarization с двумя говорящими
Рабочий контур, 20-секундный smoke · 11.09.2026. Реальный результат, не макет.
Sources: src/stt_whisper_to_nats.py · src/webui/file_mode.py · src/diarization.py · tests/test_diarization.py
Runtime flow C

Staged mode отделяет вычисления от combine

Реальный staged pipeline с журналом и измерениями
Рабочий `/whisper-staged/`: transcribe → diarize → combine. Тайминги относятся только к этому smoke.

prepare

Один upload создаёт reusable audio artifacts.

transcribeиdiarize

Этапы можно запускать и повторять независимо. Результаты сохраняются на файловой системе.

combine

Не вызывает модели повторно; читает готовые JSON/text artifacts.

Bench layer

Сохраняет прогоны в results.jsonl и считает timing, RTF и quality proxies. Это не WER/DER.

Sources: src/webui/staged_jobs.py · src/webui/bench.py · src/webui/static/staged_app.js · tests/test_diarization.py
Data architecture

Основное состояние — память процесса и локальная файловая система

Live

ephemeral

PCM buffers, VAD state, active phrase tasks.

Consistency boundary: один процесс bridge. Restart сбрасывает незавершённые фразы.

Automatic file job

filesystem

state.json, input, normalized audio, chunks, transcript и diarization payloads.

Terminal job directory планируется к удалению через 30 s.

Staged / bench

reusable

Artifacts переживают отдельные вызовы этапов; bench дописывает results.jsonl.

Зависимые artifacts инвалидируются при повторе upstream step.

Model cache

Docker volume

HF / Torch / NeMo caches принадлежат sidecar containers.

В репозитории нет schema, migrations, ORM или application database.

Практический эффект: HTTP snapshot — резервный канал состояния, но automatic artifacts имеют короткое окно после завершения; staged artifacts рассчитаны на повторный анализ.

Sources: src/webui/file_mode.py · src/webui/staged_jobs.py · src/webui/bench.py · docker/docker-compose.yml
Contracts

HTTP surface состоит из UI API и двух модельных контрактов

WebUI API

POST /api/file-transcribecombined automatic job
POST /api/file-preparestaged upload + media artifacts
POST /api/file-{transcribe|diarize|combine}-stepindependent stage
GET /api/file-jobsnapshot / heavy artifacts
GET /healthWebUI liveness

Model API

POST /transcribemultipart file → text or JSON with word timestamps
POST /diarizemultipart audio → speakers, segments, exclusive_segments
GET /healthzready/model metadata; 200 or 503

Contract-sensitive

Имена полей и timestamps используются Python merge logic и JavaScript renderers. Менять producer, consumer и tests нужно вместе.

Sources: src/webui/server.py · src/webui/file_mode.py · src/diarization.py · tests/test_model_transport.py
Contracts

NATS несёт live audio, результат и прогресс; файл передаётся по HTTP

КаналPayload / роль
ASR_IN_PREFIX + suffix[meta_len][meta JSON][pcm16]
ASR_OUT_PREFIX + suffixStreaming: version 1 partial/final/rejected/error, session_id/stream_id/phrase_id. Batch: legacy pending/final/error.
file job subjectsprogress и result envelopes для браузера
NATS WebSocketбыстрые UI updates; HTTP polling остаётся fallback
to.inference.linto.*HTTP CONNECT transport через nats-proxy

Wire validation

Размер metadata, JSON и PCM frame проверяются до обработки.

Browser boundary

При настроенном NATS сервер внедряет WS credentials в HTML meta. Это функциональный контракт и security-sensitive boundary.

Событие progress не доказывает доставку самого media к модели. Нужны requester, matching receiver, upstream health и итоговый result.

Sources: src/streaming_asr/protocol.py · src/stt_whisper_to_nats.py · src/webui/static/nats_ws_client.js · stack/stack.drs
Model adapters

Три sidecar реализуют один HTTP-контракт, но имеют разные runtime-профили

ServiceМодель / исполнениеОсобенностиОбщий контракт
pyannotespeaker-diarization-community-1
CPU/GPU по DEVICE
HF gated token; exclusive diarization; pipeline lockGET /health[z]
POST /diarize

segments
exclusive_segments
speaker_count
timings
sherpa-onnxsegmentation + 3D-Speaker embeddings
CPU-oriented
Загрузка ONNX artifacts; explicit readiness
SortformerNeMo diar_streaming_sortformer_4spk-v2.1До 4 speakers; окна и stitching для длинных файлов; Triton runtime compile

Progress

Sidecar может публиковать hook-based NATS events, если переданы job metadata и NATS config.

Serialization

Model invocation защищён lock: запросы внутри процесса не исполняются одновременно.

Fallback

Automatic file mode продолжает ASR без speakers, если preflight diarization не проходит.

Sources: src/pyannote_diarization_server.py · src/sherpa_onnx_diarization_server.py · src/sortformer_diarization_server.py · src/diarization.py
Integrations

Production model traffic может идти через HTTP CONNECT поверх NATS

py_faster_whisperaiohttp client nats-proxyrequester / CONNECT LinTO H100external receiver HTTPNATS WebUIthis repo Ingress + lockvoice stack Model stackrag-stack / H100

Fail closed

Если proxy URL задан, код не переключается на прямой HTTP при ошибке proxy.

Ownership

Этот stack владеет всеми voice UI, diagnostics, lock, requesters, ASR bridge и CPU sidecars. Public routes — в voice stack; matching H100 receivers и модели остаются снаружи.

Current runtime evidence

04.10.2026: WebUI, streaming ASR, H100 requesters, три CPU backend и внутренние admin targets — OK. Direct H100 probe остаётся INFO FAIL.

Sources: src/model_transport.py · stack/stack.drs · src/webui/diagnostics.py · DOCS/PRODUCTION_STATE.md
Delivery

Source → build-labels images → Dry Stack runtime

Git commitsource + Dockerbuild pushimagesdeploydefault branchDry Stack16 servicesexternal net--prune

Deployed services in this stack

Один bridge, пять file UI, diagnostics, lock, пять requesters, три CPU sidecars и gateway.

Статус py_faster_whisper: пять страниц OK
Рабочий `/status/`, 11.09.2026: пять WebUI routes отмечены OK.

Streaming checks обязательны. Полная unit suite проверена локально. Selective build использует diff предыдущего SHA; image revision и manual deploy проверяются отдельно.

Sources: .gitlab-ci.yml · docker/Dockerfile.build · stack/Dockerfile.deploy · stack/stack.drs
Verification

Локальные tests широкие; production E2E требует отдельного runtime evidence

167 / 167

Локальный unittest run

Выполнен 04.10.2026. Покрыты orchestration, streaming NATS, contracts, locks, transports, diagnostics и sidecar helpers.

VERIFIED this checkout

Что доказывают tests

Поведение Python-кода с локальными HTTP/NATS stubs, merge logic, retries, readiness и error shaping.

Чего они не доказывают

Загрузку реальных GPU-моделей, внешний NATS receiver, ingress и named production behavior.

Live smoke

На WAV 9.32 s проверены transcription, staged, четыре H100 cases и три CPU backends: два говорящих. Status/smoke OK; снимок 04.10.2026.

Green build или merge — не подтверждение rollout. Для поставки нужны раздельные доказательства: commit/CI → image → stack health → пользовательский сценарий.

Sources: tests/test_diarization.py · tests/test_model_transport.py · tests/test_diagnostics.py · .gitlab-ci.yml
Software archaeology

Основные следы эволюции видны в документации, зависимостях и границах модулей

EvidenceAs-is выводПрактический риск
Chat и voice разделеныVoice владеет 16 services и зависит от общего NATSПеред prune проверять полный состав, сеть и storage
stt_whisper_to_nats.py, file_mode.py, server.py очень крупныеINFERRED: широкие change surfacesИзменение контракта затрагивает несколько concerns
dtorry/nats-proxy:latestFloating runtime dependencyОдинаковый source может получить другой proxy image
NeMo dependency указывает на Git mainНепинованный upstreamВоспроизводимость Sortformer build ограничена
Streaming checks обязательны; full suite локальнаяCI gate покрывает streaming protocol и integrationFile UI и модели требуют отдельной функциональной приёмки

UNKNOWN: почему эти компромиссы приняты. Git и code показывают состояние, но не подтверждают rationale.

Sources: README.md · stack/stack.drs · .gitlab-ci.yml · src/requirements.sortformer.txt
Изменения

Чтобы добавить возможность, меняйте контракт на его реальной границе

Новый diarization backendреализовать /healthz + /diarize → добавить image/stack → contract tests
Новое WebUI действиеroute в server.py → orchestration/job artifact → JS state/render → HTTP tests
Новое поле result eventPython payload producer → NATS/HTTP snapshot → browser consumer → backwards-compat tests
Другой model transportmodel_transport.py → environment contract → stack requester/receiver → cold/warm smoke
Новая benchmark metricbench.py calculation → result schema → summary renderer; назвать proxy честно
Иная retention policyautomatic cleanup scheduler и staged store lifecycle → download/snapshot UX → disk evidence

Сначала

Зафиксировать producer/consumer и ownership данных.

Потом

Проверить source, image, stack и live behavior как четыре разных уровня.

Sources: src/diarization.py · src/webui/server.py · src/webui/bench.py · stack/stack.drs
Change impact guide

Пять областей, где локальная правка легко становится межсервисной

Если меняетсяПроверь вместеПоследствие пропуска
Wire packet / NATS subjectvoice producer, bridge, consumer, JS WS clientТихая потеря audio или result events
Word timestamps / diarization JSONLinTO response parser, attribution, sidecars, downloadsНеверные speaker turns
Job lifecycle / cleanuprunner, store, lock, polling, download windowПропавшие artifacts или конфликт jobs
Proxy routerequester, NATS subject roots, external receiver, upstream healthProgress без фактической доставки media
Stack service/imagebuild labels, registry path, Dry Stack, external networkSource и runtime расходятся
VERIFIED

Один active automatic file job на процесс.

INFERRED

Horizontal scale требует общего lock и продуманного artifact ownership.

UNKNOWN

Целевой SLA и допустимая retention не заданы.

Sources: src/stt_whisper_to_nats.py · src/webui/job_lock.py · src/model_transport.py · tests/test_diarization.py
Developer onboarding

Как войти в проект без чтения всех файлов подряд

1

Запуск и flags

Начать с _main_async и settings в stt_whisper_to_nats.py.

2

Выбрать flow

Live → stream service. File → runner + file_mode.py. Staged → staged_jobs.py.

3

Найти boundary

HTTP route, NATS subject, artifact или Dry Stack service.

4

Доказать изменение

Узкий test → full suite → runtime smoke по затронутому маршруту.

Технический итог

  • Репозиторий — orchestration layer, а не единая ASR-модель.
  • Live и file flows используют общие model contracts, но разное state.
  • Filesystem artifacts — часть API поведения, особенно в staged mode.
  • Runtime ownership пересекает этот repo, WebRTC stack и H100 stack.
  • Любое утверждение о production требует проверки всей цепочки.

Навигация: ← → / PgUp PgDn / Space · Home End · F fullscreen · swipe

Sources: src/stt_whisper_to_nats.py · CODEMAP.md · .knowledge/project-inventory.md · tests/
1 / 19