О проекте
Команда: UB
Кейс HackAlem.ai: Инновации — Самрук-Казына
Стадия: Рабочий MVP
Задача кейса: «Хаттама»: протокол и поручения по аудиозаписи совещания (каз./рус./смешанная речь)
Суть
Локальная система живого протоколирования совещаний. Звук берётся из вкладки Meet, Teams или Zoom через расширение Chrome или с микрофона, система распознаёт RU/KZ/смешанную речь, извлекает поручения (действие, исполнитель, срок), а секретарь проверяет и утверждает протокол с экспортом в PDF/DOCX.
Как устроено
Расширение Chrome MV3 (tabCapture → offscreen → AudioWorklet) шлёт PCM-кадры по собственному WebSocket-протоколу с подтверждением после fsync. ASR-воркер на faster-whisper large-v3-turbo распознаёт речь живыми окнами и финальным проходом. Pipeline-воркер определяет говорящих (pyannote), извлекает события LLM Qwen3-4B GGUF через llama.cpp, связывает их, проверяет основания и сроки. Всё работает локально с egress guard, данные хранятся в SQLite/PostgreSQL.
Ключевые решения
- faster-whisper large-v3-turbo
- llama.cpp
- Qwen3-4B GGUF Q4_K_M
- pyannote diarization
- VAD
- Chrome tabCapture + AudioWorklet
- WebSocket PCM protocol
- egress guard
- извлечение сроков и исполнителей
Метрики
ASR turbo int8_float16 на GPU: RTF 0.05, ~0.9–1.15 GiB VRAM; на CPU int8: RTF 0.44, ~1.2 GiB RAM; Qwen3-4B Q4_K_M ≈3.2 GiB
Особенности
Полностью локальная обработка без внешних AI API, с блокировкой исходящего трафика. Звук захватывается живым потоком из вкладки браузера по собственному протоколу без потерь. Есть профили ресурсов под машины с 8 ГБ RAM, а ревизии моделей и их sha256 закреплены в манифесте. Английские галлюцинации Whisper помечаются.
Стек
Python · FastAPI · SQLite · PostgreSQL · Alembic · JavaScript · Chrome Extension MV3 · llama.cpp · uv
Модели
Whisper large-v3-turbo · Whisper large-v3 · Qwen3-4B · Qwen3-14B · pyannote community-1
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-8a4ed672-ub.
README
README.mdХаттама Live — локальное автопротоколирование совещаний
Живой захват звука встречи (Google Meet / Teams Web / Zoom Web через расширение Chrome, или микрофон компьютера), распознавание RU / KZ / смешанной речи во время встречи, финальный проход после неё, извлечение поручений (действие, исполнитель, срок с основаниями), проверка секретарём, утверждение и экспорт в PDF/DOCX. Все модели работают локально: записи, тексты и промпты не отправляются во внешние AI API.
Статус: рабочий прототип. Что проверено и что нет — в STATUS.md. Не production-ready.
Архитектура (кратко)
Chrome + расширение (tabCapture → offscreen → AudioWorklet) ─┐ протокол hattama.audio.v1 (WebSocket,
Веб-панель (локальный микрофон) ─┼─▶ бинарные PCM-кадры, ACK после fsync)
│
FastAPI (apps/api/hattama) ── SQLite/PostgreSQL ── хранилище PCM (по позиции, без потерь)
├─ ASR-воркер: faster-whisper large-v3-turbo (live rolling windows + финальный проход)
├─ pipeline-воркер: говорящие → извлечение событий (LLM) → связывание → проверка оснований → вопросы
└─ llama.cpp server (Qwen3-4B GGUF, только 127.0.0.1)
| Путь | Что там |
|---|---|
packages/contracts/ | протокол аудиоприёма v1 (spec, Python-кодек, тест-векторы) |
packages/audio-client/ | браузерный кодек, AudioWorklet, загрузчик с буфером и переподключением |
apps/api/hattama/ | API, приём, ASR, извлечение поручений, сроки, экспорт, уведомления |
apps/extension/ | расширение Chrome MV3 «Хаттама Live Companion» |
apps/web/static/ | веб-панель (без сборки и CDN) |
model-configs/ | манифест моделей (ревизии, sha256), профили ресурсов |
tests/ | unit, integration (WebSocket/БД), тест с реальной моделью |
Быстрый старт (Windows / Linux, Python 3.11, Node 20)
python -m pip install --user uv
python tasks.py setup --gpu # или --asr (без NVIDIA GPU)
python tasks.py doctor # оборудование, рекомендуемый профиль
python tasks.py models-prepare # whisper turbo (1.6 ГБ) + Qwen3-4B Q4_K_M (2.5 ГБ), sha256 проверяется
python tasks.py runtimes-prepare # только Windows: llama.cpp b11120 CUDA 12.4
copy .env.example .env # Linux: cp; при необходимости поправьте профиль
python tasks.py create-user --email [email protected] --name "Секретарь" --role secretary
python tasks.py dev # API + воркеры + LLM; интерфейс: http://localhost:8000
Подготовка (скачивание) и запуск — разные команды: dev, test, smoke-local ничего не скачивают.
Путь к репозиторию с кириллицей работает: tasks.py сам выставляет PYTHONUTF8 и PYTHONPATH.
Не храните данные и модели в OneDrive: по умолчанию они лежат в %LOCALAPPDATA%\Hattama.
Расширение Chrome
python tasks.py build-extension # → apps/extension/dist
chrome://extensions → «Режим разработчика» → «Загрузить распакованное» → apps/extension/dist.
Настройка микрофона: страница «Параметры» расширения (разрешение, выбор устройства, проверка уровня).
Текущий веб-MVP
Панель: Встречи, Протокол, Поручения. Создание встречи со ссылкой Meet/Zoom/Teams, запись вкладки или микрофона, таймер, пауза, завершение, обработка и проверка протокола подключены к API. При временном обрыве связи аудио остаётся в буфере текущей страницы: не закрывайте её до окончания сохранения. Утверждение недоступно до готовности финальной расшифровки, анализа и итогов; пустой протокол утвердить нельзя.
Как провести встречу
- Веб-панель → «Новая встреча»: название, платформа, ссылка Meet/Zoom/Teams, дата и участники.
- Уведомите участников, подтвердите это в форме подготовки и нажмите «Подготовить запись».
- Откройте встречу в отдельной вкладке Chrome/Edge. В Хаттаме нажмите «Начать запись вкладки», выберите вкладку встречи и включите передачу её аудио. Для очной встречи выберите запись микрофона.
- Дополнительный микрофон пишет ваш голос независимо от mute в Meet/Teams/Zoom; отключите его флажок перед стартом, если он не нужен. Используйте наушники. Проверяйте уровень звука и таймер.
- Можно поставить запись на паузу и продолжить. «Завершить запись» сначала сохраняет весь звук, включая последний неполный фрагмент, затем запускает обработку. При обрыве связи оставьте страницу открытой; при ошибке нажмите «Повторить сохранение».
- Дождитесь готовности расшифровки и анализа → проверьте текст, поручения и вопросы → «Утвердить» → PDF/DOCX. Нулевое число поручений допустимо, отсутствие расшифровки или итогов — нет. Черновой экспорт доступен после готовности итогов.
Быстрая проверка: запишите 30–60 секунд речи с явным поручением, например «Ерлан, подготовь отчёт к 25 сентября». После завершения проверьте текст, поручение, исполнителя и срок. Тишина или отказ в разрешении не должны приводить к готовому пустому протоколу. Запись вкладки требует поддержки браузером передачи аудио; если во встроенном браузере её нет, откройте сайт в Chrome/Edge.
Настольные клиенты Zoom/Teams не поддерживаются (только веб-клиенты во вкладке Chrome). Бот-участник (meeting-agent) не реализован.
Команда с 8 ГБ RAM
Замеры на этой машине: turbo int8_float16 на GPU занимает ≈0.9–1.15 ГиБ VRAM и 0.65 ГиБ RAM, RTF 0.05.
На CPU int8 RAM ≈1.2 ГиБ (пик 1.56 ГиБ при загрузке), RTF 0.44 за один проход.
Qwen3-4B Q4_K_M занимает ≈3.2 ГиБ (веса + KV-кэш на 4096 токенов).
При 8 ГБ RAM ОС и Chrome с открытой встречей уже занимают 4–5 ГБ, поэтому ASR и LLM одновременно не помещаются.
Рекомендуемый вариант: один сервер на команду, остальные — тонкие клиенты.
- Сервер (
tasks.py dev) запускается на одной машине с NVIDIA GPU ≥6 ГБ или с ≥16 ГБ RAM. - Коллегам с 8 ГБ нужен только Chrome с расширением: оно передаёт звук вкладки на сервер и почти не расходует память.
- На сервере добавьте его адрес в
HATTAMA_ALLOWED_ORIGINS. Для работы по сети нужен HTTPS/WSS (браузер требует защищённый контекст). Этот сценарий не проверен — см. STATUS.md.
Если сервер обязательно запускать на ноутбуке с 8 ГБ без GPU:
- В
.envукажитеHATTAMA_PROFILE=cpu-8gb. Live-распознавание пойдёт на CPU с задержкой, не в real-time, а LLM во время встречи не запускается. - Во время встречи:
python tasks.py dev --no-llm. - После встречи остановите
dev(это освобождает ≈1.5 ГБ RAM ASR-воркера) и запуститеpython tasks.py llmиpython tasks.py dev --no-asr. Анализ поручений выполнится из очереди. - Закройте лишние вкладки и приложения. Swap спасает от падения, но делает работу очень медленной.
Тесты
python tasks.py test # unit (Python) + кодек JS против общих тест-векторов
python tasks.py test-integration # API, WebSocket-протокол, БД (без моделей)
python tasks.py smoke-local --with-models # полный маршрут с реальными моделями, внешняя сеть заблокирована
Лицензии моделей
Whisper large-v3-turbo (CT2, dropbox-dash/faster-whisper-large-v3-turbo): MIT.
Qwen3-4B-GGUF: Apache-2.0. llama.cpp: MIT. Шрифт DejaVu: лицензия в apps/api/hattama/export/fonts.
pyannote community-1 — gated-модель: условия принимает сам пользователь на Hugging Face.
Ревизии и sha256 закреплены в model-configs/model-manifest.json.
hack-8a4ed672-ub
Hackathon team repository for UB
There are problems occured. Can you wait a little bit more for the main codebase.
Авторы коммитов
История коммитов
- 2026-09-23 17:58Merge branch 'main' into zhassyn2Zhassyn
- 2026-09-23 17:56Merge pull request #3 from BAITC-Hacks/codex/meeting-recording-flowRuslan
- 2026-09-23 17:51Changed README.mdZhassyn Yegnay
- 2026-09-23 17:48Implement reliable browser meeting recording and approval readinessRuslan
- 2026-09-23 17:22just saveOlzhas
- 2026-09-23 17:15Merge pull request #2 from BAITC-Hacks/zhassynRuslan
- 2026-09-23 17:09FrontendZhassyn Yegnay
- 2026-09-23 16:40Исправления по контрольным записям: метка источника не считается исполнителем, английские галлюцинации Whisper помечаются; результаты в STATUS.mdOlzhas
Все коммиты (15)
- 2026-09-23 16:28Инструкция запуска на GPU-сервере (Brev), профиль gpu-server, закреплённые large-v3 и Qwen3-14BOlzhas
- 2026-09-23 16:17Скрипт эмуляции расширения, промпт запуска для команды, результаты живого прогонаOlzhas
- 2026-09-23 16:11Merge pull request #1 from BAITC-Hacks/feature/hattama-liveZhassyn
- 2026-09-23 16:10Merge branch 'main' into feature/hattama-liveZhassyn
- 2026-09-23 16:07Хаттама Live: локальный live-протокол совещаний (прототип)Olzhas
- 2026-09-23 16:02Second update to README.mdZhassyn Yegnay
- 2026-09-23 14:37Change README.mdZhassyn Yegnay
Структура репозитория (164 файлов)
.env.example .gitignore README.md STATUS.md apps/api/alembic.ini apps/api/hattama/__init__.py apps/api/hattama/api/__init__.py apps/api/hattama/api/app.py apps/api/hattama/api/deps.py apps/api/hattama/api/routes/__init__.py apps/api/hattama/api/routes/auth.py apps/api/hattama/api/routes/capture.py apps/api/hattama/api/routes/diagnostics.py apps/api/hattama/api/routes/live.py apps/api/hattama/api/routes/meetings.py apps/api/hattama/api/routes/review.py apps/api/hattama/asr/__init__.py apps/api/hattama/asr/base.py apps/api/hattama/asr/cuda_win.py apps/api/hattama/asr/faster_whisper_provider.py apps/api/hattama/audio/__init__.py apps/api/hattama/audio/reader.py apps/api/hattama/audio/resample.py apps/api/hattama/audio/vad.py apps/api/hattama/cli.py apps/api/hattama/config.py apps/api/hattama/db/__init__.py apps/api/hattama/db/models.py apps/api/hattama/db/session.py apps/api/hattama/db/types.py apps/api/hattama/diagnostics/__init__.py apps/api/hattama/diagnostics/asr_bench.py apps/api/hattama/diagnostics/doctor.py apps/api/hattama/diagnostics/hardware.py apps/api/hattama/diagnostics/profiles.py apps/api/hattama/diagnostics/resources.py apps/api/hattama/diarization/__init__.py apps/api/hattama/diarization/provider.py apps/api/hattama/domain/__init__.py apps/api/hattama/domain/deadlines.py apps/api/hattama/domain/enums.py apps/api/hattama/domain/meeting_status.py apps/api/hattama/domain/names.py apps/api/hattama/domain/numbers.py apps/api/hattama/domain/readiness.py apps/api/hattama/evaluation/__init__.py apps/api/hattama/evaluation/metrics.py apps/api/hattama/evaluation/smoke.py apps/api/hattama/export/__init__.py apps/api/hattama/export/fonts/DejaVuSans-Bold.ttf apps/api/hattama/export/fonts/DejaVuSans.ttf apps/api/hattama/export/fonts/LICENSE_DEJAVU apps/api/hattama/export/protocol.py apps/api/hattama/extraction/__init__.py apps/api/hattama/extraction/evidence.py apps/api/hattama/extraction/linker.py apps/api/hattama/extraction/persist.py apps/api/hattama/extraction/pipeline.py apps/api/hattama/extraction/prompts.py apps/api/hattama/extraction/schemas.py apps/api/hattama/ingest/__init__.py apps/api/hattama/ingest/service.py apps/api/hattama/ingest/store.py apps/api/hattama/ingest/ws.py apps/api/hattama/jobs/__init__.py apps/api/hattama/jobs/queue.py apps/api/hattama/live/__init__.py apps/api/hattama/live/transcriber.py apps/api/hattama/llm/__init__.py apps/api/hattama/llm/client.py apps/api/hattama/logging_setup.py apps/api/hattama/modelstore/__init__.py apps/api/hattama/modelstore/manifest.py apps/api/hattama/modelstore/prepare.py apps/api/hattama/modelstore/runtimes.py apps/api/hattama/notifications/__init__.py apps/api/hattama/notifications/scheduler.py apps/api/hattama/pipeline/__init__.py apps/api/hattama/pipeline/final_asr.py apps/api/hattama/pipeline/stages.py apps/api/hattama/runtime.py apps/api/hattama/security/__init__.py apps/api/hattama/security/egress_guard.py apps/api/hattama/security/origins.py apps/api/hattama/security/passwords.py apps/api/hattama/security/tokens.py apps/api/hattama/security/urls.py apps/api/hattama/services/__init__.py apps/api/hattama/services/events.py apps/api/hattama/workers/__init__.py apps/api/hattama/workers/asr_worker.py apps/api/hattama/workers/live_asr.py apps/api/hattama/workers/pipeline_worker.py apps/api/migrations/env.py apps/api/migrations/script.py.mako apps/api/migrations/versions/0001_initial_schema.py apps/api/pyproject.toml apps/extension/build.mjs apps/extension/src/background.js apps/extension/src/manifest.json apps/extension/src/offscreen.html apps/extension/src/offscreen.js apps/extension/src/popup.css apps/extension/src/popup.html apps/extension/src/popup.js apps/extension/src/setup.html apps/extension/src/setup.js apps/meeting-agent/hattama_agent/__init__.py apps/meeting-agent/pyproject.toml apps/web/README.md apps/web/recording-ui.test.mjs apps/web/static/api.js apps/web/static/app.js apps/web/static/fonts/onest-cyrillic-ext.woff2 apps/web/static/fonts/onest-cyrillic.woff2 apps/web/static/fonts/onest-latin.woff2 apps/web/static/index.html apps/web/static/recorder.js apps/web/static/recording-ui.js apps/web/static/style.css apps/web/static/ui.js apps/web/ui.test.mjs fixtures/audio/synthetic/manifest.json fixtures/audio/synthetic/ru_synth_dialog_a.ref.json fixtures/audio/synthetic/ru_synth_dialog_a.wav fixtures/audio/synthetic/ru_synth_dialog_b.ref.json fixtures/audio/synthetic/ru_synth_dialog_b.wav fixtures/audio/synthetic/ru_synth_numbers_h.ref.json fixtures/audio/synthetic/ru_synth_numbers_h.wav model-configs/model-manifest.json model-configs/profiles.toml model-configs/runtimes-manifest.json packages/audio-client/package.json packages/audio-client/pcm-worklet.js packages/audio-client/protocol.js packages/audio-client/protocol.test.mjs packages/audio-client/recorder.test.mjs packages/audio-client/uploader.js packages/audio-client/uploader.test.mjs packages/audio-client/worklet.test.mjs packages/contracts/audio-frame-v1.md packages/contracts/python/hattama_contracts/__init__.py packages/contracts/python/hattama_contracts/frame.py packages/contracts/python/hattama_contracts/messages.py packages/contracts/python/pyproject.toml packages/contracts/test-vectors/audio-frame-v1.json pyproject.toml scripts/make_synthetic_audio.py scripts/synth_tts_onecore.ps1 scripts/synth_tts_windows.ps1 tasks.py tests/conftest.py tests/helpers/__init__.py tests/helpers/ingest.py tests/integration/test_ingest_ws.py tests/integration/test_live_vertical_models.py tests/integration/test_web_mvp.py tests/unit/test_deadlines.py tests/unit/test_ingest_store.py tests/unit/test_linker_scenarios.py tests/unit/test_live_transcriber.py tests/unit/test_protocol.py tests/unit/test_resample.py uv.lock
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.