Назначение и границы
Диалоговый runtime должен связать сигналинг, передачу медиа, маршрутизацию запроса и завершение сессии, не оставляя незакрытых соединений.
Короткая голосовая или текстовая сессия через собственную WebRTC-инфраструктуру. Транспорт и LangGraph работают реально, ASR/LLM/TTS заменены обозначенными моками.
- Фиксированная ASR-фраза не является распознаванием речи. Короткий тон не является синтезированной речью.
- Одновременно разрешены две сессии; третья отклоняется. Аудио не записывается, контекст хранится в памяти и удаляется.
- TURN разрешает peer только на адресе собственной VPS, имеет квоты и короткие credentials.
- Микрофонные QA-потоки созданы синтетическим устройством Chromium; передача DTLS/SRTP, TURN и счётчики медиа реальны.
Архитектура и схемы
- Браузер использует relay через собственный coturn. SDP ограничен одним аудиопотоком и DataChannel.
- Исходный WorkflowEngine и handlers сохранены; MockIO заменяет внешние AI-вызовы.
- ASR возвращает фиксированную фразу только после фактического получения аудиокадров. Вместо TTS передаётся короткий тон.
- Сессия живёт 90 секунд и допускает десять сообщений. Старое закрытие соединения проверяет идентичность сессии и не завершает новую.
Code-map: от функции к коду
Карта привязана к версии b16c97886356. Она помогает проследить изменение через интерфейс, API, модуль, данные и проверку.
| Функция | Экран / API | Модуль | Данные / проверка |
|---|---|---|---|
| Сигналинг | GET config / POST offer | portfolio/server.py config, offer | HMAC cookie; SDP validate; production QA |
| Аудио | Микрофон / stats | receive_audio; MockTone | кадры без записи; два настоящих потока |
| Граф | DataChannel text/asr | portfolio/runtime.py; WorkflowEngine | echo/free_speech; два unit-теста |
| Таймаут / повтор | LLM timeout button | DemoRuntime.run / asyncio.wait_for | отмена через 2 с; успешный повтор |
| Срок сессии | status / DELETE session | expiry; close; state_change | память; 90-секундная production QA |
Как работать с картой
- Перед изменением найти функцию и пройти связи до API, состояния и хранилища.
- Проверить входы, ошибки, повторные события и зависимые сценарии.
- После изменения обновить карту и затронутые схемы вместе с кодом.
- Выполнить связанные проверки и привязать новые материалы к версии исходников.
Сценарии и API
- Подключитесь без микрофона и отправьте echo: ответ проходит исходный граф.
- Проверьте шаблонный ответ, таймаут LLM и успешный запрос после отмены.
- Разрешите микрофон, дождитесь аудиокадров на сервере и примените мок ASR.
- Откройте stats, сбросьте контекст и дождитесь автоматического завершения через 90 секунд.
Проверка опубликованной версии
- Два unit-теста графа, 14 production-кадров, две одновременные аудиосессии и фактический TTL 90 секунд.
- Real relay/DataChannel, original echo, mock LLM, timeout then retry, context reset and close
- Two real simultaneous audio sessions; third rejected; closing other session preserves first
- Actual 90-second expiry closes RTC and deletes context
- Подтверждённого GitHub CI для этого SHA нет; перечислены выполненные локальные проверки и сценарии опубликованной версии. Исторические CI-ссылки, если есть, отмечены отдельно.
Результаты описывают проверенные сценарии и конкретную версию. Они не являются оценкой коммерческого успеха или качества моделей на независимой выборке.
Измерения
- Сохранено 14 содержательных кадров фактического интерфейса.
- Дата, сценарий и версия указаны у каждого кадра.
- Максимум RAM контейнеров в коротком тесте: 89.62 MiB. Общие службы учитываются отдельно; магазин включает свою БД.
- Измерено 2 повторений сценария; медиана 3660.5 мс, максимум 4226 мс. Время включает браузер и HTTPS; методика и ограничения приложены.
- Два аудиопотока подтверждены серверными кадрами и browser getStats. Третье подключение отклонено лимитом.
Запуск и эксплуатация
Исходная архитектура допускает внешние ASR/LLM/TTS. Публичный runtime использует только MockIO и не хранит аудио. Реальная транспортная часть проверена getStats и серверным счётчиком кадров.
Dockerfile.portfolio собирается вне VPS. App слушает 127.0.0.1:18406, coturn — 3478 UDP/TCP. Host network нужен для ICE на публичном интерфейсе; служебные HTTP-порты наружу не открыты.
TURN-конфигурация root-only содержит auth secret; её нельзя публиковать в документации. Разрешён только peer VPS, не произвольные внешние адреса. До 16 краткоживущих TURN allocations, но не более двух пользовательских RTC-сессий.
Проверять /healthz, ICE relay, поступающие кадры и DataChannel. При сетевом сбое завершить сессию и повторить. TTL закрывает соединение через 90 секунд; таймаут графа через две секунды не мешает следующему запросу.
Общие правила эксплуатации: готовые файлы и закреплённые образы собираются вне VPS; секреты не входят в артефакты. Общесерверный docker prune не применяется. Логи backend ограничены ротацией, изменения log options требуют пересоздания контейнера.
Перед изменением пройти code-map от функции к экрану/API, модулю и данным. После изменения обновить карту и схемы, выполнить связанные сценарии, включая ошибку, повтор и сброс. Источник истины — конкретная версия кода, а не старая диаграмма.
Откат проверен 2026-09-07T01:06:33.669720+00:00: 20260907-verified → 20260907e → 20260907-verified. После каждого переключения подтверждены HTTPS, readiness и SHA. Это проверка конфигурации и артефактов на одном проверенном SHA; обратная миграция БД не выполнялась.
Стек
| WebRTC / aiortc | Настоящие ICE, DTLS/SRTP, аудио и DataChannel. |
|---|---|
| coturn | Собственный ограниченный relay, временные credentials и peer allowlist. |
| Python / aiohttp | HTTPS-сигналинг за Nginx, жизненный цикл сессий и счётчики. |
| LangGraph | Исходная маршрутизация echo/free_speech, память и отмена. |
Материалы и исходники
История кода: с октября 2025. Публичный runtime и собственный TURN: 7 сентября 2026.