File size: 15,636 Bytes
11dde31
d548a42
11dde31
721a95b
fdce04f
11dde31
8823c04
11dde31
 
 
 
bedb958
3153e8a
11dde31
61b536d
 
 
3623e17
 
bedb958
 
3153e8a
61b536d
45d0a11
11dde31
 
 
 
 
 
 
 
 
 
 
bedb958
11dde31
 
 
 
 
 
 
d548a42
bedb958
11dde31
3623e17
bedb958
11dde31
 
 
 
 
 
 
 
 
 
 
 
 
bedb958
11dde31
 
bedb958
11dde31
 
 
 
 
 
 
 
3153e8a
 
 
 
11dde31
 
 
 
3623e17
11dde31
 
 
 
3153e8a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11dde31
3153e8a
11dde31
3153e8a
 
11dde31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9ed0730
11dde31
 
9ed0730
721a95b
 
 
 
 
 
 
 
53cefbb
721a95b
 
 
 
 
 
 
53cefbb
721a95b
 
 
 
 
 
 
 
 
 
24799c3
721a95b
 
 
 
 
 
61b536d
11dde31
bedb958
11dde31
bedb958
f168caf
11dde31
ba36f37
721a95b
d548a42
11dde31
 
ba36f37
11dde31
 
 
721a95b
11dde31
d548a42
bedb958
61b536d
 
bedb958
11dde31
721a95b
bedb958
11dde31
 
 
bedb958
721a95b
 
 
 
bedb958
9ed0730
11dde31
f168caf
3153e8a
 
11dde31
3153e8a
 
 
 
 
 
 
 
 
3623e17
3153e8a
 
 
 
 
 
 
 
 
 
11dde31
3153e8a
 
 
 
 
 
 
 
 
11dde31
721a95b
 
 
 
710d9c4
7f691ba
721a95b
 
 
 
 
 
 
 
61b536d
 
c87a82e
a6a6319
721a95b
a6a6319
c87a82e
 
 
 
61b536d
 
721a95b
 
 
c87a82e
721a95b
 
 
 
 
 
 
 
 
 
 
 
61b536d
 
 
 
721a95b
 
11dde31
721a95b
 
 
 
 
 
 
 
 
 
 
 
 
9ed0730
d548a42
721a95b
 
 
bedb958
721a95b
6483b01
721a95b
 
11dde31
 
53cefbb
 
61b536d
 
 
 
bedb958
 
11dde31
53cefbb
 
 
 
721a95b
 
 
 
 
11dde31
61b536d
721a95b
 
 
 
c87a82e
721a95b
bedb958
f168caf
721a95b
 
 
 
61b536d
 
 
 
721a95b
 
 
11dde31
721a95b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61b536d
 
 
 
 
 
721a95b
 
 
 
 
bedb958
 
11dde31
 
 
721a95b
 
11dde31
bedb958
11dde31
3153e8a
721a95b
 
11dde31
d548a42
11dde31
b12fb1b
721a95b
11dde31
721a95b
 
11dde31
b12fb1b
 
 
11dde31
721a95b
 
b12fb1b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
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
    )