DHEIVER commited on
Commit
1e45ac8
·
verified ·
1 Parent(s): c4ba10f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +110 -56
app.py CHANGED
@@ -2,58 +2,91 @@ import gradio as gr
2
  import torch
3
  from sentence_transformers import SentenceTransformer, util
4
  from transformers import T5ForConditionalGeneration, T5Tokenizer
 
 
5
 
6
  # --- 1. Carregamento dos Modelos (faça isso apenas uma vez) ---
7
  # Esta parte não muda. Usaremos os mesmos modelos eficientes.
8
-
9
- # Modelo para criar embeddings (vetores) a partir do texto
10
  print("Carregando o modelo de recuperação (Sentence Transformer)...")
11
  retriever_model = SentenceTransformer('all-MiniLM-L6-v2')
12
-
13
- # Modelo para gerar as respostas (um T5 do Hugging Face)
14
  print("Carregando o modelo de geração (Flan-T5)...")
15
  generator_tokenizer = T5Tokenizer.from_pretrained('google/flan-t5-base')
16
  generator_model = T5ForConditionalGeneration.from_pretrained('google/flan-t5-base')
17
  print("Modelos carregados com sucesso!")
18
 
19
-
20
- # --- 2. Base de Conhecimento: DADOS DOS CERTIFICADOS DE CALIBRAÇÃO ---
21
- # Esta é a principal modificação.
22
- # Cada string representa os dados essenciais de um certificado de calibração.
23
- # Em um sistema real, isso viria de um banco de dados ou da leitura de PDFs.
24
-
25
- knowledge_base = [
26
- "Certificado ID: CAL-2023-001. Instrumento TAG: PI-101 (Manômetro de Pressão). Data da Calibração: 15/01/2023. Próxima Calibração: 15/01/2024. Resultado: APROVADO. Incerteza da medição: 0.05 bar. Padrão utilizado: Fluke 754 (ID: P-05). Técnico: Ana Oliveira.",
27
- "Certificado ID: CAL-2023-002. Instrumento TAG: TT-205 (Transmissor de Temperatura). Data da Calibração: 20/02/2023. Próxima Calibração: 20/08/2023. Resultado: REPROVADO 'como encontrado', APROVADO 'como deixado' após ajuste. Tolerância: ±0.1°C. Observação: Encontrado desvio de +0.3°C no ponto de 100°C.",
28
- "Certificado ID: CAL-2023-003. Instrumento TAG: FV-300 (Válvula de Controle). Data do Teste: 05/03/2023. Próximo Teste: 05/03/2025. Procedimento: POP-123-Rev02. Resultado: APROVADO. Observação: Histerese de 1.5% encontrada, dentro do limite de 2.0%.",
29
- "Certificado ID: CAL-2023-004. Instrumento TAG: BAL-01 (Balança Analítica). Data da Calibração: 10/04/2023. Próxima Calibração: 10/04/2024. Resultado: APROVADO. Incerteza da medição: ±0.001g. Padrões de massa com rastreabilidade à RBC/Inmetro.",
30
- "Certificado ID: CAL-2023-005. Instrumento TAG: PI-102 (Manômetro de Pressão de reserva). Data da Calibração: 18/01/2023. Próxima Calibração: 18/01/2024. Resultado: APROVADO. Técnico: Carlos Pereira. O instrumento estava armazenado e foi calibrado antes do uso potencial."
31
- ]
32
-
33
- # --- 3. Pré-processamento da Base de Conhecimento ---
34
- # Esta parte não muda. Convertemos nossa nova base de conhecimento em vetores.
35
- print("Processando a base de conhecimento (certificados)...")
36
- knowledge_base_embeddings = retriever_model.encode(knowledge_base, convert_to_tensor=True)
37
- print("Base de conhecimento pronta!")
38
-
39
-
40
- # --- 4. A Função Principal do RAG ---
41
- # Esta função é agnóstica ao domínio, então não precisa de alterações.
42
- def answer_question(question):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  """
44
- Esta função recebe uma pergunta, encontra o certificado mais relevante na base de conhecimento
45
- e gera uma resposta baseada nos dados daquele certificado.
46
  """
 
 
 
 
 
 
 
 
47
  # Etapa de Recuperação (Retrieval)
48
  question_embedding = retriever_model.encode(question, convert_to_tensor=True)
49
  cosine_scores = util.cos_sim(question_embedding, knowledge_base_embeddings)
 
 
50
  best_doc_index = torch.argmax(cosine_scores)
51
  retrieved_context = knowledge_base[best_doc_index]
52
 
53
- # Log para depuração, para vermos qual certificado foi recuperado.
54
  print(f"\n--- Nova Pergunta de Auditoria ---")
55
  print(f"Pergunta: {question}")
56
- print(f"Certificado Recuperado (Contexto): {retrieved_context}")
57
 
58
  # Etapa de Geração (Generation)
59
  prompt = f"""
@@ -61,15 +94,14 @@ def answer_question(question):
61
 
62
  Pergunta: {question}
63
 
64
- Com base estritamente no contexto do certificado fornecido, responda à pergunta do auditor.
65
  Resposta:
66
  """
67
 
68
  input_ids = generator_tokenizer(prompt, return_tensors="pt").input_ids
69
-
70
  outputs = generator_model.generate(
71
  input_ids,
72
- max_length=150,
73
  num_beams=5,
74
  early_stopping=True
75
  )
@@ -77,26 +109,48 @@ def answer_question(question):
77
  answer = generator_tokenizer.decode(outputs[0], skip_special_tokens=True)
78
  return answer
79
 
80
- # --- 5. Criação da Interface com Gradio ---
81
- # Modificamos o título e a descrição para a nossa nova aplicação.
82
- interface = gr.Interface(
83
- fn=answer_question,
84
- inputs=gr.Textbox(
85
- lines=3,
86
- placeholder="Faça uma pergunta sobre um certificado ou instrumento...\nEx: Qual o resultado do manômetro PI-101?\nQuando vence a calibração do TT-205?\nQuem calibrou a balança BAL-01?",
87
- label="Pergunta do Auditor"
88
- ),
89
- outputs=gr.Textbox(label="Resposta Baseada no Certificado"),
90
- title="🤖 RAG - Auditor de Certificados de Calibração",
91
- description="Este sistema usa RAG para responder perguntas sobre certificados de calibração. Pergunte sobre o status, datas, técnicos ou resultados de um instrumento específico (PI-101, TT-205, FV-300, BAL-01).",
92
- examples=[
93
- ["Qual foi o resultado da calibração do PI-101?"],
94
- ["Quando é a próxima calibração do transmissor TT-205?"],
95
- ["Qual a incerteza da balança BAL-01?"],
96
- ["Houve alguma observação no certificado da válvula FV-300?"]
97
- ]
98
- )
99
-
100
- # --- 6. Lançamento do App ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  if __name__ == "__main__":
102
  interface.launch()
 
2
  import torch
3
  from sentence_transformers import SentenceTransformer, util
4
  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)...")
13
  generator_tokenizer = T5Tokenizer.from_pretrained('google/flan-t5-base')
14
  generator_model = T5ForConditionalGeneration.from_pretrained('google/flan-t5-base')
15
  print("Modelos carregados com sucesso!")
16
 
17
+ # --- 2. Função para Processar Arquivos Enviados ---
18
+ def process_files(files):
19
+ """
20
+ 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)
33
+ for page in reader.pages:
34
+ page_text = page.extract_text()
35
+ if page_text:
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:
43
+ knowledge_text += f.read() + "\n"
44
+ except Exception as e:
45
+ return None, f"Erro ao ler o arquivo TXT {os.path.basename(file_path)}: {e}"
46
+
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
+
74
+ if not knowledge_state or not knowledge_state[0] or knowledge_state[1] is None:
75
+ return "⚠️ A base de conhecimento está vazia. Por favor, processe alguns arquivos primeiro."
76
+
77
+ knowledge_base, knowledge_base_embeddings = 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"""
 
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
  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__":
156
  interface.launch()