NMT / scripts /nmt_client.py
marconolimits's picture
deploy: clean orphan branch for HF Spaces - CPU threading optimisation
c7b4419
Raw
History Blame Contribute Delete
2.53 kB
"""
Production-friendly client for the NMT HTTP API.
Always sends POST /translate with Content-Type: application/json and body {"text": "..."}.
Use this from services, jobs, and tests to avoid format mistakes.
"""
from __future__ import annotations
import json
import ssl
import urllib.error
import urllib.request
from dataclasses import dataclass
from typing import Any
@dataclass(frozen=True)
class TranslateResult:
translation: str
latency_ms: float
request_id: str
raw: dict[str, Any]
def translate(
base_url: str,
text: str,
*,
api_key: str | None = None,
timeout_s: float = 120.0,
request_id: str | None = None,
) -> TranslateResult:
"""
Translate English text to Italian via POST /translate.
base_url: e.g. "https://marconolimits-nmt.hf.space" (no trailing slash)
api_key: sent as X-API-Key when set (match Space secrets).
"""
root = base_url.rstrip("/")
url = f"{root}/translate"
payload = json.dumps({"text": text}, ensure_ascii=False).encode("utf-8")
headers = {
"Content-Type": "application/json; charset=utf-8",
"Accept": "application/json",
}
if api_key:
headers["X-API-Key"] = api_key
if request_id:
headers["X-Request-Id"] = request_id
req = urllib.request.Request(url, data=payload, headers=headers, method="POST")
ctx = ssl.create_default_context()
try:
with urllib.request.urlopen(req, timeout=timeout_s, context=ctx) as resp:
raw_body = resp.read().decode("utf-8")
data = json.loads(raw_body)
except urllib.error.HTTPError as e:
err_body = e.read().decode("utf-8", errors="replace")
raise RuntimeError(f"HTTP {e.code}: {err_body}") from e
if not isinstance(data, dict):
raise RuntimeError(f"Unexpected response: {data!r}")
if "translation" not in data:
raise RuntimeError(f"Missing translation in response: {data!r}")
return TranslateResult(
translation=str(data["translation"]),
latency_ms=float(data.get("latency_ms", 0.0)),
request_id=str(data.get("request_id", "")),
raw=data,
)
def healthz(base_url: str, *, timeout_s: float = 30.0) -> bool:
root = base_url.rstrip("/")
req = urllib.request.Request(f"{root}/healthz", method="GET")
ctx = ssl.create_default_context()
try:
with urllib.request.urlopen(req, timeout=timeout_s, context=ctx) as resp:
return resp.status == 200
except OSError:
return False