fix: responder a partir dos livros com embeddings em português

Usa o modelo multilingual, ignora trechos curtos e o template do Llama 3.2
para a resposta sair em uma frase completa. O chat deixa a API livre durante
a geração, o upload indexa o PDF e os agendamentos não são gravados duas vezes.
This commit is contained in:
lgcosta committed 2026-11-01 12:34:54 -03:00
1 parent 7af7ba530d
commit 8eeb6b89f4
11 files changed
+185 -90

No files matched your search

+37 -35
View File
@@ -2,9 +2,10 @@ from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct, Filter, FieldCondition, MatchValue
import numpy as np
from typing import List, Dict, Optional
import os
import json
import os
import time
import uuid
class QdrantService:
def __init__(self, url: str, collection_name: str = "espiritismo_books"):
@@ -46,24 +47,22 @@ class QdrantService:
def add_chunks(self, chunks: List[Dict]):
"""Add chunks to the collection."""
points = []
for i, chunk in enumerate(chunks):
point = PointStruct(
id=chunk.get("id") or i,
points = [
PointStruct(
id=str(chunk.get("id") or uuid.uuid4()),
vector=chunk["embedding"],
payload={
"content": chunk["content"],
"metadata": chunk["metadata"],
}
},
)
points.append(point)
for chunk in chunks
]
for start in range(0, len(points), 128):
batch = points[start:start + 128]
self.client.upsert(collection_name=self.collection_name, points=batch)
if points:
self.client.upsert(
collection_name=self.collection_name,
points=points,
)
print(f"Added {len(points)} chunks to Qdrant")
def search(self, query_embedding, top_k: int = 3) -> List[Dict]:
@@ -87,17 +86,22 @@ class QdrantService:
def get_books(self) -> List[str]:
"""Get list of books in the collection."""
points = self.client.scroll(
collection_name=self.collection_name,
limit=10000,
)[0]
books = set()
for point in points:
metadata = point.payload["metadata"]
books.add(metadata.get("title", "Unknown"))
offset = None
while True:
points, offset = self.client.scroll(
collection_name=self.collection_name,
limit=256,
offset=offset,
with_vectors=False,
)
for point in points:
metadata = (point.payload or {}).get("metadata") or {}
books.add(metadata.get("title", "Unknown"))
if offset is None:
break
return sorted(list(books))
return sorted(books)
def get_collection_info(self) -> Dict:
"""Get information about the collection."""
@@ -138,21 +142,19 @@ class RAGService:
"""Generate a response based on the query and context."""
context_text = "\n\n".join(context)
system_prompt = f"""Você é um assistente especializado em espiritismo. Use as informações abaixo para responder à pergunta do usuário.
system_prompt = f"""Você responde perguntas sobre espiritismo usando apenas o contexto.
Escreva uma ou duas frases completas, em português. Não repita a pergunta nem as instruções.
Se o contexto não bastar, responda apenas: Não encontrei essa informação nos livros indexados.
Informações:
{context_text}
Instruções:
- Responda de forma clara e concisa
- Use o contexto fornecido
- Quando citar passagens, mencione o livro e capítulo (se disponível)
- Se não souber a resposta, diga que não encontrou na base de dados"""
prompt = f"{system_prompt}\n\nPergunta: {query}\nResposta:"
response = self._get_llm().generate(prompt, max_tokens=500)
return response
Contexto:
{context_text}"""
template = (
"<|start_header_id|>user<|end_header_id|>\n\n"
"{0}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n"
)
with self._get_llm().chat_session(system_prompt=system_prompt, prompt_template=template):
response = self.llm.generate(query, max_tokens=160, temp=0.1)
return response.strip()
def query(self, query: str, top_k: int = 3) -> Dict:
"""Query the RAG system."""