aldohenrique commited on
Commit
d5df267
·
verified ·
1 Parent(s): 33f2b60

Update ai_logic.py

Browse files
Files changed (1) hide show
  1. ai_logic.py +684 -222
ai_logic.py CHANGED
@@ -9,75 +9,57 @@ from urllib.parse import urljoin, urlparse
9
  from langchain.text_splitter import RecursiveCharacterTextSplitter
10
  from langchain_community.vectorstores import FAISS
11
  from langchain_community.embeddings import HuggingFaceEmbeddings
 
 
 
12
 
13
  # --- Configurações ---
14
  BLOG_URL = "https://aldohenrique.com.br/"
15
  VECTOR_STORE_PATH = "faiss_index_store.pkl"
16
  PROCESSED_URLS_PATH = "processed_urls.pkl"
17
  HF_TOKEN = os.getenv("HF_TOKEN")
18
- if not HF_TOKEN:
19
- raise ValueError("Token HF_TOKEN não encontrado ")
 
20
 
21
- # Lista inicial de modelos
22
- MODELS = {}
23
-
24
- # --- Função para buscar modelos ---
25
- headers = {
26
- "Authorization": f"Bearer {HF_TOKEN}"
27
- }
28
-
29
- # Modelos fixos que você quer manter
30
  NEW_MODELS_TO_TEST = [
31
  ("Phi-3 Mini (Mais rápido)", "microsoft/Phi-3-mini-4k-instruct"),
32
  ("Zephyr 7B (Meio Termo)", "HuggingFaceH4/zephyr-7b-beta"),
33
- ("Microsoft 8B (Meio Termo)","meta-llama/Meta-Llama-3-8B-Instruct"),
34
- ("Mistral-7B","mistralai/Mistral-7B-Instruct-v0.3"),
35
- ("DialoGPT","microsoft/DialoGPT-medium"),
36
- ("Google","google/flan-t5-base"),
37
- ("Facebook","facebook/bart-large-cnn")
38
  ]
39
 
40
- # --- Consulta a API da Hugging Face ---
41
- url = "https://huggingface.co/api/models?filter=text-generation,transformers,conversational,license:mit,text-generation-inference,safetensors,autotrain_compatible,endpoints_compatible,region:us"
42
- params = {
 
 
 
43
 
44
- "private":"false",
45
- "limit": 300, # Aumente se quiser trazer mais modelos
46
- "full": "true"
47
- }
48
-
49
- response = requests.get(url, headers=headers, params=params)
50
-
51
- if response.status_code != 200:
52
- raise Exception(f"Erro na API: {response.status_code} - {response.text}")
53
-
54
- models_data = response.json()
55
-
56
- # --- Filtra modelos que possuem base_model ---
57
- for model in models_data:
58
- tags = model.get("tags", [])
59
- base_model_tags = [tag for tag in tags if tag.startswith("base_model:")]
60
- if base_model_tags:
61
- model_name = model.get("id")
62
- display_name = model_name.split("/")[-1]
63
-
64
- # Verifica se já não está na lista para evitar duplicados
65
- if not any(model_name == m[1] for m in NEW_MODELS_TO_TEST):
66
- NEW_MODELS_TO_TEST.append((display_name, model_name))
67
-
68
- # --- Resultado ---
69
- print("Lista atualizada de modelos:\n")
70
- for name, model_id in NEW_MODELS_TO_TEST:
71
- print(f'("{name}", "{model_id}"),')
72
-
73
- print(f"\nTotal de modelos na lista: {len(NEW_MODELS_TO_TEST)}")
74
-
75
- # Nota: Alguns modelos podem requerer aprovação ou ter restrições de acesso
76
- # Recomenda-se testar cada modelo individualmente para verificar disponibilidade
77
 
78
- DEFAULT_MODEL = "Zephyr 7B (Meio Termo)"
 
 
79
 
80
- # --- Gerenciamento de Sessão ---
81
  user_sessions: Dict[str, Dict[str, List | Dict]] = {}
82
  MAX_MEMORY_LENGTH = 5
83
 
@@ -173,7 +155,7 @@ def clear_memory(session_id: str) -> str:
173
  os.remove(memory_path)
174
  return "Memória limpa com sucesso!"
175
 
176
- # --- RAG (Crawling e Vector Store) ---
177
  vector_store: Optional[FAISS] = None
178
 
179
  def get_all_blog_links(url: str) -> set:
@@ -245,94 +227,25 @@ def retrieve_context_from_blog(query: str, k: int = 4) -> str:
245
  print(f"Erro ao buscar contexto: {e}")
246
  return ""
247
 
248
- # --- API Client ---
249
- class HuggingFaceAPIClient:
250
- def __init__(self, token: str):
251
- self.headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
252
-
253
- def check_model_info(self, model_name: str) -> Tuple[bool, str]:
254
- """Verifica informações do modelo via API do Hugging Face."""
255
- url = f"https://huggingface.co/api/models/{model_name}"
256
- try:
257
- response = requests.get(url, headers=self.headers, timeout=90)
258
- if response.status_code == 200:
259
- model_info = response.json()
260
- if model_info.get('disabled', False):
261
- return False, "Modelo desabilitado"
262
- if model_info.get('gated', False):
263
- return False, "Modelo requer aprovação/aceite de licença"
264
- return True, "Modelo disponível"
265
- elif response.status_code == 404:
266
- return False, "Modelo não encontrado"
267
- else:
268
- return False, f"Erro HTTP {response.status_code}"
269
- except requests.exceptions.RequestException as e:
270
- return False, f"Erro na requisição: {str(e)}"
271
-
272
- def test_model_inference(self, model_name: str) -> Tuple[bool, str]:
273
- """Testa se o modelo está disponível para inferência."""
274
- url = f"https://api-inference.huggingface.co/models/{model_name}"
275
- test_payload = {
276
- "inputs": "Teste de disponibilidade do modelo.",
277
- "parameters": {
278
- "max_new_tokens": 10,
279
- "temperature": 0.1,
280
- "return_full_text": False
281
- }
282
- }
283
 
284
- try:
285
- response = requests.post(url, headers=self.headers, json=test_payload, timeout=90)
286
-
287
- if response.status_code == 200:
288
- result = response.json()
289
- if isinstance(result, list) and len(result) > 0:
290
- return True, "Modelo disponível para inferência"
291
- elif isinstance(result, dict) and 'error' not in result:
292
- return True, "Modelo disponível para inferência"
293
- else:
294
- return False, f"Resposta inesperada: {result}"
295
-
296
- elif response.status_code == 503:
297
- return False, "Modelo está carregando (503)"
298
- elif response.status_code == 400:
299
- error_msg = response.json().get('error', 'Erro 400')
300
- if 'loading' in error_msg.lower():
301
- return False, "Modelo está carregando"
302
- return False, f"Erro 400: {error_msg}"
303
- elif response.status_code == 401:
304
- return False, "Token inválido ou sem permissão"
305
- elif response.status_code == 404:
306
- return False, "Modelo não encontrado"
307
- else:
308
- return False, f"Erro HTTP {response.status_code}: {response.text}"
309
-
310
- except requests.exceptions.Timeout:
311
- return False, "Timeout na requisição"
312
- except requests.exceptions.RequestException as e:
313
- return False, f"Erro na requisição: {str(e)}"
314
-
315
- def test_model_availability(self, model_name: str) -> Tuple[bool, str]:
316
- """Testa se um modelo está disponível, combinando verificação de info e inferência."""
317
- print(f"Testando modelo: {model_name}")
318
-
319
- info_available, info_msg = self.check_model_info(model_name)
320
- if not info_available:
321
- return False, f"Info check failed: {info_msg}"
322
-
323
- print(f" ✓ Info check: {info_msg}")
324
-
325
- inference_available, inference_msg = self.test_model_inference(model_name)
326
 
327
- if inference_available:
328
- print(f" ✓ Inference check: {inference_msg}")
329
- return True, f"Disponível - {info_msg}"
330
- else:
331
- print(f" ✗ Inference check: {inference_msg}")
332
- return False, f"Não disponível para inferência: {inference_msg}"
333
 
334
- def query_model(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
335
- """Faz requisição ao modelo usando text-generation."""
 
 
 
336
  prompt = self._convert_messages_to_prompt(messages)
337
 
338
  url = f"https://api-inference.huggingface.co/models/{model_name}"
@@ -347,7 +260,7 @@ class HuggingFaceAPIClient:
347
  }
348
 
349
  try:
350
- response = requests.post(url, headers=self.headers, json=payload, timeout=2500)
351
  response.raise_for_status()
352
 
353
  result = response.json()
@@ -358,10 +271,171 @@ class HuggingFaceAPIClient:
358
  else:
359
  return f"Formato de resposta inesperado: {result}"
360
 
361
- except requests.exceptions.HTTPError as http_err:
362
- return f"Erro HTTP: {http_err.response.status_code} - {http_err.response.text}"
363
  except requests.exceptions.RequestException as e:
364
- return f"Erro na requisição: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
 
366
  def _convert_messages_to_prompt(self, messages: List[Dict]) -> str:
367
  """Converte mensagens do formato chat para prompt simples."""
@@ -380,67 +454,70 @@ class HuggingFaceAPIClient:
380
  prompt_parts.append("Assistente:")
381
  return "\n\n".join(prompt_parts)
382
 
383
- api_client = HuggingFaceAPIClient(HF_TOKEN)
 
384
 
385
  # --- Função para Testar e Atualizar Modelos ---
386
  def test_and_update_models() -> int:
387
- """
388
- Testa a disponibilidade dos novos modelos e atualiza a lista MODELS.
389
- Garante que o DEFAULT_MODEL seja sempre o primeiro da lista.
390
- Retorna o número de modelos disponíveis.
391
- """
392
- print("Testando disponibilidade dos novos modelos...")
393
- print(f"Token HF disponível: {'Sim' if HF_TOKEN else 'Não'}")
394
- print("-" * 60)
395
-
396
- # Cria um dicionário temporário para os modelos disponíveis
397
- temp_models = {}
398
 
399
- # Primeiro verifica o modelo padrão
400
- default_label, default_name = "Mistral 7B (Mais acertivo)", "mistralai/Mistral-7B-Instruct-v0.3"
401
- is_available, message = api_client.test_model_availability(default_name)
402
-
403
- if is_available:
404
- temp_models[default_label] = default_name
405
- print(f"✓ {default_label} (DEFAULT MODEL)")
406
- else:
407
- print(f"✗ {default_label} - {message} (MODELO PADRÃO INDISPONÍVEL)")
408
 
409
- # Depois verifica os outros modelos
 
410
  for model_label, model_name in NEW_MODELS_TO_TEST:
411
- # Pula o modelo padrão se já foi testado
412
- if model_label == default_label and model_name == default_name:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
413
  continue
414
-
415
- is_available, message = api_client.test_model_availability(model_name)
416
 
 
417
  if is_available:
418
- temp_models[model_label] = model_name
419
- print(f" {model_label}")
420
  else:
421
- print(f" {model_label} - {message}")
422
-
423
  time.sleep(1)
424
 
425
- # Atualiza MODELS garantindo que o padrão seja o primeiro
426
- global MODELS
427
- MODELS.clear()
428
-
429
- # Adiciona primeiro o modelo padrão (se disponível)
430
- if default_label in temp_models:
431
- MODELS[default_label] = temp_models.pop(default_label)
432
 
433
- # Adiciona os demais modelos
434
- MODELS.update(temp_models)
 
 
 
 
435
 
436
- print("\n" + "=" * 60)
437
- print("MODELOS DISPONÍVEIS (ORDEM):")
438
- print("=" * 60)
439
- for i, (label, name) in enumerate(MODELS.items(), 1):
440
- print(f"{i}. {label}")
441
 
442
- print(f"\nTOTAL DE MODELOS DISPONÍVEIS: {len(MODELS)}")
443
- print("=" * 60)
444
 
445
  save_updated_models()
446
  return len(MODELS)
@@ -448,18 +525,31 @@ def test_and_update_models() -> int:
448
  def save_updated_models():
449
  """Salva a lista atualizada de modelos em um arquivo."""
450
  try:
 
 
 
 
 
 
 
451
  with open("models_available.json", "w", encoding="utf-8") as f:
452
- json.dump(MODELS, f, ensure_ascii=False, indent=2)
453
- print("Lista de modelos disponíveis salva em 'models_available.json'")
454
  except Exception as e:
455
- print(f"Erro ao salvar lista de modelos: {e}")
456
 
457
  # --- Chat Principal ---
458
- def responder_como_aldo(session_id: str, pergunta: str, modelo: str = DEFAULT_MODEL) -> str:
459
- """Gera resposta como Dr. Aldo Henrique."""
460
  if not pergunta.strip():
461
  return "Por favor, faça uma pergunta válida."
462
-
 
 
 
 
 
 
463
  load_conversation_memory(session_id)
464
  update_user_profile(session_id, pergunta)
465
 
@@ -483,7 +573,7 @@ def responder_como_aldo(session_id: str, pergunta: str, modelo: str = DEFAULT_MO
483
  - Use exemplos práticos.
484
  - Considere o nível do usuário (iniciante, intermediário ou avançado).
485
  - Use Markdown para formatar respostas, com ``` para blocos de código.
486
- - Dentro do código sempre coloque comentários explicando para o alunos aprender com os comentários.
487
  - Foque em tecnologia; se a pergunta for fora do escopo, informe educadamente que não é seu domínio.
488
  """
489
 
@@ -495,44 +585,416 @@ def responder_como_aldo(session_id: str, pergunta: str, modelo: str = DEFAULT_MO
495
  {"role": "user", "content": mensagem_usuario}
496
  ]
497
 
498
- model_name = MODELS.get(modelo, MODELS[DEFAULT_MODEL])
499
- resposta = api_client.query_model(model_name, messages)
500
- add_to_memory(session_id, pergunta, resposta)
501
- return resposta
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
 
503
  # --- Inicialização ---
504
  def inicializar_sistema():
505
  """
506
- Inicializa o sistema, garantindo no mínimo 3 modelos disponíveis.
507
- Retorna uma tupla: (status: bool, models: dict)
508
- - status: True se >= 3 modelos disponíveis, False caso contrário
509
- - models: Dicionário com os modelos disponíveis
510
  """
511
- print("Inicializando Chatbot Dr. Aldo...")
512
 
513
  num_available_models = test_and_update_models()
514
 
515
  if num_available_models >= 1:
516
  load_vector_store()
517
- print("Sistema inicializado e pronto para uso com modelos suficientes!")
518
- return True, MODELS
 
519
  else:
520
- print(f"Erro: Apenas {num_available_models} modelos disponíveis. São necessários pelo menos 3 modelos para iniciar o sistema.")
521
- return False, MODELS
 
522
 
 
523
  if __name__ == "__main__":
524
- status, models = inicializar_sistema()
 
 
 
 
 
 
 
 
 
525
  if status:
526
- print("\n" + "="*50)
527
- print("SISTEMA INICIADO: Realizando teste básico do Chatbot... ")
528
- print("="*50)
529
- session_id = "teste_123"
530
- print(responder_como_aldo(session_id, "O que é Java?"))
531
- print("\n" + "-"*50)
532
- print(responder_como_aldo(session_id, "Mostre um exemplo de código Java."))
533
- print("\n" + "-"*50)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
534
  print(clear_memory(session_id))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535
  else:
536
- print("\nSistema não pôde ser iniciado devido à falta de modelos suficientes.")
537
- print(f"Modelos disponíveis: {', '.join(models.keys()) if models else 'Nenhum'}")
538
- print("Por favor, verifique a conexão com o Hugging Face e o token de acesso.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  from langchain.text_splitter import RecursiveCharacterTextSplitter
10
  from langchain_community.vectorstores import FAISS
11
  from langchain_community.embeddings import HuggingFaceEmbeddings
12
+ import openai
13
+ from groq import Groq
14
+ import google.generativeai as genai
15
 
16
  # --- Configurações ---
17
  BLOG_URL = "https://aldohenrique.com.br/"
18
  VECTOR_STORE_PATH = "faiss_index_store.pkl"
19
  PROCESSED_URLS_PATH = "processed_urls.pkl"
20
  HF_TOKEN = os.getenv("HF_TOKEN")
21
+ GROQ_API_KEY = os.getenv("GROQ_API_KEY")
22
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
23
+ OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") # Para usar modelos gratuitos do OpenAI via outras APIs
24
 
25
+ # Lista inicial de modelos HuggingFace
 
 
 
 
 
 
 
 
26
  NEW_MODELS_TO_TEST = [
27
  ("Phi-3 Mini (Mais rápido)", "microsoft/Phi-3-mini-4k-instruct"),
28
  ("Zephyr 7B (Meio Termo)", "HuggingFaceH4/zephyr-7b-beta"),
29
+ ("Microsoft 8B (Meio Termo)", "meta-llama/Meta-Llama-3-8B-Instruct"),
30
+ ("Mistral-7B", "mistralai/Mistral-7B-Instruct-v0.3"),
31
+ ("DialoGPT", "microsoft/DialoGPT-medium"),
32
+ ("Google", "google/flan-t5-base"),
33
+ ("Facebook", "facebook/bart-large-cnn")
34
  ]
35
 
36
+ # Modelos alternativos gratuitos
37
+ FALLBACK_MODELS = [
38
+ # Groq (gratuito com rate limit)
39
+ ("Llama 3 8B (Groq)", "llama3-8b-8192", "groq"),
40
+ ("Mixtral 8x7B (Groq)", "mixtral-8x7b-32768", "groq"),
41
+ ("Gemma 7B (Groq)", "gemma-7b-it", "groq"),
42
 
43
+ # Google Gemini (gratuito com rate limit)
44
+ ("Gemini 1.5 Flash (Google)", "gemini-1.5-flash", "gemini"),
45
+ ("Gemini 1.5 Pro (Google)", "gemini-1.5-pro", "gemini"),
46
+
47
+ # Cohere (gratuito com rate limit)
48
+ ("Command R+ (Cohere)", "command-r-plus", "cohere"),
49
+
50
+ # Anthropic via outras APIs (quando disponível gratuitamente)
51
+ ("Claude 3 Haiku (Fallback)", "claude-3-haiku-20240307", "anthropic"),
52
+
53
+ # Modelos via APIs públicas gratuitas
54
+ ("Llama 2 7B (Together)", "togethercomputer/llama-2-7b-chat", "together"),
55
+ ("CodeLlama 7B (Together)", "togethercomputer/CodeLlama-7b-Instruct", "together"),
56
+ ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
+ # Dicionário unificado de modelos
59
+ MODELS = {}
60
+ DEFAULT_MODEL = "Phi-3 Mini (Mais rápido)"
61
 
62
+ # --- Gerenciamento de Sessão (mantido igual) ---
63
  user_sessions: Dict[str, Dict[str, List | Dict]] = {}
64
  MAX_MEMORY_LENGTH = 5
65
 
 
155
  os.remove(memory_path)
156
  return "Memória limpa com sucesso!"
157
 
158
+ # --- RAG (Crawling e Vector Store) - Mantido igual ---
159
  vector_store: Optional[FAISS] = None
160
 
161
  def get_all_blog_links(url: str) -> set:
 
227
  print(f"Erro ao buscar contexto: {e}")
228
  return ""
229
 
230
+ # --- Classe Unificada de API Client ---
231
+ class UnifiedAPIClient:
232
+ def __init__(self, hf_token: str = None, groq_api_key: str = None, gemini_api_key: str = None):
233
+ self.hf_token = hf_token
234
+ self.groq_api_key = groq_api_key
235
+ self.gemini_api_key = gemini_api_key
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
 
237
+ # Inicializa clientes
238
+ self.hf_headers = {"Authorization": f"Bearer {hf_token}", "Content-Type": "application/json"} if hf_token else None
239
+ self.groq_client = Groq(api_key=groq_api_key) if groq_api_key else None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
 
241
+ if gemini_api_key:
242
+ genai.configure(api_key=gemini_api_key)
 
 
 
 
243
 
244
+ def query_huggingface(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
245
+ """Consulta modelos do Hugging Face."""
246
+ if not self.hf_headers:
247
+ return "Token do Hugging Face não configurado"
248
+
249
  prompt = self._convert_messages_to_prompt(messages)
250
 
251
  url = f"https://api-inference.huggingface.co/models/{model_name}"
 
260
  }
261
 
262
  try:
263
+ response = requests.post(url, headers=self.hf_headers, json=payload, timeout=30)
264
  response.raise_for_status()
265
 
266
  result = response.json()
 
271
  else:
272
  return f"Formato de resposta inesperado: {result}"
273
 
 
 
274
  except requests.exceptions.RequestException as e:
275
+ return f"Erro na requisição HuggingFace: {str(e)}"
276
+
277
+ def query_groq(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
278
+ """Consulta modelos do Groq."""
279
+ if not self.groq_client:
280
+ return "API Key do Groq não configurada"
281
+
282
+ try:
283
+ # Converte mensagens para formato do Groq
284
+ groq_messages = []
285
+ for msg in messages:
286
+ groq_messages.append({
287
+ "role": msg["role"],
288
+ "content": msg["content"]
289
+ })
290
+
291
+ response = self.groq_client.chat.completions.create(
292
+ model=model_name,
293
+ messages=groq_messages,
294
+ max_tokens=max_tokens,
295
+ temperature=0.7
296
+ )
297
+
298
+ return response.choices[0].message.content.strip()
299
+
300
+ except Exception as e:
301
+ return f"Erro na requisição Groq: {str(e)}"
302
+
303
+ def query_gemini(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
304
+ """Consulta modelos do Google Gemini."""
305
+ if not self.gemini_api_key:
306
+ return "API Key do Gemini não configurada"
307
+
308
+ try:
309
+ # Converte mensagens para formato do Gemini
310
+ conversation_text = ""
311
+ for msg in messages:
312
+ if msg["role"] == "system":
313
+ conversation_text += f"Instrução: {msg['content']}\n\n"
314
+ elif msg["role"] == "user":
315
+ conversation_text += f"Usuário: {msg['content']}\n\n"
316
+ elif msg["role"] == "assistant":
317
+ conversation_text += f"Assistente: {msg['content']}\n\n"
318
+
319
+ conversation_text += "Assistente:"
320
+
321
+ model = genai.GenerativeModel(model_name)
322
+ response = model.generate_content(
323
+ conversation_text,
324
+ generation_config=genai.types.GenerationConfig(
325
+ max_output_tokens=max_tokens,
326
+ temperature=0.7
327
+ )
328
+ )
329
+
330
+ return response.text.strip()
331
+
332
+ except Exception as e:
333
+ return f"Erro na requisição Gemini: {str(e)}"
334
+
335
+ def query_cohere(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
336
+ """Consulta modelos do Cohere via API pública."""
337
+ try:
338
+ # Converte mensagens para prompt
339
+ prompt = self._convert_messages_to_prompt(messages)
340
+
341
+ # Usa API pública do Cohere (se disponível)
342
+ url = "https://api.cohere.ai/v1/generate"
343
+ headers = {
344
+ "Content-Type": "application/json",
345
+ "Authorization": f"Bearer {os.getenv('COHERE_API_KEY', 'demo-key')}"
346
+ }
347
+
348
+ payload = {
349
+ "model": model_name,
350
+ "prompt": prompt,
351
+ "max_tokens": max_tokens,
352
+ "temperature": 0.7
353
+ }
354
+
355
+ response = requests.post(url, headers=headers, json=payload, timeout=30)
356
+
357
+ if response.status_code == 200:
358
+ result = response.json()
359
+ return result.get("generations", [{}])[0].get("text", "").strip()
360
+ else:
361
+ return f"Erro Cohere: {response.status_code}"
362
+
363
+ except Exception as e:
364
+ return f"Erro na requisição Cohere: {str(e)}"
365
+
366
+ def query_together(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
367
+ """Consulta modelos via Together AI (API pública)."""
368
+ try:
369
+ prompt = self._convert_messages_to_prompt(messages)
370
+
371
+ # API do Together AI
372
+ url = "https://api.together.xyz/inference"
373
+ headers = {
374
+ "Content-Type": "application/json",
375
+ "Authorization": f"Bearer {os.getenv('TOGETHER_API_KEY', 'demo-key')}"
376
+ }
377
+
378
+ payload = {
379
+ "model": model_name,
380
+ "prompt": prompt,
381
+ "max_tokens": max_tokens,
382
+ "temperature": 0.7
383
+ }
384
+
385
+ response = requests.post(url, headers=headers, json=payload, timeout=30)
386
+
387
+ if response.status_code == 200:
388
+ result = response.json()
389
+ return result.get("output", {}).get("choices", [{}])[0].get("text", "").strip()
390
+ else:
391
+ return f"Erro Together: {response.status_code}"
392
+
393
+ except Exception as e:
394
+ return f"Erro na requisição Together: {str(e)}"
395
+
396
+ def query_model(self, model_display_name: str, model_info: Tuple[str, str], messages: List[Dict], max_tokens: int = 1000) -> str:
397
+ """Consulta um modelo baseado no seu tipo/provedor."""
398
+ model_name, provider = model_info
399
+
400
+ try:
401
+ if provider == "huggingface":
402
+ return self.query_huggingface(model_name, messages, max_tokens)
403
+ elif provider == "groq":
404
+ return self.query_groq(model_name, messages, max_tokens)
405
+ elif provider == "gemini":
406
+ return self.query_gemini(model_name, messages, max_tokens)
407
+ elif provider == "cohere":
408
+ return self.query_cohere(model_name, messages, max_tokens)
409
+ elif provider == "together":
410
+ return self.query_together(model_name, messages, max_tokens)
411
+ else:
412
+ return f"Provedor desconhecido: {provider}"
413
+
414
+ except Exception as e:
415
+ return f"Erro ao consultar modelo {model_display_name}: {str(e)}"
416
+
417
+ def test_model_availability(self, model_name: str, provider: str) -> Tuple[bool, str]:
418
+ """Testa se um modelo está disponível."""
419
+ test_messages = [
420
+ {"role": "system", "content": "Você é um assistente útil."},
421
+ {"role": "user", "content": "Teste de disponibilidade. Responda apenas 'OK'."}
422
+ ]
423
+
424
+ try:
425
+ response = self.query_model(
426
+ f"Teste {model_name}",
427
+ (model_name, provider),
428
+ test_messages,
429
+ max_tokens=10
430
+ )
431
+
432
+ if response and not response.startswith("Erro"):
433
+ return True, "Modelo disponível"
434
+ else:
435
+ return False, response
436
+
437
+ except Exception as e:
438
+ return False, f"Erro no teste: {str(e)}"
439
 
440
  def _convert_messages_to_prompt(self, messages: List[Dict]) -> str:
441
  """Converte mensagens do formato chat para prompt simples."""
 
454
  prompt_parts.append("Assistente:")
455
  return "\n\n".join(prompt_parts)
456
 
457
+ # Inicializa o cliente unificado
458
+ api_client = UnifiedAPIClient(HF_TOKEN, GROQ_API_KEY, GEMINI_API_KEY)
459
 
460
  # --- Função para Testar e Atualizar Modelos ---
461
  def test_and_update_models() -> int:
462
+ """Testa a disponibilidade de todos os modelos e atualiza a lista MODELS."""
463
+ print("Testando disponibilidade dos modelos...")
464
+ print(f"Tokens disponíveis: HF={bool(HF_TOKEN)}, Groq={bool(GROQ_API_KEY)}, Gemini={bool(GEMINI_API_KEY)}")
465
+ print("-" * 80)
 
 
 
 
 
 
 
466
 
467
+ global MODELS
468
+ MODELS.clear()
 
 
 
 
 
 
 
469
 
470
+ # Testa modelos do Hugging Face
471
+ print("🔍 TESTANDO MODELOS HUGGING FACE:")
472
  for model_label, model_name in NEW_MODELS_TO_TEST:
473
+ if HF_TOKEN:
474
+ is_available, message = api_client.test_model_availability(model_name, "huggingface")
475
+ if is_available:
476
+ MODELS[model_label] = (model_name, "huggingface")
477
+ print(f"✅ {model_label}")
478
+ else:
479
+ print(f"❌ {model_label} - {message}")
480
+ else:
481
+ print(f"⚠️ {model_label} - Token HF não configurado")
482
+ time.sleep(1)
483
+
484
+ # Testa modelos de fallback
485
+ print("\n🔍 TESTANDO MODELOS DE FALLBACK:")
486
+ for model_label, model_name, provider in FALLBACK_MODELS:
487
+ # Verifica se as credenciais estão disponíveis
488
+ if provider == "groq" and not GROQ_API_KEY:
489
+ print(f"⚠️ {model_label} - API Key Groq não configurada")
490
+ continue
491
+ elif provider == "gemini" and not GEMINI_API_KEY:
492
+ print(f"⚠️ {model_label} - API Key Gemini não configurada")
493
  continue
 
 
494
 
495
+ is_available, message = api_client.test_model_availability(model_name, provider)
496
  if is_available:
497
+ MODELS[model_label] = (model_name, provider)
498
+ print(f" {model_label} ({provider.upper()})")
499
  else:
500
+ print(f" {model_label} - {message}")
 
501
  time.sleep(1)
502
 
503
+ print("\n" + "=" * 80)
504
+ print("📊 RESUMO DOS MODELOS DISPONÍVEIS:")
505
+ print("=" * 80)
 
 
 
 
506
 
507
+ # Organiza por provedor
508
+ providers = {}
509
+ for label, (model_name, provider) in MODELS.items():
510
+ if provider not in providers:
511
+ providers[provider] = []
512
+ providers[provider].append(label)
513
 
514
+ for provider, models in providers.items():
515
+ print(f"\n🔹 {provider.upper()}:")
516
+ for i, model in enumerate(models, 1):
517
+ print(f" {i}. {model}")
 
518
 
519
+ print(f"\n🎯 TOTAL DE MODELOS DISPONÍVEIS: {len(MODELS)}")
520
+ print("=" * 80)
521
 
522
  save_updated_models()
523
  return len(MODELS)
 
525
  def save_updated_models():
526
  """Salva a lista atualizada de modelos em um arquivo."""
527
  try:
528
+ models_info = {}
529
+ for label, (model_name, provider) in MODELS.items():
530
+ models_info[label] = {
531
+ "model_name": model_name,
532
+ "provider": provider
533
+ }
534
+
535
  with open("models_available.json", "w", encoding="utf-8") as f:
536
+ json.dump(models_info, f, ensure_ascii=False, indent=2)
537
+ print("📁 Lista de modelos disponíveis salva em 'models_available.json'")
538
  except Exception as e:
539
+ print(f"Erro ao salvar lista de modelos: {e}")
540
 
541
  # --- Chat Principal ---
542
+ def responder_como_aldo(session_id: str, pergunta: str, modelo: str = None) -> str:
543
+ """Gera resposta como Dr. Aldo Henrique usando o modelo selecionado."""
544
  if not pergunta.strip():
545
  return "Por favor, faça uma pergunta válida."
546
+
547
+ # Seleciona modelo disponível
548
+ if not modelo or modelo not in MODELS:
549
+ if not MODELS:
550
+ return "❌ Nenhum modelo está disponível no momento. Verifique as configurações das APIs."
551
+ modelo = next(iter(MODELS.keys())) # Pega o primeiro modelo disponível
552
+
553
  load_conversation_memory(session_id)
554
  update_user_profile(session_id, pergunta)
555
 
 
573
  - Use exemplos práticos.
574
  - Considere o nível do usuário (iniciante, intermediário ou avançado).
575
  - Use Markdown para formatar respostas, com ``` para blocos de código.
576
+ - Dentro do código sempre coloque comentários explicando para o aluno aprender com os comentários.
577
  - Foque em tecnologia; se a pergunta for fora do escopo, informe educadamente que não é seu domínio.
578
  """
579
 
 
585
  {"role": "user", "content": mensagem_usuario}
586
  ]
587
 
588
+ # Obtém informações do modelo
589
+ model_info = MODELS[modelo]
590
+ provider = model_info[1]
591
+
592
+ print(f"🤖 Usando modelo: {modelo} ({provider.upper()})")
593
+
594
+ resposta = api_client.query_model(modelo, model_info, messages)
595
+
596
+ # Adiciona informação do modelo usado na resposta
597
+ resposta_final = f"{resposta}\n\n---\n*Resposta gerada por: {modelo} ({provider.upper()})*"
598
+
599
+ add_to_memory(session_id, pergunta, resposta_final)
600
+ return resposta_final
601
+
602
+ def listar_modelos_disponiveis() -> str:
603
+ """Retorna uma lista formatada dos modelos disponíveis."""
604
+ if not MODELS:
605
+ return "❌ Nenhum modelo está disponível no momento."
606
+
607
+ resultado = "🤖 **MODELOS DISPONÍVEIS:**\n\n"
608
+
609
+ # Organiza por provedor
610
+ providers = {}
611
+ for label, (model_name, provider) in MODELS.items():
612
+ if provider not in providers:
613
+ providers[provider] = []
614
+ providers[provider].append(label)
615
+
616
+ for provider, models in providers.items():
617
+ resultado += f"**{provider.upper()}:**\n"
618
+ for i, model in enumerate(models, 1):
619
+ resultado += f" {i}. {model}\n"
620
+ resultado += "\n"
621
+
622
+ return resultado
623
 
624
  # --- Inicialização ---
625
  def inicializar_sistema():
626
  """
627
+ Inicializa o sistema, testando todos os modelos disponíveis.
628
+ Retorna uma tupla: (status: bool, models: dict, message: str)
 
 
629
  """
630
+ print("🚀 Inicializando Chatbot Dr. Aldo com Fallback para Modelos Gratuitos...")
631
 
632
  num_available_models = test_and_update_models()
633
 
634
  if num_available_models >= 1:
635
  load_vector_store()
636
+ message = f"Sistema inicializado com {num_available_models} modelo(s) disponível(is)!"
637
+ print(message)
638
+ return True, MODELS, message
639
  else:
640
+ message = " Nenhum modelo disponível. Verifique as configurações das APIs."
641
+ print(message)
642
+ return False, MODELS, message
643
 
644
+ # --- Exemplo de uso ---
645
  if __name__ == "__main__":
646
+ # Configuração de exemplo das APIs (coloque suas chaves aqui)
647
+ print("🔧 Configuração das APIs:")
648
+ print(f" HuggingFace: {'✅ Configurado' if HF_TOKEN else '❌ Não configurado'}")
649
+ print(f" Groq: {'✅ Configurado' if GROQ_API_KEY else '❌ Não configurado'}")
650
+ print(f" Gemini: {'✅ Configurado' if GEMINI_API_KEY else '❌ Não configurado'}")
651
+ print()
652
+
653
+ # Inicializa o sistema
654
+ status, models, message = inicializar_sistema()
655
+
656
  if status:
657
+ print("\n" + "="*70)
658
+ print("🧪 REALIZANDO TESTE BÁSICO DO CHATBOT...")
659
+ print("="*70)
660
+
661
+ # Lista modelos disponíveis
662
+ print(listar_modelos_disponiveis())
663
+
664
+ # Testa com diferentes modelos
665
+ session_id = "teste_demo"
666
+
667
+ # Primeira pergunta
668
+ print("👤 PERGUNTA 1: O que é Java?")
669
+ print("🤖 RESPOSTA:")
670
+ resposta1 = responder_como_aldo(session_id, "O que é Java?")
671
+ print(resposta1)
672
+
673
+ print("\n" + "-"*70)
674
+
675
+ # Segunda pergunta
676
+ print("👤 PERGUNTA 2: Mostre um exemplo de código Java simples.")
677
+ print("🤖 RESPOSTA:")
678
+ resposta2 = responder_como_aldo(session_id, "Mostre um exemplo de código Java simples.")
679
+ print(resposta2)
680
+
681
+ print("\n" + "-"*70)
682
+
683
+ # Terceira pergunta para testar contexto
684
+ print("👤 PERGUNTA 3: Explique melhor o conceito de classe no exemplo anterior.")
685
+ print("🤖 RESPOSTA:")
686
+ resposta3 = responder_como_aldo(session_id, "Explique melhor o conceito de classe no exemplo anterior.")
687
+ print(resposta3)
688
+
689
+ print("\n" + "-"*70)
690
+ print("🧹 LIMPANDO MEMÓRIA DE TESTE...")
691
  print(clear_memory(session_id))
692
+ print("="*70)
693
+
694
+ else:
695
+ print(f"\n❌ {message}")
696
+ print("\n💡 DICAS PARA RESOLVER:")
697
+ print("1. Configure pelo menos uma das APIs:")
698
+ print(" - HuggingFace: export HF_TOKEN='seu_token_aqui'")
699
+ print(" - Groq: export GROQ_API_KEY='sua_chave_aqui'")
700
+ print(" - Gemini: export GEMINI_API_KEY='sua_chave_aqui'")
701
+ print("\n2. APIs gratuitas recomendadas:")
702
+ print(" - Groq: https://console.groq.com/ (gratuito)")
703
+ print(" - Google AI Studio: https://aistudio.google.com/ (gratuito)")
704
+ print(" - HuggingFace: https://huggingface.co/settings/tokens (gratuito)")
705
+
706
+
707
+ # --- Funções Auxiliares para Integração ---
708
+
709
+ def criar_interface_gradio():
710
+ """Cria interface Gradio para o chatbot (opcional)."""
711
+ try:
712
+ import gradio as gr
713
+
714
+ def chat_interface(message, history, model_choice):
715
+ """Interface do chat para Gradio."""
716
+ session_id = "gradio_session"
717
+
718
+ if not message.strip():
719
+ return "", history
720
+
721
+ # Seleciona modelo se especificado
722
+ modelo_selecionado = model_choice if model_choice in MODELS else None
723
+
724
+ # Gera resposta
725
+ resposta = responder_como_aldo(session_id, message, modelo_selecionado)
726
+
727
+ # Atualiza histórico
728
+ history.append((message, resposta))
729
+
730
+ return "", history
731
+
732
+ def listar_modelos():
733
+ """Lista modelos para dropdown."""
734
+ return list(MODELS.keys()) if MODELS else ["Nenhum modelo disponível"]
735
+
736
+ # Cria interface
737
+ with gr.Blocks(title="Dr. Aldo Henrique - Chatbot Educacional") as demo:
738
+ gr.Markdown("# 🤖 Dr. Aldo Henrique - Chatbot Educacional")
739
+ gr.Markdown("Assistente especializado em Ciência da Computação, IA e Programação")
740
+
741
+ with gr.Row():
742
+ with gr.Column(scale=3):
743
+ chatbot = gr.Chatbot(
744
+ label="Conversa",
745
+ height=500,
746
+ show_label=True
747
+ )
748
+
749
+ with gr.Row():
750
+ msg = gr.Textbox(
751
+ label="Sua pergunta",
752
+ placeholder="Digite sua pergunta sobre tecnologia...",
753
+ lines=2,
754
+ scale=4
755
+ )
756
+ send_btn = gr.Button("Enviar", scale=1)
757
+
758
+ with gr.Column(scale=1):
759
+ model_dropdown = gr.Dropdown(
760
+ choices=listar_modelos(),
761
+ label="Modelo",
762
+ value=list(MODELS.keys())[0] if MODELS else None,
763
+ interactive=True
764
+ )
765
+
766
+ gr.Markdown("### 📊 Modelos Disponíveis")
767
+ model_info = gr.Markdown(listar_modelos_disponiveis())
768
+
769
+ refresh_btn = gr.Button("🔄 Atualizar Modelos")
770
+ clear_btn = gr.Button("🧹 Limpar Conversa")
771
+
772
+ # Eventos
773
+ send_btn.click(
774
+ chat_interface,
775
+ inputs=[msg, chatbot, model_dropdown],
776
+ outputs=[msg, chatbot]
777
+ )
778
+
779
+ msg.submit(
780
+ chat_interface,
781
+ inputs=[msg, chatbot, model_dropdown],
782
+ outputs=[msg, chatbot]
783
+ )
784
+
785
+ def refresh_models():
786
+ test_and_update_models()
787
+ return gr.Dropdown(choices=listar_modelos()), listar_modelos_disponiveis()
788
+
789
+ refresh_btn.click(
790
+ refresh_models,
791
+ outputs=[model_dropdown, model_info]
792
+ )
793
+
794
+ def clear_chat():
795
+ clear_memory("gradio_session")
796
+ return []
797
+
798
+ clear_btn.click(clear_chat, outputs=[chatbot])
799
+
800
+ return demo
801
+
802
+ except ImportError:
803
+ print("⚠️ Gradio não está instalado. Para usar a interface web, instale com:")
804
+ print(" pip install gradio")
805
+ return None
806
+
807
+ def criar_interface_streamlit():
808
+ """Cria interface Streamlit para o chatbot (opcional)."""
809
+ try:
810
+ import streamlit as st
811
+
812
+ def main():
813
+ st.title("🤖 Dr. Aldo Henrique - Chatbot Educacional")
814
+ st.markdown("Assistente especializado em Ciência da Computação, IA e Programação")
815
+
816
+ # Sidebar com informações
817
+ with st.sidebar:
818
+ st.header("🔧 Configurações")
819
+
820
+ # Seleção de modelo
821
+ if MODELS:
822
+ modelo_selecionado = st.selectbox(
823
+ "Selecione o modelo:",
824
+ options=list(MODELS.keys()),
825
+ index=0
826
+ )
827
+ else:
828
+ st.error("Nenhum modelo disponível")
829
+ return
830
+
831
+ # Botão para atualizar modelos
832
+ if st.button("🔄 Atualizar Modelos"):
833
+ with st.spinner("Testando modelos..."):
834
+ test_and_update_models()
835
+ st.success("Modelos atualizados!")
836
+ st.rerun()
837
+
838
+ # Informações dos modelos
839
+ st.markdown("### 📊 Modelos Disponíveis")
840
+ st.markdown(listar_modelos_disponiveis())
841
+
842
+ # Limpar conversa
843
+ if st.button("🧹 Limpar Conversa"):
844
+ clear_memory("streamlit_session")
845
+ if "messages" in st.session_state:
846
+ del st.session_state.messages
847
+ st.success("Conversa limpa!")
848
+ st.rerun()
849
+
850
+ # Inicializar mensagens
851
+ if "messages" not in st.session_state:
852
+ st.session_state.messages = []
853
+
854
+ # Exibir mensagens
855
+ for message in st.session_state.messages:
856
+ with st.chat_message(message["role"]):
857
+ st.markdown(message["content"])
858
+
859
+ # Input do usuário
860
+ if prompt := st.chat_input("Digite sua pergunta sobre tecnologia..."):
861
+ # Adicionar mensagem do usuário
862
+ st.session_state.messages.append({"role": "user", "content": prompt})
863
+ with st.chat_message("user"):
864
+ st.markdown(prompt)
865
+
866
+ # Gerar resposta
867
+ with st.chat_message("assistant"):
868
+ with st.spinner("Pensando..."):
869
+ resposta = responder_como_aldo("streamlit_session", prompt, modelo_selecionado)
870
+ st.markdown(resposta)
871
+
872
+ # Adicionar resposta do assistente
873
+ st.session_state.messages.append({"role": "assistant", "content": resposta})
874
+
875
+ return main
876
+
877
+ except ImportError:
878
+ print("⚠️ Streamlit não está instalado. Para usar a interface web, instale com:")
879
+ print(" pip install streamlit")
880
+ return None
881
+
882
+ def executar_interface_web(tipo="gradio"):
883
+ """Executa interface web do chatbot."""
884
+ print(f"🌐 Iniciando interface web ({tipo})...")
885
+
886
+ # Inicializa sistema
887
+ status, models, message = inicializar_sistema()
888
+
889
+ if not status:
890
+ print(f"❌ Não foi possível inicializar: {message}")
891
+ return
892
+
893
+ if tipo.lower() == "gradio":
894
+ demo = criar_interface_gradio()
895
+ if demo:
896
+ demo.launch(
897
+ server_name="0.0.0.0",
898
+ server_port=7860,
899
+ share=True,
900
+ debug=True
901
+ )
902
+ elif tipo.lower() == "streamlit":
903
+ main_func = criar_interface_streamlit()
904
+ if main_func:
905
+ print("Execute com: streamlit run nome_do_arquivo.py")
906
+ return main_func
907
  else:
908
+ print(" Tipo de interface não suportado. Use 'gradio' ou 'streamlit'")
909
+
910
+ # --- Função para Instalar Dependências ---
911
+ def instalar_dependencias():
912
+ """Instala dependências necessárias para o sistema."""
913
+ import subprocess
914
+ import sys
915
+
916
+ dependencias = [
917
+ "requests",
918
+ "beautifulsoup4",
919
+ "langchain",
920
+ "langchain-community",
921
+ "faiss-cpu",
922
+ "sentence-transformers",
923
+ "groq",
924
+ "google-generativeai",
925
+ "gradio",
926
+ "streamlit"
927
+ ]
928
+
929
+ print("📦 Instalando dependências...")
930
+ for dep in dependencias:
931
+ try:
932
+ subprocess.check_call([sys.executable, "-m", "pip", "install", dep])
933
+ print(f"✅ {dep} instalado com sucesso")
934
+ except subprocess.CalledProcessError:
935
+ print(f"❌ Erro ao instalar {dep}")
936
+
937
+ # --- Instruções de Uso ---
938
+ def mostrar_instrucoes():
939
+ """Mostra instruções de uso do sistema."""
940
+ print("""
941
+ 🚀 INSTRUÇÕES DE USO - Dr. Aldo Henrique Chatbot
942
+
943
+ 1. 🔑 CONFIGURAÇÃO DAS APIs:
944
+ Configure pelo menos uma das variáveis de ambiente:
945
+
946
+ export HF_TOKEN="seu_token_huggingface"
947
+ export GROQ_API_KEY="sua_chave_groq"
948
+ export GEMINI_API_KEY="sua_chave_gemini"
949
+
950
+ 2. 🆓 APIS GRATUITAS RECOMENDADAS:
951
+
952
+ • Groq (Recomendado): https://console.groq.com/
953
+ - Modelos: Llama 3, Mixtral, Gemma
954
+ - Rate limit: 30 req/min (gratuito)
955
+
956
+ • Google AI Studio: https://aistudio.google.com/
957
+ - Modelos: Gemini 1.5 Flash/Pro
958
+ - Rate limit: 15 req/min (gratuito)
959
+
960
+ • HuggingFace: https://huggingface.co/settings/tokens
961
+ - Modelos: Diversos modelos open source
962
+ - Rate limit: Variável por modelo
963
+
964
+ 3. 📚 EXEMPLOS DE USO:
965
+
966
+ # Uso básico
967
+ python nome_do_arquivo.py
968
+
969
+ # Interface web Gradio
970
+ executar_interface_web("gradio")
971
+
972
+ # Interface web Streamlit
973
+ executar_interface_web("streamlit")
974
+
975
+ 4. 🎯 FUNCIONALIDADES:
976
+
977
+ • Chat inteligente com memória de conversa
978
+ • Múltiplos modelos de IA como fallback
979
+ • RAG (busca no blog do Dr. Aldo)
980
+ • Perfil adaptativo do usuário
981
+ • Respostas educacionais personalizadas
982
+
983
+ 5. 🔧 SOLUÇÃO DE PROBLEMAS:
984
+
985
+ • Sem modelos disponíveis: Verifique as chaves das APIs
986
+ • Erro de token: Regenere as chaves nas respectivas plataformas
987
+ • Rate limit: Aguarde alguns minutos entre as requisições
988
+ • Erro de dependência: Execute instalar_dependencias()
989
+
990
+ 6. 📞 SUPORTE:
991
+
992
+ Para dúvidas técnicas sobre o código, consulte:
993
+ • Blog: https://aldohenrique.com.br/
994
+ • Documentação das APIs utilizadas
995
+
996
+ """)
997
+
998
+ # Executar instruções se chamado diretamente
999
+ if __name__ == "__main__":
1000
+ mostrar_instrucoes()