Files
apuc 04a7b31a75 Веб-приложение диагностики по видео (ФПГ GigaDoc)
- Загрузка/сканирование видео, извлечение кадров, анализ через SDK ФПГ
- Понятный диагноз с сохранением в SQLite и share-ссылками
- Экспорт PDF/DOCX, скачивание записанного видео
- Камерное сканирование на мобильных (canvas + MediaRecorder)
- Секреты вынесены в переменные окружения
2026-09-07 19:01:06 +03:00

196 lines
6.7 KiB
Python

"""
Тестовый скрипт для SDK ФПГ (GigaDoc).
Покрывает: авторизацию → создание сессии → WebSocket (изображения) → удаление сессии.
Использование:
python3 test_fpg.py [--ws-host HOST] [--ws-port PORT] [--image-dir DIR]
"""
import argparse
import asyncio
import glob
import json
import os
import sys
import time
import requests
# ─── Конфигурация ─────────────────────────────────────────────
OAUTH_URL = "https://oauth.sbermed.ai/token"
CLIENT_ID = "client_fpg_front"
CLIENT_SECRET = os.environ.get("FPG_CLIENT_SECRET", "")
REST_HOST = "gigadoc-sdk.sbermed.ai"
REST_BASE = f"https://{REST_HOST}"
DEVICE_ID = "web_prod"
FORM_FACTOR = "web_prod"
def get_token() -> str:
"""Получить access token через client_credentials."""
resp = requests.post(
OAUTH_URL,
data={
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
},
timeout=10,
)
resp.raise_for_status()
data = resp.json()
print(f"[AUTH] Токен получен (действует {data['expires_in']} сек)")
return data["access_token"]
def create_session(token: str) -> str:
"""Создать сессию и вернуть uid."""
resp = requests.post(
f"{REST_BASE}/api/v1/predict/new",
params={"device_id": DEVICE_ID, "form_factor": FORM_FACTOR},
headers={
"Authorization": f"Bearer {token}",
"Accept": "application/json",
},
timeout=10,
)
resp.raise_for_status()
uid = resp.json()["uid"]
print(f"[SESSION] Сессия создана: {uid}")
return uid
def delete_session(token: str, uid: str):
"""Удалить сессию."""
resp = requests.delete(
f"{REST_BASE}/api/v1/predict/{uid}",
headers={"Authorization": f"Bearer {token}"},
timeout=10,
)
print(f"[SESSION] Сессия {uid} удалена ({resp.status_code})")
async def ws_scan(token: str, uid: str, ws_host: str, ws_port: int, image_dir: str):
"""Подключиться по WebSocket, отправить изображения, получить результат."""
import websockets
uri = f"wss://{ws_host}:{ws_port}/api/v2/ws/predict/{uid}/image"
print(f"[WS] Подключение: {uri}")
async with websockets.connect(
uri,
open_timeout=10,
additional_headers={"Authorization": f"Bearer {token}"},
) as ws:
print("[WS] Соединение установлено")
# Собираем изображения
patterns = ["*.jpg", "*.jpeg", "*.png"]
images = []
for p in patterns:
images.extend(glob.glob(os.path.join(image_dir, p)))
images.sort()
if not images:
print(f"[WS] Нет изображений в {image_dir}, отправляю тестовое изображение")
images = ["/tmp/test_face.jpg"]
print(f"[WS] Отправляю {len(images)} изображений...")
for i, img_path in enumerate(images):
with open(img_path, "rb") as f:
data = f.read()
await ws.send(data)
try:
resp = await asyncio.wait_for(ws.recv(), timeout=5)
result = json.loads(resp)
progress = result.get("progress", "?")
# Краткий вывод прогресса
if i % 30 == 0 or progress == 1.0:
print(
f" [{i+1}/{len(images)}] progress={progress} "
f"face_ok={result.get('face_ok')}"
)
# Финальный результат
if progress == 1.0 or (isinstance(progress, (int, float)) and progress >= 1.0):
print("\n" + "=" * 60)
print("📊 ФИНАЛЬНЫЙ РЕЗУЛЬТАТ ДИАГНОСТИКИ:")
print("=" * 60)
print(json.dumps(result, indent=2, ensure_ascii=False))
return result
except asyncio.TimeoutError:
if i % 50 == 0:
print(f" [{i+1}/{len(images)}] ожидание ответа...")
print("[WS] Соединение закрыто без финального результата")
return None
def create_test_image():
"""Создать тестовое JPEG-изображение если нет своих."""
try:
from PIL import Image
img = Image.new("RGB", (1280, 720), color=(128, 128, 128))
img.save("/tmp/test_face.jpg", "JPEG", quality=80)
print("[INIT] Создано тестовое изображение /tmp/test_face.jpg")
except ImportError:
print("[INIT] PIL не установлен, тестовое изображение не создано")
def main():
parser = argparse.ArgumentParser(description="Тест SDK ФПГ")
parser.add_argument("--ws-host", default="sdk.sbermed.ai", help="WebSocket host")
parser.add_argument("--ws-port", type=int, default=8443, help="WebSocket port")
parser.add_argument("--image-dir", default=".", help="Директория с JPEG-файлами")
parser.add_argument("--rest-only", action="store_true", help="Только REST API (без WS)")
args = parser.parse_args()
print("=" * 60)
print("🏥 Тестирование SDK ФПГ (GigaDoc)")
print("=" * 60)
# 0. Тестовое изображение
create_test_image()
# 1. Авторизация
token = get_token()
# 2. Создание сессии
uid = create_session(token)
# 3. WebSocket
if not args.rest_only:
try:
result = asyncio.run(
ws_scan(token, uid, args.ws_host, args.ws_port, args.image_dir)
)
except Exception as e:
print(f"\n[WS] Ошибка: {type(e).__name__}: {e}")
print("[WS] Проверьте доступность WebSocket хоста")
result = None
else:
result = None
print("[SKIP] WebSocket тест пропущен (--rest-only)")
# 4. Удаление сессии
delete_session(token, uid)
# Итог
print("\n" + "=" * 60)
if result:
print("✅ Тест завершён успешно — результат получен")
else:
print("⚠️ REST API работает, WebSocket недоступен")
print("=" * 60)
if __name__ == "__main__":
main()