"""Translation provider factory and HTTP provider implementation.""" from __future__ import annotations import logging from typing import Any, Dict, Optional import requests from config.services_config import get_translation_config, get_translation_base_url logger = logging.getLogger(__name__) class HttpTranslationProvider: """Translation via HTTP service.""" def __init__( self, base_url: str, model: str = "qwen", timeout_sec: float = 10.0, ): self.base_url = (base_url or "").rstrip("/") self.model = model or "qwen" self.timeout_sec = float(timeout_sec or 10.0) def _translate_once( self, text: str, target_lang: str, source_lang: Optional[str] = None, context: Optional[str] = None, prompt: Optional[str] = None, ) -> Optional[str]: if not text or not str(text).strip(): return text try: url = f"{self.base_url}/translate" payload = { "text": text, "target_lang": target_lang, "source_lang": source_lang or "auto", "model": self.model, } if context: payload["context"] = context if prompt: payload["prompt"] = prompt response = requests.post(url, json=payload, timeout=self.timeout_sec) if response.status_code != 200: logger.warning( "HTTP translator failed: status=%s body=%s", response.status_code, (response.text or "")[:200], ) return None data = response.json() translated = data.get("translated_text") return translated if translated is not None else None except Exception as exc: logger.warning("HTTP translator request failed: %s", exc, exc_info=True) return None def translate( self, text: str, target_lang: str, source_lang: Optional[str] = None, context: Optional[str] = None, prompt: Optional[str] = None, ) -> Optional[str]: return self._translate_once( text=text, target_lang=target_lang, source_lang=source_lang, context=context, prompt=prompt, ) def create_translation_provider(query_config: Any = None) -> Any: """ Create translation provider from services config. query_config: optional, for api_key/glossary_id/context (used by direct provider). """ cfg = get_translation_config() provider = cfg.provider pc = cfg.get_provider_cfg() if provider in ("qwen-mt", "direct", "local", "inprocess"): from query.qwen_mt_translate import Translator model = pc.get("model") or "qwen-mt-flash" qc = query_config or _empty_query_config() return Translator( model=model, api_key=getattr(qc, "translation_api_key", None), use_cache=True, glossary_id=getattr(qc, "translation_glossary_id", None), translation_context=getattr(qc, "translation_context", "e-commerce product search"), ) elif provider in ("http", "service"): base_url = get_translation_base_url() model = pc.get("model") or "qwen" timeout = pc.get("timeout_sec", 10.0) qc = query_config or _empty_query_config() return HttpTranslationProvider( base_url=base_url, model=model, timeout_sec=float(timeout), ) elif provider == "llm": from query.llm_translate import LLMTranslatorProvider model = pc.get("model") timeout = float(pc.get("timeout_sec", 30.0)) base_url = (pc.get("base_url") or "").strip() or None return LLMTranslatorProvider( model=model, timeout_sec=timeout, base_url=base_url, ) elif provider == "deepl": from query.deepl_provider import DeepLProvider qc = query_config or _empty_query_config() return DeepLProvider( api_key=getattr(qc, "translation_api_key", None), timeout=float(pc.get("timeout_sec", 10.0)), glossary_id=pc.get("glossary_id") or getattr(qc, "translation_glossary_id", None), ) raise ValueError(f"Unsupported translation provider: {provider}") def _empty_query_config() -> Any: """Minimal object with default translation attrs.""" class _QC: translation_api_key = None translation_glossary_id = None translation_context = "e-commerce product search" return _QC()