Files
sber_med/README.md
T
apuc 7375618b1d Синхронизация с server/: нормализация видео, овал-подсказка, хосты с путём, DNR-стенд
- app.py: probe_video(), HDR→bt709, fps=30, -t 20, логирование progress/face_ok,
  split_host_path() для хостов с путём (domain.com/v1/giga), FPG_WS_PORT
- templates/index.html: овал-подсказка, canvas 1080×1080, запас 10%
- templates/result.html: стилевые правки (цвета)
- gigadoc_ws.py: поддержка пути в --sdk-host
- test_fpg.py: переведён на DNR-стенд (bearer subprotocol, Origin)
- README: хосты с путём, FPG_WS_PORT, нормализация
- .gitignore: server/, wordpress/, wordpress-plugin/ (отдельные репозитории)
2026-09-17 15:35:10 +03:00

9.3 KiB
Raw Blame History

Med Diagnostics — API-сервер (ФПГ GigaDoc)

Веб-приложение: пользователь загружает или записывает видео с лицом → система извлекает кадры → отправляет в SDK ФПГ (GigaDoc) → показывает понятный диагноз с сохранением в SQLite, share-ссылками, экспортом PDF/DOCX и скачиванием записанного видео.

Требования (проверено на сервере)

Компонент Версия
Python 3.10.10
ffmpeg 4.2.7 (нужен для извлечения кадров)
Flask 3.1.1
waitress 3.0.2
websockets 10.4 (важно: API extra_headers/origin появился в 10.x)
requests 2.28.2
reportlab 5.0.1 (PDF-экспорт, кириллица через DejaVu)
python-docx 1.2.0 (DOCX-экспорт)

Быстрый запуск (локально)

# 1. Клонировать
git clone https://git.itguild.info/apuc/sber-med-server.git med-server
cd med-server

# 2. Зависимости (рекомендуется venv)
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# 3. Шрифты DejaVu для кириллицы в PDF (обычно уже есть в системе)
sudo apt install -y fonts-dejavu

# 4. Секреты SDK ФПГ (обязательно!)
export FPG_CLIENT_ID=client_fpg_front_dnr
export FPG_CLIENT_SECRET=ВАШ_СЕКРЕТ

# 5. Запуск (dev-режим, порт 5000)
python3 app.py
# или через waitress (как на проде):
python3 -c "from waitress import serve; from app import app; serve(app, host='127.0.0.1', port=18018, threads=8)"

Приложение само создаёт при старте:

  • videos/ — сохранённые записи сканирования (рядом с app.py)
  • results.db — SQLite с результатами (share_id начиная с 10005)

Переменные окружения (секреты!)

Секреты не хранятся в репозитории — задаются через окружение:

Переменная Описание
FPG_CLIENT_ID client_id для OAuth SDK ФПГ (по умолчанию client_fpg_front_dnr — персональный стенд)
FPG_CLIENT_SECRET client_secret для OAuth SDK ФПГ (обязательна, без неё авторизация не работает)
CORS_ORIGINS (необязательно) список разрешённых Origin для CORS через запятую, например https://site1.ru,https://site2.ru. По умолчанию *
FPG_OAUTH_URL (необязательно) URL OAuth-токена (по умолчанию https://oauth.sbermed.ai/token)
FPG_REST_HOST (необязательно) REST-хост SDK (по умолчанию gigadoc-dnr-sdk.sbermed.ai — персональный стенд)
FPG_WS_HOST (необязательно) WebSocket-хост SDK (по умолчанию gigadoc-dnr-sdk.sbermed.ai)
FPG_WS_PORT (необязательно) WebSocket-порт SDK (по умолчанию 8443)
FPG_WS_ORIGIN (необязательно) Origin для WebSocket (по умолчанию https://gigadoc-dnr-sdk.sbermed.ai)

Хосты с путём. FPG_REST_HOST и FPG_WS_HOST могут содержать не только домен, но и путь — например domain.com/v1/giga (или полностью https://domain.com/v1/giga). Путь автоматически подставляется в REST-базу и в WebSocket-URI (wss://domain.com:8443/v1/giga/api/v2/ws/predict/...).

Развёртывание на сервере

1. Клонирование и структура

sudo mkdir -p /opt/med && sudo chown $USER:$USER /opt/med
git clone https://git.itguild.info/apuc/sber-med-server.git /opt/med
cd /opt/med
mkdir -p templates static videos

2. Systemd-сервис

/etc/systemd/system/med.service:

[Unit]
Description=Med Diagnostics (FPG GigaDoc)
After=network.target

[Service]
Type=simple
User=apuc
WorkingDirectory=/opt/med
Environment=PYTHONUNBUFFERED=1
Environment=FPG_CLIENT_ID=client_fpg_front_dnr
Environment=FPG_CLIENT_SECRET=ВАШ_СЕКРЕТ
ExecStart=/usr/bin/python3 -c "from waitress import serve; from app import app; serve(app, host='127.0.0.1', port=18018, threads=8)"
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now med.service
sudo systemctl status med.service

3. Nginx (HTTPS)

/etc/nginx/sites-enabled/med.my-dpr.ru:

server {
    server_name med.my-dpr.ru;

    client_max_body_size 100M;   # видео до 100 МБ

    location / {
        proxy_pass http://127.0.0.1:18018;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 60s;
        client_body_timeout 300s;   # важно: мобильная сеть может загружать медленно
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/med.my-dpr.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/med.my-dpr.ru/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}

Сертификат: sudo certbot --nginx -d med.my-dpr.ru

4. Обновление кода

cd /opt/med && git pull
sudo systemctl restart med.service

Маршруты

Маршрут Описание
/ Главная: загрузка файла или сканирование с камеры
/analyze (POST) Принимает video (mp4/avi/mov/mkv/webm/m4v), возвращает диагноз + share_id/share_url/video_url
/r/<share_id> Публичная страница результата (с OG-тегами)
/download/<share_id>/pdf Экспорт в PDF
/download/<share_id>/docx Экспорт в DOCX
/download/<video_id>/video Скачивание записанного видео (есть даже при ошибке анализа)

Как работает анализ

  1. Видео сохраняется в videos/ (копия записи — доступна для скачивания)
  2. ffmpeg извлекает до 300 кадров 1280×720 (первые 20 секунд, fps=30) с нормализацией: HDR→bt709 (iPhone P3/HDR), поворот по метаданным, yuv420p
  3. OAuth-токен → создание сессии → кадры по WebSocket (wss://gigadoc-dnr-sdk.sbermed.ai:8443, subprotocol bearer.<token>, Origin https://gigadoc-dnr-sdk.sbermed.ai)
  4. Интерпретация JSON SDK → summary/metrics/warnings/advice → сохранение в SQLite

Важные нюансы

  • SDK ФПГ не находит лицо на кадрах 640×480 — нужны кадры 1280×720.
  • Камерное сканирование (мобильные): canvas 1080×1080 (квадрат), овал-подсказка для позиционирования лица, запас 10% при захвате (голова не обрезается), MediaRecorder с битрейтом 1.5 Мбит/с (~1–2 МБ за 310 кадров), автоповтор fetch до 3 попыток при обрыве сети.
  • Логирование прогресса SDK: в логах сервера пишется progress и face_ok при каждом изменении; если финальный результат не пришёл — предупреждение в лог.
  • iOS MediaRecorder пишет mp4 (webm может не поддерживаться) — расширение выбирается из blob.type.
  • Порт 5000 на сервере занят другим сервисом — приложение слушает 18018.
  • Дисклеймер «не медицинский диагноз» — во всех отчётах и на страницах.

Структура

server/
├── app.py            — Flask-приложение (маршруты, CORS, анализ)
├── storage.py        — SQLite (share_id, результаты)
├── export.py         — PDF/DOCX-экспорт
├── interpret.py      — интерпретация JSON SDK → понятный результат
├── fpg_stream.py     — утилита: потоковая отправка кадров в SDK
├── fpg_connect.py    — утилита: проверка подключения к SDK
├── gigadoc_ws.py     — утилита: низкоуровневый WebSocket-клиент SDK (нужен aiohttp)
├── test_fpg.py       — тестовая отправка кадров
├── templates/        — index.html, result.html
├── static/           — og-image.png
└── requirements.txt