caarleexx commited on
Commit
7702d81
·
verified ·
1 Parent(s): b8e3205

Update backend/main.py

Browse files
Files changed (1) hide show
  1. backend/main.py +43 -22
backend/main.py CHANGED
@@ -35,8 +35,7 @@ app.add_middleware(
35
  # --- 2. Configurações de IA ---
36
  HF_EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
37
 
38
- # MUDANÇA CRÍTICA: Removi o os.getenv para ignorar configurações antigas do ambiente
39
- # e forçar o uso do modelo novo e funcional.
40
  model = ChatGroq(
41
  model="llama-3.3-70b-versatile",
42
  temperature=0.3
@@ -47,7 +46,6 @@ embeddings = HuggingFaceEmbeddings(
47
  model_kwargs={'device': 'cpu'}
48
  )
49
 
50
- # System Prompt Otimizado
51
  rag_system_prompt = (
52
  "Você é um assistente experiente e prestativo. "
53
  "Sua tarefa é fornecer respostas detalhadas e ricas em contexto com base nas informações fornecidas. "
@@ -60,7 +58,9 @@ rag_prompt = ChatPromptTemplate.from_messages(
60
  [("system", rag_system_prompt), ("human", "{input}")]
61
  )
62
 
 
63
  rag_chain = None
 
64
 
65
  # --- 3. Modelo de Dados ---
66
  class ChatRequest(BaseModel):
@@ -69,7 +69,7 @@ class ChatRequest(BaseModel):
69
  # --- 4. Helpers ---
70
  def format_docs(docs):
71
  return "\n\n---\n\n".join(
72
- f"Conteúdo: {doc.page_content}\n(Página {doc.metadata.get('page', 'N/A')})"
73
  for doc in docs
74
  )
75
 
@@ -77,7 +77,7 @@ def format_docs(docs):
77
 
78
  @app.post("/upload-document")
79
  async def upload_document(file: UploadFile = File(...)):
80
- global rag_chain
81
 
82
  if file.content_type != "application/pdf":
83
  raise HTTPException(status_code=400, detail="Apenas arquivos PDF são suportados.")
@@ -91,24 +91,16 @@ async def upload_document(file: UploadFile = File(...)):
91
  loader = PyPDFLoader(temp_path)
92
  docs = loader.load()
93
 
94
- # Chunking otimizado
95
  text_splitter = RecursiveCharacterTextSplitter(chunk_size=1200, chunk_overlap=200)
96
  splits = text_splitter.split_documents(docs)
97
 
98
  vectorstore = FAISS.from_documents(documents=splits, embedding=embeddings)
99
 
100
- # Recuperação otimizada (k=6)
101
- retriever = vectorstore.as_retriever(search_kwargs={"k": 6})
102
 
103
- # Chain
104
- rag_chain = (
105
- RunnablePassthrough.assign(
106
- context=(lambda x: x["input"]) | retriever | format_docs
107
- )
108
- | rag_prompt
109
- | model
110
- | StrOutputParser()
111
- )
112
 
113
  return {
114
  "message": "Processamento concluído!",
@@ -126,19 +118,48 @@ async def upload_document(file: UploadFile = File(...)):
126
 
127
  @app.post("/chat")
128
  async def chat(request: ChatRequest):
 
 
 
129
  current_chain = rag_chain
 
 
130
 
131
- if current_chain is None:
132
- base_prompt = ChatPromptTemplate.from_messages(
133
- [("system", "Você é um assistente útil. Nenhum documento foi carregado ainda."), ("human", "{input}")]
 
 
 
 
 
 
 
 
 
 
 
 
134
  )
135
- current_chain = base_prompt | model | StrOutputParser()
136
 
 
137
  async def stream_generator():
138
  try:
139
- async for chunk in current_chain.astream({"input": request.content}):
 
 
 
 
 
 
140
  if chunk:
141
  yield chunk
 
 
 
 
 
 
142
  except Exception as e:
143
  print(f"Erro stream: {e}")
144
  yield f"Erro no serviço de IA: {e}"
 
35
  # --- 2. Configurações de IA ---
36
  HF_EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
37
 
38
+ # Configuração do Modelo (Ignorando variáveis antigas para garantir funcionamento)
 
39
  model = ChatGroq(
40
  model="llama-3.3-70b-versatile",
41
  temperature=0.3
 
46
  model_kwargs={'device': 'cpu'}
47
  )
48
 
 
49
  rag_system_prompt = (
50
  "Você é um assistente experiente e prestativo. "
51
  "Sua tarefa é fornecer respostas detalhadas e ricas em contexto com base nas informações fornecidas. "
 
58
  [("system", rag_system_prompt), ("human", "{input}")]
59
  )
60
 
61
+ # Variáveis globais para armazenar a "inteligência" do RAG
62
  rag_chain = None
63
+ global_retriever = None # MUDANÇA: Retriever global para acessarmos no chat
64
 
65
  # --- 3. Modelo de Dados ---
66
  class ChatRequest(BaseModel):
 
69
  # --- 4. Helpers ---
70
  def format_docs(docs):
71
  return "\n\n---\n\n".join(
72
+ f"📄 Conteúdo: {doc.page_content}\n(🔖 Fonte: Página {doc.metadata.get('page', 'N/A')})"
73
  for doc in docs
74
  )
75
 
 
77
 
78
  @app.post("/upload-document")
79
  async def upload_document(file: UploadFile = File(...)):
80
+ global rag_chain, global_retriever
81
 
82
  if file.content_type != "application/pdf":
83
  raise HTTPException(status_code=400, detail="Apenas arquivos PDF são suportados.")
 
91
  loader = PyPDFLoader(temp_path)
92
  docs = loader.load()
93
 
 
94
  text_splitter = RecursiveCharacterTextSplitter(chunk_size=1200, chunk_overlap=200)
95
  splits = text_splitter.split_documents(docs)
96
 
97
  vectorstore = FAISS.from_documents(documents=splits, embedding=embeddings)
98
 
99
+ # MUDANÇA: Salvamos o retriever globalmente
100
+ global_retriever = vectorstore.as_retriever(search_kwargs={"k": 6})
101
 
102
+ # A chain agora é simples, pois faremos a recuperação manual no endpoint chat
103
+ rag_chain = rag_prompt | model | StrOutputParser()
 
 
 
 
 
 
 
104
 
105
  return {
106
  "message": "Processamento concluído!",
 
118
 
119
  @app.post("/chat")
120
  async def chat(request: ChatRequest):
121
+ """
122
+ Endpoint de chat com Auditoria (envia contexto ao final)
123
+ """
124
  current_chain = rag_chain
125
+ context_str = ""
126
+ docs_source = []
127
 
128
+ # 1. Recuperação Manual de Contexto (Se o RAG estiver ativo)
129
+ if global_retriever:
130
+ try:
131
+ # Busca os documentos relevantes
132
+ docs_source = global_retriever.invoke(request.content)
133
+ context_str = format_docs(docs_source)
134
+ except Exception as e:
135
+ print(f"Erro na recuperação: {e}")
136
+ context_str = "Erro ao recuperar contexto."
137
+ else:
138
+ # Fallback se não houver PDF
139
+ current_chain = (
140
+ ChatPromptTemplate.from_messages([("system", "Você é um assistente útil."), ("human", "{input}")])
141
+ | model
142
+ | StrOutputParser()
143
  )
 
144
 
145
+ # 2. Gerador de Streaming com "Payload Oculto"
146
  async def stream_generator():
147
  try:
148
+ # Passa o contexto manualmente para o prompt
149
+ input_data = {"input": request.content}
150
+ if context_str:
151
+ input_data["context"] = context_str
152
+
153
+ # Stream da resposta da IA
154
+ async for chunk in current_chain.astream(input_data):
155
  if chunk:
156
  yield chunk
157
+
158
+ # MUDANÇA: Ao final, enviamos um separador e o contexto para auditoria
159
+ if context_str:
160
+ debug_data = f"\n\n###__DEBUG__###\n**Auditoria de Contexto (RAG):**\n\n{context_str}"
161
+ yield debug_data
162
+
163
  except Exception as e:
164
  print(f"Erro stream: {e}")
165
  yield f"Erro no serviço de IA: {e}"