Spaces:
Running
Running
| import gradio as gr | |
| import uuid | |
| from ai_logic import ( | |
| responder_como_aldo, | |
| build_and_save_vector_store, | |
| MODELS, | |
| DEFAULT_MODEL, | |
| inicializar_sistema | |
| ) | |
| css_customizado = """ | |
| .gradio-container { | |
| max-width: 1400px !important; | |
| margin: 0 auto; | |
| width: 99%; | |
| height: 100vh !important; | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| } | |
| .main-content { | |
| display: flex; | |
| flex-direction: column; | |
| height: 100vh; | |
| overflow: hidden; | |
| flex-shrink: 0; | |
| } | |
| .titulo-principal { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; | |
| color: white !important; | |
| padding: 10px !important; | |
| border-radius: 10px !important; | |
| margin-bottom: 10px !important; | |
| text-align: center !important; | |
| flex-shrink: 0; | |
| } | |
| .chat-area { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| } | |
| .chat-container { | |
| flex: 1; | |
| overflow-y: auto; | |
| margin-bottom: 10px; | |
| } | |
| .input-container { | |
| flex-shrink: 0; | |
| padding: 10px 0; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| } | |
| .additional-content { | |
| overflow-y: auto; | |
| padding-top: 20px; | |
| } | |
| /* Estilos para o chat - Melhorias na legibilidade */ | |
| .chatbot { | |
| height: 100% !important; | |
| max-height: none !important; | |
| } | |
| /* Mensagens do usuário */ | |
| .message.user { | |
| background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%) !important; | |
| color: white !important; | |
| border-radius: 18px 18px 6px 18px !important; | |
| padding: 12px 16px !important; | |
| margin: 8px 0 !important; | |
| font-size: 15px !important; | |
| line-height: 1.5 !important; | |
| box-shadow: 0 2px 8px rgba(79, 70, 229, 0.3) !important; | |
| border: none !important; | |
| } | |
| /* Mensagens do bot */ | |
| .message.bot { | |
| background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%) !important; | |
| color: #1e293b !important; | |
| border: 1px solid #e2e8f0 !important; | |
| border-radius: 18px 18px 18px 6px !important; | |
| padding: 16px 20px !important; | |
| margin: 8px 0 !important; | |
| font-size: 15px !important; | |
| line-height: 1.6 !important; | |
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05) !important; | |
| } | |
| /* Estilização para código dentro das mensagens */ | |
| .message pre { | |
| background: #1e293b !important; | |
| color: #e2e8f0 !important; | |
| border-radius: 8px !important; | |
| padding: 16px !important; | |
| margin: 12px 0 !important; | |
| overflow-x: auto !important; | |
| font-family: 'Fira Code', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace !important; | |
| font-size: 14px !important; | |
| line-height: 1.5 !important; | |
| border: 1px solid #374151 !important; | |
| } | |
| .message code { | |
| background: #e2e8f0 !important; | |
| color: #1e293b !important; | |
| padding: 2px 6px !important; | |
| border-radius: 4px !important; | |
| font-family: 'Fira Code', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace !important; | |
| font-size: 13px !important; | |
| } | |
| /* Código inline dentro de pre */ | |
| .message pre code { | |
| background: transparent !important; | |
| color: #e2e8f0 !important; | |
| padding: 0 !important; | |
| border-radius: 0 !important; | |
| } | |
| /* Estilos específicos do Gradio para chatbot */ | |
| .chatbot .message-wrap { | |
| margin: 8px 0 !important; | |
| } | |
| .chatbot .message-wrap.user { | |
| justify-content: flex-end !important; | |
| } | |
| .chatbot .message-wrap.bot { | |
| justify-content: flex-start !important; | |
| } | |
| /* Melhorias na área de input */ | |
| #entrada_usuario textarea { | |
| background: linear-gradient(135deg, #1e293b 0%, #374151 100%) !important; | |
| color: white !important; | |
| font-size: 15px !important; | |
| line-height: 1.5 !important; | |
| border: 2px solid #374151 !important; | |
| border-radius: 12px !important; | |
| padding: 12px 16px !important; | |
| min-height: 60px !important; | |
| box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important; | |
| } | |
| #entrada_usuario textarea:focus { | |
| border-color: #4f46e5 !important; | |
| box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1) !important; | |
| } | |
| #entrada_usuario textarea::placeholder { | |
| color: #9ca3af !important; | |
| } | |
| /* Botão de enviar */ | |
| .gradio-button.primary { | |
| background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%) !important; | |
| border: none !important; | |
| border-radius: 12px !important; | |
| padding: 12px 24px !important; | |
| font-weight: 600 !important; | |
| font-size: 15px !important; | |
| transition: all 0.2s ease !important; | |
| } | |
| .gradio-button.primary:hover { | |
| transform: translateY(-1px) !important; | |
| box-shadow: 0 4px 12px rgba(79, 70, 229, 0.4) !important; | |
| } | |
| /* Dropdown do modelo */ | |
| .modelo-dropdown { | |
| margin-bottom: 15px !important; | |
| } | |
| .modelo-dropdown .gr-dropdown { | |
| border-radius: 8px !important; | |
| border: 1px solid #d1d5db !important; | |
| } | |
| /* Responsividade melhorada */ | |
| @media (max-width: 768px) { | |
| .titulo-principal { | |
| padding: 8px !important; | |
| font-size: 14px !important; | |
| } | |
| #entrada_usuario textarea { | |
| min-height: 50px !important; | |
| font-size: 16px !important; | |
| } | |
| .message.user, | |
| .message.bot { | |
| font-size: 14px !important; | |
| padding: 10px 14px !important; | |
| } | |
| .message pre { | |
| font-size: 12px !important; | |
| padding: 12px !important; | |
| } | |
| } | |
| /* Animações suaves */ | |
| .message { | |
| animation: fadeInUp 0.3s ease-out !important; | |
| } | |
| @keyframes fadeInUp { | |
| from { | |
| opacity: 0; | |
| transform: translateY(10px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| /* Melhorias gerais na tipografia */ | |
| .chatbot { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif !important; | |
| } | |
| /* Scroll personalizado para o chat */ | |
| .chat-container::-webkit-scrollbar { | |
| width: 6px; | |
| } | |
| .chat-container::-webkit-scrollbar-track { | |
| background: #f1f5f9; | |
| border-radius: 3px; | |
| } | |
| .chat-container::-webkit-scrollbar-thumb { | |
| background: #cbd5e1; | |
| border-radius: 3px; | |
| } | |
| .chat-container::-webkit-scrollbar-thumb:hover { | |
| background: #94a3b8; | |
| } | |
| /* Força aplicação dos estilos */ | |
| #component-6 { flex-grow: initial !important; } | |
| #component-7 { flex-grow: initial !important; } | |
| .message-wrap.svelte-gjtrl6 .prose.chatbot.md { | |
| opacity: 1 !important; | |
| } | |
| /* Estilo para links */ | |
| .message a { | |
| color: #4f46e5 !important; | |
| text-decoration: underline !important; | |
| } | |
| .message.user a { | |
| color: #e0e7ff !important; | |
| } | |
| /* Estilo para listas */ | |
| .message ul, .message ol { | |
| margin: 12px 0 !important; | |
| padding-left: 20px !important; | |
| } | |
| .message li { | |
| margin: 6px 0 !important; | |
| line-height: 1.6 !important; | |
| } | |
| /* Estilo para tabelas */ | |
| .message table { | |
| border-collapse: collapse !important; | |
| width: 100% !important; | |
| margin: 12px 0 !important; | |
| } | |
| .message th, .message td { | |
| border: 1px solid #d1d5db !important; | |
| padding: 8px 12px !important; | |
| text-align: left !important; | |
| } | |
| .message th { | |
| background: #f8fafc !important; | |
| font-weight: 600 !important; | |
| } | |
| """ | |
| def criar_interface(): | |
| with gr.Blocks(title="Dr. Aldo Henrique - API Externa", theme=gr.themes.Soft(), css=css_customizado) as interface: | |
| session_id_state = gr.State(str(uuid.uuid4())) # Geração do session_id único | |
| with gr.Column(elem_classes="main-content"): | |
| gr.HTML(""" | |
| <div class="titulo-principal"> | |
| <h4 style="margin: 0;">🤖 iAldo - Converse com o <a href="https://aldohenrique.com.br/" style="color: white; text-decoration: underline;">Prof. Dr. Aldo Henrique</a></h4> | |
| </div> | |
| """) | |
| with gr.Column(elem_classes="chat-area"): | |
| with gr.Column(elem_classes="chat-container"): | |
| chatbot = gr.Chatbot( | |
| label="💬 Área do chat", | |
| elem_id="chat", | |
| height="100%", | |
| show_label=False, | |
| container=True, | |
| scale=1, | |
| min_width=160, | |
| visible=True, | |
| elem_classes="chatbot" | |
| ) | |
| with gr.Column(elem_classes="input-container"): | |
| with gr.Row(): | |
| modelo_select = gr.Dropdown( | |
| choices=list(MODELS.keys()), | |
| value=DEFAULT_MODEL, | |
| label="🧠 Selecione o Modelo de Pensamento", | |
| elem_classes="modelo-dropdown" | |
| ) | |
| with gr.Row(): | |
| user_input = gr.Textbox( | |
| show_label=False, | |
| placeholder="Digite sua pergunta e pressione Enter ou clique em Enviar", | |
| lines=2, | |
| elem_id="entrada_usuario", | |
| max_lines=6 | |
| ) | |
| enviar_btn = gr.Button("Enviar", variant="primary", size="lg") | |
| with gr.Column(elem_classes="additional-content"): | |
| with gr.Accordion("⚙️ Controle do Conhecimento (RAG)", open=False): | |
| status_rag = gr.Textbox(label="Status do Retreino", interactive=False) | |
| botao_retreinar = gr.Button("🔄 Atualizar Conhecimento do Blog", variant="stop") | |
| download_faiss_file = gr.File(label="Download do Índice FAISS", interactive=False, file_count="single", file_types=[".pkl"]) | |
| download_urls_file = gr.File(label="Download das URLs Processadas", interactive=False, file_count="single", file_types=[".pkl"]) | |
| with gr.Accordion("📚 Exemplos de Perguntas", open=False): | |
| gr.Examples( | |
| examples=[ | |
| ["Como implementar uma lista ligada em C com todas as operações básicas?", DEFAULT_MODEL], | |
| ["Qual a sua opinião sobre o uso de ponteiros em C++ moderno, baseada no seu blog?", "Mistral 7B (Mais acertivo)"], | |
| ["Resuma o que você escreveu sobre machine learning no seu blog.", "Zephyr 7B (Meio Termo)"], | |
| ], | |
| inputs=[user_input, modelo_select] | |
| ) | |
| with gr.Accordion("🔧 Status da API", open=False): | |
| status_api = gr.Textbox(label="Status dos Modelos", interactive=False, lines=8, | |
| value="Modelos carregados com sucesso! Verifique o console para detalhes.") | |
| with gr.Accordion("ℹ️ Informações", open=False): | |
| gr.Markdown(""" | |
| ### Sobre o Dr. Aldo Henrique: | |
| - **Especialidade**: Linguagens C, Java, Desenvolvimento Web, Inteligência Artificial | |
| - **Conhecimento Adicional**: Conteúdo do blog aldohenrique.com.br | |
| ### Dicas para melhores respostas: | |
| - Faça perguntas específicas sobre o conteúdo do blog para ver o RAG em ação! | |
| - Peça resumos ou opiniões sobre temas que o professor aborda. | |
| ### Melhorias na Interface: | |
| - **Mensagens do usuário**: Estilo moderno com gradiente azul/roxo | |
| - **Respostas do bot**: Fundo claro com excelente contraste para leitura | |
| - **Códigos**: Syntax highlighting com fundo escuro e fonte monospace | |
| - **Responsivo**: Otimizado para desktop e mobile | |
| """) | |
| def responder(chat_history, user_msg, modelo, session_id): | |
| if not user_msg.strip(): | |
| return chat_history, "" | |
| # Adiciona a mensagem do usuário ao histórico | |
| chat_history = chat_history + [[user_msg, "🤖 Dr. Aldo Henrique está digitando..."]] | |
| yield chat_history, "" | |
| try: | |
| # Obtem a resposta do modelo | |
| resposta_final = responder_como_aldo(session_id, user_msg, modelo) | |
| # Atualiza o histórico com a resposta final | |
| chat_history[-1][1] = resposta_final | |
| yield chat_history, "" | |
| except Exception as e: | |
| # Em caso de erro, mostra uma mensagem amigável | |
| chat_history[-1][1] = f"❌ Desculpe, ocorreu um erro ao processar sua mensagem: {str(e)}" | |
| yield chat_history, "" | |
| # Eventos de clique e submit | |
| enviar_btn.click( | |
| fn=responder, | |
| inputs=[chatbot, user_input, modelo_select, session_id_state], | |
| outputs=[chatbot, user_input], | |
| show_progress=True | |
| ) | |
| user_input.submit( | |
| fn=responder, | |
| inputs=[chatbot, user_input, modelo_select, session_id_state], | |
| outputs=[chatbot, user_input], | |
| show_progress=True | |
| ) | |
| botao_retreinar.click( | |
| fn=build_and_save_vector_store, | |
| outputs=[status_rag, download_faiss_file, download_urls_file], | |
| show_progress=True | |
| ) | |
| # Script para focar no input ao carregar a página | |
| gr.HTML(""" | |
| <script> | |
| window.addEventListener("load", function() { | |
| const textarea = document.querySelector("#entrada_usuario textarea"); | |
| if (textarea) { | |
| setTimeout(() => { | |
| textarea.focus(); | |
| // Adiciona evento para redimensionar automaticamente | |
| textarea.addEventListener('input', function() { | |
| this.style.height = 'auto'; | |
| this.style.height = this.scrollHeight + 'px'; | |
| }); | |
| }, 100); | |
| } | |
| }); | |
| </script> | |
| """) | |
| return interface | |
| def configurar_interface(): | |
| """ | |
| Configura a interface Gradio apenas se o sistema for inicializado com pelo menos 3 modelos disponíveis. | |
| Lança uma exceção com a lista de modelos disponíveis se a inicialização falhar. | |
| """ | |
| try: | |
| status, available_models = inicializar_sistema() | |
| if status: | |
| return criar_interface() | |
| else: | |
| error_msg = f"Não foi possível inicializar o sistema: menos de 3 modelos de IA disponíveis. Modelos disponíveis: {', '.join(available_models.keys()) if available_models else 'Nenhum'}" | |
| raise RuntimeError(error_msg) | |
| except Exception as e: | |
| print(f"Erro na configuração da interface: {e}") | |
| raise | |
| if __name__ == "__main__": | |
| try: | |
| app = configurar_interface() | |
| app.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| debug=False, | |
| show_error=True | |
| ) | |
| except Exception as e: | |
| print(f"Erro ao iniciar a aplicação: {e}") | |
| exit(1) |