portalprogramando / interface.py
aldohenrique's picture
Update interface.py
9019817 verified
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)