Spaces:
Running
Running
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 | |
) |