from __future__ import annotations import json from typing import Any, Dict, List, Optional import requests class LLMError(RuntimeError): pass def chat_completion( api_key: str, messages: List[Dict[str, str]], model: str = "gpt-4o-mini", base_url: str = "https://api.openai.com", timeout_s: int = 45, ) -> str: """ Minimal OpenAI-compatible Chat Completions call. Expects provider that supports: POST {base_url}/v1/chat/completions """ if not api_key or not api_key.strip(): raise LLMError("LLM API key is empty.") url = base_url.rstrip("/") + "/v1/chat/completions" headers = { "Authorization": f"Bearer {api_key.strip()}", "Content-Type": "application/json", } payload: Dict[str, Any] = { "model": model, "messages": messages, "temperature": 0.3, } try: r = requests.post(url, headers=headers, json=payload, timeout=timeout_s) except Exception as e: raise LLMError(f"Request failed: {e}") from e if r.status_code >= 400: raise LLMError(f"LLM HTTP {r.status_code}: {r.text[:400]}") data = r.json() try: return data["choices"][0]["message"]["content"] except Exception: raise LLMError(f"Unexpected LLM response shape: {json.dumps(data)[:600]}")