Spaces:
Sleeping
Sleeping
File size: 7,647 Bytes
088f610 79466e6 6cecfcc 79466e6 4c60df3 79466e6 088f610 79466e6 d54e468 ccdd1cb 79466e6 088f610 79466e6 dd4a612 79466e6 a35e3d3 79466e6 6cecfcc ccdd1cb 79466e6 d54e468 79466e6 088f610 79466e6 a35e3d3 79466e6 b7b37be ccdd1cb 79466e6 088f610 79466e6 dc2efd2 6cecfcc dc2efd2 79466e6 d54e468 79466e6 088f610 79466e6 088f610 79466e6 bf0265c 79466e6 dc2efd2 79466e6 dc2efd2 79466e6 088f610 79466e6 6cecfcc 79466e6 dc2efd2 088f610 |
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 203 204 205 206 207 |
# Autor: Luan Alysson de Souza
# -*- coding: utf-8 -*-
"""app"""
import gradio as gr
import os
from dotenv import load_dotenv
from langchain_community.chat_models import ChatOpenAI
from langchain_community.document_loaders import PyPDFLoader
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.chains import RetrievalQA
import tempfile
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
# Carrega variáveis de ambiente
load_dotenv()
OPENROUTER_API_KEY = os.getenv("ROUTER_API_KEY")
if not OPENROUTER_API_KEY:
raise ValueError("❌ A variável de ambiente ROUTER_API_KEY não está definida. Verifique o arquivo .env.")
# Embedding robusto
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")
qa_chain = None
processed_file = None
# Carrega o PDF fixo automaticamente
def load_default_pdf():
global qa_chain, processed_file
try:
loader = PyPDFLoader("LegisMiner.pdf")
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=300)
docs = text_splitter.split_documents(documents)
vectorstore = FAISS.from_documents(docs, embeddings)
llm = ChatOpenAI(
openai_api_key=OPENROUTER_API_KEY,
openai_api_base="https://openrouter.ai/api/v1",
model="mistralai/mistral-7b-instruct:free",
temperature=0.3
)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=vectorstore.as_retriever(),
return_source_documents=True
)
processed_file = "LegisMiner.pdf"
print("✅ LegisMiner.pdf carregado automaticamente.")
except Exception as e:
print(f"❌ Erro ao carregar LegisMiner.pdf automaticamente: {e}")
def calculate_rag_metrics(query, response, source_docs):
metrics = {}
try:
query_embedding = embeddings.embed_query(query)
response_embedding = embeddings.embed_query(response)
metrics["query_response_similarity"] = cosine_similarity(
[query_embedding], [response_embedding]
)[0][0]
# Mantido apenas para fins internos, mas não será exibido
doc_similarities = []
for doc in source_docs:
doc_embedding = embeddings.embed_query(doc.page_content[:1000])
similarity = cosine_similarity([response_embedding], [doc_embedding])[0][0]
doc_similarities.append(similarity)
metrics["avg_response_source_similarity"] = np.mean(doc_similarities) if doc_similarities else 0
metrics["max_response_source_similarity"] = max(doc_similarities) if doc_similarities else 0
metrics["num_source_documents"] = len(source_docs)
except Exception as e:
metrics["error"] = str(e)
return metrics
def process_pdf(file):
global qa_chain, processed_file
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp:
tmp.write(file)
pdf_path = tmp.name
try:
loader = PyPDFLoader(pdf_path)
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=300)
docs = text_splitter.split_documents(documents)
vectorstore = FAISS.from_documents(docs, embeddings)
llm = ChatOpenAI(
openai_api_key=OPENROUTER_API_KEY,
openai_api_base="https://openrouter.ai/api/v1",
model="mistralai/mistral-7b-instruct:free",
temperature=0.3
)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=vectorstore.as_retriever(),
return_source_documents=True
)
processed_file = os.path.basename(pdf_path)
return f"✅ PDF processado com sucesso: {processed_file}"
except Exception as e:
return f"❌ Erro ao processar PDF: {str(e)}"
def ask_question(question):
global qa_chain
if qa_chain is None:
return "⚠️ Por favor, carregue um PDF primeiro", "", ""
try:
system_prompt = (
"Você é um assistente especialista em mineração, legislação ambiental e políticas públicas. "
"Seu papel é responder perguntas com base no conteúdo do PDF carregado, que trata do ambiente regulatório da mineração. "
"Siga estas instruções com rigor:\n\n"
"1. A resposta deve estar no mesmo idioma em que a pergunta foi feita.\n"
"2. Utilize apenas as informações contidas no PDF como base.\n"
"3. Nunca omita dados relevantes encontrados no conteúdo original.\n"
"4. Mencione, sempre que possível, trechos, leis, datas ou tópicos do PDF usados como base.\n"
"5. Se a pergunta for técnica, use linguagem técnica. Se for simples, explique de forma acessível.\n"
"6. Caso a resposta exija algo que não está no PDF, diga claramente: "
"\"Com base no conteúdo fornecido, não há informação direta sobre este ponto específico.\"\n"
"7. Seja objetivo, preciso e fiel ao conteúdo carregado.\n\n"
"Agora, responda a pergunta abaixo com base no PDF:"
)
resposta = qa_chain.invoke({
"query": f"{system_prompt}\n\nPergunta: {question}"
})
sources = "\n\n".join(
[f"📄 Fonte {i+1}:\n{doc.page_content[:500]}..."
for i, doc in enumerate(resposta['source_documents'])]
)
metrics = calculate_rag_metrics(
question,
resposta['result'],
resposta['source_documents']
)
# Exibe apenas o nível de confiança
confidence = metrics.get("query_response_similarity", 0)
metrics_text = f"🔎 Nível de Confiança da Resposta: {confidence:.2f}"
return resposta['result'], sources, metrics_text
except Exception as e:
return f"❌ Erro ao processar pergunta: {str(e)}", "", ""
# Interface Gradio
with gr.Blocks(title="Chat com PDF usando RAG", theme=gr.themes.Soft()) as demo:
gr.Markdown("# 🧠 Artificial Intelligence Applied to Regulatory Standard Processing in Mining\n### Development of a Decision Support Tool")
with gr.Row():
with gr.Column(scale=1):
file_input = gr.File(label="📤 Envie um PDF", type="binary")
process_btn = gr.Button("Processar PDF", variant="primary")
status_output = gr.Textbox(label="Status")
with gr.Column(scale=2):
question_input = gr.Textbox(label="Faça uma pergunta sobre Normas da Mineração", lines=3)
ask_btn = gr.Button("Enviar Pergunta", variant="primary")
answer_output = gr.Textbox(label="✅ Resposta", interactive=False)
with gr.Accordion("📄 Fontes usadas", open=False):
sources_output = gr.Textbox(label="Trechos relevantes", lines=10)
with gr.Accordion("📊 Métricas RAG", open=False):
metrics_output = gr.Textbox(label="Métricas", lines=4)
process_btn.click(
fn=process_pdf,
inputs=file_input,
outputs=status_output
)
ask_btn.click(
fn=ask_question,
inputs=question_input,
outputs=[answer_output, sources_output, metrics_output]
)
# Carrega o PDF fixo ao iniciar
load_default_pdf()
# Compartilhamento opcional
share = True if 'COLAB_JUPYTER_TRANSPORT' in os.environ else False
demo.launch(share=share, debug=False)
|