Spaces:
Sleeping
Sleeping
File size: 8,710 Bytes
121fc9e 6050f7a 1e45ac8 be1ab03 121fc9e 6050f7a be1ab03 121fc9e 6050f7a be1ab03 6050f7a 121fc9e be1ab03 1e45ac8 be1ab03 1e45ac8 37f3bb4 1e45ac8 be1ab03 1e45ac8 37f3bb4 1e45ac8 be1ab03 1e45ac8 be1ab03 1e45ac8 37f3bb4 1e45ac8 be1ab03 37f3bb4 be1ab03 1e45ac8 be1ab03 37f3bb4 1e45ac8 c2667bf 74abfdf c2667bf 74abfdf c2667bf 74abfdf c2667bf 74abfdf c2667bf be1ab03 c2667bf 963b058 c2667bf 74abfdf c2667bf 74abfdf c2667bf 1e45ac8 74abfdf 963b058 be1ab03 963b058 1e45ac8 be1ab03 1e45ac8 be1ab03 1e45ac8 be1ab03 1e45ac8 963b058 be1ab03 74abfdf 1e45ac8 74abfdf 957e316 c2667bf 1e45ac8 c2667bf 121fc9e 74abfdf |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
import gradio as gr
import torch
from sentence_transformers import SentenceTransformer, util
from transformers import AutoTokenizer, AutoModelForCausalLM
from pypdf import PdfReader
import os
import re
# --- 1. Carregamento dos Modelos ---
print("A carregar o modelo de recuperação (Sentence Transformer)...")
retriever_model = SentenceTransformer('all-MiniLM-L6-v2')
print("A carregar o modelo de geração (DeepSeek)...")
generator_tokenizer = AutoTokenizer.from_pretrained(
'deepseek-ai/deepseek-coder-1.3b-instruct',
trust_remote_code=True
)
generator_model = AutoModelForCausalLM.from_pretrained(
'deepseek-ai/deepseek-coder-1.3b-instruct',
trust_remote_code=True
)
print("Modelos carregados com sucesso!")
# --- 2. Função de Processamento de Ficheiros (Chunking Estruturado) ---
def process_files(files):
if not files:
return None, "Por favor, envie um ou mais ficheiros."
knowledge_text = ""
for file in files:
file_path = file.name
if file_path.endswith(".pdf"):
try:
reader = PdfReader(file_path)
for page in reader.pages:
page_text = page.extract_text()
if page_text:
knowledge_text += page_text + "\n\n"
except Exception as e:
return None, f"Erro ao ler o ficheiro PDF {os.path.basename(file_path)}: {e}"
elif file_path.endswith(".txt"):
try:
with open(file_path, 'r', encoding='utf-8') as f:
knowledge_text += f.read() + "\n\n"
except Exception as e:
return None, f"Erro ao ler o ficheiro TXT {os.path.basename(file_path)}: {e}"
if not knowledge_text.strip():
return None, "Não foi possível extrair texto dos ficheiros fornecidos."
chunk_pattern = r"(?m)(^\d+\..*)"
text_chunks = [chunk.strip() for chunk in re.split(chunk_pattern, knowledge_text) if chunk.strip()]
structured_chunks = []
i = 0
while i < len(text_chunks):
if re.match(chunk_pattern, text_chunks[i]) and i + 1 < len(text_chunks):
structured_chunks.append(text_chunks[i] + "\n" + text_chunks[i+1])
i += 2
else:
structured_chunks.append(text_chunks[i])
i += 1
if not structured_chunks:
return None, "O texto extraído não continha blocos de texto válidos para processamento."
print(f"A processar {len(structured_chunks)} chunks estruturados dos ficheiros...")
knowledge_base_embeddings = retriever_model.encode(structured_chunks, convert_to_tensor=True, show_progress_bar=True)
print("Base de conhecimento criada a partir dos ficheiros.")
return (structured_chunks, knowledge_base_embeddings), f"✅ Sucesso! {len(files)} ficheiro(s) processado(s), gerando {len(structured_chunks)} chunks estruturados."
# --- 3. O CÉREBRO DA ANÁLISE: generate_compliance_report ---
def generate_compliance_report(task, knowledge_state, progress=gr.Progress()):
"""
Esta função orquestra o processo de RAG com melhor feedback e tratamento de erros.
"""
try:
if not task:
return "Por favor, forneça uma tarefa de análise."
if not knowledge_state or not knowledge_state[0] or knowledge_state[1] is None:
return "⚠️ A base de conhecimento está vazia. Por favor, processe alguns ficheiros primeiro."
knowledge_base, knowledge_base_embeddings = knowledge_state
progress(0, desc="A iniciar análise...")
# Passo 1: Recuperação Ampla do Contexto
progress(0.1, desc="A recuperar contexto relevante do documento...")
search_query = "Informações completas do certificado de calibração"
question_embedding = retriever_model.encode(search_query, convert_to_tensor=True)
cosine_scores = util.cos_sim(question_embedding, knowledge_base_embeddings)
top_k = min(15, len(knowledge_base))
top_results = torch.topk(cosine_scores, k=top_k, dim=-1)
retrieved_context = "\n\n---\n\n".join([knowledge_base[i] for i in top_results.indices[0]])
progress(0.4, desc="Contexto recuperado. A gerar o relatório com o modelo de IA (pode demorar)...")
# Passo 2: Geração com "Super-Prompt"
final_prompt = f"""### Instruction:
Você é um auditor de metrologia a preencher um relatório de conformidade. Com base no 'Contexto do Documento' fornecido, preencha cada item da 'Checklist de Análise' abaixo. Se uma informação não for encontrada no contexto, escreva 'Não encontrado'.
**Contexto do Documento:**
{retrieved_context}
**Checklist de Análise:**
# Relatório de Análise de Conformidade
## 1. Incerteza de Medição
- **1.1 a 1.2 Casas Decimais / Compatibilidade:**
- **1.3 Nível de Confiança, Fator de Abrangência (k) e Graus de Liberdade:**
- **1.4 Declaração de Rastreabilidade dos Resultados:**
## 2. Resultados da Calibração
- **2.1 a 2.3 Unidades SI, Casas Decimais e Algarismos Significativos:**
## 3. Conformidade da Faixa
- **3.1 Faixa e Especificações Solicitadas:**
## 4. Condições Ambientais
- **4.1 Registro das Condições e Incerteza Associada:**
## 5. Identificação do Item
- **5.1 Descrição e Identificação do Item:**
## 6. Identificação do Método
- **6.1 Método/Procedimento Utilizado:**
## 7. Identificação do Cliente
- **7.1 Nome e Endereço do Cliente:**
## 8. Identificação do Laboratório
- **8.1 Nome e Endereço do Laboratório:**
## 9. Identificação do Certificado
- **9.1 Número do Certificado:**
## 10. Autorização
- **10.1 Pessoas Autorizadas:**
### Response:
"""
input_ids = generator_tokenizer(final_prompt, return_tensors="pt").input_ids
# Parâmetros de geração otimizados
outputs = generator_model.generate(
input_ids,
max_new_tokens=800, # Reduzido para maior eficiência
do_sample=False,
pad_token_id=generator_tokenizer.eos_token_id
)
progress(0.9, desc="A formatar o relatório final...")
final_report = generator_tokenizer.decode(outputs[0], skip_special_tokens=True)
# Limpa a resposta para remover o prompt inicial
if "### Response:" in final_report:
final_report = final_report.split("### Response:")[1].strip()
progress(1, desc="Análise concluída.")
return final_report
except Exception as e:
# Tratamento de erros para retornar uma mensagem clara ao utilizador
print(f"Ocorreu um erro durante a geração do relatório: {e}")
return f"### ⚠️ Ocorreu um erro durante a análise.\n\n**Causa provável:** O modelo de IA pode ter excedido os limites de memória ou tempo. Por favor, tente novamente com um documento mais simples ou verifique os logs para mais detalhes.\n\n**Detalhes do Erro:** {str(e)}"
# --- 4. Interface Gráfica (Simplificada para o novo fluxo) ---
with gr.Blocks(theme=gr.themes.Soft()) as interface:
knowledge_state = gr.State()
gr.Markdown(
"""
# 🤖 Agente de Análise de Conformidade Metrológica (v14 - Robusto)
**1. Carregue um documento**: Envie um certificado de calibração (`.pdf` ou `.txt`).
**2. Processe o documento**: Clique no botão para criar a base de conhecimento.
**3. Inicie a Análise**: Dê uma tarefa ao agente (ex: "Analisar conformidade deste certificado") e clique em "Iniciar Análise".
"""
)
with gr.Row():
with gr.Column(scale=1):
file_uploader = gr.File(label="Carregar Documento (.pdf, .txt)", file_count="multiple", file_types=[".pdf", ".txt"])
process_button = gr.Button("Processar Documento", variant="primary")
status_box = gr.Textbox(label="Status do Processamento", interactive=False)
with gr.Column(scale=2):
task_box = gr.Textbox(label="Tarefa de Análise", placeholder='Ex: Avaliar a conformidade deste certificado de calibração.')
submit_button = gr.Button("Iniciar Análise", variant="primary")
with gr.Row():
report_box = gr.Markdown(label="Relatório Final de Análise")
# A chamada de click continua a mesma, pois o gr.Progress é gerido dentro da função
process_button.click(fn=process_files, inputs=[file_uploader], outputs=[knowledge_state, status_box])
submit_button.click(fn=generate_compliance_report, inputs=[task_box, knowledge_state], outputs=[report_box])
# --- 5. Lançamento do App ---
if __name__ == "__main__":
interface.launch()
|