aldohenrique commited on
Commit
1bcec59
·
verified ·
1 Parent(s): c5ec8c2

Update ai_logic.py

Browse files
Files changed (1) hide show
  1. ai_logic.py +253 -42
ai_logic.py CHANGED
@@ -14,23 +14,202 @@ from langchain_community.embeddings import HuggingFaceEmbeddings
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
-
22
- MODELS = {
 
23
  "Mistral 7B (Mais acertivo)": "mistralai/Mistral-7B-Instruct-v0.3",
24
  "Phi-3 Mini (Mais rápido)": "microsoft/Phi-3-mini-4k-instruct",
25
- "Zephyr 7B (Meio Termo)": "HuggingFaceH4/zephyr-7b-beta"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  }
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
- DEFAULT_MODEL = "Mistral 7B (Mais acertivo)"
 
 
30
 
31
- # --- Gerenciamento de Sessão ---
32
- user_sessions: Dict[str, Dict[str, List | Dict]] = {} # {session_id: {'conversation': [], 'user_profile': {}}}
33
- MAX_MEMORY_LENGTH = 5 # Máximo de trocas (user + assistant)
 
 
 
 
 
 
 
 
34
 
35
  def get_session_memory_path(session_id: str) -> str:
36
  """Retorna o caminho do arquivo de memória para a sessão."""
@@ -79,13 +258,11 @@ def update_user_profile(session_id: str, user_message: str):
79
  profile = user_sessions[session_id]['user_profile']
80
  message_lower = user_message.lower()
81
 
82
- # Atualiza nível
83
  if any(word in message_lower for word in ['básico', 'iniciante']):
84
  profile['nivel'] = 'iniciante'
85
  elif any(word in message_lower for word in ['avançado', 'complexo']):
86
  profile['nivel'] = 'avançado'
87
 
88
- # Atualiza interesses
89
  topics = {
90
  'java': ['java', 'classe', 'objeto'],
91
  'web': ['html', 'css', 'javascript'],
@@ -101,7 +278,7 @@ def update_user_profile(session_id: str, user_message: str):
101
  def get_conversation_context(session_id: str) -> str:
102
  """Gera o contexto da conversa recente."""
103
  load_conversation_memory(session_id)
104
- conversation = user_sessions[session_id]['conversation'][-4:] # Últimas 2 trocas
105
  if not conversation:
106
  return ""
107
  return "\n".join(f"{msg['role'].upper()}: {msg['content']}" for msg in conversation)
@@ -198,36 +375,19 @@ def retrieve_context_from_blog(query: str, k: int = 3) -> str:
198
  print(f"Erro ao buscar contexto: {e}")
199
  return ""
200
 
201
- # --- API Client ---
202
- class HuggingFaceAPIClient:
203
- def __init__(self, token: str):
204
- self.headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
205
-
206
- def query_model(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
207
- """Faz requisição à API do Hugging Face."""
208
- url = f"https://api-inference.huggingface.co/models/{model_name}/v1/chat/completions"
209
- print(messages)
210
- payload = {
211
- "model": model_name,
212
- "messages": messages,
213
- "max_tokens": max_tokens,
214
- "temperature": 0.7
215
- }
216
- try:
217
- response = requests.post(url, headers=self.headers, json=payload, timeout=500)
218
- response.raise_for_status()
219
- return response.json()["choices"][0]["message"]["content"].strip()
220
- except Exception as e:
221
- return f"Erro na API: {str(e)}"
222
-
223
  api_client = HuggingFaceAPIClient(HF_TOKEN)
224
 
225
  # --- Chat Principal ---
226
- def responder_como_aldo(session_id: str, pergunta: str, modelo: str = DEFAULT_MODEL) -> str:
227
  """Gera resposta como Dr. Aldo Henrique."""
228
  if not pergunta.strip():
229
  return "Por favor, faça uma pergunta válida."
230
 
 
 
 
 
231
  load_conversation_memory(session_id)
232
  update_user_profile(session_id, pergunta)
233
 
@@ -258,11 +418,11 @@ def responder_como_aldo(session_id: str, pergunta: str, modelo: str = DEFAULT_MO
258
  mensagem_usuario = f"{conteudo_contexto}\n\n**Pergunta**: {pergunta}"
259
 
260
  messages = [
261
- {"role": "system", "content": system_prompt},
262
- {"role": "user", "content": mensagem_usuario}
263
- ]
264
 
265
- model_name = MODELS.get(modelo, MODELS[DEFAULT_MODEL])
266
  resposta = api_client.query_model(model_name, messages)
267
  add_to_memory(session_id, pergunta, resposta)
268
  return resposta
@@ -270,13 +430,64 @@ def responder_como_aldo(session_id: str, pergunta: str, modelo: str = DEFAULT_MO
270
  # --- Inicialização ---
271
  def inicializar_sistema():
272
  """Inicializa o sistema."""
273
- print("Inicializando Chatbot Dr. Aldo...")
 
274
  load_vector_store()
275
- print("Sistema inicializado!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
276
 
277
  if __name__ == "__main__":
278
  inicializar_sistema()
 
 
 
 
279
  session_id = "teste_123"
280
- print(responder_como_aldo(session_id, "O que é Java?"))
281
- print(responder_como_aldo(session_id, "Mostre um exemplo de código Java."))
282
- print(clear_memory(session_id))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  BLOG_URL = "https://aldohenrique.com.br/"
15
  VECTOR_STORE_PATH = "faiss_index_store.pkl"
16
  PROCESSED_URLS_PATH = "processed_urls.pkl"
17
+ AVAILABLE_MODELS_PATH = "available_models.json"
18
  HF_TOKEN = os.getenv("HF_TOKEN")
19
  if not HF_TOKEN:
20
  raise ValueError("Token HF_TOKEN não encontrado")
21
 
22
+ # Lista expandida de modelos para testar
23
+ CANDIDATE_MODELS = {
24
+ # Modelos originais
25
  "Mistral 7B (Mais acertivo)": "mistralai/Mistral-7B-Instruct-v0.3",
26
  "Phi-3 Mini (Mais rápido)": "microsoft/Phi-3-mini-4k-instruct",
27
+ "Zephyr 7B (Meio Termo)": "HuggingFaceH4/zephyr-7b-beta",
28
+
29
+ # Novos modelos para testar
30
+ "Llama 2 7B Chat": "meta-llama/Llama-2-7b-chat-hf",
31
+ "Code Llama 7B": "codellama/CodeLlama-7b-Instruct-hf",
32
+ "Falcon 7B Instruct": "tiiuae/falcon-7b-instruct",
33
+ "Gemma 7B Instruct": "google/gemma-7b-it",
34
+ "Vicuna 7B": "lmsys/vicuna-7b-v1.5",
35
+ "OpenHermes 2.5": "teknium/OpenHermes-2.5-Mistral-7B",
36
+ "Neural Chat 7B": "Intel/neural-chat-7b-v3-3",
37
+ "Starling 7B": "Nexusflow/Starling-LM-7B-beta",
38
+ "Yi 6B Chat": "01-ai/Yi-6B-Chat",
39
+ "Qwen 7B Chat": "Qwen/Qwen-7B-Chat",
40
+ "Baichuan2 7B Chat": "baichuan-inc/Baichuan2-7B-Chat",
41
+ "ChatGLM3 6B": "THUDM/chatglm3-6b",
42
+ "InternLM 7B Chat": "internlm/internlm-chat-7b",
43
+ "Alpaca 7B": "chavinlo/alpaca-native",
44
+ "Orca Mini 7B": "microsoft/Orca-2-7b",
45
+ "WizardLM 7B": "WizardLM/WizardLM-7B-V1.0"
46
  }
47
 
48
+ # Modelos disponíveis (será preenchido dinamicamente)
49
+ MODELS = {}
50
+ DEFAULT_MODEL = None
51
+
52
+ class HuggingFaceAPIClient:
53
+ def __init__(self, token: str):
54
+ self.headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
55
+
56
+ def test_model_availability(self, model_name: str) -> bool:
57
+ """Testa se um modelo está disponível na API do Hugging Face."""
58
+ url = f"https://api-inference.huggingface.co/models/{model_name}"
59
+
60
+ try:
61
+ # Primeiro, verifica se o modelo existe
62
+ response = requests.get(url, headers=self.headers, timeout=10)
63
+ if response.status_code != 200:
64
+ print(f"❌ Modelo {model_name} não encontrado (Status: {response.status_code})")
65
+ return False
66
+
67
+ # Testa uma requisição simples de chat
68
+ chat_url = f"{url}/v1/chat/completions"
69
+ test_payload = {
70
+ "model": model_name,
71
+ "messages": [{"role": "user", "content": "Hello"}],
72
+ "max_tokens": 10,
73
+ "temperature": 0.1
74
+ }
75
+
76
+ chat_response = requests.post(
77
+ chat_url,
78
+ headers=self.headers,
79
+ json=test_payload,
80
+ timeout=30
81
+ )
82
+
83
+ if chat_response.status_code == 200:
84
+ result = chat_response.json()
85
+ if "choices" in result and len(result["choices"]) > 0:
86
+ print(f"✅ Modelo {model_name} disponível e funcionando")
87
+ return True
88
+ else:
89
+ print(f"⚠️ Modelo {model_name} retornou resposta inválida")
90
+ return False
91
+ else:
92
+ print(f"❌ Modelo {model_name} indisponível (Status: {chat_response.status_code})")
93
+ return False
94
+
95
+ except requests.exceptions.Timeout:
96
+ print(f"⏰ Timeout ao testar modelo {model_name}")
97
+ return False
98
+ except requests.exceptions.RequestException as e:
99
+ print(f"❌ Erro de conexão ao testar modelo {model_name}: {e}")
100
+ return False
101
+ except Exception as e:
102
+ print(f"❌ Erro inesperado ao testar modelo {model_name}: {e}")
103
+ return False
104
+
105
+ def query_model(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
106
+ """Faz requisição à API do Hugging Face."""
107
+ url = f"https://api-inference.huggingface.co/models/{model_name}/v1/chat/completions"
108
+ payload = {
109
+ "model": model_name,
110
+ "messages": messages,
111
+ "max_tokens": max_tokens,
112
+ "temperature": 0.7
113
+ }
114
+ try:
115
+ response = requests.post(url, headers=self.headers, json=payload, timeout=60)
116
+ response.raise_for_status()
117
+ return response.json()["choices"][0]["message"]["content"].strip()
118
+ except Exception as e:
119
+ return f"Erro na API: {str(e)}"
120
+
121
+ def check_and_update_available_models() -> Dict[str, str]:
122
+ """Verifica quais modelos estão disponíveis e atualiza a lista."""
123
+ print("🔍 Verificando disponibilidade dos modelos...")
124
+ print("=" * 60)
125
+
126
+ api_client = HuggingFaceAPIClient(HF_TOKEN)
127
+ available_models = {}
128
+
129
+ for display_name, model_path in CANDIDATE_MODELS.items():
130
+ print(f"Testando: {display_name} ({model_path})")
131
+
132
+ if api_client.test_model_availability(model_path):
133
+ available_models[display_name] = model_path
134
+ time.sleep(1) # Pausa para evitar rate limit
135
+ else:
136
+ time.sleep(0.5) # Pausa menor para modelos que falharam
137
+
138
+ print("=" * 60)
139
+ print(f"✅ {len(available_models)} modelos disponíveis de {len(CANDIDATE_MODELS)} testados")
140
+
141
+ # Salva a lista de modelos disponíveis
142
+ try:
143
+ with open(AVAILABLE_MODELS_PATH, 'w', encoding='utf-8') as f:
144
+ json.dump({
145
+ 'models': available_models,
146
+ 'last_updated': time.time(),
147
+ 'timestamp': time.strftime('%Y-%m-%d %H:%M:%S')
148
+ }, f, ensure_ascii=False, indent=2)
149
+ print(f"💾 Lista de modelos salva em {AVAILABLE_MODELS_PATH}")
150
+ except Exception as e:
151
+ print(f"⚠️ Erro ao salvar lista de modelos: {e}")
152
+
153
+ return available_models
154
+
155
+ def load_available_models() -> Dict[str, str]:
156
+ """Carrega a lista de modelos disponíveis do arquivo."""
157
+ if os.path.exists(AVAILABLE_MODELS_PATH):
158
+ try:
159
+ with open(AVAILABLE_MODELS_PATH, 'r', encoding='utf-8') as f:
160
+ data = json.load(f)
161
+
162
+ # Verifica se os dados não são muito antigos (24 horas)
163
+ if time.time() - data.get('last_updated', 0) < 86400:
164
+ print(f"📁 Carregando modelos disponíveis (última atualização: {data.get('timestamp', 'desconhecida')})")
165
+ return data.get('models', {})
166
+ else:
167
+ print("⏰ Lista de modelos desatualizada, verificando novamente...")
168
+
169
+ except Exception as e:
170
+ print(f"⚠️ Erro ao carregar lista de modelos: {e}")
171
+
172
+ return check_and_update_available_models()
173
+
174
+ def initialize_models():
175
+ """Inicializa a lista de modelos disponíveis."""
176
+ global MODELS, DEFAULT_MODEL
177
+
178
+ MODELS = load_available_models()
179
+
180
+ if not MODELS:
181
+ print("⚠️ Nenhum modelo disponível! Verificando novamente...")
182
+ MODELS = check_and_update_available_models()
183
+
184
+ if MODELS:
185
+ # Define o modelo padrão (prioriza Mistral se disponível)
186
+ if "Mistral 7B (Mais acertivo)" in MODELS:
187
+ DEFAULT_MODEL = "Mistral 7B (Mais acertivo)"
188
+ else:
189
+ DEFAULT_MODEL = list(MODELS.keys())[0]
190
+
191
+ print(f"🎯 Modelo padrão definido: {DEFAULT_MODEL}")
192
+ print(f"📋 Modelos disponíveis:")
193
+ for i, model_name in enumerate(MODELS.keys(), 1):
194
+ print(f" {i}. {model_name}")
195
+ else:
196
+ raise RuntimeError("❌ Nenhum modelo LLM está disponível!")
197
 
198
+ def get_available_models() -> Dict[str, str]:
199
+ """Retorna a lista atual de modelos disponíveis."""
200
+ return MODELS.copy()
201
 
202
+ def refresh_models():
203
+ """Força a verificação de modelos disponíveis."""
204
+ global MODELS, DEFAULT_MODEL
205
+ print("🔄 Atualizando lista de modelos...")
206
+ MODELS = check_and_update_available_models()
207
+ initialize_models()
208
+
209
+ # --- Resto do código original (gerenciamento de sessão, RAG, etc.) ---
210
+
211
+ user_sessions: Dict[str, Dict[str, List | Dict]] = {}
212
+ MAX_MEMORY_LENGTH = 5
213
 
214
  def get_session_memory_path(session_id: str) -> str:
215
  """Retorna o caminho do arquivo de memória para a sessão."""
 
258
  profile = user_sessions[session_id]['user_profile']
259
  message_lower = user_message.lower()
260
 
 
261
  if any(word in message_lower for word in ['básico', 'iniciante']):
262
  profile['nivel'] = 'iniciante'
263
  elif any(word in message_lower for word in ['avançado', 'complexo']):
264
  profile['nivel'] = 'avançado'
265
 
 
266
  topics = {
267
  'java': ['java', 'classe', 'objeto'],
268
  'web': ['html', 'css', 'javascript'],
 
278
  def get_conversation_context(session_id: str) -> str:
279
  """Gera o contexto da conversa recente."""
280
  load_conversation_memory(session_id)
281
+ conversation = user_sessions[session_id]['conversation'][-4:]
282
  if not conversation:
283
  return ""
284
  return "\n".join(f"{msg['role'].upper()}: {msg['content']}" for msg in conversation)
 
375
  print(f"Erro ao buscar contexto: {e}")
376
  return ""
377
 
378
+ # --- API Client (atualizado) ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  api_client = HuggingFaceAPIClient(HF_TOKEN)
380
 
381
  # --- Chat Principal ---
382
+ def responder_como_aldo(session_id: str, pergunta: str, modelo: str = None) -> str:
383
  """Gera resposta como Dr. Aldo Henrique."""
384
  if not pergunta.strip():
385
  return "Por favor, faça uma pergunta válida."
386
 
387
+ # Se não especificou modelo ou modelo não disponível, usa o padrão
388
+ if not modelo or modelo not in MODELS:
389
+ modelo = DEFAULT_MODEL
390
+
391
  load_conversation_memory(session_id)
392
  update_user_profile(session_id, pergunta)
393
 
 
418
  mensagem_usuario = f"{conteudo_contexto}\n\n**Pergunta**: {pergunta}"
419
 
420
  messages = [
421
+ {"role": "system", "content": system_prompt},
422
+ {"role": "user", "content": mensagem_usuario}
423
+ ]
424
 
425
+ model_name = MODELS[modelo]
426
  resposta = api_client.query_model(model_name, messages)
427
  add_to_memory(session_id, pergunta, resposta)
428
  return resposta
 
430
  # --- Inicialização ---
431
  def inicializar_sistema():
432
  """Inicializa o sistema."""
433
+ print("🤖 Inicializando Chatbot Dr. Aldo...")
434
+ initialize_models()
435
  load_vector_store()
436
+ print("Sistema inicializado com sucesso!")
437
+ print(f"🎯 Modelo padrão: {DEFAULT_MODEL}")
438
+ print(f"📊 Total de modelos disponíveis: {len(MODELS)}")
439
+
440
+ # --- Funções auxiliares para gerenciamento ---
441
+ def listar_modelos():
442
+ """Lista todos os modelos disponíveis."""
443
+ print("\n📋 Modelos LLM Disponíveis:")
444
+ print("=" * 50)
445
+ for i, (nome, caminho) in enumerate(MODELS.items(), 1):
446
+ status = "🎯 PADRÃO" if nome == DEFAULT_MODEL else ""
447
+ print(f"{i:2d}. {nome} {status}")
448
+ print(f" └─ {caminho}")
449
+ print("=" * 50)
450
+
451
+ def verificar_status_modelo(modelo_nome: str):
452
+ """Verifica o status de um modelo específico."""
453
+ if modelo_nome in MODELS:
454
+ print(f"✅ {modelo_nome} está disponível")
455
+ return True
456
+ else:
457
+ print(f"❌ {modelo_nome} não está disponível")
458
+ return False
459
 
460
  if __name__ == "__main__":
461
  inicializar_sistema()
462
+
463
+ # Exemplo de uso
464
+ listar_modelos()
465
+
466
  session_id = "teste_123"
467
+ print("\n" + "="*60)
468
+ print("🧪 TESTE DE FUNCIONAMENTO")
469
+ print("="*60)
470
+
471
+ # Testa com modelo padrão
472
+ print(f"\n🎯 Testando com modelo padrão ({DEFAULT_MODEL}):")
473
+ resposta1 = responder_como_aldo(session_id, "O que é Java?")
474
+ print(f"Resposta: {resposta1[:200]}...")
475
+
476
+ # Testa com outro modelo se disponível
477
+ modelos_disponiveis = list(MODELS.keys())
478
+ if len(modelos_disponiveis) > 1:
479
+ outro_modelo = modelos_disponiveis[1]
480
+ print(f"\n🔄 Testando com {outro_modelo}:")
481
+ resposta2 = responder_como_aldo(session_id, "Mostre um exemplo de código Java.", outro_modelo)
482
+ print(f"Resposta: {resposta2[:200]}...")
483
+
484
+ print(f"\n🧹 {clear_memory(session_id)}")
485
+
486
+ # Mostra comandos úteis
487
+ print("\n" + "="*60)
488
+ print("🛠️ COMANDOS ÚTEIS")
489
+ print("="*60)
490
+ print("- listar_modelos(): Lista todos os modelos disponíveis")
491
+ print("- refresh_models(): Atualiza a lista de modelos")
492
+ print("- verificar_status_modelo('nome'): Verifica se um modelo está disponível")
493
+ print("- get_available_models(): Retorna dicionário com modelos disponíveis")