146 lines
6.2 KiB
Markdown
146 lines
6.2 KiB
Markdown
# Диагностика по видео (ФПГ 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-экспорт) |
|
||
|
||
Установка зависимостей (на сервере venv могут быть сломаны — ставится через `pip install --user`):
|
||
|
||
```bash
|
||
pip install --user flask waitress websockets requests reportlab python-docx
|
||
```
|
||
|
||
Шрифты DejaVu для кириллицы в PDF (обычно уже есть в системе):
|
||
```bash
|
||
apt list --installed 2>/dev/null | grep fonts-dejavu || sudo apt install -y fonts-dejavu
|
||
```
|
||
|
||
## Переменные окружения (секреты!)
|
||
|
||
Секреты **не хранятся в репозитории** — задаются через окружение:
|
||
|
||
| Переменная | Описание |
|
||
|---|---|
|
||
| `FPG_CLIENT_ID` | client_id для OAuth SDK ФПГ (по умолчанию `client_fpg_front`) |
|
||
| `FPG_CLIENT_SECRET` | client_secret для OAuth SDK ФПГ (**обязательна**, без неё авторизация не работает) |
|
||
|
||
## Развёртывание
|
||
|
||
### 1. Клонирование и структура
|
||
|
||
```bash
|
||
sudo mkdir -p /opt/med && sudo chown $USER:$USER /opt/med
|
||
git clone https://git.itguild.info/apuc/sber_med.git /opt/med
|
||
cd /opt/med
|
||
mkdir -p templates static videos
|
||
```
|
||
|
||
Приложение само создаёт при старте:
|
||
- `videos/` — сохранённые записи сканирования (рядом с app.py)
|
||
- `results.db` — SQLite с результатами (share_id начиная с 10005)
|
||
|
||
### 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.
|
||
- Дисклеймер «не медицинский диагноз» — во всех отчётах и на страницах. |