Транскрипт в веб-интерфейсе¶
Веб-интерфейс Speech-Expert позволяет не только просмотреть результат STT, но и подготовить его к дальнейшей работе: назначить спикерам понятные имена, перейти к найденным сущностям, открыть эмоциональный эпизод на исходном аудио и скачать транскрипт в TXT, SRT, WebVTT или JSON. Эти действия доступны сразу после распознавания и в разделе сохранённых записей.
Порядок обработки¶
Перед запуском распознавания в интерфейсе можно включить LLM-коррекцию текста, извлечение именованных сущностей и для русского locale — эмоциональную динамику. LLM-этапы выполняются последовательно, а локальный emotion inference запускается параллельно ASR:
- распознавание речи;
- восстановление пунктуации, если оно используется выбранным сценарием;
- LLM-коррекция готового транскрипта;
- извлечение сущностей уже из исправленного текста;
- саммаризация окончательного текста, если выбран пресет.
Таким образом, текст и символьные позиции в entities[].occurrences относятся
к окончательной версии реплик, которую возвращает API.
Фоновая операция: прогресс, отмена и восстановление¶
Веб-интерфейс отправляет распознавание через
POST /api/stt/v1:recognizeAsync, а затем опрашивает операцию раз в две секунды.
Во время обработки показываются короткий идентификатор, серверный статус,
процент выполнения и текущий этап: очередь, загрузка или конвертация аудио,
распознавание, коррекция текста, извлечение сущностей, саммаризация и
финализация.
Кнопка Отменить вызывает POST /api/operations/{operation_id}:cancel и
останавливает дальнейший polling. Для ElevenLabs-Scribe-v2 она намеренно
недоступна: текущий бэкенд этой модели не поддерживает отмену. Если операция
была запущена над уже сохранённой записью, отмена не удаляет саму запись.
Активная неприватная задача сохраняется в localStorage браузера на срок до 24
часов. Идентификатор приватной операции намеренно не записывается в
localStorage, хотя ещё активную задачу интерфейс может найти через серверный
список операций. При
повторном открытии страницы интерфейс:
- проверяет сохранённый идентификатор через
GET /api/operations/{id}; - если он недоступен, ищет незавершённые операции пользователя через
GET /api/operations?done=false&kind=stt_v1_async; - восстанавливает выбранные модель, язык, режим каналов, диаризацию,
maxSpeakers, LLM-коррекцию, извлечение сущностей, эмоциональную динамику и её порог, пресет и подробность саммаризации, а также metadata приватности и согласия; - продолжает показывать прогресс или сразу открывает готовый результат.
Полный исходный URL удалённого видео в localStorage не записывается. Доступ к
самой операции всё равно проверяется сервером в рамках текущего пользователя.
Повторное распознавание сохранённой записи¶
В разделе Мои записи кнопка Распознать открывает запись в STT-панели.
Можно выбрать другую модель и параметры и нажать Распознать снова. В этом
случае интерфейс передаёт recordingId в multipart-форме асинхронного метода;
аудио повторно из браузера не загружается. Метод работает только для записи,
принадлежащей текущему пользователю, и после успешного выполнения обновляет её
STT-результат.
Диаризация и режим каналов¶
Блок диаризации в Playground показывается всегда, а значение по умолчанию остаётся выключенным. Его поведение зависит от выбранного режима:
- в
monoможно включить диаризацию и задатьmaxSpeakersот 1 до 20; - в
stereoпереключатель неактивен с подсказкой «Для диаризации сведите каналы в mono», потому что физические каналы уже распознаются независимо; - для
ElevenLabs-Scribe-v2вместо переключателя отображается «Диаризация встроена», отдельная внешняя кластеризация не запускается.
stereo следует выбирать только тогда, когда разные участники действительно
записаны в разные каналы. Если оба канала содержат один общий микс, сервер пока
не удаляет дубли автоматически и текст может повториться — выберите mono.
Текущая граница ElevenLabs
Надпись в UI отражает способность провайдера, но текущий файловый STT v1 не
гарантирует utterances с provider-native speaker labels для
ElevenLabs-Scribe-v2. Не полагайтесь на это поле без проверки ответа.
Эмоциональная динамика¶
Переключатель доступен только при lang=ru-RU. После обработки интерфейс
показывает долю времени с негативным сигналом, пик, изменение сигнала к финалу,
временную шкалу и устойчивые негативные, позитивные или неопределённые эпизоды.
Пять исходных вероятностей DUSHA (angry, neutral, other, positive,
sad) раскрываются по запросу и не подменяются одной категоричной меткой.
Нажатие на окно или эпизод перематывает плеер к start_ms, подсвечивает
пересекающуюся реплику и показывает её текст/спикера, если такая атрибуция
однозначна. В сохранённой записи панель строится из response.emotion_analysis,
поэтому повторно запускать модель для просмотра не нужно.
Кнопки JSON и CSV в заголовке панели выгружают полный emotion-контракт
или плоский список эпизодов; если устойчивых эпизодов нет, CSV содержит окна.
Это вероятностный акустический слой для навигации по записи. other означает
другую или неопределённую окраску, а uncertain — производное состояние слоя
эмоциональной динамики при низкой уверенности или малом отрыве классов.
Результат нельзя использовать как единственное
основание для оценки человека или автоматического кадрового/финансового
решения. Подробные формулы и API-контракт приведены в
Emotion API и STT v1.
Экспорт транскрипта¶
Меню Скачать находится в заголовке готового транскрипта. Файлы формируются
в браузере из utterances, затем из segments, а при их отсутствии — из
цельного result. Отдельные words не превращаются в субтитры автоматически.
В JSON сохраняются слова с непустым текстом и полными числовыми границами
start/end; неполные элементы отбрасываются.
| Формат | Содержимое | Когда доступен |
|---|---|---|
| TXT | Отображаемый текст; у размеченных реплик — с таймкодами и назначенными именами спикеров | Для любого готового результата |
| SRT | Нумерованные субтитры с миллисекундами и именами спикеров | Когда у каждой непустой строки есть пригодные таймкоды, не помеченные synthetic или timing_estimated=true |
| VTT | WebVTT с заголовком WEBVTT, таймкодами и именами спикеров |
На тех же условиях, что и SRT |
| JSON | Версионированный документ с метаданными, репликами, словами, спикерами и сущностями | Для любого готового результата |
Пункты SRT и VTT отключены и показывают сообщение Нет таймкодов, если хотя бы
у одной непустой строки нет начала или допустимого конца либо её тайминг явно
помечен synthetic/timing_estimated=true. Отсутствие метки происхождения само
по себе экспорт не блокирует. Для реплики с корректным началом, но без конца,
конец берётся из начала следующей реплики или известной длительности записи.
Назначенные имена входят в TXT, SRT и VTT как подписи, например
Оператор: Добрый день. В JSON они сохраняются в speakers[].name и
utterances[].speaker_name.
JSON-схема экспорта¶
Текущая версия экспортного документа — 1.2. Основные поля:
{
"schema_version": "1.2",
"name": "call.wav",
"duration_ms": 42000,
"language": "ru-RU",
"model": "SpeechExpert-STT",
"channel_mode": "stereo",
"timing_source": "riva",
"timing_estimated": false,
"transcript": "Добрый день\nЗдравствуйте",
"speakers": [
{"id": 0, "name": "Оператор"},
{"id": 1, "name": "Клиент"}
],
"utterances": [],
"words": [],
"entities": [],
"entity_extraction_status": "ready",
"summarization": {
"schema_version": "2.0",
"id": "4a518cc8-4f70-470d-b868-40e39420fba5",
"created_at": "2026-07-15T12:00:00+00:00",
"preset": "conversation",
"detail_level": "standard",
"output_language": null,
"title": "Итоги звонка",
"summary": "Клиент подтвердил следующий шаг.",
"key_points": ["Клиент согласовал демонстрацию"],
"sections": [],
"decisions": ["Провести демонстрацию"],
"action_items": ["Оператор отправит приглашение"],
"open_questions": [],
"risks": [],
"structured": {
"key_points": [],
"sections": [],
"decisions": [
{
"text": "Провести демонстрацию",
"confirmation": "confirmed",
"sources": [
{
"ref": "S0004",
"quote": "Давайте проведём демонстрацию завтра.",
"start_ms": 18400,
"end_ms": 20700,
"speaker": 1,
"speaker_name": "Клиент",
"utterance_index": 3,
"timing_estimated": false
}
]
}
],
"action_items": [
{
"text": "Оператор отправит приглашение",
"assignee": "Оператор",
"due_date": "сегодня",
"sources": [
{
"ref": "S0005",
"quote": "Сегодня отправлю приглашение.",
"start_ms": 21000,
"end_ms": 22600,
"speaker": 0,
"speaker_name": "Оператор",
"utterance_index": 4,
"timing_estimated": false
}
]
}
],
"open_questions": [],
"risks": []
}
},
"summarization_status": "ready"
}
У каждой реплики сохраняются index, speaker, speaker_name, start_ms,
end_ms, text, timing_source и timing_estimated. Верхнеуровневый
timing_source становится mixed, если источники таймкодов у реплик
различаются. Если в Playground был выбран пресет саммаризации, JSON также
содержит структурированный объект summarization и статус
summarization_status; без выбранного пресета оба поля равны null.
После распознавания пресет и подробность можно выбрать или сменить прямо в
готовом результате Playground и в разделе Мои записи. Встроены сценарии
короткого резюме, конспекта, итогов разговора, задач, тем с таймкодами, лекции,
продаж/CRM, контакт-центра, интервью, исследовательского отчёта с JTBD и глав подкаста. Интерфейс вызывает только
POST /api/stt/v1:summarize: аудио повторно не распознаётся.
Без отдельного выбора все заголовки, тезисы, задачи, вопросы и ответы создаются
на преобладающем языке исходной речи. В Playground, готовом результате и окне
дайджеста селектор Язык результата позволяет независимо выбрать русский,
английский, казахский, кыргызский, узбекский или таджикский; запрос передаёт
summarizationOutputLanguage при распознавании либо outputLanguage при
повторной обработке. Выбранный locale распознавания остаётся подсказкой о языке
источника и не меняется. Серверные цитаты, ссылки, таймкоды, имена и дословные
фрагменты сохраняются в оригинале. Тот же контракт действует для собственных
шаблонов, дайджестов и готовых наборов; функция Спросить архив по-прежнему
отвечает на преобладающем языке выбранных записей.
В Моих записях отдельное действие Перевести транскрипт создаёт полный перевод, а не резюме. Перевод хранится как самостоятельный производный результат с версиями, показывает исходные реплики и переходит по их таймкодам, но не заменяет исходный текст. Временные границы переведённых слов не вычисляются: интерфейс использует только таймкоды исходных серверных фрагментов. API-контракт описан в разделе Перевод готового транскрипта.
Исследовательский отчёт можно применить к одной записи или к дайджесту из 2–20 интервью. Он отдельно показывает повторяющиеся темы, Jobs to be Done, возражения и выводы; каждый пункт содержит проверенные сервером ссылки на исходные реплики. В межзаписном отчёте тема считается повторяющейся только при подтверждении как минимум из двух разных интервью. Длинные дайджесты обрабатываются в два уровня: сначала сервер собирает доказательные наблюдения по каждой записи, затем сводит их в общий отчёт. Финальный этап видит только реально отобранные исходные реплики и не использует этот набор для расчёта процентов или «большинства».
Отдельные готовые наборы Voice Inbox, Учебный набор и Creator Pack
создаются через POST /api/stt/v1:derive; центр поручений использует тот же
метод с kind=action_center. Они хранят собственные версии, а подтверждение,
исправление или отклонение задачи записывается отдельно от неизменяемого ответа
модели. Кнопка Спросить архив ищет по сохранённым расшифровкам и показывает
только тезисы с переходом к записи, таймкоду и подтверждающей цитате.
Для содержательной long-form записи расширенный Creator Pack возвращает тезисы, главы, кандидаты фрагментов, готовую к редактированию статью, show notes, описание видео, рассылку и публикации для social, Telegram и VK. Текст статьи сохраняет абзацы. Субтитры SRT/VTT экспортируются из исходного транскрипта, когда у него есть тайминги. Разбор, статья и публикации генерируются отдельными структурированными этапами и собираются сервером в один проверенный пакет. Короткая запись или пользовательский шаблон могут вернуть полезный частичный пакет; интерфейс помечает такой результат отдельно.
У сохранённой записи каждый успешный запуск добавляется в историю. Текущая
версия остаётся в response.summarization для совместимости, а переключение
версии не запускает LLM. Источники внутри structured ведут к точной реплике и
позиции проигрывателя; таймкод и цитата берутся сервером из STT-ответа, а не из
текста модели. Решения помечаются как подтверждённые, предложенные, отклонённые
или неясные; у задач отдельно показываются явно названные исполнитель и срок.
Ошибка LLM не удаляет уже имеющуюся саммаризацию.
В приватном режиме новый результат остаётся только в открытой вкладке:
запись не создаётся и не обновляется, идентификатор операции не сохраняется в
localStorage, а Playground очищает серверное содержимое вызовом :purge
после копирования результата. Резервный deadline по умолчанию равен 15 минутам
от запуска операции и проверяется сервером раз в минуту. Без отдельного согласия отключаются внешние
LLM-функции и ElevenLabs. Для обычной сохранённой записи аудио можно удалить
отдельно, оставив транскрипт и все производные результаты. Живые субтитры из
микрофона работают через WebSocket и также не сохраняются автоматически.
В разделе Мои записи также доступны собственные шаблоны и дайджест 2–20 записей. Шаблон задаёт фокус поверх встроенного сценария и сохраняется с номером ревизии. В дайджесте источник дополнительно указывает запись, из которой взят факт. API-контракты истории, шаблонов и дайджестов описаны в разделе Саммаризация STT v1.
Экспорт выполняется на клиенте
Отдельных HTTP-методов для SRT, VTT и JSON сейчас нет. API-клиент получает структурированный STT-ответ и при необходимости формирует нужный формат самостоятельно.
Переименование спикеров¶
Блок Участники появляется, когда результат содержит реплики с полем
speaker. Для каждого исходного идентификатора SPK N можно задать имя длиной
до 80 символов. Лишние пробелы нормализуются.
- Enter или потеря фокуса применяют имя;
- Escape отменяет несохранённое изменение;
- пустое значение возвращает подпись
Спикер N; - новое имя сразу применяется ко всем репликам, экспортам и подписям спикеров у найденных сущностей.
Для сохранённой записи интерфейс записывает словарь в
response.speaker_names и одновременно обновляет текстовое представление через
PATCH /api/account/recordings/{recording_id}. Этот метод требует сессию
портала. У ещё не сохранённого результата имя меняется локально; интерфейс
предупреждает, что для постоянного хранения нужно сохранить запись.
При самостоятельном PATCH передавайте полный пользовательский вариант
response, а не только speaker_names. Сервер при этом сохраняет принадлежащие
ему поля активной саммаризации (summarization и summarization_status): их
нельзя подменить или стереть общим методом обновления записи. Специального
публичного STT-метода для переименования спикера сейчас нет.
Именованные сущности¶
В веб-интерфейсе извлечение сущностей включено по умолчанию. Для прямого вызова
STT v1 оно включается явно параметром entityExtraction=true; значение можно
передать в query string или multipart-форме:
curl -X POST \
"https://api.speech.example.com/api/stt/v1:recognizeAsync?llmCorrection=true&entityExtraction=true" \
-H "Authorization: Api-Key $API_KEY" \
-F "audio=@call.wav"
Параметр поддерживается синхронным POST /api/stt/v1 и асинхронным
POST /api/stt/v1:recognizeAsync. По умолчанию в API он равен false.
Сервис извлекает только явно присутствующие в тексте упоминания следующих типов:
person, organization, location, product, event, date, time,
money, phone, email, url, address, document, identifier.
Ответ содержит сгруппированные сущности и каждое точное упоминание:
{
"entities": [
{
"id": "organization:1",
"type": "organization",
"text": "Acme",
"normalized": "ACME",
"occurrences": [
{
"utterance_index": 0,
"mention": "Acme",
"char_start": 0,
"char_end": 4,
"speaker": 0,
"start_ms": 1200,
"end_ms": 3100
}
]
}
],
"entity_extraction_status": "ready"
}
char_start включителен, char_end исключителен. Это позиции Unicode-символов
в тексте соответствующей реплики. Сервер вычисляет их только для точного
вхождения mention и отклоняет упоминания, которых нет в исходном сегменте.
Варианты написания с
одинаковыми типом и нормализованным значением объединяются в одну сущность.
Статусы извлечения¶
| Статус | Значение |
|---|---|
ready |
Все части транскрипта обработаны и прошли проверку |
partial |
Сохранены валидные сущности, но часть ответа, чанков или упоминаний была отклонена либо достигнут лимит |
failed |
Извлечение не удалось; сам транскрипт всё равно возвращён |
unavailable |
Не настроен API-ключ LLM; транскрипт возвращён без сущностей |
Извлечение работает по принципу fail-open: ошибка внешней LLM не превращает успешное распознавание в ошибку STT.
Переход к упоминанию¶
Панель Сущности и реквизиты группирует результаты по типам. Кнопка упоминания показывает таймкод, номер реплики или подпись текст — в зависимости от доступных данных. При нажатии интерфейс:
- плавно прокручивает транскрипт к нужной реплике;
- выделяет точный диапазон
char_start:char_end; - переводит позицию аудио- или видеоплеера на
start_ms, если он известен.
Позиции обрабатываются как Unicode code points, поэтому выделение остаётся корректным и при наличии emoji перед сущностью. Переход меняет позицию проигрывателя, но не запускает воспроизведение автоматически.
Настройка модели NER¶
Извлечение использует OpenAI-совместимый POST /chat/completions. Если отдельные
настройки NER пусты, сервис наследует настройки LLM-коррекции:
| Переменная | Назначение | Значение по умолчанию / fallback |
|---|---|---|
LLM_ENTITY_EXTRACTION_API_KEY |
Отдельный ключ NER | LLM_CORRECTION_API_KEY, затем VSEGPT_API_KEY |
LLM_ENTITY_EXTRACTION_BASE_URL |
URL OpenAI-совместимого API | LLM_CORRECTION_BASE_URL |
LLM_ENTITY_EXTRACTION_MODEL |
Модель NER | LLM_CORRECTION_MODEL |
LLM_ENTITY_EXTRACTION_TIMEOUT |
Таймаут одного запроса, секунды | 60 |
LLM_ENTITY_EXTRACTION_MAX_TOKENS |
Максимум токенов ответа | 8000 |
LLM_ENTITY_EXTRACTION_TEMPERATURE |
Температура | 0 |
LLM_ENTITY_EXTRACTION_CHUNK_CHARS |
Размер чанка транскрипта | 12000 |
LLM_ENTITY_EXTRACTION_MAX_ENTITIES |
Максимум валидных упоминаний | 500 |
В .env.example и Docker Compose отдельная модель NER не задана, поэтому при
настройках по умолчанию используется google/gemini-3.5-flash-minimal из
LLM_CORRECTION_MODEL. После изменения модели, URL или лимитов перезапустите
API, чтобы сервис перечитал настройки.
Границы текущей реализации¶
entityExtractionреализован для синхронного и асинхронного STT v1; в потоковом WebSocket/gRPC и STT v3 этот флаг сейчас не используется.- переименование и скачивание файлов — функции веб-интерфейса, а не новые форматы ответа публичного STT API;
- SRT и VTT недоступны для таймкодов, явно помеченных синтетическими или оценочными, а также для строк без начала или выводимого конца;
- имена спикеров постоянно хранятся только вместе с записью портала.
Схемы исходного STT-ответа и таймстемпов описаны в разделе Синхронное распознавание, а получение фоновой операции — в Операциях. Полный CRUD сохранённых файлов и транскриптов описан в API записей.