osint-dashboard/news/summerizer/nous_client.py

58 lines
2 KiB
Python
Raw Normal View History

"""HTTP client for the Nous inference chat completions API."""
from __future__ import annotations
import os
import httpx
_DEFAULT_UA = "osint-dashboard-news-summarizer"
_DEFAULT_BASE = "https://inference-api.nousresearch.com/v1"
_JSON_SYSTEM = (
"You are an OSINT executive briefer. Reply with a single complete JSON object. "
"Never truncate mid-sentence. If you run out of room, drop the lowest-priority item."
)
def chat(prompt, *, api_key, model, base_url, json_mode=False) -> str:
resolved = (base_url or os.environ.get("NOUS_BASE_URL", _DEFAULT_BASE)).rstrip("/")
url = f"{resolved}/chat/completions"
headers = {
"Authorization": f"Bearer {api_key}",
"User-Agent": os.environ.get("OSINT_USER_AGENT") or _DEFAULT_UA,
}
max_tokens = 8192 if json_mode else 4096
timeout = 120.0 if json_mode else 60.0
messages = [{"role": "user", "content": prompt}]
if json_mode:
messages = [
{"role": "system", "content": _JSON_SYSTEM},
{"role": "user", "content": prompt},
]
payload = {
"model": model,
"messages": messages,
"temperature": 0.2,
"max_tokens": max_tokens,
}
if json_mode:
payload["response_format"] = {"type": "json_object"}
last_content = ""
try:
for attempt in range(2):
with httpx.Client(timeout=timeout) as client:
resp = client.post(url, headers=headers, json=payload)
if resp.status_code == 401 or resp.status_code >= 500:
return ""
data = resp.json()
choice = (data.get("choices") or [{}])[0]
last_content = (choice.get("message") or {}).get("content") or ""
finish = choice.get("finish_reason")
if finish == "length" and attempt == 0:
payload["max_tokens"] = min(int(payload["max_tokens"]) * 2, 16384)
continue
return last_content
return last_content
except Exception:
return ""