Initial commit: RAGGER - Sistema RAG per associazione di volontariato

This commit is contained in:
truetype committed 2026-02-22 17:19:53 +01:00
commit 0204feb8bf
36 files changed
+4116

No files matched your search

+189
View File
@@ -0,0 +1,189 @@
import httpx
import warnings
from typing import Optional
from config import settings
from logger import get_logger
warnings.filterwarnings("ignore", message="Unverified HTTPS request")
log = get_logger("ollama_client")
PROVIDER_BASE_URLS = {
"openrouter": "https://openrouter.ai/api/v1",
"openai": "https://api.openai.com/v1",
"groq": "https://api.groq.com/openai/v1",
"opencode": "https://opencode.ai/zen/v1",
}
class LLMClient:
def __init__(self):
self.provider = settings.LLM_PROVIDER
self.timeout = httpx.Timeout(300.0, connect=30.0)
log.info(f"Initializing LLMClient: provider={self.provider}")
if self.provider == "ollama":
self.host = settings.OLLAMA_HOST
log.debug(f"Ollama host: {self.host}")
self.client = httpx.Client(timeout=self.timeout, verify=False)
else:
base_url = settings.LLM_BASE_URL or PROVIDER_BASE_URLS.get(self.provider, "")
api_key = settings.LLM_API_KEY or ""
log.debug(f"External API: {self.provider} -> {base_url}")
self.client = httpx.Client(
timeout=self.timeout,
base_url=base_url,
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
)
if self.provider == "openrouter":
self.client.headers["HTTP-Referer"] = "https://github.com/ragger"
self.client.headers["X-Title"] = "RAGGER"
def embed(self, text: str) -> list[float]:
model = settings.OLLAMA_EMBED_MODEL
log.debug(f"Embedding: model={model}, text_len={len(text)}")
url = f"{settings.OLLAMA_HOST.rstrip('/')}/api/embeddings"
log.debug(f"POST {url}")
try:
response = self.client.post(
url,
json={"model": model, "prompt": text}
)
response.raise_for_status()
embedding = response.json()["embedding"]
log.debug(f"Embedding success: {len(embedding)} dims")
return embedding
except httpx.HTTPStatusError as e:
log.error(f"HTTP error: {e.response.status_code} - {e.response.text}")
raise
except Exception as e:
log.error(f"Embedding error: {e}")
raise
def generate(
self,
prompt: str,
system: Optional[str] = None,
context: Optional[str] = None
) -> str:
log.debug(f"Generate: provider={self.provider}, prompt_len={len(prompt)}")
if self.provider == "ollama":
return self._generate_ollama(prompt, system, context)
else:
return self._generate_openai(prompt, system, context)
def _generate_ollama(
self,
prompt: str,
system: Optional[str] = None,
context: Optional[str] = None
) -> str:
model = settings.OLLAMA_MODEL
log.debug(f"Ollama generate: model={model}")
full_prompt = ""
if system:
full_prompt += f"System: {system}\n\n"
if context:
full_prompt += f"Contesto:\n{context}\n\n"
full_prompt += prompt
log.debug(f"Full prompt length: {len(full_prompt)} chars")
url = f"{settings.OLLAMA_HOST.rstrip('/')}/api/generate"
log.debug(f"POST {url}")
try:
response = self.client.post(
url,
json={"model": model, "prompt": full_prompt, "stream": False}
)
response.raise_for_status()
result = response.json()["response"]
log.debug(f"Response length: {len(result)} chars")
log.info(f"Generated response ({len(result)} chars)")
return result
except httpx.HTTPStatusError as e:
log.error(f"HTTP error: {e.response.status_code} - {e.response.text}")
raise
except Exception as e:
log.error(f"Generation error: {e}")
raise
def _generate_openai(
self,
prompt: str,
system: Optional[str] = None,
context: Optional[str] = None
) -> str:
model = settings.LLM_MODEL or "openrouter/auto"
log.debug(f"OpenAI generate: model={model}")
messages = []
if system:
messages.append({"role": "system", "content": system})
user_content = ""
if context:
user_content += f"Contesto:\n{context}\n\n"
user_content += prompt
messages.append({"role": "user", "content": user_content})
log.debug(f"Messages: {len(messages)} items")
try:
response = self.client.post(
"/chat/completions",
json={"model": model, "messages": messages}
)
response.raise_for_status()
result = response.json()["choices"][0]["message"]["content"]
log.info(f"Generated response ({len(result)} chars)")
return result
except httpx.HTTPStatusError as e:
log.error(f"HTTP error: {e.response.status_code} - {e.response.text}")
raise
except Exception as e:
log.error(f"Generation error: {e}")
raise
def is_available(self) -> bool:
log.debug("Checking availability...")
try:
if self.provider == "ollama":
url = f"{settings.OLLAMA_HOST.rstrip('/')}/api/tags"
log.debug(f"GET {url}")
response = self.client.get(url, timeout=5.0)
available = response.status_code == 200
log.debug(f"Ollama available: {available}")
return available
else:
log.debug("External API - assuming available")
return True
except Exception as e:
log.warning(f"Availability check failed: {e}")
return False
def list_models(self) -> list[str]:
if self.provider != "ollama":
return []
try:
url = f"{settings.OLLAMA_HOST.rstrip('/')}/api/tags"
response = self.client.get(url, timeout=5.0)
response.raise_for_status()
models = response.json().get("models", [])
return [m["name"] for m in models]
except Exception as e:
log.error(f"Error listing models: {e}")
return []
llm = LLMClient()
ollama = llm