aldohenrique's picture
Update app.py
7f691ba verified
raw
history blame
15.6 kB
import requests
import os
import json
import re
import gradio as gr
from typing import Dict, Any
# Configuração da API
HF_TOKEN = os.getenv("HF_TOKEN")
if not HF_TOKEN:
raise ValueError("Token HF_TOKEN não encontrado nas variáveis de ambiente")
# Modelos disponíveis via API (testados e funcionais)
MODELS = {
"Phi-3 Mini (Microsoft)": "microsoft/Phi-3-mini-4k-instruct",
"Mistral 7B": "mistralai/Mistral-7B-Instruct-v0.3",
"Zephyr 7B": "HuggingFaceH4/zephyr-7b-beta",
"Llama 3.2 3B (Meta)": "meta-llama/Llama-3.2-3B-Instruct",
"DeepSeek-Coder-V2": "deepseek-ai/DeepSeek-Coder-V2-Lite-Instruct", # Replaced DeepSeek-Code
}
# Modelo padrão (mais confiável)
DEFAULT_MODEL = "Phi-3 Mini (Microsoft)"
class HuggingFaceAPIClient:
def __init__(self, token: str):
self.token = token
self.headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
def query_model(self, model_name: str, messages: list, max_tokens: int = 500) -> str:
"""Faz requisição para a API do Hugging Face"""
url = f"https://api-inference.huggingface.co/models/{model_name}/v1/chat/completions"
payload = {
"model": model_name,
"messages": messages,
"max_tokens": max_tokens,
"temperature": 0.7,
"top_p": 0.9,
"stream": False
}
try:
response = requests.post(url, headers=self.headers, json=payload, timeout=9999)
if response.status_code == 200:
result = response.json()
return result["choices"][0]["message"]["content"]
else:
# Fallback para API de texto simples se a API de chat não funcionar
return self._fallback_text_generation(model_name, messages, max_tokens)
except Exception as e:
return f"Erro na API: {str(e)}"
def _fallback_text_generation(self, model_name: str, messages: list, max_tokens: int) -> str:
"""Fallback usando API de geração de texto simples"""
url = f"https://api-inference.huggingface.co/models/{model_name}"
# Converte mensagens para prompt simples
prompt = self._messages_to_prompt(messages)
payload = {
"inputs": prompt,
"parameters": {
"max_new_tokens": max_tokens,
"temperature": 0.7,
"top_p": 0.9,
"do_sample": True,
"return_full_text": False
},
"options": {
"wait_for_model": True, # Espera modelo carregar
"use_cache": False
}
}
try:
response = requests.post(url, headers=self.headers, json=payload, timeout=9999)
if response.status_code == 200:
result = response.json()
if isinstance(result, list) and len(result) > 0:
generated_text = result[0].get("generated_text", "")
# Limpa o texto gerado
if generated_text:
# Remove o prompt original da resposta
if "Assistente: " in generated_text:
parts = generated_text.split("Assistente: ")
if len(parts) > 1:
return parts[-1].strip()
return generated_text.strip()
return "Resposta vazia"
elif isinstance(result, dict):
if "error" in result:
return f"Erro do modelo: {result['error']}"
elif "generated_text" in result:
return result["generated_text"].strip()
return "Formato de resposta inesperado"
elif response.status_code == 404:
return f"❌ Modelo '{model_name}' não encontrado. Tente outro modelo."
elif response.status_code == 503:
return "⏳ Modelo carregando... Aguarde alguns segundos e tente novamente."
elif response.status_code == 429:
return "⚠️ Muitas requisições. Aguarde um momento antes de tentar novamente."
else:
return f"Erro HTTP {response.status_code}: {response.text[:200]}..."
except requests.Timeout:
return "⏰ Timeout - Modelo demorou muito para responder. Tente novamente."
except Exception as e:
return f"Erro na requisição: {str(e)}"
def _messages_to_prompt(self, messages: list) -> str:
"""Converte mensagens para formato de prompt"""
prompt = ""
for msg in messages:
if msg["role"] == "system":
prompt += f"Sistema: {msg['content']}\n\n"
elif msg["role"] == "user":
prompt += f"Usuário: {msg['content']}\n\n"
elif msg["role"] == "assistant":
prompt += f"Assistente: {msg['content']}\n\n"
prompt += "Assistente: "
return prompt
# Inicializar cliente da API
api_client = HuggingFaceAPIClient(HF_TOKEN)
def formatar_resposta_com_codigo(resposta: str) -> str:
"""Formata a resposta destacando códigos em blocos separados"""
if not resposta:
return resposta
# Detecta blocos de código com ```
resposta_formatada = re.sub(
r'```(\w+)?\n(.*?)\n```',
r'<div style="background-color: #f8f9fa; color: #1a1a1a; border: 1px solid #e9ecef; border-radius: 8px; padding: 15px; margin: 10px 0; font-family: Monaco, Consolas, monospace; overflow-x: auto;"><strong style="color: #1a1a1a;">💻 Código:</strong><br><pre style="color: #1a1a1a; margin: 5px 0; white-space: pre-wrap; word-wrap: break-word;"><code>\2</code></pre></div>',
resposta,
flags=re.DOTALL
)
# Detecta código inline com `
resposta_formatada = re.sub(
r'`([^`]+)`',
r'<code style="background-color: #f1f3f4; color: #1a1a1a; padding: 2px 4px; border-radius: 4px; font-family: Monaco, Consolas, monospace;">\1</code>',
resposta_formatada
)
# Adiciona quebras de linha para melhor visualização
resposta_formatada = resposta_formatada.replace('\n\n', '<br><br>')
resposta_formatada = resposta_formatada.replace('\n', '<br>')
# Destaca títulos/seções
resposta_formatada = re.sub(
r'^\*\*(.*?)\*\*',
r'<h3 style="color: #1a1a1a; margin-top: 20px; margin-bottom: 10px;">\1</h3>',
resposta_formatada,
flags=re.MULTILINE
)
return resposta_formatada
def responder_como_aldo(pergunta: str, modelo_escolhido: str = DEFAULT_MODEL) -> str:
"""Função principal para gerar respostas via API"""
if not pergunta.strip():
return "Por favor, faça uma pergunta."
try:
# Preparar mensagens
pergunta_completa = f"{pergunta} Não responda nada se a pergunta não for sobre o universo de programação e tecnologia, informe que o Dr. Aldo Henrique só tem domínio em TI. Você é o Professor Dr. Aldo Henrique, foque em explicar e não em só mostrar o resultado. Quando apresentar código, use blocos de código formatados com ```. Sempre responda primeiro a explicação e depois modestre o código."
messages = [
{
"role": "system",
"content": "Você é o professor Dr. Aldo Henrique, especialista em C, Java, desenvolvimento web e inteligência artificial. Sempre responda primeiro a explicação e depois modestre o código. Responda com clareza, profundidade e tom acadêmico, como um professor experiente. Evite respostas genéricas e forneça exemplos práticos quando aplicável. Foque em explicar e não em só mostrar o resultado. Responda sempre em português brasileiro. Use blocos de código formatados com ``` quando apresentar código. Não responda nada se a pergunta não for sobre o universo de programação e tecnologia."
},
{
"role": "user",
"content": pergunta_completa
}
]
# Obter o nome real do modelo
model_name = MODELS.get(modelo_escolhido, MODELS[DEFAULT_MODEL])
# Fazer requisição
resposta = api_client.query_model(model_name, messages, max_tokens=800)
# Limpar resposta se necessário
if resposta.startswith("Assistente: "):
resposta = resposta.replace("Assistente: ", "")
# Formatar resposta com código
resposta_formatada = formatar_resposta_com_codigo(resposta.strip())
return resposta_formatada
except Exception as e:
return f"Erro ao processar sua pergunta: {str(e)}"
def verificar_modelo_disponivel(model_name: str) -> str:
"""Verifica se um modelo está disponível na API"""
try:
url = f"https://api-inference.huggingface.co/models/{model_name}"
headers = {"Authorization": f"Bearer {HF_TOKEN}"}
# Teste simples
payload = {
"inputs": "Hello",
"parameters": {"max_new_tokens": 5}
}
response = requests.post(url, headers=headers, json=payload, timeout=9999)
if response.status_code == 200:
return "✅ Disponível"
elif response.status_code == 404:
return "❌ Não encontrado"
elif response.status_code == 503:
return "⏳ Carregando..."
else:
return f"⚠️ Status {response.status_code}"
except Exception as e:
return f"❌ Erro: {str(e)[:50]}..."
def testar_todos_modelos():
"""Testa todos os modelos disponíveis"""
resultados = []
for nome, modelo in MODELS.items():
status = verificar_modelo_disponivel(modelo)
resultados.append(f"{nome}: {status}")
return "\n".join(resultados)
# CSS customizado para melhor visualização
css_customizado = """
.gradio-container {
max-width: 1400px !important;
margin: 0 auto;
width: 85%;
}
.gr-textbox textarea {
font-size: 14px !important;
line-height: 1.5 !important;
}
.resposta-container {
background-color: #ffffff !important;
color: #1a1a1a !important;
border: 1px solid #e0e0e0 !important;
border-radius: 20px !important;
padding: 20px !important;
margin: 20px 0 !important;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05) !important;
}
.resposta-container pre code {
color: #1a1a1a !important;
background-color: #f8f9fa !important;
}
.pergunta-container {
background-color: #f0f8ff !important;
border-radius: 8px !important;
padding: 15px !important;
}
.titulo-principal {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
color: white !important;
padding: 20px !important;
border-radius: 10px !important;
margin-bottom: 20px !important;
text-align: center !important;
}
.modelo-dropdown {
margin-bottom: 15px !important;
}
"""
# Interface Gradio
with gr.Blocks(
title="Dr. Aldo Henrique - API Externa",
theme=gr.themes.Soft(),
css=css_customizado
) as interface:
# Cabeçalho estilizado
gr.HTML("""
<div class="titulo-principal">
<h1>🤖 Dr. Aldo Henrique - Especialista em TI</h1>
<p style="font-size: 14px; opacity: 0.9;">Dúvidas sobre C, Java, desenvolvimento web, IA e muito mais!</p>
</div>
""")
with gr.Row():
# Coluna da esquerda - Entrada
with gr.Column(scale=2):
gr.Markdown("### 📝 Faça sua pergunta:")
entrada = gr.Textbox(
label="",
placeholder="Digite sua pergunta aqui.",
lines=6,
elem_classes="pergunta-container"
)
modelo_select = gr.Dropdown(
choices=list(MODELS.keys()),
value=DEFAULT_MODEL,
label="🧠 Selecione o Modelo de IA",
info="Escolha o modelo para responder sua pergunta",
elem_classes="modelo-dropdown"
)
with gr.Row():
botao_perguntar = gr.Button(
"🤔 Perguntar ao Dr. Aldo",
variant="primary",
size="lg"
)
botao_testar = gr.Button(
"🔍 Testar Modelos",
variant="secondary"
)
# Coluna da direita - Saída
with gr.Column(scale=3):
gr.Markdown("### 💬 Resposta do Dr. Aldo Henrique:")
saida = gr.HTML(
label="",
value="<div style='padding: 20px; text-align: center; color: #1a1a1a;'>Aguardando sua pergunta...</div>",
elem_classes="resposta-container"
)
# Seção expandida para exemplos
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],
["Explique a diferença entre == e equals() em Java com exemplos práticos", "Mistral 7B"],
["Como funciona o algoritmo de machine learning Random Forest?", "Llama 3.2 3B (Meta)"],
["Mostre como criar uma API REST completa com Spring Boot", "Zephyr 7B"]
],
inputs=[entrada, modelo_select]
)
# Status da API (expandível)
with gr.Accordion("🔧 Status da API", open=False):
status_api = gr.Textbox(
label="Status dos Modelos",
interactive=False,
lines=8
)
# Informações adicionais
with gr.Accordion("ℹ️ Informações", open=False):
gr.Markdown("""
### Sobre o Dr. Aldo Henrique:
- **Especialidade**: Linguagens C, Java, Desenvolvimento Web, Inteligência Artificial
- **Foco**: Explicações didáticas e exemplos práticos
- **Abordagem**: Acadêmica e profissional
### Modelos Disponíveis:
- **Phi-3 Mini**: Modelo compacto e eficiente da Microsoft
- **Llama 3.2 3B**: Versão menor do modelo da Meta
- **Mistral 7B**: Modelo francês de alta qualidade
- **Zephyr 7B**: Versão otimizada para diálogo
### Dicas para melhores respostas:
- Seja específico em suas perguntas
- Mencione o contexto (iniciante, intermediário, avançado)
- Peça exemplos práticos quando necessário
""")
# Eventos
botao_perguntar.click(
fn=responder_como_aldo,
inputs=[entrada, modelo_select],
outputs=saida,
show_progress=True
)
botao_testar.click(
fn=testar_todos_modelos,
outputs=status_api,
show_progress=True
)
# Lançar aplicação
if __name__ == "__main__":
print("🚀 Iniciando Dr. Aldo Henrique com Interface Melhorada...")
print(f"🔑 Token HF encontrado: {HF_TOKEN[:8]}...")
print("🌐 Interface otimizada para melhor visualização!")
print("💻 Formatação especial para códigos implementada!")
interface.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
max_threads=8,
show_error=True
)