dashhdata's picture
Upload folder using huggingface_hub
1e8bb26 verified
Raw
History Blame Contribute Delete
2.88 kB
"""RAG pipeline: retrieve relevant chunks, then generate a grounded answer."""
from __future__ import annotations
from functools import lru_cache
from typing import List, Optional
from .config import get_settings
from .embeddings import embed_query
from .models import ChatResponse, Source
from . import vector_store
SYSTEM_PROMPT = (
"You are a document assistant. Answer the user's question using ONLY the provided "
"context excerpts from their uploaded documents. Cite the supporting sources inline "
"as [1], [2], etc., matching the numbered context blocks. If the answer is not "
"contained in the context, say you could not find it in the documents. Be concise "
"and accurate."
)
@lru_cache
def _llm():
from openai import OpenAI
settings = get_settings()
if not settings.openrouter_api_key:
raise RuntimeError("OPENROUTER_API_KEY is not set in the environment / .env file.")
return OpenAI(
base_url=settings.openrouter_base_url,
api_key=settings.openrouter_api_key,
)
def _build_context(hits) -> str:
blocks = []
for i, hit in enumerate(hits, start=1):
payload = hit.payload or {}
blocks.append(
f"[{i}] (source: {payload.get('filename', '?')}, "
f"chunk {payload.get('chunk_index', '?')})\n{payload.get('text', '')}"
)
return "\n\n".join(blocks)
def answer_question(
question: str,
document_ids: Optional[List[str]] = None,
top_k: Optional[int] = None,
) -> ChatResponse:
settings = get_settings()
k = top_k or settings.top_k
query_vector = embed_query(question)
hits = vector_store.search(query_vector, top_k=k, document_ids=document_ids)
if not hits:
return ChatResponse(
answer="I couldn't find anything relevant in your uploaded documents.",
sources=[],
)
context = _build_context(hits)
user_message = (
f"Context excerpts:\n\n{context}\n\n"
f"Question: {question}\n\n"
"Answer using only the context above and cite sources as [n]."
)
client = _llm()
response = client.chat.completions.create(
model=settings.openrouter_model,
max_tokens=1024,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
)
answer_text = (response.choices[0].message.content or "").strip()
sources = [
Source(
document_id=(hit.payload or {}).get("document_id", ""),
filename=(hit.payload or {}).get("filename", "?"),
chunk_index=(hit.payload or {}).get("chunk_index", -1),
score=float(hit.score),
snippet=((hit.payload or {}).get("text", "")[:280]),
)
for hit in hits
]
return ChatResponse(answer=answer_text, sources=sources)