| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- from __future__ import annotations
- from dataclasses import dataclass
- import os
- from typing import Any, Dict
- def _env(name: str, default: str) -> str:
- v = os.getenv(name, "").strip()
- return v or default
- def _env_float(name: str, default: float) -> float:
- v = os.getenv(name, "").strip()
- if not v:
- return float(default)
- try:
- return float(v)
- except Exception:
- return float(default)
- @dataclass(frozen=True)
- class ServiceConfig:
- hardware: str
- interp: str
- analysis: str
- SERVICES = ServiceConfig(
- hardware=_env("HARDWARE_BASE_URL", "http://127.0.0.1:8000"),
- interp=_env("INTERP_BASE_URL", "http://127.0.0.1:7475"),
- analysis=_env("ANALYSIS_BASE_URL", "http://127.0.0.1:1717"),
- )
- HARDWARE_BASE_URL: str = SERVICES.hardware
- INTERP_BASE_URL: str = SERVICES.interp
- ANALYSIS_BASE_URL: str = SERVICES.analysis
- BASE_URL: str = HARDWARE_BASE_URL
- HTTP_TIMEOUT_SEC: float = _env_float("HTTP_TIMEOUT_SEC", 5.0)
- ENDPOINTS: Dict[str, Any] = {
- # -----------------------------
- # scanner / systems / sequences
- # -----------------------------
- "sequence_params": "/sequence/params", # POST sequence params JSON
- "sequence_interpret": {
- "interpret": "/interpret/", # POST multipart file (.seq)
- "status": "/status/", # GET status of interpretation tasks
- },
- "systems": {
- "gradient": {
- "health": "/systems/gradient/health", # GET
- "upload_config": "/systems/gradient/config", # POST multipart file
- "start": "/systems/gradient/start", # POST
- },
- "rf": {
- "health": "/systems/rf/health",
- "upload_config": "/systems/rf/config",
- "start": "/systems/rf/start",
- },
- "adc": {
- "health": "/systems/adc/health",
- "upload_config": "/systems/adc/config",
- "start": "/systems/adc/start",
- },
- },
- "scan": {
- # Real spectrometer service API (measurement-based)
- "start": "/api/measurement", # POST (or GET fallback) -> measurement id
- "start_fallback_get": "/api/measurement", # GET starts measurement on some deployments
- "state_by_id": "/api/measurement/{scan_id}/state", # GET
- "data_by_id": "/api/measurement/{scan_id}/data", # GET
- "state": "/api/mstate", # GET optional legacy state endpoint
- # Backward compatibility for older backend shape
- "progress": "/scan/progress", # GET params: scan_id=...
- "stop": "/scan/stop", # POST optional
- },
- # -----------------------------
- # ANALYSIS
- # -----------------------------
- "analysis": {
- "upload": "/upload/", # POST multipart
- "filter": "/filter/", # POST form
- "fft": "/fft/", # POST form
- "result": "/result/", # GET params session_id
- "export": "/export/", # POST form
- "plot_raw": "/plot-raw/", # POST form
- # readme_spectrum endpoints
- "export_raw_data": "/export-raw-data/", # POST form
- "export_filter_data": "/export-filter-data/", # POST form
- "export_decdem_data": "/export-decdem-data/", # POST form
- "export_position_freq": "/export-position-freq/", # POST form
- "export_fwhm": "/export-FWHM/", # POST form
- "export_max_amplitude_freq": "/export-max-amplitude-freq/",# POST form
- },
- }
- def join_url(base_url: str, path: str) -> str:
- b = (base_url or "").rstrip("/")
- p = (path or "")
- if not p.startswith("/"):
- p = "/" + p
- return b + p
- def build_url(service: str, path: str) -> str:
- base = getattr(SERVICES, service)
- return join_url(base, path)
- def get_endpoint(*keys: str) -> str:
- """Resolve endpoint path from ENDPOINTS by keys.
- Examples:
- get_endpoint("sequence_params")
- get_endpoint("systems", "gradient", "health")
- get_endpoint("analysis", "upload")
- """
- cur: Any = ENDPOINTS
- for k in keys:
- cur = cur[k]
- if not isinstance(cur, str):
- raise TypeError(f"Endpoint {keys} resolved to non-string: {type(cur)}")
- return cur
|