Files
sber-med-server/README.md
T

178 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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-экспорт) |
## Быстрый запуск (локально)
```bash
# 1. Клонировать
git clone <URL-репозитория> 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
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=8063, threads=8)"
```
Приложение само создаёт при старте:
- `videos/` — сохранённые записи сканирования (рядом с app.py)
- `results.db` — SQLite с результатами (share_id начиная с 10005)
## Переменные окружения (секреты!)
Секреты **не хранятся в репозитории** — задаются через окружение:
| Переменная | Описание |
|---|---|
| `FPG_CLIENT_ID` | client_id для OAuth SDK ФПГ (по умолчанию `client_fpg_front`) |
| `FPG_CLIENT_SECRET` | client_secret для OAuth SDK ФПГ (**обязательна**, без неё авторизация не работает) |
| `CORS_ORIGINS` | (необязательно) список разрешённых Origin для CORS через запятую, например `https://site1.ru,https://site2.ru`. По умолчанию `*` |
## Развёртывание на сервере
### 1. Клонирование и структура
```bash
sudo mkdir -p /opt/med && sudo chown $USER:$USER /opt/med
git clone <URL-репозитория> /opt/med
cd /opt/med
mkdir -p templates static videos
```
### 2. Systemd-сервис
`/etc/systemd/system/med.service`:
```ini
[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
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=8063, threads=8)"
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
```
```bash
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`:
```nginx
server {
server_name med.my-dpr.ru;
client_max_body_size 100M; # видео до 100 МБ
location / {
proxy_pass http://127.0.0.1:8063;
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. Обновление кода
```bash
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 (bt709 + yuv420p — важно для iPhone MOV с P3/HDR)
3. OAuth-токен → создание сессии → кадры по WebSocket (`wss://gigadoc-sdk.sbermed.ai:8443`, subprotocol `bearer.<token>`, Origin `https://gigadoc.sbermed.ai`)
4. Интерпретация JSON SDK → summary/metrics/warnings/advice → сохранение в SQLite
## Важные нюансы
- **SDK ФПГ не находит лицо на кадрах 640×480** — нужны кадры 1280×720.
- **Камерное сканирование** (мобильные): canvas 720×720 (квадрат, без обрезки головы), MediaRecorder с битрейтом 1.5 Мбит/с (~1–2 МБ за 310 кадров), автоповтор fetch до 3 попыток при обрыве сети.
- **iOS MediaRecorder** пишет mp4 (webm может не поддерживаться) — расширение выбирается из `blob.type`.
- **Порт 5000** на сервере занят другим сервисом — приложение слушает 8063.
- Дисклеймер «не медицинский диагноз» — во всех отчётах и на страницах.
## Структура
```
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
```