"""HTTP client for the translation service.""" from __future__ import annotations import logging from typing import List, Optional, Sequence, Union import requests from requests.adapters import HTTPAdapter from config.loader import get_app_config from translation.settings import normalize_translation_model, normalize_translation_scene logger = logging.getLogger(__name__) class TranslationServiceClient: """Business-side translation client that talks to the translator service.""" def __init__( self, *, base_url: Optional[str] = None, default_model: Optional[str] = None, default_scene: Optional[str] = None, timeout_sec: Optional[float] = None, ) -> None: cfg = get_app_config().services.translation.as_dict() self.base_url = str(base_url or cfg["service_url"]).rstrip("/") self.default_model = normalize_translation_model(cfg, default_model or cfg["default_model"]) self.default_scene = normalize_translation_scene(cfg, default_scene or cfg["default_scene"]) self.timeout_sec = float(cfg["timeout_sec"] if timeout_sec is None else timeout_sec) self._session = requests.Session() self._session.mount("http://", HTTPAdapter(pool_connections=32, pool_maxsize=32, max_retries=0)) self._session.mount("https://", HTTPAdapter(pool_connections=32, pool_maxsize=32, max_retries=0)) @property def model(self) -> str: return self.default_model @property def supports_batch(self) -> bool: return True def translate( self, text: Union[str, Sequence[str]], target_lang: str, source_lang: Optional[str] = None, scene: Optional[str] = None, model: Optional[str] = None, ) -> Union[Optional[str], List[Optional[str]]]: if isinstance(text, tuple): text = list(text) payload = { "text": text, "target_lang": target_lang, "source_lang": source_lang, "model": (model or self.default_model), "scene": self.default_scene if scene is None else scene, } try: response = self._session.post( f"{self.base_url}/translate", json=payload, timeout=(2.0, self.timeout_sec), ) if response.status_code != 200: logger.warning( "Translation service request failed: status=%s body=%s", response.status_code, (response.text or "")[:300], ) return self._empty_result_for(text) data = response.json() return data.get("translated_text") except Exception as exc: logger.warning("Translation service request error: %s", exc, exc_info=True) return self._empty_result_for(text) @staticmethod def _empty_result_for( text: Union[str, Sequence[str]], ) -> Union[Optional[str], List[Optional[str]]]: if isinstance(text, (list, tuple)): return [None for _ in text] return None def create_translation_client() -> TranslationServiceClient: """Create the business-side translation client.""" return TranslationServiceClient()