Веб-приложение для HR-отдела вуза. Объединяет ИИ-ассистента по кадровым вопросам, базу знаний, генерацию кадровых документов, мессенджер, новости, уведомления и контур персональных данных. Модель работает локально (GGUF + GPU) — данные не покидают контур организации.
ИИ-ассистент. Чат со стриминговыми ответами и ссылками на источники. Ответы строятся по базе знаний (RAG): гибридный поиск — векторный (Qdrant) и BM25 с русской лемматизацией — плюс реранкер. Запросы к модели встают в очередь с видимой позицией; несколько генераций считаются параллельно.
База знаний. Загрузка документов (PDF, Word, Excel, PowerPoint, ODF, RTF, текст, изображения), OCR сканов через Tesseract, парсинг старых форматов Office через LibreOffice. Веб-источники с периодическим обновлением, приоритеты документов, контроль актуальности, индексация с возобновлением после сбоя.
Генерация кадровых документов. Диалоговые инструменты-мастера Б1–Б7: справки, характеристики, описи дел, отчёты ДПО и другие. Недостающие поля ассистент дозапрашивает в диалоге, автозаполнение берёт данные из базы. Готовые файлы — .docx по шаблонам (docxtemplater). Встроенный просмотрщик документов всех поддерживаемых форматов, приведение схем бизнес-процессов к единому виду (SVG).
Мессенджер. Личные и групповые переписки, вложения с предпросмотром, индикатор набора текста, отметки о прочтении, плавающая панель с перетаскиванием и закреплением, вынос в отдельное окно (Document Picture-in-Picture).
Новости и голосования. Редактор с встроенной обработкой картинок (поворот, обрезка, масштаб), голосования с итогами.
Уведомления. Realtime через SSE, Web Push (работает и при закрытой вкладке), счётчики непрочитанного с автопометкой по видимости.
Контур персональных данных. Карточки сотрудников, документы ПДн, автоудаление по истечении срока хранения, аудит доступа, сохранение черновика при истечении сессии.
Админка. Пользователи, их активность, диалоги и переписки, аудит ПДн.
PWA. Манифест, офлайн-страница, установка на телефон; доступ из локальной
сети (.\start.ps1 -OpenFirewall).
HR_Helper/
├── app/ # Next.js 16 — всё приложение: UI, API, ML-контур
├── docker-compose.yml # PostgreSQL + Qdrant
├── dev.ps1, start.ps1 # запуск
└── README.md
Предыдущая реализация (Python/FastAPI) — в ветке legacy.
Одно приложение на Next.js 16 (App Router): страницы, 111 обработчиков API, RAG и локальная LLM в одном процессе, плюс отдельный worker для фоновых заданий.
app/proxy.ts по наличию сессионной cookie;
protected API сам отвечает 401.GET /api/events (SSE) подключается в layout и раздаёт события
страницам через DOM CustomEvents hr:*.POST /api/chat/stream читается через
fetch + ReadableStream (app/lib/api.ts → postSSE).app/prisma/schema.prisma)
и Qdrant для векторов; файлы документов лежат на диске, в базе — метаданные.app/public/sw.js, manifest.webmanifest, офлайн-страница, Web Push.app/lib/ml/)node-llama-cpp на GPU.
Несколько независимых последовательностей считаются в одном контексте общим
батчем; лимиты — LLM_MAX_CONCURRENT (одновременные генерации),
ASSISTANT_QUEUE_MAXSIZE (предел очереди), ASSISTANT_MAX_PER_USER
(анти-флуд).app/lib/ml/bm25.ts: Az.js → стеммер Snowball → исходное слово); реранкер
jina-reranker-v2.unpdf, сканы распознаёт Tesseract (страница скана
и есть картинка), старые форматы Office конвертирует LibreOffice.Тонкости настройки GPU:
LLM_N_GPU_LAYERS=max; значение -1 в node-llama-cpp
оставляет модель на процессоре, и скорость падает примерно в 50 раз.LLM_GPU_BACKEND=cuda — иначе выбирается Vulkan,
который на NVIDIA заметно медленнее.{max: N}), а не жёстко: KV-кэш
на 16k × несколько слотов не помещается в 12 ГБ видеопамяти вместе с весами.serverExternalPackages
(next.config.ts) — иначе после сборки модель молча не грузится и чат
отвечает заглушкой.Всё поднимается одной командой:
.\start.ps1
Скрипт проверит окружение, поднимет PostgreSQL и Qdrant в Docker, соберёт приложение и запустит два процесса в отдельных окнах. Открывать — http://localhost:3000.
| Ключ | Что делает |
|---|---|
.\start.ps1 | боевой режим: собранный Next.js |
.\start.ps1 -Dev | режим разработки с горячей перезагрузкой |
.\start.ps1 -NoLlm | без локальной модели — старт за секунды, ответы-заглушки |
.\start.ps1 -SkipBuild | не пересобирать приложение |
.\start.ps1 -OpenFirewall | открыть порт 3000 для домашней сети (от админа) |
.\start.ps1 -Stop | остановить всё |
Что именно запускается:
Первый ответ ассистента занимает около десяти секунд — модель загружается в видеопамять. Дальше ответы идут за считанные секунды.
Если что-то нужно поднять вручную:
cd app; npm run start # :3000 (или npm run dev)
cd app; npm run worker # фоновые задания
Рабочий файл — app/.env (шаблон — app/.env.example). Ключевые переменные:
DATABASE_URL — PostgreSQL в формате Prisma (postgresql://…);SECRET_KEY — ключ подписи сессионной cookie;CRON_SECRET — секрет cron-эндпоинтов; без него фоновые задания
(в том числе автоудаление ПДн) не запустятся;LLM_* — путь к GGUF-модели и настройки GPU (см. выше).Периодические задания живут в отдельном процессе (npm run worker).
Либо их можно дёргать внешним планировщиком (Windows Task Scheduler, cron):
POST /api/cron/web-sources
POST /api/cron/documents-freshness
POST /api/cron/pii-cleanup
POST /api/cron/resume-indexing
Эндпоинты закрыты секретом CRON_SECRET (заголовок X-Cron-Secret либо
Authorization: Bearer). Без него — 401.
npm start) таймаутов нет.
Serverless-хостинг вроде Vercel не подходит: генерация на минуту-две
упирается в лимит функции.react-hooks/set-state-in-effect,
refs, immutability) — правила нового React-плагина срабатывают на
рабочих паттернах; сборке и работе не мешают.4 commits
TypeScript
98.2%
Веб-приложение для HR-отдела вуза. Объединяет ИИ-ассистента по кадровым вопросам, базу знаний, генерацию кадровых документов, мессенджер, новости, уведомления и контур персональных данных. Модель работает локально (GGUF + GPU) — данные не покидают контур организации.
ИИ-ассистент. Чат со стриминговыми ответами и ссылками на источники. Ответы строятся по базе знаний (RAG): гибридный поиск — векторный (Qdrant) и BM25 с русской лемматизацией — плюс реранкер. Запросы к модели встают в очередь с видимой позицией; несколько генераций считаются параллельно.
База знаний. Загрузка документов (PDF, Word, Excel, PowerPoint, ODF, RTF, текст, изображения), OCR сканов через Tesseract, парсинг старых форматов Office через LibreOffice. Веб-источники с периодическим обновлением, приоритеты документов, контроль актуальности, индексация с возобновлением после сбоя.
Генерация кадровых документов. Диалоговые инструменты-мастера Б1–Б7: справки, характеристики, описи дел, отчёты ДПО и другие. Недостающие поля ассистент дозапрашивает в диалоге, автозаполнение берёт данные из базы. Готовые файлы — .docx по шаблонам (docxtemplater). Встроенный просмотрщик документов всех поддерживаемых форматов, приведение схем бизнес-процессов к единому виду (SVG).
Мессенджер. Личные и групповые переписки, вложения с предпросмотром, индикатор набора текста, отметки о прочтении, плавающая панель с перетаскиванием и закреплением, вынос в отдельное окно (Document Picture-in-Picture).
Новости и голосования. Редактор с встроенной обработкой картинок (поворот, обрезка, масштаб), голосования с итогами.
Уведомления. Realtime через SSE, Web Push (работает и при закрытой вкладке), счётчики непрочитанного с автопометкой по видимости.
Контур персональных данных. Карточки сотрудников, документы ПДн, автоудаление по истечении срока хранения, аудит доступа, сохранение черновика при истечении сессии.
Админка. Пользователи, их активность, диалоги и переписки, аудит ПДн.
PWA. Манифест, офлайн-страница, установка на телефон; доступ из локальной
сети (.\start.ps1 -OpenFirewall).
HR_Helper/
├── app/ # Next.js 16 — всё приложение: UI, API, ML-контур
├── docker-compose.yml # PostgreSQL + Qdrant
├── dev.ps1, start.ps1 # запуск
└── README.md
Предыдущая реализация (Python/FastAPI) — в ветке legacy.
Одно приложение на Next.js 16 (App Router): страницы, 111 обработчиков API, RAG и локальная LLM в одном процессе, плюс отдельный worker для фоновых заданий.
app/proxy.ts по наличию сессионной cookie;
protected API сам отвечает 401.GET /api/events (SSE) подключается в layout и раздаёт события
страницам через DOM CustomEvents hr:*.POST /api/chat/stream читается через
fetch + ReadableStream (app/lib/api.ts → postSSE).app/prisma/schema.prisma)
и Qdrant для векторов; файлы документов лежат на диске, в базе — метаданные.app/public/sw.js, manifest.webmanifest, офлайн-страница, Web Push.app/lib/ml/)node-llama-cpp на GPU.
Несколько независимых последовательностей считаются в одном контексте общим
батчем; лимиты — LLM_MAX_CONCURRENT (одновременные генерации),
ASSISTANT_QUEUE_MAXSIZE (предел очереди), ASSISTANT_MAX_PER_USER
(анти-флуд).app/lib/ml/bm25.ts: Az.js → стеммер Snowball → исходное слово); реранкер
jina-reranker-v2.unpdf, сканы распознаёт Tesseract (страница скана
и есть картинка), старые форматы Office конвертирует LibreOffice.Тонкости настройки GPU:
LLM_N_GPU_LAYERS=max; значение -1 в node-llama-cpp
оставляет модель на процессоре, и скорость падает примерно в 50 раз.LLM_GPU_BACKEND=cuda — иначе выбирается Vulkan,
который на NVIDIA заметно медленнее.{max: N}), а не жёстко: KV-кэш
на 16k × несколько слотов не помещается в 12 ГБ видеопамяти вместе с весами.serverExternalPackages
(next.config.ts) — иначе после сборки модель молча не грузится и чат
отвечает заглушкой.Всё поднимается одной командой:
.\start.ps1
Скрипт проверит окружение, поднимет PostgreSQL и Qdrant в Docker, соберёт приложение и запустит два процесса в отдельных окнах. Открывать — http://localhost:3000.
| Ключ | Что делает |
|---|---|
.\start.ps1 | боевой режим: собранный Next.js |
.\start.ps1 -Dev | режим разработки с горячей перезагрузкой |
.\start.ps1 -NoLlm | без локальной модели — старт за секунды, ответы-заглушки |
.\start.ps1 -SkipBuild | не пересобирать приложение |
.\start.ps1 -OpenFirewall | открыть порт 3000 для домашней сети (от админа) |
.\start.ps1 -Stop | остановить всё |
Что именно запускается:
Первый ответ ассистента занимает около десяти секунд — модель загружается в видеопамять. Дальше ответы идут за считанные секунды.
Если что-то нужно поднять вручную:
cd app; npm run start # :3000 (или npm run dev)
cd app; npm run worker # фоновые задания
Рабочий файл — app/.env (шаблон — app/.env.example). Ключевые переменные:
DATABASE_URL — PostgreSQL в формате Prisma (postgresql://…);SECRET_KEY — ключ подписи сессионной cookie;CRON_SECRET — секрет cron-эндпоинтов; без него фоновые задания
(в том числе автоудаление ПДн) не запустятся;LLM_* — путь к GGUF-модели и настройки GPU (см. выше).Периодические задания живут в отдельном процессе (npm run worker).
Либо их можно дёргать внешним планировщиком (Windows Task Scheduler, cron):
POST /api/cron/web-sources
POST /api/cron/documents-freshness
POST /api/cron/pii-cleanup
POST /api/cron/resume-indexing
Эндпоинты закрыты секретом CRON_SECRET (заголовок X-Cron-Secret либо
Authorization: Bearer). Без него — 401.
npm start) таймаутов нет.
Serverless-хостинг вроде Vercel не подходит: генерация на минуту-две
упирается в лимит функции.react-hooks/set-state-in-effect,
refs, immutability) — правила нового React-плагина срабатывают на
рабочих паттернах; сборке и работе не мешают.4 commits
TypeScript
98.2%