TheColdGuy251/HR_Helper

0

stars

4

commits

TypeScript

primary language

Aug 12, 2026

updated

README

HR-помощник ТИУ

Веб-приложение для 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.
  • Realtime: GET /api/events (SSE) подключается в layout и раздаёт события страницам через DOM CustomEvents hr:*.
  • Стриминг ответа ассистента: POST /api/chat/stream читается через fetch + ReadableStream (app/lib/api.ts → postSSE).
  • Хранилища: PostgreSQL (через Prisma, схема — app/prisma/schema.prisma) и Qdrant для векторов; файлы документов лежат на диске, в базе — метаданные.
  • PWA: app/public/sw.js, manifest.webmanifest, офлайн-страница, Web Push.

ML-контур (app/lib/ml/)

  • LLM — локальная GGUF-модель (~4,6 ГБ) через node-llama-cpp на GPU. Несколько независимых последовательностей считаются в одном контексте общим батчем; лимиты — LLM_MAX_CONCURRENT (одновременные генерации), ASSISTANT_QUEUE_MAXSIZE (предел очереди), ASSISTANT_MAX_PER_USER (анти-флуд).
  • RAG-пайплайн — исправление опечаток, определение намерения, планировщик запроса (структурные режимы отвечают детерминированно по индексу), HyDE, декомпозиция запросов, self-check, семантический роутер.
  • Поиск — эмбеддинги ONNX через Transformers.js, косинусная метрика в Qdrant; BM25 с лемматизацией Az.js на словарях OpenCorpora (порядок разбора в app/lib/ml/bm25.ts: Az.js → стеммер Snowball → исходное слово); реранкер jina-reranker-v2.
  • Парсеры — PDF читает unpdf, сканы распознаёт Tesseract (страница скана и есть картинка), старые форматы Office конвертирует LibreOffice.

Тонкости настройки GPU:

  • Число 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остановить всё

Что именно запускается:

  • Next.js :3000 — всё приложение, включая ИИ-ассистента; сюда и заходить;
  • воркер — фоновые задания: автоудаление ПДн, обновление веб-источников, контроль актуальности документов, возобновление зависших индексаций.

Первый ответ ассистента занимает около десяти секунд — модель загружается в видеопамять. Дальше ответы идут за считанные секунды.

Если что-то нужно поднять вручную:

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.

Ограничения

  • WebSocket. Обработчики маршрутов Next.js не умеют protocol upgrade, поэтому индикатор набора и отметки о прочтении в мессенджере ходят по HTTP-пути.
  • Один инстанс. Онлайн-статус выводится из открытых SSE-подключений в памяти процесса; там же живёт состояние добора полей при генерации документа. При горизонтальном масштабировании их нужно выносить в Redis или БД.
  • Долгие LLM-запросы. При self-hosted (npm start) таймаутов нет. Serverless-хостинг вроде Vercel не подходит: генерация на минуту-две упирается в лимит функции.

Известные недоработки

  • Линтер выдаёт 37 предупреждений (react-hooks/set-state-in-effect, refs, immutability) — правила нового React-плагина срабатывают на рабочих паттернах; сборке и работе не мешают.

Contributors

TheColdGuy251

4 commits

TheColdGuy251/HR_Helper

0

stars

4

commits

TypeScript

primary language

Aug 12, 2026

updated

README

HR-помощник ТИУ

Веб-приложение для 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.
  • Realtime: GET /api/events (SSE) подключается в layout и раздаёт события страницам через DOM CustomEvents hr:*.
  • Стриминг ответа ассистента: POST /api/chat/stream читается через fetch + ReadableStream (app/lib/api.ts → postSSE).
  • Хранилища: PostgreSQL (через Prisma, схема — app/prisma/schema.prisma) и Qdrant для векторов; файлы документов лежат на диске, в базе — метаданные.
  • PWA: app/public/sw.js, manifest.webmanifest, офлайн-страница, Web Push.

ML-контур (app/lib/ml/)

  • LLM — локальная GGUF-модель (~4,6 ГБ) через node-llama-cpp на GPU. Несколько независимых последовательностей считаются в одном контексте общим батчем; лимиты — LLM_MAX_CONCURRENT (одновременные генерации), ASSISTANT_QUEUE_MAXSIZE (предел очереди), ASSISTANT_MAX_PER_USER (анти-флуд).
  • RAG-пайплайн — исправление опечаток, определение намерения, планировщик запроса (структурные режимы отвечают детерминированно по индексу), HyDE, декомпозиция запросов, self-check, семантический роутер.
  • Поиск — эмбеддинги ONNX через Transformers.js, косинусная метрика в Qdrant; BM25 с лемматизацией Az.js на словарях OpenCorpora (порядок разбора в app/lib/ml/bm25.ts: Az.js → стеммер Snowball → исходное слово); реранкер jina-reranker-v2.
  • Парсеры — PDF читает unpdf, сканы распознаёт Tesseract (страница скана и есть картинка), старые форматы Office конвертирует LibreOffice.

Тонкости настройки GPU:

  • Число 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остановить всё

Что именно запускается:

  • Next.js :3000 — всё приложение, включая ИИ-ассистента; сюда и заходить;
  • воркер — фоновые задания: автоудаление ПДн, обновление веб-источников, контроль актуальности документов, возобновление зависших индексаций.

Первый ответ ассистента занимает около десяти секунд — модель загружается в видеопамять. Дальше ответы идут за считанные секунды.

Если что-то нужно поднять вручную:

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.

Ограничения

  • WebSocket. Обработчики маршрутов Next.js не умеют protocol upgrade, поэтому индикатор набора и отметки о прочтении в мессенджере ходят по HTTP-пути.
  • Один инстанс. Онлайн-статус выводится из открытых SSE-подключений в памяти процесса; там же живёт состояние добора полей при генерации документа. При горизонтальном масштабировании их нужно выносить в Redis или БД.
  • Долгие LLM-запросы. При self-hosted (npm start) таймаутов нет. Serverless-хостинг вроде Vercel не подходит: генерация на минуту-две упирается в лимит функции.

Известные недоработки

  • Линтер выдаёт 37 предупреждений (react-hooks/set-state-in-effect, refs, immutability) — правила нового React-плагина срабатывают на рабочих паттернах; сборке и работе не мешают.

Contributors

TheColdGuy251

4 commits

Languages

TypeScript

98.2%