# ТЗ. Цифровая рецепция (видеоаналитика фронт-офиса) **Статус:** v0.1 (драфт для обсуждения) **Контекст:** компонент Платформы цифровых сервисов клиники (ПЦС), блок «Цифровые сервисы для администрации и управления». **Руководитель направления ПЦС:** Пётр Потураев. --- ## 1. Цели и KPI **Бизнес-цели:** - Контроль качества обслуживания на рецепции (объективные, а не «по ощущениям» цифры). - Снижение времени ожидания пациента и времени простоя администратора. - Раннее обнаружение инцидентов (неадекватное поведение). - Персональная история визитов пациента на рецепции для разбора жалоб и кейс-стади. **Целевые метрики (фиксируются как KPI):** - Среднее время ожидания в очереди (мин). - Среднее время обслуживания у стойки (мин). - Длина очереди (среднее, пиковое, по часам). - Время простоя администратора (мин/смена, %). - Количество пациентов, ушедших без обслуживания (шт/смена). - Количество и тип инцидентов (агрессия, скопление и т.п.). **Нормативов сейчас нет.** В админке пороги делаем редактируемыми (default — пустые). Базовые значения подбираем после 1–2 недель baseline-замеров на проде в анонимном режиме (Фаза 0). --- ## 2. Сценарии наблюдения **Зоны (логические, привязываются к камерам в админке):** - Зона A — вход в клинику. - Зона B — коридор / зона ожидания. - Зона C — стойка рецепции (рабочее место администратора). **События жизненного цикла визита:** | Событие | Триггер | |---|---| | `arrived` | трек впервые появился в зоне A | | `waiting` | трек удерживается в зоне B без позиции у стойки | | `service_started` | трек оказался у стойки C на расстоянии < X от администратора, > N сек | | `service_ended` | трек покинул зону C | | `left_without_service` | трек ушёл из зоны A/B без `service_started`, >= Tmin времени с `arrived` | Все пороги (X, N, Tmin) — настраиваемые. --- ## 3. Источники видео - IP-камеры (RTSP), уже стоят в клинике. Сырое видео **не храним**. - В рамках Фазы 0: **инвентаризация камер** (отдельная активность с заказчиком на месте): - ID/имя камеры, RTSP URL, разрешение, FPS, угол обзора, освещение, привязка к зоне (A/B/C). - Минимум для запуска: 1 камера на вход, 1 на коридор, 1 над стойкой. Желательно с перекрытием — нужно для cross-camera re-id. - Подключение по локальной сети клиники. Внешний доступ — только через VPN. --- ## 4. Идентификация пациентов ### 4.1 Подход В МИС Полимед фотографий пациентов нет, поэтому базу эмбеддингов строим сами. Используется только при наличии бумажного согласия пациента (см. 4.4). ### 4.2 Ручной enrollment (через web-admin) Сценарий старшего администратора: 1. Открывает страницу «Новые треки за смену». 2. Видит карточки треков. Один трек = серия кадров одного и того же человека, объединённая cross-camera re-id по лицевому эмбеддингу (вход → коридор → стойка). 3. Рядом — журнал записей на приём из Полимед за это же временное окно (REST: поиск пациентов / журнал записей). 4. Сопоставляет трек ↔ запись на приём → ставит галочку «бумажное согласие получено» → подтверждает. 5. Эмбеддинг сохраняется в нашей БД с привязкой к `patient_id` из Полимед. Без галочки согласия эмбеддинг в долгую базу не уходит; трек живёт обезличенно до конца смены и удаляется. ### 4.3 Автоматическое распознавание (повторные визиты) - При появлении лица — поиск ближайшего эмбеддинга в pgvector (cos distance, top-5). - Threshold 0.35 (как в time-tracker, тюнингуем после первой партии данных). - При match → подтягиваем из Полимед текущий приём → метрики становятся персональными. ### 4.4 Согласие - Только бумажный носитель (договор/анкета). - В админке оператор ставит галочку «согласие получено». - Отзыв согласия → удаление эмбеддинга и персональной истории визитов в течение 24 ч. Обезличенные агрегаты остаются. --- ## 5. Приватность и 152-ФЗ - Биометрические ПДн (лицевые эмбеддинги) обрабатываются только при наличии письменного согласия. - Сырое видео **не записывается** на диск. - Хранятся: - Лицевые эмбеддинги (512-d) — pgvector. - Метаданные треков (timestamps, camera_id, события). - Кадры-доказательства для инцидентов — MinIO, TTL 30 дней (настраиваемо). - ЕБС не используется. - Журнал доступа к биометрии (кто, когда, к чьим данным) — для аудита. - Контур развёртывания — внутри ЛВС клиники. Внешний доступ только через VPN. --- ## 6. Архитектура ### 6.1 Сервисы | Сервис | Стек | Назначение | |---|---|---| | `video-ingest` | Python, OpenCV/ffmpeg, YOLOv8 (или RT-DETR), ByteTrack/BoT-SORT | На каждую RTSP-камеру отдельный воркер. Декод (по возможности NVDEC), детекция людей, трекинг внутри камеры, выдача кропов лиц и событий треков. | | `face-service` | Python/FastAPI, InsightFace `buffalo_l`, pgvector | Эмбеддинги лиц, поиск ближайших, эндпоинт cross-camera re-id (склейка треков с разных камер по эмбеддингу в окне T минут). Переиспользуется из `work-pcs-adm-time-tracker`. | | `behavior-service` | Python, action recognition (SlowFast / X3D / MoViNet) | Распознавание агрессии. **Фаза 2.** | | `analytics-worker` | Node.js, BullMQ | Считает метрики (очередь, время ожидания/обслуживания), формирует инциденты. | | `api` | Nest.js, Prisma | Коннектор к Полимед, enrollment-API, дашборд-API, RBAC. | | `web-admin` | Next.js 15 (App Router), shadcn/ui, Recharts | Дашборд управляющего, ручной enrollment, фиксация согласий, пороги, расписание алертов, лента инцидентов. | | `max-bot` | Node.js | Рассылка алертов в мессенджер Max. Фаза 2 (после `behavior-service`). | ### 6.2 Инфраструктура - PostgreSQL 16 + pgvector. - Redis (BullMQ). - MinIO (кадры-доказательства). - GPU-сервер (NVIDIA, CUDA, nvidia-container-toolkit) — для `video-ingest`, `face-service`, `behavior-service`. - Docker Compose (по образцу time-tracker, отдельный `docker-compose.prod.yml`). - Монорепо: pnpm + Turborepo. ### 6.3 Видеопайплайн (детально) 1. `video-ingest` открывает RTSP по камере (1 воркер = 1 камера). 2. Декодирование на GPU (NVDEC) при поддержке камеры; fallback на CPU. 3. Детектор людей — каждый N-й кадр (целевая частота ~5 fps хватит для рецепции). 4. Трекер (ByteTrack или BoT-SORT) — треки внутри одной камеры. 5. На каждый трек периодически вырезается лучший по качеству кроп лица (фронтальность, размер, sharpness) → в `face-service`. 6. `face-service` считает эмбеддинг. Если в окне последних T минут есть открытый трек с близким эмбеддингом — треки склеиваются (cross-camera re-id). Окно T — настраиваемо. 7. События трека (`arrived` / `waiting` / `service_started` / `service_ended` / `left_without_service`) уходят в `api` → `analytics-worker`. --- ## 7. Интеграции ### 7.1 МИС Полимед (REST) - **Read:** поиск пациента по ФИО, журнал записей на дату, статус визита. - **Write:** события визита на рецепции (`arrived`, `service_started`, `service_ended`) — назад в Полимед (объём write-операций уточняется со стороны Полимед). ### 7.2 Мессенджер Max (бот) - Минимально (Фаза 2): инциденты «неадекватное поведение» (агрессия) → сообщение с кадром-доказательством. - Получатели и расписание — настраиваются в админке. - Расширения (по запросу): сводки за смену, триггерные алерты по очереди и т.п. ### 7.3 ПЦС-портал - SSO и общие роли (Управляющий, Старший администратор, Безопасность, Админ системы) — на уровне ПЦС. На время Фазы 0 — локальная авторизация (как в time-tracker, JWT + refresh). --- ## 8. Роли и UI | Роль | Что видит / делает | |---|---| | Управляющий клиники | Live-дашборд (текущая очередь, метрики смены), отчёты день/неделя/месяц, лента инцидентов. | | Старший администратор | Очередь задач на enrollment, ручная привязка треков к пациентам Полимед, фиксация согласий, отзыв согласия. | | Безопасность | Лента инцидентов «неадекватное поведение» + кадры. | | Админ системы | Камеры (RTSP, привязка к зонам), пороги метрик, расписание алертов, пользователи и роли. | --- ## 9. Фазы ### Фаза 0 — MVP, анонимная аналитика (2–4 нед) - Инвентаризация камер. - `video-ingest` + детекция + трекинг (без идентификации). - Метрики: длина очереди, время ожидания, время обслуживания, время простоя администратора, ушедшие без обслуживания. - Дашборд управляющего (live + отчёт за день/смену). - Baseline-замеры для подбора порогов. **Критерий завершения:** управляющий видит реальные цифры по своей рецепции и может настроить пороги. ### Фаза 1 — идентификация + Полимед (+4–6 нед) - `face-service` + pgvector. - Cross-camera re-id (склейка треков по лицевому эмбеддингу). - Web-admin: страница ручного enrollment с журналом записей из Полимед. - Фиксация бумажных согласий, отзыв согласия (удаление за 24 ч). - Персональная история визитов пациента. - Write-события визитов в Полимед (если согласовано со стороны МИС). **Критерий завершения:** при повторном визите пациента (после первого ручного enrollment) система автоматически узнаёт его и подтягивает текущий приём из Полимед. ### Фаза 2 — поведенческие сигналы (+6–8 нед) - `behavior-service`: action recognition на агрессию. - `max-bot`: алерты в Max с кадром-доказательством. - Логика «уход без обслуживания» (поверх треков, без отдельной модели). - Скопление в зоне (counter, без отдельной модели). **Критерий завершения:** инцидент агрессии у стойки рецепции в течение ≤ N секунд попадает в Max нужному получателю. ### Фаза 3+ — по запросу - Дополнительные поведенческие сигналы. - Сводки и триггерные алерты в Max. - Интеграции с другими компонентами ПЦС. --- ## 10. Открытые вопросы - Точная спецификация REST-эндпоинтов Полимед (методы, форматы, аутентификация). - Допустимость write-операций назад в Полимед и их объём. - Параметры Max-бота (как регистрируется бот, какой API/SDK). - Хостинг GPU-сервера (внутри ЛВС клиники, требования по сети и питанию). - Шаблон согласия на обработку биометрических ПДн (юр. отдел). - SSO от ПЦС: на каком этапе подключаем. --- ## Приложение A. Тех. стек = `work-pcs-adm-time-tracker` + дельта | Компонент | Из time-tracker (`/Users/alekseyrazorvinm4/Project-with-LLM/work-pcs-adm-time-tracker`) | Дельта для «Цифровой рецепции» | |---|---|---| | Языки | Node.js (Nest.js, Next.js), Python (FastAPI) | + Python для `video-ingest` и `behavior-service` | | Распознавание лиц | InsightFace `buffalo_l` (`/apps/face-service`) | — (переиспользуем) | | Векторный поиск | PostgreSQL + pgvector (`/packages/db/prisma/schema.prisma`) | — (переиспользуем) | | Видео-вход | MediaDevices браузера, кадр раз в 2 сек | → серверный RTSP-консьюмер (OpenCV/ffmpeg), GPU | | Трекинг | нет | + ByteTrack / BoT-SORT | | Cross-camera re-id | нет | + по лицевому эмбеддингу в окне T мин | | Action recognition | нет | + SlowFast / X3D / MoViNet (Фаза 2) | | Хранилище | Postgres + pgvector, Redis | + MinIO (кадры-доказательства) | | Деплой | docker-compose (`/docker/docker-compose.yml`) | + GPU-runtime (nvidia-container-toolkit), `docker-compose.prod.yml` | | Авторизация | JWT + refresh в httpOnly cookie (`/apps/api`) | — (Ф0), → SSO от ПЦС (Ф1+) | | Монорепо | pnpm + Turborepo | — (переиспользуем) | **Ссылки для разработки:** - `/Users/alekseyrazorvinm4/Project-with-LLM/work-pcs-adm-time-tracker/ARCHITECTURE.md` — техническая схема time-tracker. - `/Users/alekseyrazorvinm4/Project-with-LLM/work-pcs-adm-time-tracker/apps/face-service/main.py` — `/recognize` эндпоинт. - `/Users/alekseyrazorvinm4/Project-with-LLM/work-pcs-adm-time-tracker/apps/face-service/requirements.txt` — версии Python-зависимостей. - `/Users/alekseyrazorvinm4/Project-with-LLM/work-pcs-adm-time-tracker/packages/db/prisma/schema.prisma` — модель данных.