О проекте
Команда: menteTeam
Кейс HackAlem.ai: Инновации — Самрук-Казына
Стадия: Рабочий MVP
Задача кейса: «Хаттама»: протокол и поручения по аудиозаписи совещания (каз./рус./смешанная речь)
Суть
Локальный ассистент совещаний: аудио (файл/микрофон/вкладка Zoom/Meet) → стенограмма со спикерами → протокол с проверяемыми цитатами и таблицей поручений → контроль исполнения.
Как устроено
faster-whisper large-v3 (int8_float16 на T4) распознаёт речь с автоопределением языка только среди kk/ru/en на каждом 30-секундном окне, pyannote Community-1 выполняет диаризацию. Gemma 4 E2B через transformers по фрагментам составляет саммари, показатели/проблемы и поручения с дословной цитатой; поручения без цитаты из стенограммы отбрасываются, остальные — черновики для проверки секретарём. Результаты хранятся в SQLite, экспорт DOCX/PDF/TXT/JSON/ICS; есть модуль безопасности (PII-детектор, prompt guard).
Ключевые решения
- faster-whisper
- pyannote diarization
- language restriction kk/ru/en
- grounding по цитатам
- chunked summarization
- PII detection
- prompt guard
- локальный offline inference
Особенности
Полностью локальный инференс без внешних API (Whisper + Gemma на одной T4 с освобождением VRAM), ограничение детектора языка тремя языками для шала қазақша, разделение говорящего и ответственного, отбрасывание поручений без подтверждающей цитаты.
Стек
Python · Streamlit · transformers · PyTorch · faster-whisper · SQLite · uv · Docker · GitHub Actions
Модели
Whisper large-v3 · Gemma 4 E2B · pyannote speaker-diarization-community-1
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-e8fa3f76-menteteam.
README
README.mdAlem Minutes
Встреча закончилась. Поручения остались. Локальный ассистент для совещаний на русском, казахском и смешанном языке: запись → стенограмма со спикерами → протокол с проверяемыми цитатами → контроль исполнения.
Whisper вызывается через Python API faster-whisper, Gemma — через transformers в том же процессе. Аудио и текст не отправляются во внешние inference API. Все задачи сначала становятся черновиками: секретарь проверяет имя, срок и цитату перед подтверждением.
Быстрый запуск
Нужны Python 3.12–3.13, uv и шрифт DejaVu Sans. Linux/WSL — основной проверяемый путь. Для мультимедиа и диаризации установите FFmpeg и libsndfile:
# Ubuntu / Debian
sudo apt-get install ffmpeg libsndfile1 fonts-dejavu-core
cp .env.example .env
./run-local.sh
Откройте http://127.0.0.1:8501. Основная конфигурация — NVIDIA T4, PyTorch 2.8 с CUDA 12.6. Нужны рабочий драйвер NVIDIA и доступ процесса к GPU (nvidia-smi). Gemma работает в FP16, Whisper — в int8_float16; перед переключением на Gemma модели распознавания освобождают VRAM. Gemma 4 E2B требует примерно 10 ГБ на диске; первое скачивание и загрузка занимают время. Отсутствие CUDA выводится как ошибка; явный CPU-режим: AI_DEVICE=cpu, WHISPER_COMPUTE=int8 (для Gemma FP32 потребуется больше 20 ГБ RAM). Для других ОС нужны соответствующие FFmpeg/шрифты; это не проверенная здесь конфигурация.
Для быстрой демонстрации интерфейса без весов и тяжёлых AI-зависимостей:
uv sync --locked
uv run --no-sync streamlit run app.py
Нажмите Открыть демонстрацию, затем вкладку Протоколы. Демонстрация использует явно обозначенную синтетическую смешанную стенограмму и заранее заданные поручения; она не выдаётся за результат запуска моделей.
Основной сценарий
- Уведомите участников о записи и ИИ-транскрибации, подтвердите право на обработку.
- Во вкладке Новое совещание (открывается первой) задайте дату и выберите файл, микрофон, запись вкладки или один из аудиопримеров. Для своего файла выберите Файл → Загрузить MP3 или другую запись: перетащите запись или нажмите Browse files. Допустимы MP3/WAV/M4A/FLAC/AAC/OGG/OPUS/MPGA/MP4/WebM/MPEG; максимум 200 МБ. Файл выбирается на вашем устройстве, обработка выполняется на сервере. После выбора доступны имя, размер и проигрыватель записи.
- Запустите анализ. По умолчанию используется Whisper
large-v3с точностьюint8_float16на GPU. Режим Авто: KZ / RU / EN · шала қазақша выбирает язык только средиkk,ru,enзаново на каждом окне Whisper (до 30 секунд). Для одноязычной записи можно вручную выбрать Қазақша, Русский или English. Шала қазақша обрабатывается как смешанная речь; режим транскрибации сохраняет исходные языки, а контекст предыдущего окна отключён, чтобы уменьшить перенос языка между окнами. Ограничение детектора не гарантирует точность текста или разделение языков внутри одной фразы; качество на вашей записи нужно измерить. Ранее сохранённые протоколы не меняются — запустите запись заново, старый кэш распознавания не используется. - В Протоколах над предпросмотром документа укажите имена и должности участников, прослушав образцы голосов. Нажмите Сохранить протокол и участников: одна кнопка сохраняет имена, роли, шапку, саммари и таблицу показателей. Говорящий и ответственный хранятся отдельно: фраза «Айжан, подготовь отчёт» не назначается говорящему.
- Проверьте цитаты и таймкоды, исправьте саммари/решения, ответственных, даты, срочность и направление поручений. Срок «завтра» / «ертең» считается от введённой даты; неоднозначные сроки требуют ручной проверки.
- Отметьте поручение проверенным, при необходимости укажите email. История, правки и статусы сохраняются в SQLite и переживают перезапуск.
- В Готовом протоколе проверьте документ по структуре
docs/meeting_minutes_2.txt: шапка с организацией и темой, Текст совещания, Саммари по ключевым пунктам с таблицей Направление / доклад — Показатель — Проблема, затем Поручения с единой таблицей Поручение / Ответственный / Срок. Должность указывается при первом появлении участника. Скачайте DOCX/PDF/TXT, JSON для импорта в СЭД или ICS для календаря. Решения, цитаты, таймкоды и статусы можно включить отдельным приложением. Для демонстрации доступна обезличенная копия; проверьте свободный текст перед публикацией. - В Обзоре поручений фильтруйте задачи по статусу, людям, направлению и совещанию. Просрочка определяется из даты и статуса выполнения.
Структура протокола по образцу
Gemma составляет общее саммари и извлекает направления докладов, показатели и проблемы с дословной цитатой. Приложение проверяет наличие цитаты в стенограмме и связывает докладчика с голосом, если цитата принадлежит одному спикеру. Подтверждённое имя автоматически появляется в таблице. Стенограмма сохраняется целиком в исходном порядке. Название организации вводится в форме, имена и должности подтверждаются пользователем; содержание образца не копируется в реальные встречи.
В форме Имена, должности и протокол → Шапка, саммари и таблица показателей можно исправлять, добавлять и удалять строки таблицы. Если проверка формы обнаружит пустую тему или направление, введённые имена и роли останутся в полях. Прежние протоколы открываются в новом оформлении. Кнопка Сохранить и сформировать таблицу показателей сначала сохраняет правки формы, затем заполняет таблицу по имеющейся стенограмме без повторного запуска Whisper; проверенные поручения сохраняются. Неподтверждённые цитатой числа отмечаются для ручной сверки. При ручном изменении докладчика, показателя или проблемы прежняя цитата отвязывается. Подтверждённая календарная дата попадает в колонку «Срок» вместе с исходной формулировкой. PDF и DOCX содержат настоящие таблицы с повторяющимися заголовками; в TXT колонки разделены табуляцией.
Диаризация и локальные веса
Для первого скачивания pyannote Community-1 примите условия модели и задайте HF_TOKEN с правом чтения в .env. После подготовки локальной копии токен не нужен для inference. Если диаризация недоступна, приложение явно показывает предупреждение и не утверждает, что спикеры распознаны.
Gemma 4 E2B загружается через AutoProcessor и AutoModelForMultimodalLM. Большая стенограмма обрабатывается ограниченными фрагментами; итоговое саммари объединяет их краткие содержания. Ответ проверяется схемой, а поручения без цитаты из реальной стенограммы отбрасываются. Совпадение цитаты не доказывает правильность её интерпретации — предусмотрена проверка человеком.
Подготовьте веса на машине с доступом к Hugging Face:
uv sync --locked --extra ai --extra diarization
uv run --no-sync python prepare_models.py
launch.py перед запуском добавляет CUDA-библиотеки из установленных wheel-пакетов в LD_LIBRARY_PATH, как требуется Faster-Whisper. Системный CUDA Toolkit не заменяет CUDA-сборку PyTorch.
Скрипт подготовки скачает модели в data/models и напечатает настройки. Укажите абсолютные пути, актуальные на целевой машине:
WHISPER_MODEL=/opt/alem/data/models/whisper-large-v3
GEMMA_MODEL=/opt/alem/data/models/gemma
DIARIZATION_MODEL=/opt/alem/data/models/diarization
ALEM_OFFLINE=1
В закрытый контур перенесите код, веса и подготовленные зависимости/образ. После подготовки запускайте без синхронизации зависимостей:
uv run --no-sync python launch.py
ALEM_OFFLINE=1 запрещает Hugging Face сетевую загрузку; модели должны быть доступны локально. run-local.sh выполняет синхронизацию пакетов и предназначен для первичной установки. Телеметрия Streamlit, Hugging Face и pyannote отключена в конфигурации проекта.
Teams, Zoom, Google Meet и live-аудио
Во вкладке Новое совещание → Teams / Zoom / Meet нажмите Открыть локальную запись. Локальная страница позволяет открыть проверенную ссылку платформы и записать звук выбранной вкладки через браузерный getDisplayMedia.
Войдите в веб-клиент участником «Alem Minutes — ведётся запись», отключите камеру/микрофон ассистента и дождитесь допуска организатора. Затем в Chrome/Edge выберите вкладку встречи и включите передачу её аудио. При необходимости добавьте свой микрофон. После остановки запись появится в списке live-записей; нажмите обновление и запустите анализ. Есть резервное скачивание аудио при сбое сохранения.
Это подключение с участием оператора: вход в аккаунт, выбор вкладки и допуск выполняются человеком. Автономный бот на официальных SDK платформ и потоковая выдача транскрипта во время записи не реализованы. Аудио захватывается вживую, анализ выполняется после остановки. Для настольного клиента платформы можно импортировать его запись; захват его системного звука зависит от ОС и браузера.
Сервис записи слушает только 127.0.0.1:8765, использует случайный токен, проверки Host/Origin, подтверждение записи и ограничение размера. Открывать эту страницу нужно на компьютере, где запущено приложение. Браузерный механизм описан в документации Chrome.
Автоматические напоминания и рассылка
Письма создаются только для проверенных незавершённых поручений с корректным email. Первое письмо содержит поручение и цитату; напоминания создаются ежедневно за три дня до срока и после просрочки. SQLite предотвращает повтор одного уведомления. Ошибка доставки допускает повторную попытку. При аварии между SMTP-доставкой и фиксацией в БД возможен повтор: получатель получает стабильный Message-ID.
По умолчанию worker сохраняет .eml локально и ничего не отправляет:
uv run --no-sync python notification_worker.py --interval 300
Настройте внутренний SMTP в .env и явно включите доставку:
SMTP_HOST=mail.internal.example
SMTP_PORT=587
[email protected]
SMTP_USER=minutes
SMTP_PASSWORD=replace-me
SMTP_STARTTLS=1
uv run --no-sync python notification_worker.py --send --interval 300
Вместо непрерывного процесса используйте cron/systemd с однократным запуском без --interval. Подготовленные локальные письма не подавляют последующую SMTP-рассылку: режимы имеют отдельные записи доставки. Уведомления не зависят от открытого Streamlit. Доступ к SMTP и адреса получателей настраивает заказчик; во время разработки реальные письма не отправлялись.
Архитектура
app.py / ui Streamlit: ввод, проверка, история, контроль
↓
services.pipeline сборка зависимостей и кэш
↓
application.process сценарий «запись → протокол»; интерфейсы ports
↓
core модели данных, цитаты, даты, правила ответственности
↑
adapters faster-whisper / pyannote / Transformers / SQLite
services.capture локальный приём live-записи из браузера
notification_worker.py независимая очередь писем и SMTP
exporters.py Unicode DOCX/PDF, JSON, ICS, обезличивание
Модели загружаются лениво; тяжёлые вызовы сериализованы. На переходах Whisper/pyannote ↔ Gemma предыдущие модели освобождаются, чтобы укладываться в память T4. Внутри этапа модель переиспользуется для всех фрагментов. Ядро не импортирует UI, модельные библиотеки или SQLite. Ключ кэша — SHA-256 содержимого записи и настроек, поэтому локальные пути моделей безопасны. Правки пользователя хранятся отдельно от кэша inference. Совещания и поручения имеют стабильные ID независимо от названий.
Проверки и воспроизводимость
./run-tests.sh
Фактические результаты, включая полный GPU-прогон, записаны в отчёте проверки.
Тесты не скачивают веса. Проверяются цитаты и таймкоды, RU/KZ сроки, атрибуция, кэш с локальными путями, SQLite, повторная доставка, HTTP-защита записи, Unicode-экспорт и сохранение правок через настоящий Streamlit AppTest. CI выполняет их на Python 3.12.
Для воспроизводимого прогона реального аудио:
uv run --no-sync python launch.py process_recording.py data/meeting1.mp3 \
--title 'Совещание 1' --date 2026-09-23 --language auto \
--output data/cache/review-meeting1.json --no-cache
Сопоставьте результат с эталонной расшифровкой, проверьте имена, пропущенные/лишние поручения и диаризацию. Качество русского, казахского и смешанного языка нельзя подтвердить только тестами бизнес-логики. Матрица требований и границ отделяет реализованные функции от интеграций, требующих окружения заказчика.
Данные и развёртывание
data/uploads — загрузки и live-записи; data/cache — исходные результаты inference; data/meetings.sqlite3 — история и правки; data/outbox — локальные письма; data/models — веса. Эти рабочие данные исключены из git. ALEM_DATA_DIR задаёт отдельный каталог. Реальные демонстрационные записи должны быть обезличены; поставляемые записи рассматривайте как данные, требующие проверки прав на использование.
Приложение рассчитано на секретаря на одном компьютере. Loopback не заменяет аутентификацию для совместного использования: для доступа по сети нужны аутентификация, TLS, разграничение доступа и резервные копии заказчика. Для чувствительных данных используйте шифрование диска и права ОС. Кнопка удаления очищает рабочую историю, кэш, загрузки и письма, сохраняя веса и поставляемые примеры; сначала остановите worker и запись.
Есть Dockerfile для подготовки CUDA-окружения. На хосте нужны драйвер NVIDIA и NVIDIA Container Toolkit. На Linux host networking сохраняет привязку обоих сервисов к loopback:
docker build -t alem-minutes .
docker run --rm --gpus all --network host --env-file .env \
-v "$PWD/data:/app/data" alem-minutes
UID пользователя контейнера — 1000; каталог data должен быть ему доступен. В .env задавайте пути внутри контейнера, например /app/data/models/gemma. Образ нужно собрать до переноса в закрытый контур. Docker-развёртывание и реальные платформенные аккаунты требуют отдельной приёмки в окружении заказчика.
Авторы коммитов
История коммитов
- 2026-09-23 17:54Update README with new image and project detailsMaqsat
- 2026-09-23 17:53Update README.mdMaqsat
- 2026-09-23 17:49Integrate local transcript security and bundle Unicode PDF fontlariho 34
- 2026-09-23 14:59Add project requirements and meeting minutesCodex
- 2026-09-23 14:51Add meeting audio samplesCodex
- 2026-09-23 14:51Merge GitHub initial commitCodex
- 2026-09-23 14:42Initial prototypeCodex
- 2026-09-23 17:09fix: persist speaker edits together and match report-table minutes formatmaqsatto
Все коммиты (14)
- 2026-09-23 16:43feat: format minutes with themed transcripts summaries and assignment tablesmaqsatto
- 2026-09-23 16:31feat: restrict Whisper detection to Kazakh Russian and Englishmaqsatto
- 2026-09-23 16:26feat: use Whisper large-v3 by default on T4maqsatto
- 2026-09-23 16:19feat: make recording uploads prominent and support more audio formatsmaqsatto
- 2026-09-23 16:02feat: deliver local meeting workflow with T4 inference and reviewed action trackingmaqsatto
- 2026-09-23 15:16feat: preserve local Python inference and action tracking prototypemaqsatto
Структура репозитория (78 файлов)
.dockerignore .env.example .github/workflows/checks.yml .gitignore .streamlit/config.toml Dockerfile README.md adapters/__init__.py adapters/gemma.py adapters/repository.py adapters/runtime.py adapters/speech.py adapters/whisper_languages.py app.py application/__init__.py application/ports.py application/process.py application/security_gate.py assets/DejaVuSans-LICENSE.txt assets/DejaVuSans-README.md assets/DejaVuSans.ttf assets/capture.html core/__init__.py core/grounding.py core/languages.py core/minutes.py core/models.py data/meeting1.mp3 data/meeting2.mp3 docs/coverage.md docs/meeting_minutes_1.txt docs/meeting_minutes_2.txt docs/requirements_ru_kz_en.txt docs/security-integration.md docs/superpowers/plans/2026-09-23-local-minutes.md docs/superpowers/specs/2026-09-23-local-minutes-design.md docs/verification.md exporters.py launch.py notification_worker.py prepare_models.py process_recording.py pyproject.toml requirements-dev.txt requirements.txt run-local.sh run-tests.sh security/README.md security/__init__.py security/audit_logger.py security/demo.py security/pii_detector.py security/prompt_guard.py security/sanitizer.py security/security_pipeline.py services/capture.py services/demo.py services/llm.py services/model_registry.py services/notifications.py services/pipeline.py services/reports.py services/tracker.py settings.py tests/test_adapters.py tests/test_capture.py tests/test_exports.py tests/test_grounding.py tests/test_repository_notifications.py tests/test_runtime.py tests/test_security.py tests/test_security_integration.py tests/test_ui.py ui/__init__.py ui/dashboard.py ui/intake.py ui/review.py uv.lock
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.