aldohenrique commited on
Commit
9834e37
·
verified ·
1 Parent(s): 094c918

Update ai_logic.py

Browse files
Files changed (1) hide show
  1. ai_logic.py +251 -87
ai_logic.py CHANGED
@@ -29,7 +29,6 @@ headers = {
29
 
30
  # Modelos fixos que você quer manter
31
  NEW_MODELS_TO_TEST = [
32
-
33
  ("GPT-2", "gpt2"),
34
  ("DistilGPT-2", "distilgpt2"),
35
  ("GPT-2 Medium", "gpt2-medium"),
@@ -52,44 +51,61 @@ NEW_MODELS_TO_TEST = [
52
  ("Facebook","facebook/bart-large-cnn")
53
  ]
54
 
55
- # --- Consulta a API da Hugging Face ---
56
- url = "https://huggingface.co/api/models?filter=text-generation,transformers,conversational,license:mit,text-generation-inference,safetensors,autotrain_compatible,endpoints_compatible,region:us"
57
- params = {
 
 
 
 
 
 
 
 
58
 
59
- "private":"false",
60
- "limit": 1, # Aumente se quiser trazer mais modelos
61
- "full": "true"
62
- }
63
-
64
- response = requests.get(url, headers=headers, params=params)
65
-
66
- if response.status_code != 200:
67
- raise Exception(f"Erro na API: {response.status_code} - {response.text}")
68
-
69
- models_data = response.json()
70
-
71
- # --- Filtra modelos que possuem base_model ---
72
- for model in models_data:
73
- tags = model.get("tags", [])
74
- base_model_tags = [tag for tag in tags if tag.startswith("base_model:")]
75
- if base_model_tags:
76
- model_name = model.get("id")
77
- display_name = model_name.split("/")[-1]
78
 
79
- # Verifica se já não está na lista para evitar duplicados
80
- if not any(model_name == m[1] for m in NEW_MODELS_TO_TEST):
81
- NEW_MODELS_TO_TEST.append((display_name, model_name))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
- # --- Resultado ---
84
  print("Lista atualizada de modelos:\n")
85
- for name, model_id in NEW_MODELS_TO_TEST:
86
  print(f'("{name}", "{model_id}"),')
87
 
88
  print(f"\nTotal de modelos na lista: {len(NEW_MODELS_TO_TEST)}")
89
 
90
- # Nota: Alguns modelos podem requerer aprovação ou ter restrições de acesso
91
- # Recomenda-se testar cada modelo individualmente para verificar disponibilidade
92
-
93
  DEFAULT_MODEL = "Zephyr 7B (Meio Termo)"
94
 
95
  # --- Gerenciamento de Sessão ---
@@ -200,7 +216,7 @@ def get_all_blog_links(url: str) -> set:
200
  if current_url in visited:
201
  continue
202
  try:
203
- response = requests.get(current_url, timeout=500)
204
  soup = BeautifulSoup(response.content, 'html.parser')
205
  visited.add(current_url)
206
  for link in soup.find_all('a', href=True):
@@ -214,7 +230,7 @@ def get_all_blog_links(url: str) -> set:
214
  def scrape_text_from_url(url: str) -> str:
215
  """Extrai texto de uma URL."""
216
  try:
217
- response = requests.get(url, timeout=500)
218
  soup = BeautifulSoup(response.content, 'html.parser')
219
  content = soup.find('article') or soup.find('main')
220
  return content.get_text(separator='\n', strip=True) if content else ""
@@ -264,66 +280,123 @@ def retrieve_context_from_blog(query: str, k: int = 4) -> str:
264
  class HuggingFaceAPIClient:
265
  def __init__(self, token: str):
266
  self.headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
 
 
267
 
268
  def check_model_info(self, model_name: str) -> Tuple[bool, str]:
269
  """Verifica informações do modelo via API do Hugging Face."""
270
- url = f"https://huggingface.co/api/models/{model_name}"
271
  try:
272
- response = requests.get(url, headers=self.headers, timeout=90)
273
  if response.status_code == 200:
274
  model_info = response.json()
 
 
275
  if model_info.get('disabled', False):
276
  return False, "Modelo desabilitado"
 
 
277
  if model_info.get('gated', False):
278
  return False, "Modelo requer aprovação/aceite de licença"
 
 
 
 
 
 
279
  return True, "Modelo disponível"
 
280
  elif response.status_code == 404:
281
  return False, "Modelo não encontrado"
 
 
 
 
282
  else:
283
  return False, f"Erro HTTP {response.status_code}"
 
 
 
284
  except requests.exceptions.RequestException as e:
285
  return False, f"Erro na requisição: {str(e)}"
286
 
287
  def test_model_inference(self, model_name: str) -> Tuple[bool, str]:
288
  """Testa se o modelo está disponível para inferência."""
289
- url = f"https://api-inference.huggingface.co/models/{model_name}"
 
 
290
  test_payload = {
291
- "inputs": "Teste de disponibilidade do modelo.",
292
  "parameters": {
293
- "max_new_tokens": 10,
294
  "temperature": 0.1,
 
295
  "return_full_text": False
296
  }
297
  }
298
 
299
  try:
300
- response = requests.post(url, headers=self.headers, json=test_payload, timeout=90)
301
 
302
  if response.status_code == 200:
303
  result = response.json()
 
 
304
  if isinstance(result, list) and len(result) > 0:
305
- return True, "Modelo disponível para inferência"
306
- elif isinstance(result, dict) and 'error' not in result:
307
- return True, "Modelo disponível para inferência"
308
- else:
309
- return False, f"Resposta inesperada: {result}"
 
 
 
 
 
 
 
 
310
 
311
  elif response.status_code == 503:
312
- return False, "Modelo está carregando (503)"
 
 
 
 
 
 
 
 
313
  elif response.status_code == 400:
314
- error_msg = response.json().get('error', 'Erro 400')
315
- if 'loading' in error_msg.lower():
316
- return False, "Modelo está carregando"
317
- return False, f"Erro 400: {error_msg}"
 
 
 
 
 
 
 
318
  elif response.status_code == 401:
319
  return False, "Token inválido ou sem permissão"
 
 
320
  elif response.status_code == 404:
321
- return False, "Modelo não encontrado"
 
 
322
  else:
323
- return False, f"Erro HTTP {response.status_code}: {response.text}"
 
 
 
 
 
324
 
325
  except requests.exceptions.Timeout:
326
- return False, "Timeout na requisição"
327
  except requests.exceptions.RequestException as e:
328
  return False, f"Erro na requisição: {str(e)}"
329
 
@@ -331,12 +404,15 @@ class HuggingFaceAPIClient:
331
  """Testa se um modelo está disponível, combinando verificação de info e inferência."""
332
  print(f"Testando modelo: {model_name}")
333
 
 
334
  info_available, info_msg = self.check_model_info(model_name)
335
  if not info_available:
 
336
  return False, f"Info check failed: {info_msg}"
337
 
338
  print(f" ✓ Info check: {info_msg}")
339
 
 
340
  inference_available, inference_msg = self.test_model_inference(model_name)
341
 
342
  if inference_available:
@@ -347,53 +423,128 @@ class HuggingFaceAPIClient:
347
  return False, f"Não disponível para inferência: {inference_msg}"
348
 
349
  def query_model(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
350
- """Faz requisição ao modelo usando text-generation."""
351
  prompt = self._convert_messages_to_prompt(messages)
352
 
353
- url = f"https://api-inference.huggingface.co/models/{model_name}"
 
 
354
  payload = {
355
  "inputs": prompt,
356
  "parameters": {
357
- "max_new_tokens": max_tokens,
358
  "temperature": 0.7,
 
359
  "do_sample": True,
360
- "return_full_text": False
 
 
 
 
 
 
361
  }
362
  }
363
 
364
- try:
365
- response = requests.post(url, headers=self.headers, json=payload, timeout=2500)
366
- response.raise_for_status()
367
-
368
- result = response.json()
369
- if isinstance(result, list) and len(result) > 0:
370
- return result[0].get('generated_text', '').strip()
371
- elif isinstance(result, dict) and 'generated_text' in result:
372
- return result['generated_text'].strip()
373
- else:
374
- return f"Formato de resposta inesperado: {result}"
375
 
376
- except requests.exceptions.HTTPError as http_err:
377
- return f"Erro HTTP: {http_err.response.status_code} - {http_err.response.text}"
378
- except requests.exceptions.RequestException as e:
379
- return f"Erro na requisição: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
380
 
381
  def _convert_messages_to_prompt(self, messages: List[Dict]) -> str:
382
- """Converte mensagens do formato chat para prompt simples."""
383
  prompt_parts = []
 
384
  for msg in messages:
385
  role = msg['role']
386
  content = msg['content']
387
 
388
  if role == 'system':
389
- prompt_parts.append(f"Sistema: {content}")
390
  elif role == 'user':
391
- prompt_parts.append(f"Usuário: {content}")
392
  elif role == 'assistant':
393
- prompt_parts.append(f"Assistente: {content}")
394
-
395
- prompt_parts.append("Assistente:")
396
- return "\n\n".join(prompt_parts)
 
 
397
 
398
  api_client = HuggingFaceAPIClient(HF_TOKEN)
399
 
@@ -404,7 +555,7 @@ def test_and_update_models() -> int:
404
  Garante que o DEFAULT_MODEL seja sempre o primeiro da lista.
405
  Retorna o número de modelos disponíveis.
406
  """
407
- print("Testando disponibilidade dos novos modelos...")
408
  print(f"Token HF disponível: {'Sim' if HF_TOKEN else 'Não'}")
409
  print("-" * 60)
410
 
@@ -412,7 +563,9 @@ def test_and_update_models() -> int:
412
  temp_models = {}
413
 
414
  # Primeiro verifica o modelo padrão
415
- default_label, default_name = "Mistral 7B (Mais acertivo)", "mistralai/Mistral-7B-Instruct-v0.3"
 
 
416
  is_available, message = api_client.test_model_availability(default_name)
417
 
418
  if is_available:
@@ -421,11 +574,17 @@ def test_and_update_models() -> int:
421
  else:
422
  print(f"✗ {default_label} - {message} (MODELO PADRÃO INDISPONÍVEL)")
423
 
424
- # Depois verifica os outros modelos
 
 
 
425
  for model_label, model_name in NEW_MODELS_TO_TEST:
426
  # Pula o modelo padrão se já foi testado
427
  if model_label == default_label and model_name == default_name:
428
  continue
 
 
 
429
 
430
  is_available, message = api_client.test_model_availability(model_name)
431
 
@@ -435,7 +594,8 @@ def test_and_update_models() -> int:
435
  else:
436
  print(f"✗ {model_label} - {message}")
437
 
438
- time.sleep(1)
 
439
 
440
  # Atualiza MODELS garantindo que o padrão seja o primeiro
441
  global MODELS
@@ -509,7 +669,11 @@ def responder_como_aldo(session_id: str, pergunta: str, modelo: str = DEFAULT_MO
509
  {"role": "user", "content": mensagem_usuario}
510
  ]
511
 
512
- model_name = MODELS.get(modelo, MODELS[DEFAULT_MODEL])
 
 
 
 
513
  resposta = api_client.query_model(model_name, messages)
514
  add_to_memory(session_id, pergunta, resposta)
515
  return resposta
@@ -517,9 +681,9 @@ def responder_como_aldo(session_id: str, pergunta: str, modelo: str = DEFAULT_MO
517
  # --- Inicialização ---
518
  def inicializar_sistema():
519
  """
520
- Inicializa o sistema, garantindo no mínimo 3 modelos disponíveis.
521
  Retorna uma tupla: (status: bool, models: dict)
522
- - status: True se >= 3 modelos disponíveis, False caso contrário
523
  - models: Dicionário com os modelos disponíveis
524
  """
525
  print("Inicializando Chatbot Dr. Aldo...")
@@ -531,7 +695,7 @@ def inicializar_sistema():
531
  print("Sistema inicializado e pronto para uso com modelos suficientes!")
532
  return True, MODELS
533
  else:
534
- print(f"Erro: Apenas {num_available_models} modelos disponíveis. São necessários pelo menos 3 modelos para iniciar o sistema.")
535
  return False, MODELS
536
 
537
  if __name__ == "__main__":
@@ -549,4 +713,4 @@ if __name__ == "__main__":
549
  else:
550
  print("\nSistema não pôde ser iniciado devido à falta de modelos suficientes.")
551
  print(f"Modelos disponíveis: {', '.join(models.keys()) if models else 'Nenhum'}")
552
- print("Por favor, verifique a conexão com o Hugging Face e o token de acesso.")
 
29
 
30
  # Modelos fixos que você quer manter
31
  NEW_MODELS_TO_TEST = [
 
32
  ("GPT-2", "gpt2"),
33
  ("DistilGPT-2", "distilgpt2"),
34
  ("GPT-2 Medium", "gpt2-medium"),
 
51
  ("Facebook","facebook/bart-large-cnn")
52
  ]
53
 
54
+ # --- Consulta a API da Hugging Face com tratamento de erro melhorado ---
55
+ def fetch_models_from_api():
56
+ """Busca modelos adicionais da API do Hugging Face com tratamento robusto."""
57
+ url = "https://huggingface.co/api/models"
58
+ params = {
59
+ "filter": "text-generation",
60
+ "sort": "downloads",
61
+ "direction": -1,
62
+ "limit": 20,
63
+ "full": True
64
+ }
65
 
66
+ try:
67
+ response = requests.get(url, headers=headers, params=params, timeout=30)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
+ if response.status_code == 200:
70
+ models_data = response.json()
71
+
72
+ # Filtra modelos que possuem base_model
73
+ for model in models_data:
74
+ try:
75
+ tags = model.get("tags", [])
76
+ model_name = model.get("id")
77
+
78
+ if not model_name:
79
+ continue
80
+
81
+ # Verifica se o modelo é adequado
82
+ if any(tag in tags for tag in ["text-generation", "conversational"]):
83
+ display_name = model_name.split("/")[-1]
84
+
85
+ # Verifica se já não está na lista para evitar duplicados
86
+ if not any(model_name == m[1] for m in NEW_MODELS_TO_TEST):
87
+ NEW_MODELS_TO_TEST.append((display_name, model_name))
88
+
89
+ except Exception as e:
90
+ print(f"Erro ao processar modelo {model.get('id', 'unknown')}: {e}")
91
+ continue
92
+
93
+ else:
94
+ print(f"Erro na API do Hugging Face: {response.status_code}")
95
+
96
+ except Exception as e:
97
+ print(f"Erro ao buscar modelos da API: {e}")
98
+ print("Continuando com a lista de modelos predefinida...")
99
+
100
+ # Executa a busca de modelos
101
+ fetch_models_from_api()
102
 
 
103
  print("Lista atualizada de modelos:\n")
104
+ for name, model_id in NEW_MODELS_TO_TEST[:10]: # Mostra apenas os primeiros 10
105
  print(f'("{name}", "{model_id}"),')
106
 
107
  print(f"\nTotal de modelos na lista: {len(NEW_MODELS_TO_TEST)}")
108
 
 
 
 
109
  DEFAULT_MODEL = "Zephyr 7B (Meio Termo)"
110
 
111
  # --- Gerenciamento de Sessão ---
 
216
  if current_url in visited:
217
  continue
218
  try:
219
+ response = requests.get(current_url, timeout=10)
220
  soup = BeautifulSoup(response.content, 'html.parser')
221
  visited.add(current_url)
222
  for link in soup.find_all('a', href=True):
 
230
  def scrape_text_from_url(url: str) -> str:
231
  """Extrai texto de uma URL."""
232
  try:
233
+ response = requests.get(url, timeout=10)
234
  soup = BeautifulSoup(response.content, 'html.parser')
235
  content = soup.find('article') or soup.find('main')
236
  return content.get_text(separator='\n', strip=True) if content else ""
 
280
  class HuggingFaceAPIClient:
281
  def __init__(self, token: str):
282
  self.headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
283
+ self.base_api_url = "https://api-inference.huggingface.co/models"
284
+ self.base_info_url = "https://huggingface.co/api/models"
285
 
286
  def check_model_info(self, model_name: str) -> Tuple[bool, str]:
287
  """Verifica informações do modelo via API do Hugging Face."""
288
+ url = f"{self.base_info_url}/{model_name}"
289
  try:
290
+ response = requests.get(url, headers=self.headers, timeout=15)
291
  if response.status_code == 200:
292
  model_info = response.json()
293
+
294
+ # Verifica se o modelo está desabilitado
295
  if model_info.get('disabled', False):
296
  return False, "Modelo desabilitado"
297
+
298
+ # Verifica se o modelo requer aprovação
299
  if model_info.get('gated', False):
300
  return False, "Modelo requer aprovação/aceite de licença"
301
+
302
+ # Verifica se o modelo existe mas não tem pipeline de text-generation
303
+ pipeline_tag = model_info.get('pipeline_tag')
304
+ if pipeline_tag and pipeline_tag not in ['text-generation', 'text2text-generation', 'conversational']:
305
+ return False, f"Modelo não suporta geração de texto (pipeline: {pipeline_tag})"
306
+
307
  return True, "Modelo disponível"
308
+
309
  elif response.status_code == 404:
310
  return False, "Modelo não encontrado"
311
+ elif response.status_code == 401:
312
+ return False, "Token inválido ou sem permissão"
313
+ elif response.status_code == 403:
314
+ return False, "Acesso negado ao modelo"
315
  else:
316
  return False, f"Erro HTTP {response.status_code}"
317
+
318
+ except requests.exceptions.Timeout:
319
+ return False, "Timeout na verificação do modelo"
320
  except requests.exceptions.RequestException as e:
321
  return False, f"Erro na requisição: {str(e)}"
322
 
323
  def test_model_inference(self, model_name: str) -> Tuple[bool, str]:
324
  """Testa se o modelo está disponível para inferência."""
325
+ url = f"{self.base_api_url}/{model_name}"
326
+
327
+ # Payload simplificado para teste
328
  test_payload = {
329
+ "inputs": "Hello",
330
  "parameters": {
331
+ "max_new_tokens": 5,
332
  "temperature": 0.1,
333
+ "do_sample": False,
334
  "return_full_text": False
335
  }
336
  }
337
 
338
  try:
339
+ response = requests.post(url, headers=self.headers, json=test_payload, timeout=60)
340
 
341
  if response.status_code == 200:
342
  result = response.json()
343
+
344
+ # Verifica diferentes formatos de resposta
345
  if isinstance(result, list) and len(result) > 0:
346
+ if 'generated_text' in result[0] or 'translation_text' in result[0] or 'summary_text' in result[0]:
347
+ return True, "Modelo disponível para inferência"
348
+
349
+ elif isinstance(result, dict):
350
+ if 'generated_text' in result or 'error' not in result:
351
+ return True, "Modelo disponível para inferência"
352
+ elif 'error' in result:
353
+ error_msg = result['error']
354
+ if 'loading' in error_msg.lower() or 'currently loading' in error_msg.lower():
355
+ return False, "Modelo está carregando"
356
+ return False, f"Erro do modelo: {error_msg}"
357
+
358
+ return False, f"Formato de resposta inesperado: {str(result)[:200]}"
359
 
360
  elif response.status_code == 503:
361
+ try:
362
+ error_data = response.json()
363
+ error_msg = error_data.get('error', 'Serviço indisponível')
364
+ if 'loading' in error_msg.lower():
365
+ return False, "Modelo está carregando"
366
+ return False, f"Serviço indisponível: {error_msg}"
367
+ except:
368
+ return False, "Modelo está carregando (503)"
369
+
370
  elif response.status_code == 400:
371
+ try:
372
+ error_data = response.json()
373
+ error_msg = error_data.get('error', 'Erro 400')
374
+ if 'loading' in error_msg.lower():
375
+ return False, "Modelo está carregando"
376
+ elif 'not supported' in error_msg.lower():
377
+ return False, "Tipo de requisição não suportado"
378
+ return False, f"Erro 400: {error_msg}"
379
+ except:
380
+ return False, "Erro de requisição malformada"
381
+
382
  elif response.status_code == 401:
383
  return False, "Token inválido ou sem permissão"
384
+ elif response.status_code == 403:
385
+ return False, "Acesso negado ao modelo"
386
  elif response.status_code == 404:
387
+ return False, "Endpoint do modelo não encontrado"
388
+ elif response.status_code == 429:
389
+ return False, "Limite de requisições excedido"
390
  else:
391
+ try:
392
+ error_data = response.json()
393
+ error_msg = error_data.get('error', response.text)
394
+ return False, f"Erro HTTP {response.status_code}: {error_msg}"
395
+ except:
396
+ return False, f"Erro HTTP {response.status_code}: {response.text[:200]}"
397
 
398
  except requests.exceptions.Timeout:
399
+ return False, "Timeout na requisição de inferência"
400
  except requests.exceptions.RequestException as e:
401
  return False, f"Erro na requisição: {str(e)}"
402
 
 
404
  """Testa se um modelo está disponível, combinando verificação de info e inferência."""
405
  print(f"Testando modelo: {model_name}")
406
 
407
+ # Primeiro verifica as informações do modelo
408
  info_available, info_msg = self.check_model_info(model_name)
409
  if not info_available:
410
+ print(f" ✗ Info check: {info_msg}")
411
  return False, f"Info check failed: {info_msg}"
412
 
413
  print(f" ✓ Info check: {info_msg}")
414
 
415
+ # Em seguida testa a inferência
416
  inference_available, inference_msg = self.test_model_inference(model_name)
417
 
418
  if inference_available:
 
423
  return False, f"Não disponível para inferência: {inference_msg}"
424
 
425
  def query_model(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
426
+ """Faz requisição ao modelo usando text-generation com retry e fallback."""
427
  prompt = self._convert_messages_to_prompt(messages)
428
 
429
+ url = f"{self.base_api_url}/{model_name}"
430
+
431
+ # Configurações otimizadas para diferentes tipos de modelo
432
  payload = {
433
  "inputs": prompt,
434
  "parameters": {
435
+ "max_new_tokens": min(max_tokens, 500), # Limita para evitar timeouts
436
  "temperature": 0.7,
437
+ "top_p": 0.9,
438
  "do_sample": True,
439
+ "return_full_text": False,
440
+ "repetition_penalty": 1.1,
441
+ "pad_token_id": 50256 # Token padrão para muitos modelos
442
+ },
443
+ "options": {
444
+ "wait_for_model": True,
445
+ "use_cache": False
446
  }
447
  }
448
 
449
+ max_retries = 2
450
+ for attempt in range(max_retries):
451
+ try:
452
+ response = requests.post(
453
+ url,
454
+ headers=self.headers,
455
+ json=payload,
456
+ timeout=120 # Timeout aumentado
457
+ )
 
 
458
 
459
+ if response.status_code == 200:
460
+ result = response.json()
461
+
462
+ # Trata diferentes formatos de resposta
463
+ if isinstance(result, list) and len(result) > 0:
464
+ generated_text = result[0].get('generated_text', '').strip()
465
+ if generated_text:
466
+ return generated_text
467
+ return "Resposta vazia do modelo"
468
+
469
+ elif isinstance(result, dict):
470
+ if 'generated_text' in result:
471
+ return result['generated_text'].strip()
472
+ elif 'error' in result:
473
+ return f"Erro do modelo: {result['error']}"
474
+ else:
475
+ return f"Formato inesperado: {str(result)[:300]}"
476
+
477
+ return f"Formato de resposta não reconhecido: {str(result)[:300]}"
478
+
479
+ elif response.status_code == 503:
480
+ if attempt < max_retries - 1:
481
+ wait_time = 5 * (attempt + 1)
482
+ print(f"Modelo carregando, aguardando {wait_time}s...")
483
+ time.sleep(wait_time)
484
+ continue
485
+ return "Modelo ainda está carregando após várias tentativas"
486
+
487
+ elif response.status_code == 400:
488
+ try:
489
+ error_data = response.json()
490
+ error_msg = error_data.get('error', 'Erro 400')
491
+ return f"Erro na requisição: {error_msg}"
492
+ except:
493
+ return "Erro na formatação da requisição"
494
+
495
+ elif response.status_code == 401:
496
+ return "Token de autenticação inválido ou expirado"
497
+
498
+ elif response.status_code == 403:
499
+ return "Acesso negado ao modelo (pode requerer aprovação)"
500
+
501
+ elif response.status_code == 429:
502
+ if attempt < max_retries - 1:
503
+ wait_time = 10 * (attempt + 1)
504
+ print(f"Rate limit atingido, aguardando {wait_time}s...")
505
+ time.sleep(wait_time)
506
+ continue
507
+ return "Limite de requisições excedido"
508
+
509
+ else:
510
+ try:
511
+ error_data = response.json()
512
+ error_msg = error_data.get('error', response.text)
513
+ return f"Erro HTTP {response.status_code}: {error_msg}"
514
+ except:
515
+ return f"Erro HTTP {response.status_code}: {response.text[:200]}"
516
+
517
+ except requests.exceptions.Timeout:
518
+ if attempt < max_retries - 1:
519
+ print(f"Timeout na tentativa {attempt + 1}, tentando novamente...")
520
+ time.sleep(5)
521
+ continue
522
+ return "Timeout: O modelo demorou muito para responder"
523
+
524
+ except requests.exceptions.RequestException as e:
525
+ return f"Erro na requisição: {str(e)}"
526
+
527
+ return "Falha após múltiplas tentativas"
528
 
529
  def _convert_messages_to_prompt(self, messages: List[Dict]) -> str:
530
+ """Converte mensagens do formato chat para prompt otimizado."""
531
  prompt_parts = []
532
+
533
  for msg in messages:
534
  role = msg['role']
535
  content = msg['content']
536
 
537
  if role == 'system':
538
+ prompt_parts.append(f"### Sistema:\n{content}\n")
539
  elif role == 'user':
540
+ prompt_parts.append(f"### Usuário:\n{content}\n")
541
  elif role == 'assistant':
542
+ prompt_parts.append(f"### Assistente:\n{content}\n")
543
+
544
+ # Adiciona prompt final para gerar resposta
545
+ prompt_parts.append("### Assistente:\n")
546
+
547
+ return "\n".join(prompt_parts)
548
 
549
  api_client = HuggingFaceAPIClient(HF_TOKEN)
550
 
 
555
  Garante que o DEFAULT_MODEL seja sempre o primeiro da lista.
556
  Retorna o número de modelos disponíveis.
557
  """
558
+ print("Testando disponibilidade dos modelos...")
559
  print(f"Token HF disponível: {'Sim' if HF_TOKEN else 'Não'}")
560
  print("-" * 60)
561
 
 
563
  temp_models = {}
564
 
565
  # Primeiro verifica o modelo padrão
566
+ default_label = "Mistral 7B"
567
+ default_name = "mistralai/Mistral-7B-Instruct-v0.3"
568
+
569
  is_available, message = api_client.test_model_availability(default_name)
570
 
571
  if is_available:
 
574
  else:
575
  print(f"✗ {default_label} - {message} (MODELO PADRÃO INDISPONÍVEL)")
576
 
577
+ # Depois verifica os outros modelos (limitando a quantidade para evitar rate limiting)
578
+ tested_count = 0
579
+ max_tests = 15 # Limita o número de testes
580
+
581
  for model_label, model_name in NEW_MODELS_TO_TEST:
582
  # Pula o modelo padrão se já foi testado
583
  if model_label == default_label and model_name == default_name:
584
  continue
585
+
586
+ if tested_count >= max_tests:
587
+ break
588
 
589
  is_available, message = api_client.test_model_availability(model_name)
590
 
 
594
  else:
595
  print(f"✗ {model_label} - {message}")
596
 
597
+ tested_count += 1
598
+ time.sleep(2) # Pausa entre testes para evitar rate limiting
599
 
600
  # Atualiza MODELS garantindo que o padrão seja o primeiro
601
  global MODELS
 
669
  {"role": "user", "content": mensagem_usuario}
670
  ]
671
 
672
+ # Verifica se o modelo existe na lista, senão usa o padrão
673
+ if modelo not in MODELS:
674
+ modelo = next(iter(MODELS)) if MODELS else DEFAULT_MODEL
675
+
676
+ model_name = MODELS.get(modelo, list(MODELS.values())[0] if MODELS else "mistralai/Mistral-7B-Instruct-v0.3")
677
  resposta = api_client.query_model(model_name, messages)
678
  add_to_memory(session_id, pergunta, resposta)
679
  return resposta
 
681
  # --- Inicialização ---
682
  def inicializar_sistema():
683
  """
684
+ Inicializa o sistema, garantindo no mínimo 1 modelo disponível.
685
  Retorna uma tupla: (status: bool, models: dict)
686
+ - status: True se >= 1 modelo disponível, False caso contrário
687
  - models: Dicionário com os modelos disponíveis
688
  """
689
  print("Inicializando Chatbot Dr. Aldo...")
 
695
  print("Sistema inicializado e pronto para uso com modelos suficientes!")
696
  return True, MODELS
697
  else:
698
+ print(f"Erro: Apenas {num_available_models} modelos disponíveis. É necessário pelo menos 1 modelo para iniciar o sistema.")
699
  return False, MODELS
700
 
701
  if __name__ == "__main__":
 
713
  else:
714
  print("\nSistema não pôde ser iniciado devido à falta de modelos suficientes.")
715
  print(f"Modelos disponíveis: {', '.join(models.keys()) if models else 'Nenhum'}")
716
+ print("Por favor, verifique a conexão com o Hugging Face e o token de acesso.")