SysOps: approved_backup — 2026-08-16 11:01 UTC
This commit is contained in:
@@ -255,6 +255,9 @@ async def chat_messages(
|
||||
provider_id: int | None = None,
|
||||
model: str | None = None,
|
||||
timeout: float = 120.0,
|
||||
user: str | None = None,
|
||||
max_tokens: int | None = None,
|
||||
temperature: float | None = None,
|
||||
) -> tuple[str, dict[str, Any]]:
|
||||
"""Returns (reply_text, meta dict with provider info)."""
|
||||
prov = resolve_provider(provider_id)
|
||||
@@ -309,9 +312,14 @@ async def chat_messages(
|
||||
payload: dict[str, Any] = {
|
||||
"model": use_model,
|
||||
"messages": messages,
|
||||
"temperature": float(extra.get("temperature", 0.4)),
|
||||
"max_tokens": int(extra.get("max_tokens", 2048)),
|
||||
"temperature": float(temperature if temperature is not None else extra.get("temperature", 0.4)),
|
||||
"max_tokens": int(max_tokens if max_tokens is not None else extra.get("max_tokens", 2048)),
|
||||
}
|
||||
# Hermes: `user` = Telegram chat_id → koppelt API-chat aan bestaande memory/sessie
|
||||
if user:
|
||||
payload["user"] = str(user)
|
||||
elif ptype == "hermes":
|
||||
payload["user"] = str(getattr(settings, "HERMES_CEO_CHAT_ID", None) or "8859782446")
|
||||
|
||||
async with httpx.AsyncClient(timeout=timeout) as client:
|
||||
resp = await client.post(url, headers=headers, json=payload)
|
||||
@@ -332,9 +340,99 @@ async def chat_messages(
|
||||
"provider_type": ptype,
|
||||
"provider_label": prov.get("label"),
|
||||
"model": use_model,
|
||||
"hermes_user": payload.get("user"),
|
||||
}
|
||||
|
||||
|
||||
|
||||
async def stream_chat_messages(
|
||||
messages: list[dict[str, str]],
|
||||
*,
|
||||
provider_id: int | None = None,
|
||||
model: str | None = None,
|
||||
timeout: float = 90.0,
|
||||
user: str | None = None,
|
||||
max_tokens: int | None = None,
|
||||
temperature: float | None = None,
|
||||
):
|
||||
"""Yield text deltas from Hermes/OpenAI-compatible streaming chat."""
|
||||
prov = resolve_provider(provider_id)
|
||||
ptype = (prov.get("provider_type") or "ollama").lower()
|
||||
use_model = model or prov.get("model") or settings.OLLAMA_MODEL
|
||||
if ptype != "hermes":
|
||||
# non-stream fallback: one chunk
|
||||
reply, _meta = await chat_messages(
|
||||
messages,
|
||||
provider_id=provider_id,
|
||||
model=model,
|
||||
timeout=timeout,
|
||||
user=user,
|
||||
max_tokens=max_tokens,
|
||||
temperature=temperature,
|
||||
)
|
||||
if reply:
|
||||
yield reply
|
||||
return
|
||||
|
||||
api_key = (prov.get("api_key") or "").strip()
|
||||
if not api_key:
|
||||
raise RuntimeError("Geen Hermes API key")
|
||||
base = (prov.get("api_base_url") or "").strip().rstrip("/")
|
||||
if not base:
|
||||
raise RuntimeError("Geen Hermes API URL")
|
||||
extra = prov.get("extra_config") or {}
|
||||
if isinstance(extra, str):
|
||||
try:
|
||||
extra = json.loads(extra)
|
||||
except Exception:
|
||||
extra = {}
|
||||
url = f"{base}/chat/completions"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "text/event-stream",
|
||||
}
|
||||
payload: dict[str, Any] = {
|
||||
"model": use_model,
|
||||
"messages": messages,
|
||||
"temperature": float(temperature if temperature is not None else extra.get("temperature", 0.35)),
|
||||
"max_tokens": int(max_tokens if max_tokens is not None else extra.get("max_tokens", 512)),
|
||||
"stream": True,
|
||||
}
|
||||
if user:
|
||||
payload["user"] = str(user)
|
||||
else:
|
||||
payload["user"] = str(getattr(settings, "HERMES_CEO_CHAT_ID", None) or "8859782446")
|
||||
|
||||
async with httpx.AsyncClient(timeout=timeout) as client:
|
||||
async with client.stream("POST", url, headers=headers, json=payload) as resp:
|
||||
if resp.status_code >= 400:
|
||||
body = (await resp.aread()).decode("utf-8", errors="replace")[:500]
|
||||
raise RuntimeError(f"Hermes stream fout ({resp.status_code}): {body}")
|
||||
async for line in resp.aiter_lines():
|
||||
if not line:
|
||||
continue
|
||||
if line.startswith(":"):
|
||||
continue
|
||||
if not line.startswith("data:"):
|
||||
continue
|
||||
data = line[5:].strip()
|
||||
if not data or data == "[DONE]":
|
||||
if data == "[DONE]":
|
||||
break
|
||||
continue
|
||||
try:
|
||||
obj = json.loads(data)
|
||||
except Exception:
|
||||
continue
|
||||
choices = obj.get("choices") or []
|
||||
if not choices:
|
||||
continue
|
||||
delta = (choices[0].get("delta") or {}).get("content")
|
||||
if delta:
|
||||
yield delta
|
||||
|
||||
|
||||
async def generate(
|
||||
prompt: str,
|
||||
system: str | None = None,
|
||||
|
||||
Reference in New Issue
Block a user