Поддержка хостов с путём (domain.com/v1/giga) в конфигурации

- split_host_path(): разделяет host/path на (scheme, hostname, base_path),
  поддерживает варианты без схемы и с ней
- REST_BASE собирается с учётом пути
- WS: hostname и base_path разделяются, WS_PATH_TEMPLATE включает base_path
- FPG_WS_PORT теперь настраивается через env (было захардкожено 8443)
- fpg_connect.py: варианты URI переписаны на WS_HOSTNAME/WS_BASE_PATH
This commit is contained in:
apuc committed 2026-09-17 15:22:06 +03:00
1 parent 5bbbe2303c
commit 5331730433
3 files changed
+73 -14

No files matched your search

+25 -4
View File
@@ -35,16 +35,37 @@ import export
# Секреты читаются из переменных окружения (не хранятся в репозитории). # Секреты читаются из переменных окружения (не хранятся в репозитории).
# На сервере задаются в /etc/systemd/system/med.service (Environment=). # На сервере задаются в /etc/systemd/system/med.service (Environment=).
# Хосты стенда можно переопределить через env (FPG_REST_HOST и т.д.). # Хосты стенда можно переопределить через env (FPG_REST_HOST и т.д.).
# ВАЖНО: хост может содержать не только домен, но и путь
# (например "domain.com/v1/giga") — это учитывается при сборке URL.
OAUTH_URL = os.environ.get("FPG_OAUTH_URL", "https://oauth.sbermed.ai/token") 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_ID = os.environ.get("FPG_CLIENT_ID", "client_fpg_front_dnr")
CLIENT_SECRET = os.environ.get("FPG_CLIENT_SECRET", "") CLIENT_SECRET = os.environ.get("FPG_CLIENT_SECRET", "")
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
REST_HOST = os.environ.get("FPG_REST_HOST", "gigadoc-dnr-sdk.sbermed.ai") REST_HOST = os.environ.get("FPG_REST_HOST", "gigadoc-dnr-sdk.sbermed.ai")
REST_BASE = f"https://{REST_HOST}" _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_HOST = os.environ.get("FPG_WS_HOST", "gigadoc-dnr-sdk.sbermed.ai") WS_HOST = os.environ.get("FPG_WS_HOST", "gigadoc-dnr-sdk.sbermed.ai")
WS_PORT = 8443 WS_PORT = int(os.environ.get("FPG_WS_PORT", "8443"))
WS_PATH_TEMPLATE = "/api/v2/ws/predict/{uid}/image" _ws_scheme, WS_HOSTNAME, WS_BASE_PATH = split_host_path(WS_HOST)
WS_PATH_TEMPLATE = f"{WS_BASE_PATH}/api/v2/ws/predict/{{uid}}/image"
WS_ORIGIN = os.environ.get("FPG_WS_ORIGIN", "https://gigadoc-dnr-sdk.sbermed.ai") WS_ORIGIN = os.environ.get("FPG_WS_ORIGIN", "https://gigadoc-dnr-sdk.sbermed.ai")
DEVICE_ID = "web_prod" DEVICE_ID = "web_prod"
@@ -154,7 +175,7 @@ async def ws_stream(token: str, uid: str, frame_files: list, fps: float = FPS):
"""Отправить кадры через WebSocket, вернуть результат.""" """Отправить кадры через WebSocket, вернуть результат."""
import websockets import websockets
uri = f"wss://{WS_HOST}:{WS_PORT}{WS_PATH_TEMPLATE.format(uid=uid)}" uri = f"wss://{WS_HOSTNAME}:{WS_PORT}{WS_PATH_TEMPLATE.format(uid=uid)}"
interval = 1.0 / fps interval = 1.0 / fps
try: try:
+27 -6
View File
@@ -27,17 +27,34 @@ from pathlib import Path
import requests import requests
# ─── Конфигурация ───────────────────────────────────────────── # ─── Конфигурация ─────────────────────────────────────────────
# ВАЖНО: хост может содержать не только домен, но и путь
# (например "domain.com/v1/giga") — это учитывается при сборке URL.
OAUTH_URL = os.environ.get("FPG_OAUTH_URL", "https://oauth.sbermed.ai/token") 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_ID = os.environ.get("FPG_CLIENT_ID", "client_fpg_front_dnr")
CLIENT_SECRET = os.environ.get("FPG_CLIENT_SECRET", "") CLIENT_SECRET = os.environ.get("FPG_CLIENT_SECRET", "")
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_HOST = os.environ.get("FPG_REST_HOST", "gigadoc-dnr-sdk.sbermed.ai") REST_HOST = os.environ.get("FPG_REST_HOST", "gigadoc-dnr-sdk.sbermed.ai")
REST_BASE = f"https://{REST_HOST}" _rest_scheme, _rest_hostname, _rest_base_path = split_host_path(REST_HOST)
REST_BASE = f"{_rest_scheme or 'https'}://{_rest_hostname}{_rest_base_path}"
# WebSocket (рабочий хост подтверждён: gigadoc-dnr-sdk.sbermed.ai:8443) # WebSocket (рабочий хост подтверждён: gigadoc-dnr-sdk.sbermed.ai:8443)
WS_HOST = os.environ.get("FPG_WS_HOST", "gigadoc-dnr-sdk.sbermed.ai") WS_HOST = os.environ.get("FPG_WS_HOST", "gigadoc-dnr-sdk.sbermed.ai")
WS_PORT = 8443 WS_PORT = int(os.environ.get("FPG_WS_PORT", "8443"))
WS_PATH_TEMPLATE = "/api/v2/ws/predict/{uid}/image" _ws_scheme, WS_HOSTNAME, WS_BASE_PATH = split_host_path(WS_HOST)
WS_PATH_TEMPLATE = f"{WS_BASE_PATH}/api/v2/ws/predict/{{uid}}/image"
WS_ORIGIN = os.environ.get("FPG_WS_ORIGIN", "https://gigadoc-dnr-sdk.sbermed.ai") WS_ORIGIN = os.environ.get("FPG_WS_ORIGIN", "https://gigadoc-dnr-sdk.sbermed.ai")
DEVICE_ID = "web_prod" DEVICE_ID = "web_prod"
@@ -239,10 +256,14 @@ async def ws_scan(token: str, uid: str, ws_host: str, ws_port: int, image_dir: s
logger.debug(f" {img} ({size} bytes)") logger.debug(f" {img} ({size} bytes)")
# ── Пробуем несколько вариантов URI ── # ── Пробуем несколько вариантов URI ──
# ws_host может быть с путём (domain.com/v1/giga) — разделяем.
_scheme, _h, _p = split_host_path(ws_host)
_ws_hostname = _h
_ws_path = _p or WS_BASE_PATH
uris = [ uris = [
f"wss://{ws_host}:{ws_port}{WS_PATH_TEMPLATE.format(uid=uid)}", f"wss://{_ws_hostname}:{ws_port}{_ws_path}/api/v2/ws/predict/{uid}/image",
f"wss://{REST_HOST}:{ws_port}{WS_PATH_TEMPLATE.format(uid=uid)}", f"wss://{WS_HOSTNAME}:{ws_port}{WS_PATH_TEMPLATE.format(uid=uid)}",
f"wss://{REST_HOST}:443{WS_PATH_TEMPLATE.format(uid=uid)}", f"wss://{WS_HOSTNAME}:443{WS_PATH_TEMPLATE.format(uid=uid)}",
] ]
last_error = None last_error = None
+21 -4
View File
@@ -19,16 +19,33 @@ import requests
import websockets import websockets
# ─── Конфигурация ───────────────────────────────────────────── # ─── Конфигурация ─────────────────────────────────────────────
# ВАЖНО: хост может содержать не только домен, но и путь
# (например "domain.com/v1/giga") — это учитывается при сборке URL.
OAUTH_URL = os.environ.get("FPG_OAUTH_URL", "https://oauth.sbermed.ai/token") 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_ID = os.environ.get("FPG_CLIENT_ID", "client_fpg_front_dnr")
CLIENT_SECRET = os.environ.get("FPG_CLIENT_SECRET", "") CLIENT_SECRET = os.environ.get("FPG_CLIENT_SECRET", "")
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_HOST = os.environ.get("FPG_REST_HOST", "gigadoc-dnr-sdk.sbermed.ai") REST_HOST = os.environ.get("FPG_REST_HOST", "gigadoc-dnr-sdk.sbermed.ai")
REST_BASE = f"https://{REST_HOST}" _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_HOST = os.environ.get("FPG_WS_HOST", "gigadoc-dnr-sdk.sbermed.ai") WS_HOST = os.environ.get("FPG_WS_HOST", "gigadoc-dnr-sdk.sbermed.ai")
WS_PORT = 8443 WS_PORT = int(os.environ.get("FPG_WS_PORT", "8443"))
WS_PATH_TEMPLATE = "/api/v2/ws/predict/{uid}/image" _ws_scheme, WS_HOSTNAME, WS_BASE_PATH = split_host_path(WS_HOST)
WS_PATH_TEMPLATE = f"{WS_BASE_PATH}/api/v2/ws/predict/{{uid}}/image"
WS_ORIGIN = os.environ.get("FPG_WS_ORIGIN", "https://gigadoc-dnr-sdk.sbermed.ai") WS_ORIGIN = os.environ.get("FPG_WS_ORIGIN", "https://gigadoc-dnr-sdk.sbermed.ai")
DEVICE_ID = "web_prod" DEVICE_ID = "web_prod"
@@ -122,7 +139,7 @@ async def ws_stream(token: str, uid: str, image_path: str, frames: int, fps: flo
logger.info("ЭТАП 3: WebSocket подключение") logger.info("ЭТАП 3: WebSocket подключение")
logger.info("=" * 60) logger.info("=" * 60)
uri = f"wss://{WS_HOST}:{WS_PORT}{WS_PATH_TEMPLATE.format(uid=uid)}" uri = f"wss://{WS_HOSTNAME}:{WS_PORT}{WS_PATH_TEMPLATE.format(uid=uid)}"
logger.info(f"URL: {uri}") logger.info(f"URL: {uri}")
# Читаем изображение (или директорию с кадрами) # Читаем изображение (или директорию с кадрами)