DHEIVER commited on
Commit
957e316
·
verified ·
1 Parent(s): 54a88fd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +32 -50
app.py CHANGED
@@ -5,8 +5,7 @@ from transformers import T5ForConditionalGeneration, T5Tokenizer
5
  from pypdf import PdfReader
6
  import os
7
 
8
- # --- 1. Carregamento dos Modelos (faça isso apenas uma vez) ---
9
- # Esta parte não muda. Usaremos os mesmos modelos eficientes.
10
  print("Carregando o modelo de recuperação (Sentence Transformer)...")
11
  retriever_model = SentenceTransformer('all-MiniLM-L6-v2')
12
  print("Carregando o modelo de geração (Flan-T5)...")
@@ -16,17 +15,12 @@ print("Modelos carregados com sucesso!")
16
 
17
  # --- 2. Função para Processar Arquivos Enviados ---
18
  def process_files(files):
19
- """
20
- Lê arquivos .pdf e .txt, extrai o texto e o divide em blocos.
21
- Retorna os blocos de texto e seus embeddings correspondentes.
22
- """
23
  if not files:
24
  return None, "Por favor, envie um ou mais arquivos."
25
 
26
  knowledge_text = ""
27
  for file in files:
28
  file_path = file.name
29
- # Extrai texto de arquivos PDF
30
  if file_path.endswith(".pdf"):
31
  try:
32
  reader = PdfReader(file_path)
@@ -36,7 +30,6 @@ def process_files(files):
36
  knowledge_text += page_text + "\n"
37
  except Exception as e:
38
  return None, f"Erro ao ler o arquivo PDF {os.path.basename(file_path)}: {e}"
39
- # Extrai texto de arquivos TXT
40
  elif file_path.endswith(".txt"):
41
  try:
42
  with open(file_path, 'r', encoding='utf-8') as f:
@@ -47,27 +40,23 @@ def process_files(files):
47
  if not knowledge_text.strip():
48
  return None, "Não foi possível extrair texto dos arquivos fornecidos."
49
 
50
- # Divide o texto em blocos menores (parágrafos) para uma melhor recuperação
51
- text_chunks = [chunk.strip() for chunk in knowledge_text.split('\n\n') if chunk.strip()]
 
 
52
 
53
  if not text_chunks:
54
  return None, "O texto extraído não continha blocos de texto válidos para processamento."
55
 
56
- # Cria os embeddings para a base de conhecimento extraída
57
  print(f"Processando {len(text_chunks)} blocos de texto dos arquivos...")
58
  knowledge_base_embeddings = retriever_model.encode(text_chunks, convert_to_tensor=True, show_progress_bar=True)
59
  print("Base de conhecimento criada a partir dos arquivos.")
60
 
61
- # Retorna a base de conhecimento (blocos e embeddings) e uma mensagem de sucesso
62
  return (text_chunks, knowledge_base_embeddings), f"✅ Sucesso! {len(files)} arquivo(s) processado(s), gerando {len(text_chunks)} blocos de texto."
63
 
64
 
65
- # --- 3. A Função Principal do RAG ---
66
  def answer_question(question, knowledge_state):
67
- """
68
- Recebe uma pergunta e o estado da base de conhecimento (texto e embeddings)
69
- e gera uma resposta.
70
- """
71
  if not question:
72
  return "Por favor, insira uma pergunta."
73
 
@@ -78,30 +67,41 @@ def answer_question(question, knowledge_state):
78
 
79
  # Etapa de Recuperação (Retrieval)
80
  question_embedding = retriever_model.encode(question, convert_to_tensor=True)
81
- cosine_scores = util.cos_sim(question_embedding, knowledge_base_embeddings)
82
 
83
- # Encontra o bloco de texto mais relevante
84
- best_doc_index = torch.argmax(cosine_scores)
85
- retrieved_context = knowledge_base[best_doc_index]
 
 
 
 
 
 
86
 
87
  print(f"\n--- Nova Pergunta de Auditoria ---")
88
  print(f"Pergunta: {question}")
89
- print(f"Contexto Recuperado: {retrieved_context}")
90
 
91
  # Etapa de Geração (Generation)
 
 
 
92
  prompt = f"""
93
- Contexto: {retrieved_context}
94
 
95
- Pergunta: {question}
 
96
 
97
- Com base estritamente no contexto do documento fornecido, responda à pergunta do auditor.
98
- Resposta:
 
 
99
  """
100
 
101
  input_ids = generator_tokenizer(prompt, return_tensors="pt").input_ids
102
  outputs = generator_model.generate(
103
  input_ids,
104
- max_length=256, # Aumentado para respostas potencialmente mais longas
105
  num_beams=5,
106
  early_stopping=True
107
  )
@@ -109,47 +109,29 @@ def answer_question(question, knowledge_state):
109
  answer = generator_tokenizer.decode(outputs[0], skip_special_tokens=True)
110
  return answer
111
 
112
- # --- 4. Criação da Interface com Gradio Blocks ---
113
  with gr.Blocks(theme=gr.themes.Soft()) as interface:
114
- # Estado para armazenar a base de conhecimento processada
115
  knowledge_state = gr.State()
116
-
117
  gr.Markdown(
118
  """
119
- # 🤖 RAG - Auditor de Documentos
120
  **1. Carregue seus arquivos**: Envie um ou mais certificados ou documentos nos formatos `.pdf` ou `.txt`.
121
  **2. Processe os arquivos**: Clique no botão para criar a base de conhecimento.
122
  **3. Faça perguntas**: Após o processamento, faça perguntas sobre o conteúdo dos documentos.
123
  """
124
  )
125
-
126
  with gr.Row():
127
  with gr.Column(scale=1):
128
- file_uploader = gr.File(
129
- label="Carregar Certificados (.pdf, .txt)",
130
- file_count="multiple",
131
- file_types=[".pdf", ".txt"]
132
- )
133
  process_button = gr.Button("Processar Arquivos", variant="primary")
134
  status_box = gr.Textbox(label="Status do Processamento", interactive=False)
135
-
136
  with gr.Column(scale=2):
137
  question_box = gr.Textbox(label="Faça sua pergunta aqui", placeholder="Ex: Qual o resultado da calibração do instrumento PI-101?")
138
  submit_button = gr.Button("Obter Resposta", variant="primary")
139
  answer_box = gr.Textbox(label="Resposta Baseada nos Documentos", interactive=False, lines=5)
140
 
141
- # Conecta os componentes às funções
142
- process_button.click(
143
- fn=process_files,
144
- inputs=[file_uploader],
145
- outputs=[knowledge_state, status_box]
146
- )
147
-
148
- submit_button.click(
149
- fn=answer_question,
150
- inputs=[question_box, knowledge_state],
151
- outputs=[answer_box]
152
- )
153
 
154
  # --- 5. Lançamento do App ---
155
  if __name__ == "__main__":
 
5
  from pypdf import PdfReader
6
  import os
7
 
8
+ # --- 1. Carregamento dos Modelos (sem alterações) ---
 
9
  print("Carregando o modelo de recuperação (Sentence Transformer)...")
10
  retriever_model = SentenceTransformer('all-MiniLM-L6-v2')
11
  print("Carregando o modelo de geração (Flan-T5)...")
 
15
 
16
  # --- 2. Função para Processar Arquivos Enviados ---
17
  def process_files(files):
 
 
 
 
18
  if not files:
19
  return None, "Por favor, envie um ou mais arquivos."
20
 
21
  knowledge_text = ""
22
  for file in files:
23
  file_path = file.name
 
24
  if file_path.endswith(".pdf"):
25
  try:
26
  reader = PdfReader(file_path)
 
30
  knowledge_text += page_text + "\n"
31
  except Exception as e:
32
  return None, f"Erro ao ler o arquivo PDF {os.path.basename(file_path)}: {e}"
 
33
  elif file_path.endswith(".txt"):
34
  try:
35
  with open(file_path, 'r', encoding='utf-8') as f:
 
40
  if not knowledge_text.strip():
41
  return None, "Não foi possível extrair texto dos arquivos fornecidos."
42
 
43
+ # MUDANÇA 1: Melhorando o "Chunking" (Divisão do Texto)
44
+ # Em vez de dividir por parágrafos (\n\n), dividimos por linha (\n).
45
+ # Isso cria chunks menores e mais focados, o que é melhor para documentos técnicos.
46
+ text_chunks = [chunk.strip() for chunk in knowledge_text.split('\n') if chunk.strip() and len(chunk) > 10]
47
 
48
  if not text_chunks:
49
  return None, "O texto extraído não continha blocos de texto válidos para processamento."
50
 
 
51
  print(f"Processando {len(text_chunks)} blocos de texto dos arquivos...")
52
  knowledge_base_embeddings = retriever_model.encode(text_chunks, convert_to_tensor=True, show_progress_bar=True)
53
  print("Base de conhecimento criada a partir dos arquivos.")
54
 
 
55
  return (text_chunks, knowledge_base_embeddings), f"✅ Sucesso! {len(files)} arquivo(s) processado(s), gerando {len(text_chunks)} blocos de texto."
56
 
57
 
58
+ # --- 3. A Função Principal do RAG (com melhorias) ---
59
  def answer_question(question, knowledge_state):
 
 
 
 
60
  if not question:
61
  return "Por favor, insira uma pergunta."
62
 
 
67
 
68
  # Etapa de Recuperação (Retrieval)
69
  question_embedding = retriever_model.encode(question, convert_to_tensor=True)
 
70
 
71
+ # MUDANÇA 2: Recuperando mais contexto (top_k=3)
72
+ # Em vez de pegar apenas o melhor chunk, pegamos os 3 melhores.
73
+ # Isso dá mais informação para a IA gerar uma resposta completa.
74
+ cosine_scores = util.cos_sim(question_embedding, knowledge_base_embeddings)
75
+ top_k = min(3, len(knowledge_base)) # Garante que não tentamos pegar mais chunks do que existem
76
+ top_results = torch.topk(cosine_scores, k=top_k, dim=-1)
77
+
78
+ # Junta os 3 melhores chunks em um único contexto
79
+ retrieved_context = "\n---\n".join([knowledge_base[i] for i in top_results.indices[0]])
80
 
81
  print(f"\n--- Nova Pergunta de Auditoria ---")
82
  print(f"Pergunta: {question}")
83
+ print(f"Contexto Recuperado (Top {top_k}):\n{retrieved_context}")
84
 
85
  # Etapa de Geração (Generation)
86
+
87
+ # MUDANÇA 3: Prompt de Geração Aprimorado
88
+ # Damos instruções mais claras para que a IA elabore a resposta.
89
  prompt = f"""
90
+ Você é um assistente de auditoria especialista. Sua tarefa é responder à pergunta do usuário de forma clara e concisa, baseando-se exclusivamente nos trechos de documentos fornecidos abaixo. Elabore uma resposta completa em vez de simplesmente copiar o texto.
91
 
92
+ **Documentos Relevantes:**
93
+ {retrieved_context}
94
 
95
+ **Pergunta do Auditor:**
96
+ {question}
97
+
98
+ **Resposta Elaborada:**
99
  """
100
 
101
  input_ids = generator_tokenizer(prompt, return_tensors="pt").input_ids
102
  outputs = generator_model.generate(
103
  input_ids,
104
+ max_length=256,
105
  num_beams=5,
106
  early_stopping=True
107
  )
 
109
  answer = generator_tokenizer.decode(outputs[0], skip_special_tokens=True)
110
  return answer
111
 
112
+ # --- 4. Interface Gráfica (sem alterações na estrutura) ---
113
  with gr.Blocks(theme=gr.themes.Soft()) as interface:
 
114
  knowledge_state = gr.State()
 
115
  gr.Markdown(
116
  """
117
+ # 🤖 RAG - Auditor de Documentos (v3)
118
  **1. Carregue seus arquivos**: Envie um ou mais certificados ou documentos nos formatos `.pdf` ou `.txt`.
119
  **2. Processe os arquivos**: Clique no botão para criar a base de conhecimento.
120
  **3. Faça perguntas**: Após o processamento, faça perguntas sobre o conteúdo dos documentos.
121
  """
122
  )
 
123
  with gr.Row():
124
  with gr.Column(scale=1):
125
+ file_uploader = gr.File(label="Carregar Certificados (.pdf, .txt)", file_count="multiple", file_types=[".pdf", ".txt"])
 
 
 
 
126
  process_button = gr.Button("Processar Arquivos", variant="primary")
127
  status_box = gr.Textbox(label="Status do Processamento", interactive=False)
 
128
  with gr.Column(scale=2):
129
  question_box = gr.Textbox(label="Faça sua pergunta aqui", placeholder="Ex: Qual o resultado da calibração do instrumento PI-101?")
130
  submit_button = gr.Button("Obter Resposta", variant="primary")
131
  answer_box = gr.Textbox(label="Resposta Baseada nos Documentos", interactive=False, lines=5)
132
 
133
+ process_button.click(fn=process_files, inputs=[file_uploader], outputs=[knowledge_state, status_box])
134
+ submit_button.click(fn=answer_question, inputs=[question_box, knowledge_state], outputs=[answer_box])
 
 
 
 
 
 
 
 
 
 
135
 
136
  # --- 5. Lançamento do App ---
137
  if __name__ == "__main__":