Full implementation from spec: ZNC/IRC client with TLS, Ollama LLM backend, per-user SQLite conversation memory, and Flask web admin portal with 7 pages. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
71 lines
2.2 KiB
Python
71 lines
2.2 KiB
Python
import httpx
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def generate(prompt: str, system: str, config: dict) -> str:
|
|
host = config.get("ollama_host", "192.168.2.10")
|
|
port = config.get("ollama_port", 11434)
|
|
model = config.get("ollama_model", "llama3.1")
|
|
timeout = config.get("response_timeout_seconds", 30)
|
|
num_predict = config.get("ollama_num_predict", 120)
|
|
num_ctx = config.get("ollama_num_ctx", 2048)
|
|
temperature = config.get("ollama_temperature", 0.7)
|
|
max_length = config.get("max_response_length", 400)
|
|
|
|
url = f"http://{host}:{port}/api/generate"
|
|
payload = {
|
|
"model": model,
|
|
"system": system,
|
|
"prompt": prompt,
|
|
"stream": False,
|
|
"options": {
|
|
"temperature": temperature,
|
|
"num_predict": num_predict,
|
|
"num_ctx": num_ctx,
|
|
},
|
|
}
|
|
|
|
logger.debug(f"[LLM] POST {url} model={model} prompt_len={len(prompt)}")
|
|
|
|
try:
|
|
response = httpx.post(url, json=payload, timeout=timeout)
|
|
response.raise_for_status()
|
|
text = response.json().get("response", "").strip()
|
|
if len(text) > max_length:
|
|
text = text[:max_length].rsplit(" ", 1)[0] + "…"
|
|
logger.debug(f"[LLM] Response ({len(text)} chars): {text[:80]}")
|
|
return text
|
|
except httpx.TimeoutException:
|
|
logger.error(f"[LLM] Timeout after {timeout}s")
|
|
raise TimeoutError(f"Ollama did not respond within {timeout}s")
|
|
except Exception as e:
|
|
logger.error(f"[LLM] Request failed: {e}")
|
|
raise
|
|
|
|
|
|
def build_prompt(
|
|
user_message: str,
|
|
nick: str,
|
|
persistent_history: list[dict],
|
|
context_buffer: list[str],
|
|
) -> str:
|
|
parts = []
|
|
|
|
if persistent_history:
|
|
parts.append("--- Past conversation with this user ---")
|
|
for ex in persistent_history:
|
|
parts.append(f"User: {ex['user']}")
|
|
parts.append(f"Assistant: {ex['assistant']}")
|
|
parts.append("--- End of past conversation ---")
|
|
|
|
if context_buffer:
|
|
parts.append("--- Recent channel activity ---")
|
|
parts.extend(context_buffer)
|
|
parts.append("--- End of channel activity ---")
|
|
|
|
parts.append(f"{nick} asks: {user_message}")
|
|
|
|
return "\n".join(parts)
|