From f11ec6298dd8ce5cf09ee45aa85bdfa0667508fc Mon Sep 17 00:00:00 2001 From: Kavalar Date: Thu, 17 Sep 2026 15:35:18 +0300 Subject: [PATCH] =?UTF-8?q?gigadoc=5Fws.py:=20=D0=BF=D0=BE=D0=B4=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B6=D0=BA=D0=B0=20=D0=BF=D1=83=D1=82=D0=B8=20?= =?UTF-8?q?=D0=B2=20--sdk-host;=20test=5Ffpg.py:=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B2=D0=B5=D0=B4=D1=91=D0=BD=20=D0=BD=D0=B0=20DNR-?= =?UTF-8?q?=D1=81=D1=82=D0=B5=D0=BD=D0=B4=20(bearer=20subprotocol,=20Origi?= =?UTF-8?q?n,=20=D1=85=D0=BE=D1=81=D1=82=D1=8B=20=D1=81=20=D0=BF=D1=83?= =?UTF-8?q?=D1=82=D1=91=D0=BC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gigadoc_ws.py | 31 +++++++++++++++++++++++++--- test_fpg.py | 56 ++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/gigadoc_ws.py b/gigadoc_ws.py index 94fa17c..5f60706 100644 --- a/gigadoc_ws.py +++ b/gigadoc_ws.py @@ -211,6 +211,22 @@ def normalize_prefix(prefix: str) -> str: return prefix.rstrip("/") +def split_host_path(host: str) -> tuple: + """Разделить 'host/path' на (scheme, hostname, base_path). + + Поддерживает варианты: "domain.com", "domain.com/v1/giga", + "https://domain.com/v1/giga". Схема возвращается без "://". + """ + host = host.strip().rstrip("/") + scheme = "" + if "://" in host: + scheme, host = host.split("://", 1) + parts = host.split("/", 1) + hostname = parts[0] + base_path = "/" + parts[1] if len(parts) > 1 else "" + return scheme, hostname, base_path + + def build_ssl_context( insecure: bool, ) -> Optional[ssl.SSLContext]: @@ -329,7 +345,8 @@ async def create_predict_session( ) url = ( - f"https://{args.sdk_host}" + f"https://{args.sdk_hostname}" + f"{args.sdk_base_path}" f"{rest_prefix}/predict/new" ) @@ -494,7 +511,8 @@ async def websocket_predict( for port in ports: ws_url = ( - f"wss://{args.sdk_host}:{port}" + f"wss://{args.sdk_hostname}:{port}" + f"{args.sdk_base_path}" f"{ws_prefix}/{uid}/image" ) @@ -918,7 +936,8 @@ async def delete_predict_session( ) url = ( - f"https://{args.sdk_host}" + f"https://{args.sdk_hostname}" + f"{args.sdk_base_path}" f"{rest_prefix}/predict/{uid}" ) @@ -993,6 +1012,12 @@ async def main(): args = parse_args() + # sdk_host может содержать путь (domain.com/v1/giga) — + # разделяем на hostname и base_path. + _scheme, args.sdk_hostname, args.sdk_base_path = split_host_path( + args.sdk_host + ) + setup_logging( args.verbose ) diff --git a/test_fpg.py b/test_fpg.py index 6ffdb93..7b1f97b 100644 --- a/test_fpg.py +++ b/test_fpg.py @@ -1,9 +1,12 @@ """ -Тестовый скрипт для SDK ФПГ (GigaDoc). +Тестовый скрипт для SDK ФПГ (GigaDoc, персональный стенд DNR). Покрывает: авторизацию → создание сессии → WebSocket (изображения) → удаление сессии. Использование: python3 test_fpg.py [--ws-host HOST] [--ws-port PORT] [--image-dir DIR] + +Хосты можно переопределить через env: FPG_REST_HOST, FPG_WS_HOST, FPG_WS_PORT. +Хост может содержать путь (domain.com/v1/giga) — он учитывается при сборке URL. """ import argparse @@ -17,17 +20,37 @@ import time import requests # ─── Конфигурация ───────────────────────────────────────────── -OAUTH_URL = "https://oauth.sbermed.ai/token" -CLIENT_ID = "client_fpg_front" +OAUTH_URL = os.environ.get("FPG_OAUTH_URL", "https://oauth.sbermed.ai/token") +CLIENT_ID = os.environ.get("FPG_CLIENT_ID", "client_fpg_front_dnr") CLIENT_SECRET = os.environ.get("FPG_CLIENT_SECRET", "") -REST_HOST = "gigadoc-sdk.sbermed.ai" -REST_BASE = f"https://{REST_HOST}" +REST_HOST = os.environ.get("FPG_REST_HOST", "gigadoc-dnr-sdk.sbermed.ai") +WS_HOST = os.environ.get("FPG_WS_HOST", "gigadoc-dnr-sdk.sbermed.ai") +WS_PORT = int(os.environ.get("FPG_WS_PORT", "8443")) +WS_ORIGIN = os.environ.get("FPG_WS_ORIGIN", "https://gigadoc-dnr-sdk.sbermed.ai") DEVICE_ID = "web_prod" FORM_FACTOR = "web_prod" +def split_host_path(host: str) -> tuple: + """Разделить 'host/path' на (scheme, hostname, base_path).""" + host = host.strip().rstrip("/") + scheme = "" + if "://" in host: + scheme, host = host.split("://", 1) + parts = host.split("/", 1) + hostname = parts[0] + base_path = "/" + parts[1] if len(parts) > 1 else "" + return scheme, hostname, base_path + + +_rest_scheme, _rest_hostname, _rest_base_path = split_host_path(REST_HOST) +REST_BASE = f"{_rest_scheme or 'https'}://{_rest_hostname}{_rest_base_path}" + +_ws_scheme, WS_HOSTNAME, WS_BASE_PATH = split_host_path(WS_HOST) + + def get_token() -> str: """Получить access token через client_credentials.""" resp = requests.post( @@ -76,13 +99,20 @@ async def ws_scan(token: str, uid: str, ws_host: str, ws_port: int, image_dir: s """Подключиться по WebSocket, отправить изображения, получить результат.""" import websockets - uri = f"wss://{ws_host}:{ws_port}/api/v2/ws/predict/{uid}/image" + # ws_host может быть с путём (domain.com/v1/giga) — разделяем. + _scheme, _hostname, _base_path = split_host_path(ws_host) + _base_path = _base_path or WS_BASE_PATH + + uri = f"wss://{_hostname}:{ws_port}{_base_path}/api/v2/ws/predict/{uid}/image" print(f"[WS] Подключение: {uri}") + # Авторизация через subprotocol bearer. (как фронт), + # Origin — обязательный заголовок. async with websockets.connect( uri, open_timeout=10, - additional_headers={"Authorization": f"Bearer {token}"}, + subprotocols=[f"bearer.{token}"], + extra_headers={"Origin": WS_ORIGIN}, ) as ws: print("[WS] Соединение установлено") @@ -145,16 +175,18 @@ def create_test_image(): 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 = argparse.ArgumentParser(description="Тест SDK ФПГ (DNR)") + parser.add_argument("--ws-host", default=WS_HOSTNAME, help="WebSocket host (может быть с путём)") + parser.add_argument("--ws-port", type=int, default=WS_PORT, 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("🏥 Тестирование SDK ФПГ (GigaDoc DNR)") print("=" * 60) + print(f"[CONFIG] REST: {REST_BASE}") + print(f"[CONFIG] WS: wss://{args.ws_host}:{args.ws_port}") # 0. Тестовое изображение create_test_image() @@ -192,4 +224,4 @@ def main(): if __name__ == "__main__": - main() + main() \ No newline at end of file