Синхронизация с 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/ (отдельные репозитории)
This commit is contained in:
1 parent
421183b7e3
commit
7375618b1d
9 files changed
+423
-108
No files matched your search
@@ -1,4 +1,4 @@
|
||||
# Диагностика по видео (ФПГ GigaDoc)
|
||||
# Med Diagnostics — API-сервер (ФПГ GigaDoc)
|
||||
|
||||
Веб-приложение: пользователь загружает или записывает видео с лицом → система извлекает кадры → отправляет в SDK ФПГ (GigaDoc) → показывает понятный диагноз с сохранением в SQLite, share-ссылками, экспортом PDF/DOCX и скачиванием записанного видео.
|
||||
|
||||
@@ -15,16 +15,34 @@
|
||||
| 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
|
||||
# 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)"
|
||||
```
|
||||
|
||||
Шрифты DejaVu для кириллицы в PDF (обычно уже есть в системе):
|
||||
```bash
|
||||
apt list --installed 2>/dev/null | grep fonts-dejavu || sudo apt install -y fonts-dejavu
|
||||
```
|
||||
Приложение само создаёт при старте:
|
||||
- `videos/` — сохранённые записи сканирования (рядом с app.py)
|
||||
- `results.db` — SQLite с результатами (share_id начиная с 10005)
|
||||
|
||||
## Переменные окружения (секреты!)
|
||||
|
||||
@@ -32,24 +50,28 @@ apt list --installed 2>/dev/null | grep fonts-dejavu || sudo apt install -y font
|
||||
|
||||
| Переменная | Описание |
|
||||
|---|---|
|
||||
| `FPG_CLIENT_ID` | client_id для OAuth SDK ФПГ (по умолчанию `client_fpg_front`) |
|
||||
| `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. Клонирование и структура
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /opt/med && sudo chown $USER:$USER /opt/med
|
||||
git clone https://git.itguild.info/apuc/sber_med.git /opt/med
|
||||
git clone https://git.itguild.info/apuc/sber-med-server.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`:
|
||||
@@ -64,9 +86,9 @@ Type=simple
|
||||
User=apuc
|
||||
WorkingDirectory=/opt/med
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
Environment=FPG_CLIENT_ID=client_fpg_front
|
||||
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=8063, threads=8)"
|
||||
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
|
||||
|
||||
@@ -91,7 +113,7 @@ server {
|
||||
client_max_body_size 100M; # видео до 100 МБ
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8063;
|
||||
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;
|
||||
@@ -133,14 +155,32 @@ sudo systemctl restart med.service
|
||||
## Как работает анализ
|
||||
|
||||
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`)
|
||||
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 720×720 (квадрат, без обрезки головы), MediaRecorder с битрейтом 1.5 Мбит/с (~1–2 МБ за 310 кадров), автоповтор fetch до 3 попыток при обрыве сети.
|
||||
- **Камерное сканирование** (мобильные): canvas 1080×1080 (квадрат), овал-подсказка для позиционирования лица, запас 10% при захвате (голова не обрезается), MediaRecorder с битрейтом 1.5 Мбит/с (~1–2 МБ за 310 кадров), автоповтор fetch до 3 попыток при обрыве сети.
|
||||
- **Логирование прогресса SDK**: в логах сервера пишется `progress` и `face_ok` при каждом изменении; если финальный результат не пришёл — предупреждение в лог.
|
||||
- **iOS MediaRecorder** пишет mp4 (webm может не поддерживаться) — расширение выбирается из `blob.type`.
|
||||
- **Порт 5000** на сервере занят другим сервисом — приложение слушает 8063.
|
||||
- Дисклеймер «не медицинский диагноз» — во всех отчётах и на страницах.
|
||||
- **Порт 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
|
||||
```
|
||||
Reference in new issue
Block a user