|
|
""" |
|
|
Interface Gradio moderna para o AgentPDF com tema escuro. |
|
|
|
|
|
Esta interface replica o design moderno da imagem fornecida. |
|
|
""" |
|
|
|
|
|
import os |
|
|
import shutil |
|
|
import gradio as gr |
|
|
from typing import List, Tuple, Optional |
|
|
|
|
|
from main_graph import get_agent_graph, process_pdf_file, ask_pdf_question |
|
|
from utils.config import Config |
|
|
from utils.logger import main_logger |
|
|
|
|
|
|
|
|
class ModernAgentPDFInterface: |
|
|
"""Interface moderna para o AgentPDF.""" |
|
|
|
|
|
def __init__(self): |
|
|
"""Inicializa a interface.""" |
|
|
self.current_state = None |
|
|
self.chat_history = [] |
|
|
self.pdf_processed = False |
|
|
self.current_pdf_name = None |
|
|
|
|
|
def upload_pdf(self, file) -> Tuple[str, str, List[List[str]]]: |
|
|
"""Processa o upload de um arquivo PDF.""" |
|
|
try: |
|
|
if file is None: |
|
|
return "❌ Erro: Nenhum arquivo selecionado", "Selecione um arquivo PDF", [] |
|
|
|
|
|
if not file.name.lower().endswith('.pdf'): |
|
|
return "❌ Erro: Formato inválido", "Apenas arquivos PDF são aceitos", [] |
|
|
|
|
|
|
|
|
upload_dir = Config.UPLOAD_DIR |
|
|
os.makedirs(upload_dir, exist_ok=True) |
|
|
|
|
|
filename = f"uploaded_{os.path.basename(file.name)}" |
|
|
pdf_path = os.path.join(upload_dir, filename) |
|
|
shutil.copy2(file.name, pdf_path) |
|
|
|
|
|
|
|
|
result = process_pdf_file(pdf_path) |
|
|
|
|
|
if result["success"]: |
|
|
self.current_state = result["result"] |
|
|
self.pdf_processed = True |
|
|
self.current_pdf_name = os.path.basename(file.name) |
|
|
self.chat_history = [] |
|
|
|
|
|
welcome_message = [ |
|
|
["Sistema", f"✅ PDF '{self.current_pdf_name}' processado com sucesso!"] |
|
|
] |
|
|
|
|
|
return ( |
|
|
"✅ Documento processado", |
|
|
f"PDF: {self.current_pdf_name}\nStatus: Pronto para perguntas", |
|
|
welcome_message |
|
|
) |
|
|
else: |
|
|
self.pdf_processed = False |
|
|
return "❌ Erro no processamento", f"Erro: {result['error']}", [] |
|
|
|
|
|
except Exception as e: |
|
|
main_logger.error(f"Erro no upload: {e}") |
|
|
return "❌ Erro inesperado", f"Erro: {str(e)}", [] |
|
|
|
|
|
def chat_with_pdf(self, message: str, history: List[List[str]]) -> Tuple[List[List[str]], str]: |
|
|
"""Processa uma mensagem do chat.""" |
|
|
try: |
|
|
if not self.pdf_processed or not self.current_state: |
|
|
error_msg = "❌ Faça upload de um PDF primeiro" |
|
|
history.append([message, error_msg]) |
|
|
return history, "" |
|
|
|
|
|
if not message.strip(): |
|
|
return history, "" |
|
|
|
|
|
|
|
|
result = ask_pdf_question(message, self.current_state) |
|
|
|
|
|
if result["success"]: |
|
|
answer = result["answer"] |
|
|
if result.get("result"): |
|
|
self.current_state = result["result"] |
|
|
else: |
|
|
answer = f"❌ Erro: {result['error']}" |
|
|
|
|
|
history.append([message, answer]) |
|
|
return history, "" |
|
|
|
|
|
except Exception as e: |
|
|
main_logger.error(f"Erro no chat: {e}") |
|
|
error_msg = f"❌ Erro inesperado: {str(e)}" |
|
|
history.append([message, error_msg]) |
|
|
return history, "" |
|
|
|
|
|
def clear_chat(self) -> Tuple[List, str]: |
|
|
"""Limpa o histórico do chat.""" |
|
|
self.chat_history = [] |
|
|
return [], "" |
|
|
|
|
|
def get_pdf_info(self) -> str: |
|
|
"""Retorna informações sobre o PDF atual.""" |
|
|
if not self.pdf_processed or not self.current_pdf_name: |
|
|
return "Nenhum documento carregado" |
|
|
|
|
|
info = f"📄 {self.current_pdf_name}\n" |
|
|
info += f"✅ Processado e indexado\n" |
|
|
|
|
|
if self.current_state: |
|
|
chunks = self.current_state.get("pdf_chunks", []) |
|
|
if chunks: |
|
|
info += f"📊 {len(chunks)} seções" |
|
|
|
|
|
return info |
|
|
|
|
|
def create_interface(self) -> gr.Blocks: |
|
|
"""Cria a interface moderna usando templates nativos do Gradio.""" |
|
|
|
|
|
|
|
|
css = """ |
|
|
.chat-container { |
|
|
height: 70vh !important; |
|
|
} |
|
|
|
|
|
.send-button { |
|
|
height: 56px !important; |
|
|
min-height: 56px !important; |
|
|
} |
|
|
|
|
|
.sidebar-config { |
|
|
max-width: 320px !important; |
|
|
min-width: 320px !important; |
|
|
width: 320px !important; |
|
|
} |
|
|
""" |
|
|
|
|
|
with gr.Blocks( |
|
|
title="AgentPDF", |
|
|
theme=gr.themes.Soft( |
|
|
primary_hue="blue", |
|
|
secondary_hue="slate", |
|
|
neutral_hue="slate" |
|
|
), |
|
|
css=css |
|
|
) as interface: |
|
|
|
|
|
with gr.Row(): |
|
|
|
|
|
with gr.Column(scale=1, elem_classes=["sidebar-config"]): |
|
|
gr.Markdown("## ⚙️ Configurações") |
|
|
|
|
|
with gr.Group(): |
|
|
file_upload = gr.File( |
|
|
label="Selecione um PDF", |
|
|
file_types=[".pdf"], |
|
|
type="filepath" |
|
|
) |
|
|
|
|
|
upload_btn = gr.Button( |
|
|
"🚀 Processar PDF", |
|
|
variant="primary", |
|
|
size="lg" |
|
|
) |
|
|
|
|
|
with gr.Group(): |
|
|
upload_status = gr.Textbox( |
|
|
label="📊 Status", |
|
|
interactive=False, |
|
|
placeholder="Aguardando upload...", |
|
|
lines=1 |
|
|
) |
|
|
|
|
|
pdf_info = gr.Textbox( |
|
|
label="📄 Informações", |
|
|
interactive=False, |
|
|
value="Nenhum documento carregado", |
|
|
lines=2 |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
with gr.Column(scale=3): |
|
|
gr.Markdown("## 💬 Conversa") |
|
|
|
|
|
chatbot = gr.Chatbot( |
|
|
elem_classes=["chat-container"], |
|
|
show_copy_button=True, |
|
|
bubble_full_width=False |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
msg_input = gr.Textbox( |
|
|
placeholder="Digite sua pergunta sobre o PDF...", |
|
|
show_label=False, |
|
|
scale=5, |
|
|
lines=1 |
|
|
) |
|
|
|
|
|
send_btn = gr.Button( |
|
|
"📤", |
|
|
variant="primary", |
|
|
scale=1, |
|
|
elem_classes=["send-button"] |
|
|
) |
|
|
|
|
|
|
|
|
upload_btn.click( |
|
|
fn=self.upload_pdf, |
|
|
inputs=[file_upload], |
|
|
outputs=[upload_status, pdf_info, chatbot], |
|
|
show_progress=True |
|
|
) |
|
|
|
|
|
send_btn.click( |
|
|
fn=self.chat_with_pdf, |
|
|
inputs=[msg_input, chatbot], |
|
|
outputs=[chatbot, msg_input], |
|
|
show_progress=True |
|
|
) |
|
|
|
|
|
msg_input.submit( |
|
|
fn=self.chat_with_pdf, |
|
|
inputs=[msg_input, chatbot], |
|
|
outputs=[chatbot, msg_input], |
|
|
show_progress=True |
|
|
) |
|
|
|
|
|
return interface |
|
|
|
|
|
|
|
|
def create_modern_gradio_app() -> gr.Blocks: |
|
|
"""Cria a aplicação Gradio moderna.""" |
|
|
interface = ModernAgentPDFInterface() |
|
|
return interface.create_interface() |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
app = create_modern_gradio_app() |
|
|
app.launch( |
|
|
server_name="0.0.0.0", |
|
|
server_port=Config.GRADIO_PORT, |
|
|
share=Config.GRADIO_SHARE, |
|
|
show_error=True |
|
|
) |
|
|
|