caarleexx commited on
Commit
9e8cd8d
·
verified ·
1 Parent(s): 9472128

Update backend/main.py

Browse files
Files changed (1) hide show
  1. backend/main.py +5 -14
backend/main.py CHANGED
@@ -13,8 +13,8 @@ from fastapi.responses import StreamingResponse
13
 
14
  # RAG Imports
15
  from langchain_community.document_loaders import PyPDFLoader
16
- from langchain_community.embeddings import HuggingFaceEmbeddings # MUDANÇA: Novo import
17
- from langchain.text_splitter import RecursiveCharacterTextSplitter
18
  from langchain_community.vectorstores import FAISS
19
  from langchain_core.runnables import RunnablePassthrough, RunnableLambda
20
  from langchain_core.output_parsers import StrOutputParser
@@ -40,11 +40,10 @@ HF_EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
40
 
41
  # Inicializa o modelo Groq e o modelo de embedding
42
  model = ChatGroq(model=os.getenv("GROQ_MODEL", "mixtral-8x7b-32768"))
43
- # MUDANÇA: Inicializa o HuggingFaceEmbeddings
44
  embeddings = HuggingFaceEmbeddings(
45
  model_name=HF_EMBEDDING_MODEL,
46
- # O device="cpu" garante que ele será executado na CPU, o que é ideal em ambientes sem GPU.
47
- model_kwargs={'device': 'cpu'}
48
  )
49
 
50
  # Prompt RAG modificado para receber contexto
@@ -72,7 +71,6 @@ class ChatRequest(BaseModel):
72
 
73
  def format_docs(docs):
74
  """Formata os documentos recuperados em uma string única para injeção no prompt."""
75
- # Adicionar metadados (se existirem) pode ajudar o LLM a "citar" o documento
76
  return "\n\n---\n\n".join(
77
  f"Conteúdo: {doc.page_content}\n(Fonte: Página {doc.metadata.get('page', 'N/A')})"
78
  for doc in docs
@@ -92,10 +90,8 @@ async def upload_document(file: UploadFile = File(...)):
92
  raise HTTPException(status_code=400, detail="Apenas arquivos PDF são suportados neste exemplo.")
93
 
94
  # 1. Salvar o arquivo temporariamente para o Loader poder ler
95
- # Mantenha essa lógica pois o PyPDFLoader precisa de um caminho de arquivo
96
  try:
97
  with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
98
- # Garante que o arquivo temporário está no disco para o PyPDFLoader
99
  content = await file.read()
100
  tmp_file.write(content)
101
  temp_path = tmp_file.name
@@ -109,9 +105,8 @@ async def upload_document(file: UploadFile = File(...)):
109
  splits = text_splitter.split_documents(docs)
110
 
111
  # 4. Vetorizar e Armazenar (Vector Store)
112
- # Atenção: O download do modelo HF (se for a primeira vez) pode demorar!
113
  vectorstore = FAISS.from_documents(documents=splits, embedding=embeddings)
114
- retriever = vectorstore.as_retriever(search_kwargs={"k": 4}) # Recupera os 4 melhores chunks
115
 
116
  # 5. Criar a nova Chain RAG
117
  rag_chain = (
@@ -145,7 +140,6 @@ async def chat(request: ChatRequest):
145
  base_prompt = ChatPromptTemplate.from_messages(
146
  [("system", "Você é um assistente prestativo. Nenhuma informação de documento foi fornecida."), ("human", "{input}")]
147
  )
148
- # Aqui, mantemos o output parser para consistência com a chain RAG
149
  current_chain = base_prompt | model | StrOutputParser()
150
 
151
  # Função geradora que produz os pedaços (chunks) da resposta
@@ -154,12 +148,9 @@ async def chat(request: ChatRequest):
154
  # 'astream' é o método de streaming assíncrono do LangChain
155
  async for chunk in current_chain.astream({"input": request.content}):
156
  if chunk:
157
- # print(f"Enviando chunk: {chunk}") # Log para depuração
158
  yield chunk
159
  except Exception as e:
160
- # Caso a chamada Groq falhe ou outro erro ocorra
161
  print(f"Erro no streaming: {e}")
162
- # Emite o erro para o cliente
163
  yield f"Erro no serviço de IA: {e}"
164
 
165
  # Retorna uma resposta de streaming
 
13
 
14
  # RAG Imports
15
  from langchain_community.document_loaders import PyPDFLoader
16
+ from langchain_community.embeddings import HuggingFaceEmbeddings
17
+ from langchain_text_splitters import RecursiveCharacterTextSplitter # CORRIGIDO: Nova importação
18
  from langchain_community.vectorstores import FAISS
19
  from langchain_core.runnables import RunnablePassthrough, RunnableLambda
20
  from langchain_core.output_parsers import StrOutputParser
 
40
 
41
  # Inicializa o modelo Groq e o modelo de embedding
42
  model = ChatGroq(model=os.getenv("GROQ_MODEL", "mixtral-8x7b-32768"))
43
+ # MUDANÇA: Inicializa o HuggingFaceEmbeddings na CPU
44
  embeddings = HuggingFaceEmbeddings(
45
  model_name=HF_EMBEDDING_MODEL,
46
+ model_kwargs={'device': 'cpu'}
 
47
  )
48
 
49
  # Prompt RAG modificado para receber contexto
 
71
 
72
  def format_docs(docs):
73
  """Formata os documentos recuperados em uma string única para injeção no prompt."""
 
74
  return "\n\n---\n\n".join(
75
  f"Conteúdo: {doc.page_content}\n(Fonte: Página {doc.metadata.get('page', 'N/A')})"
76
  for doc in docs
 
90
  raise HTTPException(status_code=400, detail="Apenas arquivos PDF são suportados neste exemplo.")
91
 
92
  # 1. Salvar o arquivo temporariamente para o Loader poder ler
 
93
  try:
94
  with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
 
95
  content = await file.read()
96
  tmp_file.write(content)
97
  temp_path = tmp_file.name
 
105
  splits = text_splitter.split_documents(docs)
106
 
107
  # 4. Vetorizar e Armazenar (Vector Store)
 
108
  vectorstore = FAISS.from_documents(documents=splits, embedding=embeddings)
109
+ retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
110
 
111
  # 5. Criar a nova Chain RAG
112
  rag_chain = (
 
140
  base_prompt = ChatPromptTemplate.from_messages(
141
  [("system", "Você é um assistente prestativo. Nenhuma informação de documento foi fornecida."), ("human", "{input}")]
142
  )
 
143
  current_chain = base_prompt | model | StrOutputParser()
144
 
145
  # Função geradora que produz os pedaços (chunks) da resposta
 
148
  # 'astream' é o método de streaming assíncrono do LangChain
149
  async for chunk in current_chain.astream({"input": request.content}):
150
  if chunk:
 
151
  yield chunk
152
  except Exception as e:
 
153
  print(f"Erro no streaming: {e}")
 
154
  yield f"Erro no serviço de IA: {e}"
155
 
156
  # Retorna uma resposta de streaming