О проекте
Команда: DARAI
Кейс HackAlem.ai: Инновации — Самрук-Казына
Стадия: Доведённый продукт
Задача кейса: «Хаттама»: протокол и поручения по аудиозаписи совещания (каз./рус./смешанная речь)
Суть
Локальный AI-ассистент совещаний в виде внутренней CRM. Из файла или live-записи в браузере строятся транскрипт, диаризация, сопоставление спикеров с голосовыми профилями сотрудников, поручения и саммари; секретарь проверяет черновик и экспортирует протокол в DOCX/PDF.
Как устроено
Pipeline: FFmpeg → ASR на faster-whisper large-v3 → диаризация pyannote 3.1 → выравнивание слов → идентификация спикеров по эмбеддингам wespeaker (кандидаты только из приглашённых) → локальная LLM (Ollama qwen3:8b через OpenAI-совместимый endpoint) выделяет поручения и саммари → проверка → DOCX/PDF через python-docx и LibreOffice. Live-режим принимает упорядоченные чанки MediaRecorder и выдаёт превью через опциональный large-v3-turbo. Данные (сотрудники, встречи, голоса, задачи) лежат в PostgreSQL + pgvector. Backend, БД и Ollama работают в изолированной сети Docker без внешнего egress.
Ключевые решения
- faster-whisper
- диаризация pyannote
- голосовые эмбеддинги wespeaker для идентификации спикеров
- pgvector
- live-транскрипция по чанкам
- выравнивание слов
- экспорт DOCX/PDF
Особенности
Весь контур локальный и закрытый (без внешнего egress), подходит для конфиденциальных совещаний. Голосовые профили сотрудников сопоставляются с диаризованными спикерами, автор и исполнитель поручения определяются раздельно. Live-превью в браузере с дозаписью остатка. Тестовые WAV-фикстуры на казахском, русском и смешанной речи, включая перекрытие голосов и неизвестный голос.
Стек
Python · FastAPI · PostgreSQL · pgvector · Alembic · React · Vite · TypeScript · Nginx · Docker Compose · FFmpeg · LibreOffice · Playwright
Модели
Whisper large-v3 · Whisper large-v3-turbo · pyannote/speaker-diarization-3.1 · pyannote/wespeaker-voxceleb-resnet34-LM · qwen3:8b via Ollama
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-615f50d9-darai.
README
README.mdDARAI — локальный ИИ-ассистент совещаний
DARAI — хакатонный прототип внутренней CRM, который превращает запись совещания в транскрипт, список поручений с ответственными и сроками, саммари и протокол DOCX/PDF. Целевые языки — русский, казахский и смешанная речь.
Система сокращает ручную работу секретаря: распознаёт разговор, предлагает личности спикеров и поручения, сохраняет подтверждающие реплики. Секретарь проверяет черновик перед утверждением; исполнители получают задачи и уведомления внутри CRM.
Статус: backend, frontend и локальный AI-пайплайн реализованы. Доступны загрузка файла и запись из браузера с предварительным транскриптом. Качество смешанной речи и задержка live зависят от записи и оборудования; это прототип, а не готовое промышленное решение.
Возможности
| Функция | Реализация |
|---|---|
| Сотрудники | ФИО, должность, департамент, локальная учётная запись |
| Выдача доступа | Временный пароль, обязательная смена, сброс и отзыв сессий |
| Голосовой профиль | Самостоятельная запись/загрузка образца, проверка качества, замена и удаление |
| Удаление сотрудника | Архивирование с блокировкой доступа и сохранением истории; права проверяются сервером |
| Совещания | Название, дата, часовой пояс, повестка, участники, необязательная ссылка на внешний звонок |
| Источники записи | Готовый аудио/видеофайл; микрофон; звук вкладки/экрана с дополнительным микрофоном |
| Live-транскрипт | Постепенные обновления, черновые реплики, состояние отправки и задержка обработки |
| Итоговый протокол | Полная транскрибация, диаризация, сопоставление голосов, поручения и саммари |
| Проверка | Ручное сопоставление спикеров, редактирование поручений и саммари, утверждение |
| Исполнение | «Мои поручения», выполнение, сроки, внутренние уведомления и напоминания |
| Экспорт | DOCX и PDF; черновик обозначается в документе |
Ссылка на Meet/Zoom/Teams только открывает внешний звонок. Бот к нему не подключается. В онлайн-режиме пользователь сам выбирает источник звука в браузере. Имена спикеров и поручения формируются при финальной обработке; live-preview предназначен прежде всего для текста.
Основной сценарий
- Администратор создаёт сотрудников и выдаёт локальные учётные записи.
- Сотрудник входит, меняет временный пароль и регистрирует голос в «Моём профиле». Без голосового профиля CRM остаётся доступна.
- Секретарь создаёт встречу, выбирает участников и уведомляет их о записи и ИИ-обработке.
- В карточке встречи выбирает язык и профиль STT, сохраняет настройки.
- Загружает готовый файл либо нажимает «Записать сейчас» → выбирает режим → «Подготовить источник» → «Начать запись».
- Во время разговора видит предварительный транскрипт. После «Завершить запись» система обрабатывает полный файл.
- Секретарь проверяет спикеров, цитаты, исполнителей и сроки, исправляет черновик и утверждает его.
- Исполнители видят подтверждённые задачи и уведомления; секретарь скачивает DOCX/PDF.
Для онлайн-записи выбирайте вкладку звонка с включённой передачей аудио. Наличие звука зависит от браузера, ОС и выбранного источника. Дополнительный микрофон записывает голос секретаря; наушники помогают избежать эха. Доступ к устройствам требует HTTPS или localhost.
Архитектура и стек
React / Vite / TypeScript
│ /api, cookie-сессия, CSRF
▼
Nginx → FastAPI / Python 3.11
├── PostgreSQL + pgvector: сотрудники, встречи, голоса, задачи
├── локальное хранилище: аудио, временные файлы, экспорт
├── live: упорядоченные чанки → FFmpeg → STT → polling snapshots
└── финал: FFmpeg → ASR → диаризация → выравнивание слов
→ идентификация → локальная LLM → проверка → DOCX/PDF
| Компонент | Технология |
|---|---|
| Итоговый STT | faster-whisper, Whisper large-v3 |
| Ускоренный live-STT | Опциональный отдельный Whisper large-v3-turbo |
| Диаризация | pyannote/speaker-diarization-3.1 + segmentation-3.0 |
| Голосовые эмбеддинги | pyannote/wespeaker-voxceleb-resnet34-LM |
| Поручения и саммари | Локальный OpenAI-совместимый endpoint; проверялась Ollama с qwen3:8b |
| Экспорт | python-docx, LibreOffice headless, локальные шрифты |
| Запуск | Docker Compose, Alembic-миграции при старте backend |
Регистрация и сравнение голосов используют одну модель и совместимую ревизию. Кандидаты ограничены приглашёнными участниками. Недостаточное сходство оставляет спикера неизвестным; автор поручения и исполнитель определяются раздельно.
В live части MediaRecorder сохраняются как один контейнер, а не декодируются как независимые файлы. Backend подтверждает последовательные чанки, публикует результат каждого окна и дорабатывает накопленный остаток. При ошибке preview сохранение аудио продолжается. Итоговая обработка заново использует полный файл.
Требования и подготовка
Нужны Docker с Compose v2, свободное место под образы и веса, а для скриптов подготовки — Python 3.11 и uv. Для локальных аудиотестов вне Docker также нужен FFmpeg. Образы включают системные зависимости.
Проверенное окружение в отчётах: Apple M4 Pro, 48 GB RAM, macOS, Docker Desktop arm64. На Mac STT внутри текущего Docker-образа работает на CPU. Для переноса на другой компьютер сначала измерьте скорость и память; CUDA-конфигурация требует отдельной настройки.
Веса основного ASR занимают около 3 GB, turbo — дополнительно около 1.6 GB, qwen3:8b — около 5.2 GB. Образы и окружение Python требуют дополнительного места.
1. Конфигурация
Все команды ниже выполняются из корня репозитория, если не указано иное.
test -f .env || cp .env.example .env
В .env задайте собственные ADMIN_PASSWORD, POSTGRES_PASSWORD и точное LLM_MODEL. Первый администратор создаётся только при пустой таблице пользователей; изменение env не сбрасывает пароль существующего аккаунта. Не коммитьте .env.
2. Подготовка моделей речи
uv venv --python 3.11 backend/.venv
uv pip install --python backend/.venv/bin/python \
-r backend/requirements.txt -r backend/requirements-ml.txt \
-r backend/requirements-dev.txt
backend/.venv/bin/python scripts/ai/diagnose_env.py
backend/.venv/bin/python scripts/ai/prepare_models.py --only asr,embedding
Для pyannote заранее примите условия доступа к segmentation-3.0 и speaker-diarization-3.1. Токен с доступом к этим моделям нужен только для первоначальной загрузки. Пример скрытого ввода в Bash:
bash
read -s -p 'Hugging Face token: ' HF_TOKEN
echo
export HF_TOKEN
backend/.venv/bin/python scripts/ai/prepare_models.py --only segmentation,diarization
unset HF_TOKEN
Загрузка весов не отправляет записи совещаний. Для изолированного сервера подготовьте зависимости, образы и веса на другой машине и перенесите их внутрь контура. Ревизии моделей закреплены в скрипте подготовки.
Проверка основных моделей с блокировкой внешних соединений:
MODELS_DIR=./models ASR_DEVICE=cpu ASR_COMPUTE_TYPE=int8 \
backend/.venv/bin/python scripts/ai/check_models.py
3. Ускоренный live-STT (опционально)
backend/.venv/bin/python scripts/ai/prepare_models.py --only live_asr
Добавьте/измените в .env:
LIVE_ASR_MODEL_PATH=faster-whisper-large-v3-turbo
LIVE_ASR_DEVICE=cpu
LIVE_ASR_COMPUTE_TYPE=int8
LIVE_ASR_CPU_THREADS=8
LIVE_PREVIEW_WINDOW_SECONDS=12
Число потоков подберите под доступные CPU; приведённые значения измерялись на M4 Pro. Относительный путь разрешается внутри MODELS_DIR (в Docker — /models). Если LIVE_ASR_MODEL_PATH отсутствует, preview использует основной large-v3. Если путь задан, но веса отсутствуют, возвращается явная ошибка без скрытой подмены. Финальная обработка в обоих случаях остаётся на large-v3.
4. Выберите размещение локальной LLM
Вариант A: Ollama уже работает на вашем компьютере. Повторно скачивать имеющуюся модель не нужно. Узнайте её точное имя через ollama list и задайте в .env:
LLM_BASE_URL=http://host.docker.internal:11434/v1
LLM_MODEL=qwen3:8b
Используйте имя реально установленной модели. Ollama должна принимать соединения из Docker; если сервис слушает только loopback и недоступен контейнеру, настройте bind-адрес для локального Docker-доступа, ограничив доступ извне.
docker compose -f docker-compose.yml -f docker-compose.host-llm.yml build
docker compose -f docker-compose.yml -f docker-compose.host-llm.yml pull db
docker compose -f docker-compose.yml -f docker-compose.host-llm.yml up -d
Контейнерная Ollama в этом варианте отключена. Override даёт backend маршрут к хосту: Docker уже не запрещает ему весь внешний egress. Для закрытого контура ограничьте исходящие соединения на уровне инфраструктуры.
Вариант B: Ollama внутри Compose. В .env:
LLM_BASE_URL=http://ollama:11434/v1
LLM_MODEL=qwen3:8b
Подготовьте образы и LLM с интернетом один раз:
docker compose build
docker compose pull db ollama
mkdir -p models/ollama
docker run -d --name darai-ollama-prep \
-v "$PWD/models/ollama:/root/.ollama" ollama/ollama:0.33.2
# Дождитесь готовности сервера Ollama; скачайте то же имя, что указано в LLM_MODEL.
docker exec darai-ollama-prep ollama pull qwen3:8b
docker rm -f darai-ollama-prep
После подготовки запуск одной командой:
docker compose up
Backend, БД и контейнерная Ollama находятся в сети internal без внешнего egress. Поэтому загрузка LLM выполняется отдельным подготовительным контейнером.
Открыть приложение
http://localhost:8080 — интерфейс; вход по ADMIN_LOGIN/ADMIN_PASSWORD. /api/health проверяет приложение и БД, но не доказывает готовность моделей. Их состояние доступно администратору через GET /api/system/status.
docker compose ps
docker compose logs -f backend frontend
docker compose down
down сохраняет volumes. Не используйте down -v, если нужно сохранить БД и записи. Перед пересозданием backend завершите и запись, и итоговую обработку: прерванные задания получают INTERRUPTED и требуют повтора.
Язык и качество распознавания
В карточке встречи доступны Авто / Русский / Қазақша и два профиля:
- Стандартный: настройки по
adilet/transcribe.py, контекст предыдущего текста, без повторного определения языка каждой реплики. - Дополнительная проверка языка: прежний алгоритм RU/KZ; профиль по умолчанию, более дорогой для финальной обработки.
Сохраните выбор перед началом записи или загрузкой. Готовый протокол автоматически не переписывается. Для live действуют отдельные настройки скорости; подробности — AI_SETUP.
По последнему отчёту AI-агента, на синтетической 73,7-секундной RU/KZ/mixed-записи с turbo, CPU M4 Pro, 8 потоками и окном 12 секунд первый текст появился через 7,9 с; максимальный измеренный лаг — 5,6 с, CER — 0,051. Это симуляция независимого поступления аудио, не гарантия задержки в браузере или на другом компьютере. Смешанные слова и короткие казахские реплики остаются источником ошибок.
Проверка и тесты
Быстрые тесты алгоритмов без настоящих моделей:
cd backend
.venv/bin/python -m pytest tests/ai -m 'not real_models and not real_llm'
API-тесты требуют отдельной PostgreSQL с pgvector. Они пересоздают darai_test; не направляйте их на рабочий сервер. Команды подготовки — в BACKEND.
# Из backend/, после запуска отдельной тестовой БД на 55433:
TEST_DATABASE_URL=postgresql+psycopg://darai:[email protected]:55433/darai \
.venv/bin/python -m pytest tests/api
Frontend:
cd frontend
npm ci
npm run build
npm test
# Однократная подготовка браузера:
npx playwright install chromium
npm run test:e2e
Браузерные тесты используют явный fixture API. Они проверяют интерфейс и контракты, а не качество реальных моделей или физического микрофона.
Реальная live-симуляция из корня, после подготовки turbo и FFmpeg:
MODELS_DIR=./models ASR_COMPUTE_TYPE=int8 \
LIVE_ASR_MODEL_PATH=faster-whisper-large-v3-turbo LIVE_ASR_CPU_THREADS=8 \
backend/.venv/bin/python scripts/ai/live_simulate.py \
backend/tests/fixtures/ai/live_long.wav \
backend/tests/fixtures/ai/meeting_ru_kk.wav --realtime --language auto
Сравнение STT-профилей: scripts/ai/compare_asr.py. Реальные AI-тесты: backend/tests/ai/test_real_models.py и test_live_real.py, с локальными моделями и LLM согласно AI_SETUP. Тестовые аудиофайлы смоделированы TTS; происхождение и эталоны находятся рядом с фикстурами.
Приватность и ограничения
- Аудио, текст и голосовые векторы обрабатываются локально; облачные inference API не используются. Веса и зависимости получают до начала работы.
- Идентификация голоса — предложение для секретаря, не способ входа. Неизвестные спикеры и неоднозначные поручения требуют проверки.
- Предварительный транскрипт может меняться; итоговая обработка использует полную запись. Поручения и имена спикеров не обещаются в live.
- На CPU распознавание может отставать. Замеры на коротких синтетических записях не подтверждают качество длинных реальных встреч.
- BackgroundTasks не является долговечной очередью; MVP использует один backend worker и ограничение конкуренции моделей.
- Одна активная запись на встречу; подтверждённый протокол нельзя молча перезаписать. Полное версионирование и согласование изменений — дальнейшая работа.
- Ссылка на звонок не заменяет выбор источника. Поддержка звука вкладки/экрана зависит от браузера и ОС.
- TLS, шифрование хранилища, аудит, резервное копирование, политика удаления и производственные проверки защиты требуют дополнительной реализации. Локальное размещение само по себе не подтверждает выполнение всех требований безопасности.
- Нет бота платформ встреч, интеграции с СЭД и внешней рассылки. Уведомления доступны внутри CRM.
Структура и документация
backend/app/ API, доступы, БД, аудио, STT, голоса, LLM, экспорт
backend/migrations/ Alembic-миграции
backend/tests/ API/AI-тесты и синтетические записи
frontend/ React-приложение и браузерные тесты
scripts/ai/ Подготовка моделей, диагностика, сравнение и симуляция
adilet/ Исходные CLI-подходы к транскрибации и извлечению
models/ Локальные веса (исключены из git)
docs/ Контракты и подробные инструкции
- Правила разработки
- План и границы хакатона
- Backend и эксплуатация
- Frontend и сценарии проверки
- Подготовка AI и измерения — ранние разделы содержат исторические результаты и блокеры; ориентируйтесь также на дату и последующие обновления.
- HTTP API и OpenAPI
- Live HTTP-контракт, Live AI-интерфейс
Команда DARAI: Raim, Daneker, Adilet.
Авторы коммитов
История коммитов
- 2026-09-23 17:56test: cover tail decoding for long live meetingsDaneker Kaliaskaruly
- 2026-09-23 17:55feat: add meeting date and time calendar pickerDaneker Kaliaskaruly
- 2026-09-23 17:49chore: remove adilet reference folderDaneker Kaliaskaruly
- 2026-09-23 17:47docs: update README and live transcription verificationDaneker Kaliaskaruly
- 2026-09-23 17:20feat: improve live transcription scheduling and progress displayDaneker Kaliaskaruly
- 2026-09-23 16:50feat: add per-meeting STT profiles and improve live transcriptionDaneker Kaliaskaruly
- 2026-09-23 16:20whisGetLivreru
- 2026-09-23 16:08feat: add live meeting recording and employee archivingDaneker Kaliaskaruly
Все коммиты (13)
- 2026-09-23 15:16feat: add employee account onboarding and self-service voice profilesDaneker Kaliaskaruly
- 2026-09-23 14:53feat: add local meeting transcription backend and AI pipelineDaneker Kaliaskaruly
- 2026-09-23 14:36feat(frontend): implement DARAI CRM interface and contract testsDaneker Kaliaskaruly
- 2026-09-23 13:59docs: document DARAI project scope and implementation planDaneker Kaliaskaruly
- 2026-09-23 13:49Update README.mdiD1eat
Структура репозитория (145 файлов)
.env.example .gitignore AGENTS.md README.md backend/.dockerignore backend/Dockerfile backend/alembic.ini backend/app/__init__.py backend/app/access.py backend/app/ai_gateway.py backend/app/ai_pipeline.py backend/app/ai_types.py backend/app/align.py backend/app/asr.py backend/app/audio.py backend/app/auth.py backend/app/config.py backend/app/db.py backend/app/diarize.py backend/app/errors.py backend/app/export.py backend/app/extract.py backend/app/live_ai.py backend/app/live_ai_types.py backend/app/live_routes.py backend/app/live_service.py backend/app/llm.py backend/app/main.py backend/app/ml.py backend/app/models.py backend/app/notifications.py backend/app/processing.py backend/app/routers/__init__.py backend/app/routers/auth_users.py backend/app/routers/employees.py backend/app/routers/meetings.py backend/app/routers/notifications.py backend/app/routers/system.py backend/app/routers/tasks.py backend/app/schemas.py backend/app/serializers.py backend/app/uploads.py backend/app/voice.py backend/migrations/env.py backend/migrations/script.py.mako backend/migrations/versions/0001_initial.py backend/migrations/versions/0002_must_change_password.py backend/migrations/versions/0003_live_sessions.py backend/migrations/versions/0004_speech_settings.py backend/openapi.json backend/pytest.ini backend/requirements-dev.txt backend/requirements-ml.txt backend/requirements.txt backend/scripts/export_openapi.py backend/tests/__init__.py backend/tests/ai/__init__.py backend/tests/ai/test_align_diarize.py backend/tests/ai/test_asr_profiles.py backend/tests/ai/test_extract.py backend/tests/ai/test_live_merge.py backend/tests/ai/test_live_real.py backend/tests/ai/test_pipeline.py backend/tests/ai/test_real_models.py backend/tests/ai/test_voice.py backend/tests/api/__init__.py backend/tests/api/conftest.py backend/tests/api/fake_ai.py backend/tests/api/test_accounts.py backend/tests/api/test_auth_access.py backend/tests/api/test_employee_delete.py backend/tests/api/test_live.py backend/tests/api/test_live_preview.py backend/tests/api/test_meetings_processing.py backend/tests/api/test_openapi.py backend/tests/api/test_review_notifications_export.py backend/tests/api/test_speech_settings.py backend/tests/fixtures/ai/enroll_kk_aru.wav backend/tests/fixtures/ai/enroll_ru_milena.wav backend/tests/fixtures/ai/enroll_short.wav backend/tests/fixtures/ai/kk_only.wav backend/tests/fixtures/ai/live_long.json backend/tests/fixtures/ai/live_long.wav backend/tests/fixtures/ai/manifest.json backend/tests/fixtures/ai/meeting_ru_kk.wav backend/tests/fixtures/ai/mixed.wav backend/tests/fixtures/ai/overlap.wav backend/tests/fixtures/ai/silence.wav backend/tests/fixtures/ai/unknown_voice.wav docker-compose.host-llm.yml docker-compose.yml docs/AI_CONTRACT.md docs/AI_HANDOFF.md docs/AI_SETUP.md docs/API_CONTRACT.md docs/BACKEND.md docs/DEVELOPMENT_PLAN.md docs/FRONTEND.md docs/LIVE_AI_CONTRACT.md docs/LIVE_CONTRACT.md frontend/.dockerignore frontend/.gitignore frontend/Dockerfile frontend/index.html frontend/nginx.conf frontend/package-lock.json frontend/package.json frontend/playwright.config.ts frontend/src/Access.tsx frontend/src/App.tsx frontend/src/DeleteEmployeeDialog.tsx frontend/src/Employees.tsx frontend/src/LiveTranscript.tsx frontend/src/MeetingDateTime.tsx frontend/src/MeetingLiveRecorder.tsx frontend/src/Meetings.tsx frontend/src/Tasks.tsx frontend/src/VoiceRecorder.tsx frontend/src/Work.tsx frontend/src/api.ts frontend/src/live-api.ts frontend/src/main.tsx frontend/src/styles.css frontend/src/types.ts frontend/src/ui.tsx frontend/src/utils.ts frontend/tests/api.test.ts frontend/tests/e2e/calendar.spec.ts frontend/tests/e2e/employee-delete.spec.ts frontend/tests/e2e/fixture-api.ts frontend/tests/e2e/live-recording.spec.ts frontend/tests/e2e/onboarding.spec.ts frontend/tests/e2e/workflow.spec.ts frontend/tests/utils.test.ts frontend/tsconfig.json frontend/vite.config.ts frontend/vitest.config.ts scripts/ai/check_models.py scripts/ai/compare_asr.py scripts/ai/diagnose_env.py scripts/ai/live_simulate.py scripts/ai/make_fixtures.py scripts/ai/make_live_fixture.py scripts/ai/prepare_models.py scripts/ai/smoke.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.