dede5e00af
Nuevas funciones Python: build_guide_prompt, generate_pwa_manifest, generate_service_worker, match_pois_to_interests (core), nominatim_reverse_geocode, ollama_chat, overpass_nearby_pois (infra). Incluye tests unitarios. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
71 lines
2.3 KiB
Python
71 lines
2.3 KiB
Python
"""Envía una solicitud de chat completion a Ollama (API local compatible con OpenAI)."""
|
|
|
|
import json
|
|
import urllib.request
|
|
import urllib.error
|
|
from typing import Any
|
|
|
|
|
|
def ollama_chat(
|
|
messages: list[dict],
|
|
model: str = "llama3.1:8b",
|
|
base_url: str = "http://localhost:11434",
|
|
temperature: float = 0.7,
|
|
max_tokens: int = 1024,
|
|
) -> dict:
|
|
"""Envía una solicitud de chat completion a Ollama.
|
|
|
|
Args:
|
|
messages: Lista de mensajes con formato {"role": "system"|"user"|"assistant", "content": str}.
|
|
model: Nombre del modelo Ollama a usar.
|
|
base_url: URL base de la instancia Ollama.
|
|
temperature: Temperatura de generación (0.0 - 1.0).
|
|
max_tokens: Número máximo de tokens a generar.
|
|
|
|
Returns:
|
|
Dict con content, model, total_duration_ms y eval_count.
|
|
|
|
Raises:
|
|
RuntimeError: Si Ollama no está corriendo o retorna error HTTP.
|
|
"""
|
|
url = f"{base_url}/api/chat"
|
|
payload = {
|
|
"model": model,
|
|
"messages": messages,
|
|
"stream": False,
|
|
"options": {
|
|
"temperature": temperature,
|
|
"num_predict": max_tokens,
|
|
},
|
|
}
|
|
body = json.dumps(payload).encode("utf-8")
|
|
req = urllib.request.Request(
|
|
url,
|
|
data=body,
|
|
headers={"Content-Type": "application/json"},
|
|
method="POST",
|
|
)
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=60) as resp:
|
|
raw = resp.read()
|
|
except urllib.error.URLError as exc:
|
|
reason = str(exc.reason) if hasattr(exc, "reason") else str(exc)
|
|
if "connection refused" in reason.lower() or "111" in reason:
|
|
raise RuntimeError(f"Ollama no está corriendo en {base_url}") from exc
|
|
raise RuntimeError(f"Error de conexión con Ollama: {reason}") from exc
|
|
except urllib.error.HTTPError as exc:
|
|
raise RuntimeError(f"Ollama retornó HTTP {exc.code}: {exc.reason}") from exc
|
|
|
|
response: dict[str, Any] = json.loads(raw)
|
|
content: str = response["message"]["content"]
|
|
total_duration_ns: int = response.get("total_duration", 0)
|
|
total_duration_ms: int = int(total_duration_ns / 1_000_000)
|
|
eval_count: int = response.get("eval_count", 0)
|
|
|
|
return {
|
|
"content": content,
|
|
"model": response.get("model", model),
|
|
"total_duration_ms": total_duration_ms,
|
|
"eval_count": eval_count,
|
|
}
|