""" 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", [] # Processa o arquivo 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) # Processa o PDF 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, "" # Processa a pergunta 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 simples e limpo 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(): # SIDEBAR - Configurações 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 ) # ÁREA PRINCIPAL - Chat 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"] ) # Eventos da interface 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 )