Ссылка на GitHub с кодом проекта в конце статьи

Транскрибация встреч и краткое summary сегодня уже не редкость: это умеют и корпоративные сервисы, и связка «транскрипт + LLM». Не хватает другого — материала, по которому можно сопоставлять позиции разных людей по одним и тем же сущностям и не терять историю принятых решений. Из этой задачи и вырос AudioToText: pet‑проект, который пытается превратить записи встреч в основу для управления требованиями на проекте, а не просто в ещё один текстовый артефакт.

В этой статье я хочу показать AudioToText не как набор ML‑экспериментов, а как продукт в его текущем состоянии: что он уже умеет, как выглядит пользовательский сценарий и в каких ситуациях такой инструмент действительно помогает. Техническую кухню, архитектурные компромиссы и путь к текущим решениям логичнее вынести в отдельную публикацию — здесь фокус именно на том, как проект работает «снаружи».

Зачем вообще нужен такой инструмент

Идея AudioToText родилась из практики внедрения проектов, преимущественно в сфере BI. На крупных внедрениях аналитики параллельно аудируют пользователей заказчика: разговаривают с разными должностными лицами, фиксируют требования, пытаются собрать целостную картину. На этом этапе часто всплывает одна и та же проблема — разные люди со стороны заказчика высказывают разнородные, а иногда и прямо противоречивые требования к одной и той же сущности. При большой команде такие расхождения не всегда удаётся своевременно отловить: они успевают превратиться в противоречивые ТЗ, составленные разными аналитиками и отданные на реализацию разным разработчикам.

Вторая сторона той же боли — потеря истории обсуждения. На встречах обсуждаются бизнес‑процессы, функциональные требования, архитектурные решения и другие важные аспекты. Запись формально всё сохраняет, но без удобного доступа команда снова и снова опирается на память и разрозненные заметки: кто‑то помнит одно, кто‑то — другое, а общая картина постепенно расползается.

Особенно сильно это проявляется уже после внедрения, когда проект переходит в поддержку силами интегратора, а на стороне заказчика так и не появляется человек, полностью погружённый в проект и его сопровождение. Через год или больше неизбежно всплывают вопросы вроде «а почему на проекте принято то или иное решение по обработке данных?» Ответ почти всегда лежит в ранних этапах — в сборе функциональных и бизнес‑требований. Наличие формальной документации от этого мало спасает: после закрытия чек‑листа приёмки к ней, как правило, уже никто не возвращается.

Именно под такую задачу и собирался AudioToText: превратить записи встреч аналитиков с заказчиком в структурированный материал, с которым можно работать дальше — читать, проверять, сопоставлять позиции разных участников и использовать это при согласовании требований.

Что такое AudioToText

Страница со списком встреч
Страница со списком встреч

AudioToText — это pet‑проект для работы с записями встреч, в котором несколько технических слоёв собраны в один продукт: распознавание речи на базе MLX Whisper, диаризация спикеров, последующая NLP‑обработка, аннотация, сценарии проверки (review workflow), экспорт результатов и простой Django‑интерфейс для работы с материалом через веб.

Если смотреть на проект как на поток, логика такая: аудиозапись проходит через ML‑пайплайн и превращается в канонический JSON‑транскрипт, после чего попадает в веб‑интерфейс. Там материал можно просматривать, проверять, связывать спикеров с пользователями приложения и при необходимости выгружать. Поверх этого автоматически выделяются именованные сущности, а затем строится summary в разрезе meeting × speaker × entity — не общее «о чём был созвон», а компактная фиксация того, кто именно и что сказал по конкретной сущности. Если нужно, тот же материал можно использовать для ручной разметки и оценки качества NER.

Как выглядит сценарий работы

Детальная страница встречи
Детальная страница встречи

Сценарий работы в AudioToText изначально задумывался как максимально прямой. Пользователь запускает обработку записи встречи через веб‑интерфейс, система выполняет транскрибацию и диаризацию и формирует структурированный результат. Этот материал затем появляется в интерфейсе: его можно посмотреть на уровне списка встреч и детальной страницы, при необходимости связать спикеров с пользователями приложения (об этом подробнее будет ниже) и выгрузить результат наружу.

Но мне было важно, чтобы всё не заканчивалось на уровне «вот вам транскрипт». Поэтому следующим шагом поверх проверенного материала автоматически выполняется выделение именованных сущностей, а затем строится summary в разрезе meeting × speaker × entity — не общее резюме созвона, а компактная фиксация того, кто именно и что сказал по конкретной теме. При необходимости тот же материал можно использовать и для ручной разметки, чтобы дальше оценивать качество NER.

Summary по сущностям внутри встречи в разрезе спикеров
Summary по сущностям внутри встречи в разрезе спикеров

Иными словами, идея проекта здесь не в самом факте распознавания речи, а в том, чтобы превратить запись встречи в рабочий артефакт: вещь, пригодную для проверки, уточнения, сопоставления позиций разных участников и последующего анализа требований.

Схема workflow AudioToText
Схема workflow AudioToText

Что уже есть в проекте

Редактирование сущностей
Редактирование сущностей

Сейчас проект находится в фазе Django MVP review workflow. В качестве текущих опорных элементов в README перечислены: канонический JSON‑контракт для транскрипта, structured‑output схемы для NER, минимальная наблюдаемость через tracing, layout датасетов и веб‑MVP с ключевыми экранами для ревью встреч.

Если разложить это по понятным продуктовым функциям, уже сейчас есть:

  • транскрибация аудио и сохранение результата в структурированном формате;

  • поддержка speaker diarization как части пайплайна;

  • подготовка канонического представления транскрипта для повторно используемой обработки;

  • интерфейс для списка встреч и просмотра деталей встречи в Django;

  • сценарии speaker identification;

  • построение summary позиций в разрезе meeting × speaker × entity;

  • экспорт данных для следующих шагов пайплайна и для оценки NER;

  • заготовленная инфраструктура для NER‑экспериментов и gold‑аннотаций.

Отдельно отмечу, что в проекте уже есть и слой наблюдаемости. Даже в pet‑проекте это оказалось полезным: если в системе появляются несколько этапов преобразования данных и LLM/NER‑компоненты, без trace‑механики быстро становится трудно понимать, где именно сломался результат и почему.

Какие возможности выглядят особенно полезными

Идентификация спикера
Идентификация спикера

Для практического использования у проекта уже сейчас есть несколько сильных сторон.

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

Вторая — каноническая структура результата. А значит, над проектом проще надстраивать новые режимы обработки.

Третья — review workflow. Между «модель что‑то распознала» и «этим можно пользоваться» здесь сознательно существует отдельный слой ревью, правки и подтверждения. Для рабочих встреч это критично: даже хороший ASR‑результат почти всегда требует человеческого взгляда, особенно если дальше из него должны рождаться заметки и сущности.

Четвёртая — локальный запуск без опоры на облачные GPU и внешние SaaS для базового контура. Проект изначально собирался так, чтобы его можно было крутить на машине разработчика с относительно скромными по меркам ML‑стека ресурсами. Весь основной контур — MLX Whisper, базовый пайплайн и эксперименты — рассчитан на Apple Silicon, что позволяет держать чувствительные записи встреч локально, а не отдавать их во внешние сервисы.

Что относится к дополнительным возможностям

Управление очередью именованных сущностей на редактирование/подтверждение
Управление очередью именованных сущностей на редактирование/подтверждение

Помимо основного сценария, в проекте уже есть дополнительные направления, которые не обязательны для каждого пользователя, но заметно повышают ценность системы для исследовательского и инженерного использования.

Одно из таких направлений — «золотые» аннотации для NER. В AudioToText предусмотрена ручная разметка сущностей, и сама разметка строится не по отдельным фрагментам, а по смысловым блокам: несколько последовательных реплик одного спикера объединяются в единый отрезок, с которым удобно работать человеку. Это пример того, как продуктовый UX и подготовка данных для ML начинают работать вместе: материал одновременно остаётся удобным для чтения и даёт основу для последующей оценки качества извлечения сущностей.

Что сознательно отложено

Важно не только то, что в проекте уже есть, но и то, чего в нём пока нет. Отдельно зафиксирован набор вещей, которые сейчас сознательно остаются за рамками: REST API, Celery или другие async‑workers, pgvector и внешние интеграции.

Такой список помогает держать рамку: не пытаться построить сразу всё, а сначала довести до осмысленного состояния базовый сценарий работы с транскриптом и ревью. PostgreSQL и векторный слой — это уже следующая фаза развития проекта. В этой фазе pgvector планируется использовать для хранения эмбеддингов по summary и семантического сравнения таких резюме между собой.

Идея проста: summary в разрезе meeting × speaker × entity превращаются в вектора, которые отражают их смысловое содержание. Дальше можно оценивать косинусное расстояние между такими векторами и программно находить случаи, где разные люди говорят про одну и ту же сущность, но их позиции плохо совпадают. Именно вокруг такого сценария — поиска противоречий по summary внутри одной категории и по одной и той же сущности — и будет строиться следующая ступень развития AudioToText: от фиксации позиций в текстовом виде к полуавтоматическому обнаружению конфликтов требований.

В этой статье я сфокусировался на том, как AudioToText выглядит снаружи — как продукт и как рабочий сценарий. В отдельной публикации уже хочу разобрать инженерную сторону: эволюцию пайплайна, канонический JSON‑контракт, trace‑слой, NER‑эксперименты и следующий этап с PostgreSQL и векторным поиском. Отдельный важный кусок этой инженерной части — модель пользователей и ролей, о ней тоже стоит сказать пару слов уже сейчас.

Пользователи, участники проекта и спикеры

Ещё один слой, который почти не виден в простом сценарии «загрузил запись → получил summary», но без которого проект теряет смысл именно как инструмент для работы с требованиями, — это разделение двух пользовательских сущностей: user и project‑member.

User — это аккаунт в приложении: человек, который может войти в систему, открыть встречи, пройтись по ревью, связать спикеров или выгрузить результат. Project‑member (участник проекта) — это человек в контексте конкретного проекта: аналитик, менеджер, стейкхолдер со стороны заказчика и т.д. У участника проекта может быть связанный аккаунт, а может и не быть: на встрече часто звучат люди, которым не нужен полный доступ в систему, но чьи позиции всё равно важно фиксировать.

К этой паре добавляется третий слой — спикеры. После диаризации в записи появляются локальные кластеры вроде Speaker_1 / Speaker_2. Сами по себе они ещё не люди: это просто «кто‑то говорил в этой встрече». Имеет смысл связать такой кластер с участником проекта, а через него — с пользователем приложения, если аккаунт есть. Тогда реплика перестаёт быть анонимным фрагментом транскрипта и становится позицией конкретного человека в конкретном проекте. Если говорящий внешний и без учётки, остаётся голосовой профиль спикера без обязательной привязки к user — и это тоже штатный сценарий, а не «дырка» в модели.

Поверх этого у AudioToText сразу закладывалась ролевая модель с несколькими типами доступа:

  • viewer — внешний участник со стороны заказчика; видит только те встречи, в которых сам участвует, без права правки.

  • viewer_full — широкий read‑only доступ ко всем встречам проекта, но без возможности менять результат.

  • project_manager — ведёт проект целиком: видит всё и управляет основными процессами.

  • analyst — работает с материалом встреч в рамках своих прав на просмотр и правку.

На уровне этой статьи я сознательно не углубляюсь в детали реализации — связи вида meeting_speaker → project_membership → user, инварианты идентификации и разрезание прав на уровне queryset — это уже материал следующей, технической публикации, где будет разбор архитектуры и внутренних решений проекта.

AudioToText GitHub