AAYMA
RU
Войти

AI Meeting Copilot

Развёрнутый сервис автопротокола: запись или загрузка аудио, собственные STT и диаризация, извлечение поручений и саммари на своей LLM, перевод…

Доведённый продукт
Команда «DBK team» 28💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: DBK team
Кейс HackAlem.ai: Инновации — Самрук-Казына
Стадия: Доведённый продукт

Задача кейса: «Хаттама»: протокол и поручения по аудиозаписи совещания (каз./рус./смешанная речь)

Суть

Развёрнутый сервис автопротокола: запись или загрузка аудио, собственные STT и диаризация, извлечение поручений и саммари на своей LLM, перевод протокола на kk/ru/en, контроль сроков с email-напоминаниями, экспорт в DOCX и PDF.

Как устроено

Фронт на Next.js кладёт запись в MinIO и отправляет событие в Kafka. Обработчик (Kafka-консьюмер) распознаёт речь через faster-whisper/CTranslate2 по двум маршрутам: общий для ru/en и собственная дообученная казахская whisper-turbo-ksc2. Диаризация на nvidia diar_streaming_sortformer_4spk-v2 и titanet_large, каждое слово приписывается говорящему по середине слова. Склеенный транскрипт уходит в Qwen3.8-27B-FP8 на своём vLLM, который выделяет поручения и саммари. Субтитры Zoom .vtt дают настоящие имена говорящих, поручения хранятся в MinIO, а уведомления отправляются через HTTP-почту.

Ключевые решения

  • faster-whisper CTranslate2
  • fine-tuned Whisper для казахского (KSC2)
  • Sortformer diarization
  • TitaNet speaker embeddings
  • word-midpoint speaker alignment
  • Kafka event pipeline
  • vLLM self-hosting

Метрики

Шала-казахский CER 0.0511 на публичном корпусе; казахский CER 0.000 на замере

Особенности

Полностью свой речевой стек в закрытом контуре: дообученный казахский Whisper, Sortformer-диаризация, собственный vLLM. Замерен CER на шала-казахском. Зафиксировано, что Zoom VTT даёт имена ответственных. Рабочая демо-версия на app.aibots.kz.

Стек

Python · Next.js · Tailwind v4 · Apache Kafka · MinIO · Docker Compose · Traefik · Caddy · Ansible · ffmpeg

Модели

Whisper (whisper-v6-ct2, whisper-turbo-ksc2-ct2) · nvidia/diar_streaming_sortformer_4spk-v2 · titanet_large · Qwen3.8-27B-FP8 (vLLM)


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-47bd9c8d-dbk-team.

README

README.md

AI Meeting Copilot — автопротоколирование совещаний с фиксацией поручений

Попробовать без установки: https://app.aibots.kz

Загрузите запись совещания или запишите её прямо в браузере — через минуту получите протокол с говорящими, поручениями и саммари, готовый к выгрузке в DOCX или PDF. Разворачивать ничего не нужно, все службы уже подняты.

Руководство пользователя со скриншотами →

Краткое описание

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

Для кого: секретари совещаний и управленческие сотрудники, которые контролируют исполнительскую дисциплину.

Кейс: docs/TASK/task.md. Проектное решение с разбором предпосылок и границ: docs/designs/meeting-protocol-agent.md.

Что реализовано

Требование кейсаГде закрыто
1. Распознавание речи участниковspeech_stack/stt, развёрнуто на stt.aibots.kz
2. Русский языкмаршрут general:whisper-v6-ct2
3. Казахский языкмаршрут ksc2:whisper-turbo-ksc2-ct2, CER 0.000 на замере
4. Шала-казахскийlanguage=auto; CER 0.0511 на публичном корпусе с человеческой расшифровкой, замер
5. Поручения с ответственным и срокомmeeting-copilot-container/summarize_transcript.py, модель на vllm.aibots.kz
6. Диаризация с привязкой к человекуspeech_stack/diarization + склейка merge_transcript.py; с субтитрами Zoom — имена вместо ярлыков
7. Экспорт протокола в файлfront/lib/export-docx.ts, front/components/printable-protocol.tsx

Из раздела «Дополнительно»

ПунктСостояние
Развёртывание в закрытом контурераспознавание, диаризация и языковая модель свои, исходники в репозитории
Дашборд статусов порученийfront/components/commitments-dashboard.tsx — в работе, просрочено, выполнено
Автоматическая рассылка ответственнымfront/lib/notifications.ts — напоминание за 3 дня до срока и при просрочке; транспорт настраивается, без настройки письма копятся в журнале
Классификация по срочности и направлениюколонка в таблице поручений: «Срочно · Договорная работа»
Голосовая идентификация по тембруслужба развёрнута (/v1/audio/identify, /v1/speakers), образцов не зарегистрировано
Интеграция с СЭДне делалась, вне обязательной части
Рассылка выдержек ответственнымне делалась

Сверх кейса: AI-перевод протокола. Протокол доступен на трёх языках — русском (оригинал), казахском и английском. На все три языка переводится и саммари, и таблица поручений: у поручения переводятся текст, цитата, срок словами и классификация, а имена людей, названия организаций, даты ГГГГ-ММ-ДД и идентификаторы остаются как есть. Разметка саммари — заголовки, списки, выделение — сохраняется, так что переведённая версия читается так же, как исходная.

Перевод считается на своей модели (vllm.aibots.kz), поэтому текст совещания не покидает контур и при переводе. Переключатель языка стоит в заголовке протокола, выбранный язык сохраняется между обновлениями страницы, а перевод одного совещания считается один раз: результат лежит рядом с исходным протоколом (result.<язык>.json) и в следующий раз показывается сразу, без обращения к модели. Транскрипт не переводится: это дословная запись сказанного, и переводить её значит подменять сказанное.

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

Поручения всех совещаний собираются в общий список и переживают перезапуск: хранятся в MinIO (results/commitments/index.json), а не в памяти процесса. Контроль сроков измеряется неделями, и список, живущий до первого рестарта, такой задачи не решает.

Вкладка «Контроль поручений» показывает срок, ответственного, статус и остаток дней. Просроченные идут сверху с красной подложкой. Рядом с каждым поручением задаётся почта ответственного — в записи совещания адресов нет, поэтому это единственное, что вводится руками. Кнопка «выполнено» закрывает поручение.

Кнопка «Проверить сроки» запускает рассылку: напоминание уходит за три дня до срока и отдельно при просрочке. Повторно одно и то же не отправляется — отметка хранится в самом поручении. Тот же вызов годится для внешнего планировщика:

curl -X POST https://app.aibots.kz/api/commitments/notify

Настройка почты. Отправка идёт по HTTP, а не по SMTP: подходит любой провайдер, принимающий POST (Resend, Mailgun, Postmark, MailChannels), и это не тянет зависимостей в образ. Три переменные окружения:

MAIL_API_URL=https://api.resend.com/emails
MAIL_API_KEY=...
[email protected]

Переменные не заданы — письма складываются в журнал (results/commitments/outbox.json) с пометкой «не отправлено: почта не настроена», и в интерфейсе видно, кому и что ушло бы. Это честное состояние, а не тишина. В развёрнутой демо-версии почта не настроена.

Как пользоваться

Откройте https://app.aibots.kz. Подробно, с экранами — в руководстве пользователя.

Запись совещания прямо в браузере. Нажмите «Начать запись» — участникам проиграется предупреждение о том, что ведётся запись и транскрибация с помощью ИИ, сначала на казахском, затем на русском. По кнопке «Остановить» запись уходит в обработку.

Или загрузите готовый файл. Перетащите запись в зону загрузки: mp3, m4a, mp4, wav, ogg, flac, webm.

Приложите субтитры Zoom, если они есть. После выбора записи появится строка «Приложить .vtt». Субтитры необязательны, но меняют результат заметно: из них берутся настоящие имена участников, и в поручениях вместо «Говорящий 2» стоит фамилия ответственного. Без субтитров говорящие различаются по голосу и остаются безымянными, а различить модель умеет не больше четырёх.

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

Вкладка «Контроль поручений» собирает поручения всех совещаний и раскладывает их по статусу: в работе, просрочено, выполнено. Впишите почту ответственного в строке поручения и нажмите «Проверить сроки» — система отправит напоминания по тем, у кого срок на подходе или уже прошёл. Это Сценарий 2 из кейса.

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

Как работает

  1. Секретарь загружает файл или включает запись с микрофона прямо в интерфейсе. К записи можно приложить субтитры Zoom — тогда имена говорящих берутся из них. Перед началом проигрывается голосовое предупреждение участникам о том, что ведётся запись и транскрибация с помощью ИИ — на казахском и русском (front/public/audio-warnings/). Запись попадает в MinIO.
  2. В Kafka уходит RecognitionRequest с идентификатором сообщения и ссылкой на папку.
  3. Обработчик забирает файлы, конвертирует в MP3 и распознаёт речь целиком, с пословными метками времени.
  4. Та же запись отдельно диаризуется. Каждое слово приписывается тому, кто говорил в его середине: на стыке реплик начало слова часто попадает в хвост предыдущего говорящего.
  5. Склеенный транскрипт уходит в LLM, которая выделяет поручения с ответственным и сроком и собирает саммари.
  6. transcript.json и summary.md возвращаются в ту же папку MinIO, в Kafka уходит RecognitionResponse. Интерфейс показывает протокол и отдаёт файл.

Технологии

СлойЧто используется
Распознавание речиfaster-whisper на CTranslate2; два маршрута: общий (ru, en) и казахский (собственная дообученная модель)
Диаризацияnvidia/diar_streaming_sortformer_4spk-v2, эмбеддер голоса titanet_large
Шлюз речевых службCaddy, один Bearer-токен на все ручки
ОбработчикPython, ffmpeg, Kafka-консьюмер, pydantic-контракты
ТранспортApache Kafka (топики запросов и ответов), MinIO (файлы)
Разбор транскриптаQwen3.8-27B-FP8 на vLLM, развёрнута на vllm.aibots.kz
ИнтерфейсNext.js (App Router), Tailwind v4, каталог front/
ИнфраструктураDocker Compose, Traefik с Let's Encrypt, IaC-документация в infrastructure/ansible/

Архитектура

front/  ──① запись──►  MinIO  uploads/<meeting_id>/
  │                      ▲
  │ ② meetings.uploaded  │ ⑤ result.json
  ▼                      │
Kafka                    │
  │ ③                    │
  ▼                      │
services/adapter ──► meeting-copilot-container ─┘
  ├──► stt.aibots.kz  /v1/audio/transcriptions   распознавание
  ├──► stt.aibots.kz  /v1/audio/diarize          диаризация
  └──► vllm.aibots.kz /v1/chat/completions       поручения и саммари
  │
  └──⑥ meetings.ready | meetings.failed ──► front/
КомпонентКаталогРоль
Веб-интерфейсfront/загрузка файла и запись с микрофона, субтитры Zoom, голосовое предупреждение участникам, статусы обработки, протокол, контроль поручений с напоминаниями, экспорт в DOCX и PDF
Доставка записей Zoomservices/zoom-ingest/забирает облачные записи и входит во встречу участником; отдаёт то же событие meetings.uploaded
Адаптер контрактовservices/adapter/переводит события интерфейса в формат обработчика и собирает result.json
Обработчикmeeting-copilot-container/Kafka-консьюмер: распознавание, диаризация, склейка, разбор
Речевые службыspeech_stack/исходники ASR, диаризации и шлюза
Транспорт и развёртываниеinfrastructure/Kafka, MinIO, Traefik, IaC-документация
Утилиты и замерыtools/извлечение поручений, бенчмарки распознавания

Речевые службы: stt.aibots.kz

Собственный стек, исходники в speech_stack/, развёрнут на машине с NVIDIA GPU. Три службы за одним шлюзом и одним токеном.

РучкаНазначениеТокен
GET /healthпроба распознаванияне нужен
GET /health/diarпроба диаризациине нужен
POST /v1/audio/transcriptionsречь → текст, OpenAI-совместимонужен
POST /v1/audio/diarizeкто когда говорилнужен
GET /v1/modelsсписок моделейнужен
POST /v1/audio/identify, /v1/audio/verify, /v1/speakersопознание говорящего по образцунужен

Авторизация — Authorization: Bearer $STT_TOKEN. Неизвестные пути тоже отвечают 401, поэтому снаружи не виден даже состав ручек.

Параметры распознавания, которые влияют на результат:

ПолеЗначение
response_formatverbose_json — даёт пословные метки времени, без них склейка с диаризацией невозможна
languageru | kk | en | auto; auto возвращает route и detected_language
hotwordsсписок собственных имён через запятую, повышает точность ФИО

Замеры на записи 4 мин 34 с (русский), артефакты в docs/TASK/records/artifacts/:

ШагВремяРезультат
Распознавание19.5 с61 сегмент, 567 слов с метками, маршрут general:whisper-v6-ct2
Диаризация2.5 с55 сегментов, 4 голоса
Склейкамгновенно30 реплик с говорящими и таймкодами

Языковая модель: vllm.aibots.kz

Qwen3.8-27B-FP8 под vLLM, OpenAI-совместимый интерфейс. Развёрнута на той же GPU-машине, что и речевые службы. Разбор транскрипта идёт здесь, поэтому текст совещания не покидает контур — этого требует раздел «Ограничения» кейса.

from openai import OpenAI
client = OpenAI(base_url="https://vllm.aibots.kz/v1", api_key=os.environ["VLLM_API_KEY"])

Имя модели — qwen3-vl-30b-instruct. Алиас исторический и оставлен намеренно: его уже знают существующие потребители.

ПараметрЗначение
Контекст65 536 токенов на запрос
Одновременных запросов6, седьмой встаёт в очередь
KV-кэшfp8, доля карты 0.65
GET /health200 без токена
GET /v1/models без токена401

Карта общая с распознаванием, диаризацией и синтезом: тяжёлый прогон разбора замедляет расшифровку. Ограничения частоты нет, единственная защита — токен, поэтому он приходит из окружения и никогда не попадает ни в репозиторий, ни в код, исполняемый в браузере.

Замер на транскрипте тестовой записи: 58 с, извлечено 10 поручений с ответственным и сроком, результат в docs/TASK/records/artifacts/commitments.json.

Установка и запуск

Инфраструктура (Kafka, MinIO)

cd infrastructure
./local-up.sh

Скрипт создаёт .env, поднимает сервисы, дожидается готовности, проверяет что топики и бакет созданы, и печатает адреса с паролями. Это единственная точка входа для инфраструктуры: отдельного compose в корне репозитория нет.

Речевые службы

Разворачиваются на машине с NVIDIA GPU:

cd speech_stack
cp .env.example .env
openssl rand -hex 32          # положить в STT_TOKEN
docker compose up -d --build

Первая сборка долгая: веса распознавания конвертируются в формат CTranslate2 внутри образа, веса диаризации тянутся при первом старте.

Обработчик

cd meeting-copilot-container
cp .env.example .env          # адреса Kafka и MinIO, токены речевых служб и модели
docker compose up -d --build

Веб-интерфейс

cd front
npm install
npm run dev                   # http://localhost:3000

Как проверить решение

Самый короткий путь — открыть развёрнутую версию

  1. Откройте https://app.aibots.kz.
  2. Перетащите в зону загрузки любую запись совещания. В репозитории лежат две готовые: docs/TASK/records/.
  3. Дождитесь обработки — на записи 4 мин 34 с это примерно минута.
  4. Проверьте протокол: транскрипт разделён по говорящим с таймкодами, в таблице поручений есть ответственный, срок и классификация, внизу саммари.
  5. Нажмите выгрузку в DOCX и PDF — файлы скачиваются из браузера.

Эталон того, что должно получиться, лежит в репозитории: docs/TASK/records/artifacts/ — сырые ответы распознавания и диаризации, собранный протокол и разобранные поручения.

Проверка служб по отдельности

Проба живости речевых служб — доступна без токена:

curl -s https://stt.aibots.kz/health
curl -s https://stt.aibots.kz/health/diar

Ответ содержит состав загруженных моделей и устройство.

Сквозной прогон одной записи, от файла до протокола с говорящими:

export STT_TOKEN=...
cd speech_stack
./tools/example.sh "../docs/TASK/records/Совещание №1.mp3" "Совещание №1" > протокол.md

Эталонный результат такого прогона лежит в репозитории и его можно сверить: docs/TASK/records/artifacts/protocol.md, рядом — сырые ответы распознавания и диаризации.

Распознавание смешанной речи: ничего не настраивать

curl -H "Authorization: Bearer $STT_TOKEN" \
     -F file=@запись.mp3 -F language=auto -F response_format=verbose_json \
     https://stt.aibots.kz/v1/audio/transcriptions

language=auto — и всё. Детектор сам уводит смешанную речь на казахский маршрут: на 31 записи из 31, без единого промаха. Указывать kk вручную не нужно, результат тот же.

Чего делать нельзя: ставить language=ru на том основании, что половина слов русские. Это ровно вдвое хуже — 0.1147 против 0.0511.

Проверить это утверждение на публичных данных:

huggingface-cli download Tim2190/kazakh-codeswitch-asr \
    --repo-type dataset --local-dir ./kazakh-codeswitch-asr
export STT_TOKEN=...
python3 tools/bench_shala.py kk ru auto

Извлечение поручений из готового протокола:

export VLLM_API_KEY=...
python3 tools/extract_commitments.py \
    docs/TASK/records/artifacts/protocol.md /tmp/commitments.json

Эталон — docs/TASK/records/artifacts/commitments.json: 10 поручений с ответственным, сроком в ISO и дословной цитатой назначения.

Данные и интеграции

  • Тестовые записи совещаний: docs/TASK/records/. Записи смоделированные, что допускается условиями кейса.
  • Речевые службы: собственный стек stt.aibots.kz, исходники в репозитории.
  • Языковая модель: собственная vllm.aibots.kz, развёрнута на своей GPU-машине.
  • Транспорт: Kafka и MinIO, поднимаются из infrastructure/.

Записи Zoom: services/zoom-ingest/

Два режима, и оба отдают одно и то же событие meetings.uploaded — дальше конвейер не знает, откуда пришла запись, и разбор идёт одинаково.

poll — облачные записи постфактум (демон, docker compose up -d --build). Server-to-Server OAuth (ZOOM_ACCOUNT_ID, ZOOM_CLIENT_ID, ZOOM_CLIENT_SECRET) к Zoom Cloud Recording API. Проход каждые ZOOM_POLL_INTERVAL_SEC (120 с) по записям за ZOOM_LOOKBACK_DAYS (1 день) у хоста ZOOM_USER_ID; пусто — по всем пользователям аккаунта. Из recording_files берётся по одному файлу на вид, только status=completed: аудио M4A (видео MP4 как замена, если аудио не отдано) и TRANSCRIPT — субтитры VTT, из которых потом берутся имена участников. Файлы кладутся в MinIO как recordings/<meeting_id>/audio.m4a и transcript.vtt, где meeting_id = zoom-<id совещания>-<UTC ГГГГММДДTЧЧММСС> — он выводится из данных Zoom, поэтому повторный проход по той же записи даёт тот же идентификатор.

bot — участник встречи (docker compose run --rm zoom-bot "<ссылка>" --name "..."). Chromium без окна (Playwright) входит в веб-клиент Zoom, звук встречи уходит в null-sink PulseAudio, ffmpeg пишет его monitor. По окончании встречи или по истечении --max-minutes (по умолчанию 180) файл уезжает в recordings/zoom-live-<id>-<ts>/live.webm и публикуется то же событие. Микрофона у бота нет: записывается только то, что звучит во встрече. Хост должен пустить бота из зала ожидания; самое хрупкое место — селекторы веб-клиента Zoom, они меняются на стороне Zoom.

Повторов не будет, потерь тоже. Обработанные uuid записей лежат в state.json бакета zoom-ingest. Запись помечается обработанной только когда аудио действительно скачано: если Zoom ещё рендерит файл и download_url не отдан, uuid остаётся непомеченным и запись забирается на следующем проходе. Упавший проход не убивает демон — traceback в лог и повтор через интервал.

Связка с остальным стеком: общая сеть meeting-copilot_web, KAFKA_BROKERS=kafka:9092, MINIO_ENDPOINT=minio:9000; бакеты recordings и zoom-ingest создаёт mc-init. На очереди — вебхук recording.completed вместо опроса (ZOOM_WEBHOOK_SECRET_TOKEN уже заложен в конфиг).

  • Внешние платные API распознавания не используются.

Ограничения

  • Рассылка напоминаний работает без почтового провайдера в режиме журнала. Логика сроков, дедупликации и статусов проверена на живых данных, но письма никуда не уходят, пока не заданы MAIL_API_URL, MAIL_API_KEY и MAIL_FROM. Адрес ответственного вводится руками: в записи совещания почты нет, а угадывать её по имени нельзя.
  • Имена участников без субтитров не определяются. Диаризация различает голоса, но не знает, кому они принадлежат, поэтому в протоколе стоят «Говорящий 1», «Говорящий 2». С приложенными субтитрами Zoom имена настоящие. Определение имён по тексту разговора (по обращениям и назначениям поручений) проверено отдельно, но в конвейер не подключено.
  • Диаризующая модель различает ровно четыре голоса. Пятый участник сливается с одним из четырёх; это архитектура модели, а не настройка. В тестовой записи названы пятеро участников и получено четыре ярлыка.
  • Шала-казахский замерен на публичном корпусе Tim2190/kazakh-codeswitch-asr (31 запись, человеческая дословная расшифровка): pooled CER 0.0511 с language=auto. Замер включает контроли — пустая гипотеза 1.0000, бессмыслица 0.9486, чужой эталон 0.9306, — то есть стенд умеет провалиться, и число не пустое. Корпус состоит из стендапа: чистая запись, близкий микрофон. На телефонной полосе, в зале с эхом или при перебиваниях число будет хуже, и насколько — мы не знаем.
  • Разговорные стяжения приводятся к литературной форме (болад → болады). Для протокола совещания это скорее плюс, но дословной записи не даёт. Ошибки сосредоточены на стыке языков — казахская вставка в русской фразе и первые слова после переключения. Реальная телефонная речь с шумом и перебиваниями не замерялась, методика и границы — в docs/TASK/records/kk/.
  • Опознание говорящего по тембру развёрнуто, но образцов голосов не зарегистрировано, поэтому имена в протоколе не проставляются автоматически.
  • Поле duration в ответе распознавания занижено; фактическая длительность считается по данным, см. speech_stack/tools/merge_transcript.py.
  • Формат AAC (.m4a) не декодируется напрямую, требуется конвертация в MP3.
  • Языковая модель и речевые службы делят одну видеокарту: параллельная нагрузка замедляет оба тракта. Потолок — шесть одновременных запросов к модели.
  • Разбор транскрипта пятиминутной записи занимает около минуты.
  • Полноценная интеграция с СЭД и промышленное развёртывание в объём работ не входили.

Дальнейшее развитие

Что известно как незакрытое и что с этим делать дальше — по убыванию отдачи.

Поиск по архиву совещаний (RAG). Протоколы, транскрипты и поручения копятся в MinIO, но каждое совещание пока живёт само по себе. Если сложить их в векторный индекс, поверх архива можно отвечать на вопросы, ради которых сейчас перечитывают протоколы руками: «что решили по этому поставщику», «какие поручения давали департаменту за квартал», «чем закончилось прошлое обсуждение». Второе применение полезнее первого: подставлять найденное прямо в разбор новой записи — тогда модель видит, что тема тянется с прошлой встречи, не заводит поручение-дубль и подхватывает принятые ранее формулировки и названия. Требование «текст не покидает контур» при этом сохраняется: и эмбеддинги, и генерация считаются на своей GPU-машине, рядом с vllm.aibots.kz.

Диаризация по сотрудникам: нужны образцы голоса. Служба опознания по тембру развёрнута (/v1/audio/identify, /v1/speakers, модель titanet_large), но образцов голосов не зарегистрировано, поэтому имена подставляются только из субтитров Zoom, а на записи с телефона или из переговорной остаются ярлыки «Говорящий 1». Достаточно разового сбора образцов сотрудников — дальше диаризация перестаёт быть безымянной: ярлык связывается с конкретным человеком, имя в поручении берётся из голоса, столбец «уверенность» перестаёт быть низким на обычных записях, а один и тот же сотрудник опознаётся от совещания к совещанию, что открывает сводку поручений по людям без ручной разметки.

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

Совещания больше четырёх голосов. Диаризация работает моделью sortformer_4spk — четыре голоса это её потолок, пятый приклеивается к кому-то из первых четырёх. Для совещаний на 8–10 человек нужна другая модель или кластеризация по эмбеддингам titanet_large, которая уже развёрнута рядом.

Поручение живёт в системе, где его ведут. Сейчас поручения хранятся в MinIO и показываются в дашборде. Отдача появится, когда они уезжают в СЭД, Jira или Bitrix — туда, где сотрудник и так смотрит задачи. Разбор уже отдаёт структуру (text, assignee, due_date, classification), так что это адаптер, а не переделка.

Почта в корпоративный контур. Транспорт напоминаний настраивается переменными (MAIL_API_URL, MAIL_API_KEY, MAIL_FROM); без настройки письма копятся в журнале results/commitments/outbox.json. Нужен корпоративный SMTP и отметка о выполнении по ссылке из письма, чтобы исполнитель закрывал поручение не заходя в интерфейс.

Доменная лексика. Шала-казахский замерен на публичном корпусе с человеческой расшифровкой (CER 0.0511). Банковская речь — номера договоров, названия продуктов, фамилии — в замер не попадала. Дальше нужны реальные записи созвонов и дообучение на них; маршрут для собственной модели в распознавании уже есть.

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

Разделение нагрузки. Языковая модель и речевые службы делят одну видеокарту, потолок — шесть одновременных запросов. Для потока совещаний это разные карты и очередь с приоритетами, а не одна машина.

Обработка по ходу встречи. Сейчас запись обрабатывается файлом целиком: протокол готов через минуту после конца. Потоковое распознавание дало бы черновик поручений уже во время совещания — можно поправить формулировку, пока участники не разошлись.

Ссылка на развёрнутую версию

Приложение: https://app.aibots.kz — загрузка записи, транскрипт с говорящими, поручения, саммари, выгрузка протокола.

КомпонентАдресОткрытая проба
Приложениеhttps://app.aibots.kz/
Речевые службыhttps://stt.aibots.kz/health, /health/diar
Языковая модельhttps://vllm.aibots.kz/health

Замер на развёрнутом стенде: запись 4 мин 34 с проходит путь целиком примерно за 60 секунд и даёт 30 реплик, 4 говорящих, 10 поручений со сроками и саммари.

Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
76
Авторы
4
Файлы
202
Ветки
5

Авторы коммитов

sergeyshmagin 40Astrohaker 18russkycloud 13russkycloud 5

История коммитов

  • 2026-09-23 17:55Merge branch 'readme'Astrohaker
  • 2026-09-23 17:54README: три языка перевода, RAG и диаризация по сотрудникамAstrohaker
  • 2026-09-23 17:50Печатный протокол: поля страницы, выключка, разрывыsergeyshmagin
  • 2026-09-23 17:47README: доставка записей Zoomsergeyshmagin
  • 2026-09-23 17:46Документация: AI-перевод, раздел дальнейшего развитияsergeyshmagin
  • 2026-09-23 17:45Merge remote-tracking branch 'origin/feature/front'sergeyshmagin
  • 2026-09-23 17:42Перевод в фоне, сохранение языка, починка таблицы порученийsergeyshmagin
  • 2026-09-23 17:41Merge branch 'zoom_ingest' into feature/frontrusskycloud
Все коммиты (76)
  • 2026-09-23 17:38Merge remote-tracking branch 'origin/main' into feature/frontrusskycloud
  • 2026-09-23 17:35zoom-ingest: не помечать запись обработанной, если аудио не скачаноrusskycloud
  • 2026-09-23 17:33Merge remote-tracking branch 'origin/meeting-copilot-container'sergeyshmagin
  • 2026-09-23 17:33Merge remote-tracking branch 'origin/zoom_ingest'sergeyshmagin
  • 2026-09-23 17:32Перевод протокола на своей модели; выравнивание Word; высота колонокsergeyshmagin
  • 2026-09-23 17:28services/zoom-ingest: записи Zoom в конвейер — поллер Cloud Recording API и бот-участникrusskycloud
  • 2026-09-23 17:26Руководство пользователя со скриншотами; форматирование саммариsergeyshmagin
  • 2026-09-23 17:23README: что фиксируется по каждому поручениюAstrohaker
  • 2026-09-23 17:18Контроль поручений: хранение и напоминания о сроках (Сценарий 2)sergeyshmagin
  • 2026-09-23 17:11Прогресс переживает обновление страницы; длинные записи режутся на кускиsergeyshmagin
  • 2026-09-23 17:01Субтитры Zoom в интерфейсе: имена участников вместо ярлыковsergeyshmagin
  • 2026-09-23 16:54Адаптер: время числом и читаемые ярлыки говорящихsergeyshmagin
  • 2026-09-23 16:48Merge branch 'main' of https://github.com/BAITC-Hacks/hack-47bd9c8d-dbk-teamsergeyshmagin
  • 2026-09-23 16:47Документация приведена в соответствие с реализациейsergeyshmagin
  • 2026-09-23 16:46Merge remote-tracking branch 'origin/meeting-copilot-container'sergeyshmagin
  • 2026-09-23 16:46Merge remote-tracking branch 'origin/feature/front'sergeyshmagin
  • 2026-09-23 16:43Merge branch 'meeting-copilot-container'Astrohaker
  • 2026-09-23 16:42адаптер: классификация поручений в контракте для интерфейсаAstrohaker
  • 2026-09-23 16:41Merge pull request #5 from BAITC-Hacks/feature/frontrusskycloud
  • 2026-09-23 16:40Merge branch 'main' into meeting-copilot-containerAstrohaker
  • 2026-09-23 16:40front: предупреждение о записи сначала на казахскомrusskycloud
  • 2026-09-23 16:39README: ссылка на развёрнутое приложениеsergeyshmagin
  • 2026-09-23 16:37front: контроль поручений (Сценарий 2), целостность записи, предупреждения rus/kaz, фиксы критикиrusskycloud
  • 2026-09-23 16:36поручения: колонка классификации по срочности и направлениюAstrohaker
  • 2026-09-23 16:30Адаптер: разбор таблицы поручений и сведение бакетовsergeyshmagin
  • 2026-09-23 16:18compose: убран дубль KAFKA_INTER_BROKER_LISTENER_NAME после мержаsergeyshmagin
  • 2026-09-23 16:18Merge branch 'main' of https://github.com/BAITC-Hacks/hack-47bd9c8d-dbk-teamsergeyshmagin
  • 2026-09-23 16:17Серверный оверлей compose для docker-serversergeyshmagin
  • 2026-09-23 16:17Merge remote-tracking branch 'origin/feature/front'sergeyshmagin
  • 2026-09-23 16:17Адаптер контрактов между интерфейсом и обработчикомsergeyshmagin
  • 2026-09-23 16:17Merge remote-tracking branch 'origin/meeting-copilot-container'sergeyshmagin
  • 2026-09-23 16:12composerusskycloud
  • 2026-09-23 16:09Merge pull request #4 from BAITC-Hacks/feature/frontrusskycloud
  • 2026-09-23 16:08front: живая запись с микрофона (Сценарий 1) — чанки в MinIO, событие в Kafkarusskycloud
  • 2026-09-23 16:00Merge branch 'meeting-copilot-container'Astrohaker
  • 2026-09-23 15:59Merge branch 'main' into meeting-copilot-containerAstrohaker
  • 2026-09-23 15:57README: правило распознавания смешанной речи в разделе проверкиsergeyshmagin
  • 2026-09-23 15:55speech: подключение к своему стеку распознавания и диаризацииAstrohaker
  • 2026-09-23 15:55Суммаризация переведена на свою модельsergeyshmagin
  • 2026-09-23 15:54Merge branch 'meeting-copilot-container': экспорт PDF и поручения в саммариsergeyshmagin
  • 2026-09-23 15:54Merge branch 'feature/front': редизайн интерфейсаsergeyshmagin
  • 2026-09-23 15:52Порядок в документации: убраны заглушки, битое и устаревшееsergeyshmagin
  • 2026-09-23 15:49front: редизайн в институциональной теме sk.kz (navy + бронза, светлый фон)russkycloud
  • 2026-09-23 15:47Шала-казахский: замер на публичном корпусе с человеческой расшифровкойsergeyshmagin
  • 2026-09-23 15:43Замер на шала-казахском: серии прогонов вместо одиночныхsergeyshmagin
  • 2026-09-23 15:41Merge branch 'main' into meeting-copilot-containerAstrohaker
  • 2026-09-23 15:36README: результаты замера на казахском и шала-казахскомsergeyshmagin
  • 2026-09-23 15:36Замер распознавания на казахском и шала-казахскомsergeyshmagin
  • 2026-09-23 15:30Merge pull request #3 from BAITC-Hacks/feature/frontrusskycloud
  • 2026-09-23 15:29summary: раздел с поручениями и экспорт в PDFAstrohaker
  • 2026-09-23 15:28Извлечение поручений на своей модели: vllm.aibots.kzsergeyshmagin
  • 2026-09-23 15:26front: веб-интерфейс meeting-copilot (загрузка, статусы, протокол, экспорт)russkycloud
  • 2026-09-23 15:26README проекта: 11 разделов по требованиям организаторовsergeyshmagin
  • 2026-09-23 15:13data: тестовые записи совещаний в gitAstrohaker
  • 2026-09-23 15:08Сквозной прогон записи: расшифровка, диаризация, протоколsergeyshmagin
  • 2026-09-23 15:01Merge branch 'meeting-copilot-container'Astrohaker
  • 2026-09-23 15:01infrastructure: локальный запуск Kafka и MinIO одной командойAstrohaker
  • 2026-09-23 14:58speech_stack: собственные службы распознавания и диаризацииsergeyshmagin
  • 2026-09-23 14:54Merge pull request #2 from BAITC-Hacks/feature/frontrusskycloud
  • 2026-09-23 14:53sterring frontrusskycloud
  • 2026-09-23 14:47Merge branch 'meeting-copilot-container'Astrohaker
  • 2026-09-23 14:46Merge pull request #1 from BAITC-Hacks/feature/frontrusskycloud
  • 2026-09-23 14:45README: архитектура и взаимодействие через Kafka и MinIOAstrohaker
  • 2026-09-23 14:42infrastructure: локальный MVP-стек (compose+traefik+LE) и IaC-документацияrusskycloud
  • 2026-09-23 14:36Постановка кейса, контракт команды и раскладка задачsergeyshmagin
  • 2026-09-23 14:27inital copilotAstrohaker
  • 2026-09-23 13:52infrarusskycloud
  • 2026-09-23 12:11DBK team — HackAlem infrastructure stacksergeyshmagin
Структура репозитория (202 файлов)
.codex/hooks.json
.env.example
.gitignore
.planning/config.json
.planning/tasks/CONTRACT.md
.planning/tasks/anton.md
.planning/tasks/ruslan.md
.planning/tasks/sergey.md
README.md
docs/GUIDE.md
docs/TASK/records/artifacts/asr1.json
docs/TASK/records/artifacts/commitments.json
docs/TASK/records/artifacts/diar1.json
docs/TASK/records/artifacts/protocol.md
docs/TASK/records/kk/README.md
docs/TASK/records/kk/shala-kazakh.md
docs/TASK/records/Совещание №1.mp3
docs/TASK/records/Совещание №2.mp3
docs/TASK/task.md
docs/designs/meeting-protocol-agent.md
docs/guide/01-main.png
docs/guide/02-commitments.png
docs/guide/03-protocol.png
docs/tecspec/zoom-cloud-recording.md
docs/Активация OpenAI и NVIDIA для участников HackAlem AI.pdf
docs/Инструкция для участников_Онлайн-курс Arizona State University.pdf
docs/Инструкция по кибербезопасности.pdf
docs/Инструкция по подготовке оборудования для участия в хакатоне.pdf
docs/Инструкция_для_участников_HackAlem_AI.pdf
docs/Инструкция_для_участников_HackAlem_AI.txt
docs/Правила зачета участия.pdf
front/.dockerignore
front/.env.example
front/.gitignore
front/DESIGN.md
front/Dockerfile
front/PRODUCT.md
front/README.md
front/app/api/commitments/notify/route.ts
front/app/api/commitments/route.ts
front/app/api/health/route.ts
front/app/api/meetings/[id]/cancel/route.ts
front/app/api/meetings/[id]/chunk/route.ts
front/app/api/meetings/[id]/finish/route.ts
front/app/api/meetings/[id]/result/route.ts
front/app/api/meetings/[id]/status/route.ts
front/app/api/meetings/[id]/translate/route.ts
front/app/api/meetings/route.ts
front/app/api/meetings/start/route.ts
front/app/globals.css
front/app/layout.tsx
front/app/page.tsx
front/components/commitments-dashboard.tsx
front/components/commitments-table.tsx
front/components/export-buttons.tsx
front/components/language-switcher.tsx
front/components/live-recorder.tsx
front/components/markdown-blocks.tsx
front/components/meeting-progress.tsx
front/components/meeting-result.tsx
front/components/printable-protocol.tsx
front/components/recording-notice.tsx
front/components/summary-view.tsx
front/components/transcript-view.tsx
front/components/ui/badge.tsx
front/components/ui/button.tsx
front/components/ui/card.tsx
front/components/ui/skeleton.tsx
front/components/upload-zone.tsx
front/components/warnings-banner.tsx
front/docker-compose.local.yml
front/docker-compose.yml
front/instrumentation.ts
front/lib/active-meeting.ts
front/lib/commitments-store.ts
front/lib/config.ts
front/lib/export-docx.ts
front/lib/kafka.ts
front/lib/languages.ts
front/lib/markdown.ts
front/lib/minio.ts
front/lib/notifications.ts
front/lib/recording-sessions.ts
front/lib/store.ts
front/lib/translate.ts
front/lib/types.ts
front/lib/utils.ts
front/mock/sample-result.json
front/next.config.ts
front/package-lock.json
front/package.json
front/postcss.config.mjs
front/public/.gitkeep
front/public/audio-warnings/kaz.mp3
front/public/audio-warnings/rus.mp3
front/tsconfig.json
infrastructure/.env.example
infrastructure/README.md
infrastructure/ansible/README.md
infrastructure/ansible/docs/00-architecture.md
infrastructure/ansible/docs/01-kafka.md
infrastructure/ansible/docs/02-minio.md
infrastructure/ansible/docs/03-meeting-copilot.md
infrastructure/ansible/docs/04-copilot-ui.md
infrastructure/docker-compose.local.yml
infrastructure/docker-compose.server.yml
infrastructure/docker-compose.yml
infrastructure/env.local.example
infrastructure/kafka/kafka-init.sh
infrastructure/local-up.sh
infrastructure/minio/copilot-uploads-rw.json
infrastructure/minio/mc-init.sh
meeting-copilot-container/.dockerignore
meeting-copilot-container/.env.example
meeting-copilot-container/.gitignore
meeting-copilot-container/.gitlab-ci.yml
meeting-copilot-container/Dockerfile
meeting-copilot-container/Dockerfile.service
meeting-copilot-container/README.md
meeting-copilot-container/audio_utils.py
meeting-copilot-container/check_health_services.py
meeting-copilot-container/chunked_transcribe.py
meeting-copilot-container/config.py
meeting-copilot-container/data/Совещание №1.mp3
meeting-copilot-container/data/Совещание №2.mp3
meeting-copilot-container/docker-compose.yml
meeting-copilot-container/entrypoint.sh
meeting-copilot-container/export_pdf.py
meeting-copilot-container/kafka_service.py
meeting-copilot-container/main.py
meeting-copilot-container/merge_transcript.py
meeting-copilot-container/model/generate_examples.py
meeting-copilot-container/model/models.py
meeting-copilot-container/requirements.txt
meeting-copilot-container/summarize_transcript.py
meeting-copilot-container/transcribers/__init__.py
meeting-copilot-container/transcribers/base.py
meeting-copilot-container/transcribers/factory.py
meeting-copilot-container/transcribers/kdb_whisper.py
meeting-copilot-container/transcribers/models.py
meeting-copilot-container/transcribers/speech_stack.py
services/adapter/Dockerfile
services/adapter/adapter.py
services/zoom-ingest/.env.example
services/zoom-ingest/Dockerfile
services/zoom-ingest/Dockerfile.bot
services/zoom-ingest/README.md
services/zoom-ingest/docker-compose.yml
services/zoom-ingest/docker/bot-entrypoint.sh
services/zoom-ingest/requirements.txt
services/zoom-ingest/tests/test_zoom_ingest.py
services/zoom-ingest/zoom_ingest/__init__.py
services/zoom-ingest/zoom_ingest/__main__.py
services/zoom-ingest/zoom_ingest/bot.py
services/zoom-ingest/zoom_ingest/config.py
services/zoom-ingest/zoom_ingest/events.py
services/zoom-ingest/zoom_ingest/poller.py
services/zoom-ingest/zoom_ingest/storage.py
services/zoom-ingest/zoom_ingest/zoom_client.py
speech_stack/.env.example
speech_stack/README.md
speech_stack/diarization/Dockerfile
speech_stack/diarization/app.py
speech_stack/diarization/config.py
speech_stack/diarization/diarize.py
speech_stack/diarization/models.py
speech_stack/diarization/requirements.txt
speech_stack/diarization/speakers.py
speech_stack/docker-compose.yml
speech_stack/gateway/Caddyfile
speech_stack/stt/Dockerfile
speech_stack/stt/app.py
speech_stack/stt/asr_models.py
speech_stack/stt/audio.py
speech_stack/stt/config.py
speech_stack/stt/decode.py
speech_stack/stt/download_models.py
speech_stack/stt/test_artefact_filter.py
speech_stack/tools/example.sh
speech_stack/tools/merge_transcript.py
tools/agents_smoke.py
tools/bench_shala.py
tools/council.py
tools/deploy.sh
tools/dev-workflow-setup.sh
tools/dev-workflow/AGENTS.md
tools/dev-workflow/HACKATHON.md
tools/dev-workflow/MODELS.md
tools/dev-workflow/README-TEMPLATE.md
tools/dev-workflow/TEAM-README.md
tools/dev-workflow/gbrain-sync.sh
tools/dev-workflow/god-file-warn.py
tools/dev-workflow/skill/SKILL.md
tools/dev-workflow/skills/steering/SKILL.md
tools/dev-workflow/skills/steering/scripts/steering.py
tools/dev-workflow/ssh-config
tools/eval_asr.py
tools/extract_commitments.py
tools/hackathon-setup.sh
tools/hackathon-watcher.sh
tools/litellm.yaml
tools/llm-bridge.sh
Ветки (5)

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.