AAYMA
RU
Войти

DARAI

Локальный AI-ассистент совещаний в виде внутренней CRM.

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

О проекте

Команда: 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.md

DARAI — локальный ИИ-ассистент совещаний

DARAI — хакатонный прототип внутренней CRM, который превращает запись совещания в транскрипт, список поручений с ответственными и сроками, саммари и протокол DOCX/PDF. Целевые языки — русский, казахский и смешанная речь.

Система сокращает ручную работу секретаря: распознаёт разговор, предлагает личности спикеров и поручения, сохраняет подтверждающие реплики. Секретарь проверяет черновик перед утверждением; исполнители получают задачи и уведомления внутри CRM.

Статус: backend, frontend и локальный AI-пайплайн реализованы. Доступны загрузка файла и запись из браузера с предварительным транскриптом. Качество смешанной речи и задержка live зависят от записи и оборудования; это прототип, а не готовое промышленное решение.

Возможности

ФункцияРеализация
СотрудникиФИО, должность, департамент, локальная учётная запись
Выдача доступаВременный пароль, обязательная смена, сброс и отзыв сессий
Голосовой профильСамостоятельная запись/загрузка образца, проверка качества, замена и удаление
Удаление сотрудникаАрхивирование с блокировкой доступа и сохранением истории; права проверяются сервером
СовещанияНазвание, дата, часовой пояс, повестка, участники, необязательная ссылка на внешний звонок
Источники записиГотовый аудио/видеофайл; микрофон; звук вкладки/экрана с дополнительным микрофоном
Live-транскриптПостепенные обновления, черновые реплики, состояние отправки и задержка обработки
Итоговый протоколПолная транскрибация, диаризация, сопоставление голосов, поручения и саммари
ПроверкаРучное сопоставление спикеров, редактирование поручений и саммари, утверждение
Исполнение«Мои поручения», выполнение, сроки, внутренние уведомления и напоминания
ЭкспортDOCX и PDF; черновик обозначается в документе

Ссылка на Meet/Zoom/Teams только открывает внешний звонок. Бот к нему не подключается. В онлайн-режиме пользователь сам выбирает источник звука в браузере. Имена спикеров и поручения формируются при финальной обработке; live-preview предназначен прежде всего для текста.

Основной сценарий

  1. Администратор создаёт сотрудников и выдаёт локальные учётные записи.
  2. Сотрудник входит, меняет временный пароль и регистрирует голос в «Моём профиле». Без голосового профиля CRM остаётся доступна.
  3. Секретарь создаёт встречу, выбирает участников и уведомляет их о записи и ИИ-обработке.
  4. В карточке встречи выбирает язык и профиль STT, сохраняет настройки.
  5. Загружает готовый файл либо нажимает «Записать сейчас» → выбирает режим → «Подготовить источник» → «Начать запись».
  6. Во время разговора видит предварительный транскрипт. После «Завершить запись» система обрабатывает полный файл.
  7. Секретарь проверяет спикеров, цитаты, исполнителей и сроки, исправляет черновик и утверждает его.
  8. Исполнители видят подтверждённые задачи и уведомления; секретарь скачивает 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
КомпонентТехнология
Итоговый STTfaster-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/                 Контракты и подробные инструкции

Команда DARAI: Raim, Daneker, Adilet.

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

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

Daneker Kaliaskaruly 11GetLivreru 1iD1eat 1

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

  • 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 комментариев

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

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