# Правки для согласования · версия 2 · 30.10.2026

Это уточнённый план и локальные макеты. Исходники проектов, GPU, runtime, образы и расширение не менялись. Рекомендации по Nemotron и исходному PCM из предыдущего REPORT.md заменены решениями пользователя ниже.

## Принятые решения

| Направление | Решение |
|---|---|
| Nemotron | Исключить из этой работы. Не загружать и не интегрировать. |
| GigaAM Large | Подготовить отдельное сравнение `large_ctc` 600M с текущими моделями. В этой итерации — проверка исходников и план эксперимента. |
| Silero | Оставить нынешний Silero/ONNX Runtime Web/WASM. |
| Opus | Проектировать передачу и хранение одного Opus-потока. Архив содержит именно принятые пакеты, из которых сервер получил вход ASR. Исходный PCM Chrome постоянно не дублируем. |
| Monitor | На верхнем уровне — транскрипции и команды; внутри — сводка, журнал и хорошо видимая схема вызовов. |
| Реализация | Пока только согласование и макеты. Загрузка новой модели в production GPU и внедрение отложены. |

## 1. Monitor: два уровня вместо общей простыни

### Верхний уровень — процессы сессии

Один блок — одна транскрипция либо одна команда:

```text
[Транскрипция] Найди форму и поставь ей фон с котом.
Готовая фраза → текст: …    Запросы / ответы: …    События / ошибки: …
                                     [Открыть журнал] [Схема вызовов]

[Команда] Найди форму и поставь ей фон с котом.
Команда → ответ: …          Запросы / ответы: …    События / ошибки: …
                                     [Открыть журнал] [Схема вызовов]
```

Транскрипция связана с созданной из неё командой через сохранённые идентификаторы. В каждой странице есть переход к соседнему процессу. Для текста существует только команда; для ошибки ASR — только транскрипция с причиной и состоянием «Команда не отправлена». Отдельные аудиофразы не объединяются в один большой блок потока.

Верхние фильтры:

- **Все процессы / Обработка звука / Обработка команд**.
- **Состояние:** в работе, готово, ошибка; при внедрении также реальные отменённые/прерванные состояния.
- **Источник:** голос или текст.
- **Поиск:** текст, request_id, phrase_id.
- **Сортировка:** ранние, поздние, дольше обрабатывались, ошибки в начале. Время относится к подписанному процессу, а не ко всему захвату.
- Существующий контекст сессии, потока, интервала и live/pause сохраняется. Макет показывает фиксированный демонстрационный снимок.

Chat UI, NATS events и отдельные subjects перемещаются в технический уровень. Они не смешиваются с фильтрами пользовательских процессов. Служебные события без доказанной связи с фразой/командой остаются доступными в существующем служебном представлении; их нельзя молча выбросить или приклеить к ближайшей фразе по времени.

### Отдельная страница выбранного процесса

1. Заголовок `[Транскрипция] — текст` или `[Команда] — текст`, статус, модель и копируемые существующие ID.
2. Краткий итог: счётчики, основные интервалы, отдельное число вызовов модели/инструментов.
3. Объяснение вложенных интервалов и, для аудио, запись/диагностика.
4. **Журнал / Схема вызовов** — постоянно видимый переключатель.
5. Локальные фильтры: участник, тип сообщения, направление наблюдения, отсутствие отметки, поиск subject/адреса/ID, ранние/поздние.
6. Быстрые технические срезы: Все каналы / Chat UI / NATS events / HTTP-модель.

Переход — отдельный URL состояния страницы. Назад возвращает фильтры и место в списке. Переключение журнала и схемы сохраняет фильтр. В макете это разные hash-страницы одного автономного HTML; в проекте используем существующую маршрутизацию Monitor.

### Что видно в каждой передаче

```text
Отправлено из                           Получено в
Gateway                          →     Audio Ingress
chat-agent_src_api_gateway              chat-agent_audio_ws_ingress
10:18:02.003                            10:18:02.005

NATS · chat.browser.audio
```

На схеме направление задаёт стрелка, на концах — участники. Subject/URL и протокол находятся на стрелке; полный адрес доступен при выборе. Для отсутствующей отметки явно показывается «Отправка/получение не зафиксировано». Известный адресат не считается доказательством доставки. Разность часов двух сервисов не выдаётся за сетевую задержку.

Подтверждённые отправку и получение можно показать рядом в одной передаче. Уже существующий `transitions()` делает это только при совпадающем `parent_event_id`, маршруте, subject, протоколе и типе. Оба исходных наблюдения остаются доступны в деталях. Новое эвристическое сопоставление не нужно.

Источник: [exchangeModel.ts](#archive-availability).

### Счётчики без удвоения

- «Запросы / ответы» — количество уникальных передач соответствующего типа внутри процесса. Подтверждённая отправка и её получение считаются один раз.
- Один запрос пользователя проходит несколько сервисов, поэтому число передач не равно числу вызовов модели. Для ASR, LLM и инструментов нужны отдельные подписанные счётчики.
- Подтверждение приёма и итоговый результат могут быть разными сообщениями. Не требовать искусственного равенства запросов и ответов.
- Отдельно показывать служебные события, ошибки и при инспекции — число наблюдений.
- Если связи или страницы журнала неполны, указывать неполноту. Не выдавать число загруженных строк за итог всего процесса.
- Фильтры журнала меняют надпись «показано N из M», но не пересчитывают общую сводку блока в незаметно другой смысл. Верхние фильтры выбирают целые процессы.

### Время: что в что входит

**Транскрипция:**

| Значение | Граница измерения |
|---|---|
| После конца речи → текст | Последний речевой отсчёт → показ текста; это пользовательская задержка |
| Окончание фразы | Последний речевой отсчёт → отправка конечной границы; включает фактическое ожидание, а не только настроенные 450 мс |
| Готовая фраза → текст | Отправка конечной границы → показ текста; часть предыдущего общего интервала |
| Обмен с ASR | Вложенный серверный обмен; уже включает модель |
| Чистое распознавание | Полное выполнение вызова модели, включая генератор результата; без очереди и транспорта |
| Кодирование, декодирование, PCM, очередь, показ | Только самостоятельные подтверждённые измерения с пояснением области |

В примере макета **704 = 450 + 254 мс**, а **163 мс модели уже входят в 254 мс**. Это учебные числа, не новый benchmark. В реальности между последним речевым отсчётом и отправкой границы могут быть обработка VAD и выпуск последнего кадра кодека: нельзя подставлять настройку паузы вместо измеренного интервала.

Длительность произнесения и внутренних пауз — длительность аудио, не время вычислений. VAD/кодирование выполняются во время захвата и могут перекрываться с передачей; их нельзя автоматически прибавлять к задержке после конца речи.

**Команда:** от отправки команды до показа итогового ответа, отдельно — очередь, работа LLM, инструменты и отображение. Транскрипция сюда не включается. Суммы CPU/GPU-работы при параллельном исполнении не равны длительности на часах.

Подготовка соединения и закрытие диагностики показываются отдельно, как в ASR Compare. Для постоянно подключённого плагина они не добавляются к каждой фразе. Где нет конечных отметок, показывается «Нет измерения»/«Ожидается», а не ноль или разность несвязанных событий.

Источник действующей семантики: [asrCompare/timeline.ts](#archive-availability).

### Как сделать без новой архитектуры

Расширить существующий `SessionSequence`, его `operations()`/`transitions()` и текущую проекцию запросов/аудиофраз. Сохранять `session_id`, `stream_id`, `phrase_id`, `request_id`, `operation_id`; не создавать новую систему trace ID, таблицы или дублирующий журнал.

В нынешнем коде страницы запросов имеют переключатель, а поток создаёт компонент с фиксированным `'events'`. Предлагаемое исправление: видимые кнопки «Журнал / Схема вызовов» и прямой вход в схему из блока; раскрывать техническую секцию для доступа к ним больше не потребуется. До внедрения production-страница остаётся прежней.

## 2. Opus: пересмотренный архивный контракт

Согласованное изменение: «Исходная запись» теперь означает **принятый Opus-поток, послуживший входом распознавания**, а не несжатые отсчёты Chrome. Название в UI — «Запись для распознавания». Формат и преобразования видны рядом с проигрывателем.

Предлагаемый первый профиль: mono, 48 кГц, Opus 32 кбит/с, кадр 20 мс. Это начальные параметры для эксперимента, не утверждение о достаточном качестве. 24 кбит/с проверять только после сравнения 32 кбит/с с PCM.

```text
Микрофон Chrome
  ├─ аналитическая копия → прежний Silero WASM → координаты фразы
  └─ Opus encoder → существующий бинарный NATS/WebSocket-транспорт
                    ↓ Audio Ingress
                    ├─ те же закодированные пакеты → существующий архив
                    └─ один постоянный decoder захвата → диапазон фразы
                                                       → прежняя подготовка 16 кГц
                                                       → прежнее batch-задание ASR
```

- Один Opus encoder на захват. Проверить WebCodecs до включения микрофона; незаметного переключения формата нет. Silero получает свою аналитическую копию и не изменяет звук ASR.
- Сначала использовать имеющийся Worker и существующий транспорт. Дополнительное NATS-соединение или менеджер кодеков не нужны. Окончательное размещение encoder проверить на задержках VAD/захвата, не считать отсутствие нового Worker самоцелью.
- В Audio Ingress уже есть PyAV `14.2.0`; сначала проверить наличие Opus decoder в текущей сборке. Использовать его, если поддерживается, без нового сервиса и универсальной codec-обвязки.
- Архив получает именно входные Opus-байты, без повторного кодирования. PCM используется в ограниченных рабочих буферах и отдельно постоянно не сохраняется.
- Версию и формат обозначить в существующем аудиоконтракте. Нельзя молча отправлять Opus под контрактом `pcm16le`. Точные изменения бинарного заголовка/subject утвердить после адресной проверки producer/consumer; имена на макетах описывают нынешние управляющие связи, а не уже выпущенный Opus-протокол.
- Сохранить последовательность, размеры, хеши, частоту, число каналов, codec config, timestamp/duration, priming/pre-skip и конечное обрезание. Координаты фразы остаются в аудиоотсчётах и учитывают задержку кодека.
- Подтверждать границу после получения всех относящихся к ней закодированных пакетов. Не ждать сохранения БД для начала ASR.
- При выключении корректно выпустить хвост encoder. Повреждение/пропуск пакета — явная ошибка, без подстановки искусственного звука в команду.
- Исторические PCM-записи остаются читаемыми по сохранённому формату. Новую историю в PCM не перекодировать; архивы Opus упаковывать для скачивания без re-encode.

**Повтор фразы:** у Opus есть состояние. Для первого доказуемого варианта сервер потоково декодирует сохранённую последовательность от начала записи до нужного диапазона, сохраняя ограниченную память. Это может замедлить переход к поздней фразе длинной записи — ограничение нельзя скрывать. Random access с pre-roll проверить отдельно до внедрения в Monitor; произвольный пакет не является точной заменой состояния decoder.

В диагностике проигрывание **входа ASR выбранной фразы** формируется сервером из того же декодированного/подготовленного диапазона. WAV для проигрывателя — производное представление, не второй постоянный архив. Для повторов сверять хеш входного PCM после одинаковой версии decoder/resampler. Разные браузерные декодеры не объявлять побайтово идентичными серверному.

Используем существующие метаданные и блоки архива. До реализации проверить ограничения текущей схемы, которые предполагают постоянные байты на отсчёт; их нельзя оставить как для PCM. Новых таблиц или служб по умолчанию не требуется.

Источники: [WebCodecs Opus — пакеты и priming](<https://www.w3.org/TR/webcodecs-opus-codec-registration/>), [Ogg Opus — pre-skip, end trimming и seeking](<https://www.rfc-editor.org/info/rfc7845/>), [зависимости ingress](#archive-availability), [подготовка текущего batch](#archive-availability).

Проверка перед внедрением: один PCM-образец и одни границы → baseline PCM и Opus32 → одна модель/настройки. Измерить полезные и wire-байты, encode/decode CPU, задержку последнего пакета, очередь, ASR, последний речевой отсчёт → текст, WER/CER. Проверить 90 мс/1 с, начало/конец слова, длинную запись и seek. Не обещать ускорение модели от сетевого сжатия.

## 3. GigaAM Large: адресная проверка

Кандидат — `ai-sage/GigaAM-Multilingual`, ветка `large_ctc`, ревизия `3905cd51c3ed4e88c8edf33f3302969ba480a327`. Веса 2,34 ГБ. Исходный снимок GPU от 10:50 MSK показывал 11,66 ГиБ свободно в ASR-разделе; перед экспериментом память проверить заново.

Дополнительная проверка исходника модели подтвердила: используются `GigaAMModel`/`GigaAMASR`, `CTCGreedyDecoding`, а класс ASR предоставляет `head` и `decoding`, как и текущий адаптер RNNT. Это основание попробовать небольшой явный профиль загрузки/параметров вместо нового inference-фреймворка. Совместимость установленных torch/transformers ещё требует import/load проверки; автоматически обновлять общие зависимости по примеру из README не следует.

Порядок будущего эксперимента:

1. Закрепить файлы и хеши модели, проверить импорты в изолированном окружении. Не подменять действующий GigaAM.
2. Один контролируемый load в разрешённом бюджете GPU: память до/после/пик, холодный запуск. OOM не должен затронуть текущие модели.
3. Одни PCM16 16 кГц, одни границы и тексты-эталоны: текущий RNNT, новый CTC, Turbo. Сначала PCM, отдельно от Opus, чтобы не смешать причины различий.
4. Короткие команды, тихая речь, имена, числа, шум, паузы; длительности 1/5/15/30 секунд. Отдельно cold/warm, медиана/p95 чистого ASR и памяти. Пунктуация и нормализация оцениваются отдельно от WER.
5. Вход напрямую массивом через decoder, без повторного VAD, WAV/base64-круга и фильтрации текста по score.
6. По результату решить: добавить альтернативную модель, заменить нынешнюю или отказаться. Решение о замене заранее не принято.

Поддержка общего класса проверена по [исходнику закреплённой модели](<https://huggingface.co/ai-sage/GigaAM-Multilingual/blob/3905cd51c3ed4e88c8edf33f3302969ba480a327/modeling_gigaam.py>) и [нашему адаптеру](#archive-availability). Модель в GPU в этой итерации не загружалась.

## 4. Материалы и проверки

- [Интерактивный макет](</experiments/voice-ai/archive/v/10/30/asr-monitor-research/v2/monitor.html>): верхние фильтры, отдельные страницы, переход транскрипция ↔ команда, журнал/схема, локальные фильтры и темы.
- [Общий список](</experiments/voice-ai/archive/v/10/30/asr-monitor-research/v2/01-processes.png>), [транскрипция](</experiments/voice-ai/archive/v/10/30/asr-monitor-research/v2/02-transcription.png>), [схема команды](</experiments/voice-ai/archive/v/10/30/asr-monitor-research/v2/03-command-sequence.png>), [мобильный эскиз 390 px](</experiments/voice-ai/archive/v/10/30/asr-monitor-research/v2/04-mobile.png>).
- Изображения — отдельные векторные эскизы, отрисованные из того же набора условных данных. Это не скриншоты работающего сайта. Они просмотрены визуально.
- [Проверки HTML](</experiments/voice-ai/archive/v/10/30/asr-monitor-research/v2/checks.json>): 13 адресных функциональных проверок JSDOM, включая прямой вход в схему, сохранение фильтров, отсутствие выдуманных отметок доставки и разделение таймингов.
- Браузерная политика ранее запретила `file://`. Повторной попытки или обхода не было; реальная браузерная вёрстка HTML, clipboard и responsive остаются непроверенными. Превью позволяют согласовать компоновку без этого доступа.
- Изменены только файлы в локальном каталоге `asr-monitor-research/v2`. Репозитории и production UI остаются прежними.
