aldohenrique commited on
Commit
c67b3dc
·
verified ·
1 Parent(s): d89148c

Update ai_logic.py

Browse files
Files changed (1) hide show
  1. ai_logic.py +142 -66
ai_logic.py CHANGED
@@ -46,7 +46,7 @@ DEFAULT_MODEL = "Llama 3.2 3B"
46
 
47
  # --- Gerenciamento de Sessão ---
48
  user_sessions: Dict[str, Dict[str, List | Dict]] = {}
49
- MAX_MEMORY_LENGTH = 5
50
 
51
  def get_session_memory_path(session_id: str) -> str:
52
  """Retorna o caminho do arquivo de memória para a sessão."""
@@ -85,6 +85,7 @@ def add_to_memory(session_id: str, user_message: str, assistant_response: str):
85
  {"role": "user", "content": user_message, "timestamp": time.time()},
86
  {"role": "assistant", "content": assistant_response, "timestamp": time.time()}
87
  ])
 
88
  if len(conversation) > MAX_MEMORY_LENGTH * 2:
89
  user_sessions[session_id]['conversation'] = conversation[-MAX_MEMORY_LENGTH * 2:]
90
  save_conversation_memory(session_id)
@@ -112,24 +113,54 @@ def update_user_profile(session_id: str, user_message: str):
112
  profile['total_perguntas'] = profile.get('total_perguntas', 0) + 1
113
  user_sessions[session_id]['user_profile'] = profile
114
 
115
- def get_conversation_context(session_id: str) -> str:
116
- """Gera o contexto da conversa recente."""
 
 
 
117
  load_conversation_memory(session_id)
118
- conversation = user_sessions[session_id]['conversation'][-4:]
119
- if not conversation:
120
- return ""
121
- return "\n".join(f"{msg['role'].upper()}: {msg['content']}" for msg in conversation)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
  def get_user_profile_context(session_id: str) -> str:
124
- """Gera o contexto do perfil do usuário."""
125
  load_conversation_memory(session_id)
126
  profile = user_sessions[session_id]['user_profile']
127
- context = f"Nível: {profile.get('nivel', 'intermediario')}\n"
128
- context += f"Total de perguntas: {profile.get('total_perguntas', 0)}\n"
129
- interesses = [f"{k.replace('interesse_', '').title()} ({v})" for k, v in profile.items() if k.startswith('interesse_')]
 
 
 
 
 
 
 
 
 
130
  if interesses:
131
- context += f"Interesses: {', '.join(interesses)}\n"
132
- return context
 
133
 
134
  def clear_memory(session_id: str) -> str:
135
  """Limpa a memória de uma sessão específica."""
@@ -216,12 +247,23 @@ def load_vector_store():
216
  print("Tentando criar novo vector store...")
217
  build_and_save_vector_store()
218
 
219
- def retrieve_context_from_blog(query: str, k: int = 4) -> str:
220
- """Busca contexto relevante no vector store."""
221
  if vector_store:
222
  try:
223
  results = vector_store.similarity_search(query, k=k)
224
- return "\n".join(doc.page_content for doc in results)
 
 
 
 
 
 
 
 
 
 
 
225
  except Exception as e:
226
  print(f"Erro ao buscar contexto: {e}")
227
  return ""
@@ -277,8 +319,8 @@ class HuggingFaceInferenceClient:
277
  else:
278
  return False, f"Erro: {str(e)[:100]}"
279
 
280
- def query_model(self, model_name: str, messages: List[Dict], max_tokens: int = 2000, temperature: float = 0.5) -> str:
281
- """Faz requisição ao modelo usando chat completion."""
282
  try:
283
  client = self.get_client(model_name)
284
 
@@ -385,9 +427,11 @@ def test_and_update_models() -> int:
385
 
386
  return len(MODELS)
387
 
388
- # --- Chat Principal ---
389
  def responder_como_aldo(session_id: str, pergunta: str, modelo: str = None) -> str:
390
- """Gera resposta como Dr. Aldo Henrique."""
 
 
391
  if not pergunta.strip():
392
  return "Por favor, faça uma pergunta válida."
393
 
@@ -400,50 +444,77 @@ def responder_como_aldo(session_id: str, pergunta: str, modelo: str = None) -> s
400
  load_conversation_memory(session_id)
401
  update_user_profile(session_id, pergunta)
402
 
403
- # Monta contexto
404
- contexto = []
405
- if perfil := get_user_profile_context(session_id):
406
- contexto.append(f"**Perfil do Usuário**\n{perfil}")
407
- if conversa := get_conversation_context(session_id):
408
- contexto.append(f"**Conversa Anterior**\n{conversa}")
409
- if blog := retrieve_context_from_blog(pergunta):
410
- contexto.append(f"**Contexto do Blog**\n{blog}")
411
-
412
- system_prompt = """Você é o Dr. Aldo Henrique,
413
- Doutor em Ciências da Computação pela UnB (2024), professor universitário especializado em:
414
- - Algoritmos e Estruturas de Dados
415
- - Inteligência Artificial
416
- - Ciência de Dados e Mineração de Dados
417
- - Desenvolvimento de Software
418
-
419
- Responda sempre em português, de forma didática e clara.
420
- - Explique conceitos antes de mostrar código
421
- - Use exemplos práticos
422
- - Considere o nível do usuário
423
- - Faça sempre uma pequena observação que seja engraçada ou interessente relacionada a algo na pergunta.
424
- - Use Markdown para formatação
425
- - Adicione comentários explicativos cada parte do código
426
- """
427
 
428
- conteudo_contexto = "\n".join(contexto)
429
- mensagem_usuario = f"{conteudo_contexto}\n\n**Pergunta**: {pergunta}" if contexto else pergunta
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
430
 
431
- messages = [
432
- {"role": "system", "content": system_prompt},
433
- {"role": "user", "content": mensagem_usuario}
434
- ]
435
 
436
- # Faz requisição usando InferenceClient
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
437
  inference_client = HuggingFaceInferenceClient(HF_TOKEN)
438
  model_name = MODELS[modelo]
439
- resposta = inference_client.query_model(model_name, messages)
440
 
441
- # Adiciona informação sobre modelo usado
442
- resposta += f"\n\n*Resposta gerada pelo modelo: {modelo} ({model_name})*"
443
 
444
- # Salva na memória
445
- add_to_memory(session_id, pergunta, resposta)
446
- return resposta
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
447
 
448
  # --- Inicialização ---
449
  def inicializar_sistema():
@@ -484,7 +555,7 @@ if __name__ == "__main__":
484
 
485
  if status:
486
  print("\n" + "="*50)
487
- print("TESTE DO SISTEMA")
488
  print("="*50)
489
 
490
  session_id = "teste_123"
@@ -494,20 +565,25 @@ if __name__ == "__main__":
494
  resposta1 = responder_como_aldo(session_id, "O que é Python?")
495
  print(f"Resposta: {resposta1[:200]}...")
496
 
497
- # Teste 2
498
- print("\n2. Testando pergunta com código...")
499
- resposta2 = responder_como_aldo(session_id, "Mostre um exemplo de função em Python")
500
  print(f"Resposta: {resposta2[:200]}...")
501
 
 
 
 
 
 
502
  # Limpeza
503
- print(f"\n3. {clear_memory(session_id)}")
504
 
505
  print("\n" + "="*50)
506
- print("SISTEMA PRONTO PARA USO!")
507
  print("="*50)
508
- print("✓ Usando huggingface_hub.InferenceClient")
509
- print(" Lembre-se: nem todos os modelos podem estar funcionais.")
510
- print(" Teste diferentes modelos se encontrar erros.")
511
 
512
  else:
513
  print("\n" + "="*50)
 
46
 
47
  # --- Gerenciamento de Sessão ---
48
  user_sessions: Dict[str, Dict[str, List | Dict]] = {}
49
+ MAX_MEMORY_LENGTH = 8 # Aumentado para ter mais contexto útil
50
 
51
  def get_session_memory_path(session_id: str) -> str:
52
  """Retorna o caminho do arquivo de memória para a sessão."""
 
85
  {"role": "user", "content": user_message, "timestamp": time.time()},
86
  {"role": "assistant", "content": assistant_response, "timestamp": time.time()}
87
  ])
88
+ # Mantém apenas as últimas conversas para evitar contexto muito longo
89
  if len(conversation) > MAX_MEMORY_LENGTH * 2:
90
  user_sessions[session_id]['conversation'] = conversation[-MAX_MEMORY_LENGTH * 2:]
91
  save_conversation_memory(session_id)
 
113
  profile['total_perguntas'] = profile.get('total_perguntas', 0) + 1
114
  user_sessions[session_id]['user_profile'] = profile
115
 
116
+ def get_conversation_messages(session_id: str) -> List[Dict]:
117
+ """
118
+ NOVA FUNÇÃO: Retorna as mensagens da conversa em formato adequado para o modelo.
119
+ Esta é a chave para resolver o problema de duplicação!
120
+ """
121
  load_conversation_memory(session_id)
122
+ conversation = user_sessions[session_id]['conversation']
123
+
124
+ # Pega apenas as últimas 6 mensagens (3 trocas) para não sobrecarregar
125
+ recent_conversation = conversation[-6:] if len(conversation) > 6 else conversation
126
+
127
+ # Converte para formato de mensagens do modelo
128
+ messages = []
129
+ for msg in recent_conversation:
130
+ # Remove metadados desnecessários das mensagens antigas
131
+ clean_content = msg['content']
132
+
133
+ # Remove a linha de informação do modelo das respostas antigas
134
+ if msg['role'] == 'assistant' and '*Resposta gerada pelo modelo:' in clean_content:
135
+ clean_content = clean_content.split('*Resposta gerada pelo modelo:')[0].strip()
136
+
137
+ messages.append({
138
+ "role": msg['role'],
139
+ "content": clean_content
140
+ })
141
+
142
+ return messages
143
 
144
  def get_user_profile_context(session_id: str) -> str:
145
+ """Gera o contexto do perfil do usuário de forma mais concisa."""
146
  load_conversation_memory(session_id)
147
  profile = user_sessions[session_id]['user_profile']
148
+
149
+ # Contexto mais conciso para não poluir o prompt
150
+ nivel = profile.get('nivel', 'intermediario')
151
+ total = profile.get('total_perguntas', 0)
152
+
153
+ context_parts = [f"Nível: {nivel}"]
154
+
155
+ # Só inclui interesses se há algum padrão significativo
156
+ interesses = [k.replace('interesse_', '').title()
157
+ for k, v in profile.items()
158
+ if k.startswith('interesse_') and v >= 2] # Só se perguntou pelo menos 2 vezes
159
+
160
  if interesses:
161
+ context_parts.append(f"Interesses: {', '.join(interesses)}")
162
+
163
+ return " | ".join(context_parts)
164
 
165
  def clear_memory(session_id: str) -> str:
166
  """Limpa a memória de uma sessão específica."""
 
247
  print("Tentando criar novo vector store...")
248
  build_and_save_vector_store()
249
 
250
+ def retrieve_context_from_blog(query: str, k: int = 3) -> str:
251
+ """Busca contexto relevante no vector store - Reduzido para evitar sobrecarga."""
252
  if vector_store:
253
  try:
254
  results = vector_store.similarity_search(query, k=k)
255
+ # Limita o tamanho do contexto para evitar tokens excessivos
256
+ context_parts = []
257
+ total_chars = 0
258
+ max_chars = 1500 # Limite de caracteres do contexto do blog
259
+
260
+ for doc in results:
261
+ if total_chars + len(doc.page_content) > max_chars:
262
+ break
263
+ context_parts.append(doc.page_content)
264
+ total_chars += len(doc.page_content)
265
+
266
+ return "\n---\n".join(context_parts)
267
  except Exception as e:
268
  print(f"Erro ao buscar contexto: {e}")
269
  return ""
 
319
  else:
320
  return False, f"Erro: {str(e)[:100]}"
321
 
322
+ def query_model(self, model_name: str, messages: List[Dict], max_tokens: int = 1500, temperature: float = 0.5) -> str:
323
+ """Faz requisição ao modelo usando chat completion - Reduzido max_tokens."""
324
  try:
325
  client = self.get_client(model_name)
326
 
 
427
 
428
  return len(MODELS)
429
 
430
+ # --- Chat Principal (VERSÃO CORRIGIDA) ---
431
  def responder_como_aldo(session_id: str, pergunta: str, modelo: str = None) -> str:
432
+ """
433
+ FUNÇÃO PRINCIPAL CORRIGIDA: Gera resposta como Dr. Aldo Henrique sem duplicação.
434
+ """
435
  if not pergunta.strip():
436
  return "Por favor, faça uma pergunta válida."
437
 
 
444
  load_conversation_memory(session_id)
445
  update_user_profile(session_id, pergunta)
446
 
447
+ # === NOVA ABORDAGEM: Monta mensagens em formato adequado ===
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
 
449
+ # 1. Obtém mensagens anteriores da conversa (já formatadas)
450
+ conversation_messages = get_conversation_messages(session_id)
451
+
452
+ # 2. Monta o system prompt (mais conciso)
453
+ perfil_info = get_user_profile_context(session_id)
454
+
455
+ system_prompt = f"""Você é o Dr. Aldo Henrique, Doutor em Ciências da Computação pela UnB (2024), professor universitário especializado em:
456
+ - Algoritmos e Estruturas de Dados
457
+ - Inteligência Artificial
458
+ - Ciência de Dados e Mineração de Dados
459
+ - Desenvolvimento de Software
460
+
461
+ Informações do usuário: {perfil_info}
462
+
463
+ Responda sempre em português, de forma didática e clara:
464
+ - Explique conceitos antes de mostrar código
465
+ - Use exemplos práticos adaptados ao nível do usuário
466
+ - Faça uma pequena observação interessante ou engraçada relacionada à pergunta
467
+ - Use Markdown para formatação
468
+ - Adicione comentários explicativos no código"""
469
 
470
+ # 3. Adiciona contexto do blog apenas se relevante (sem repetir na conversa)
471
+ blog_context = retrieve_context_from_blog(pergunta)
472
+ if blog_context:
473
+ system_prompt += f"\n\nContexto do seu blog (use apenas se relevante para a pergunta):\n{blog_context}"
474
 
475
+ # 4. Monta as mensagens finais
476
+ messages = [{"role": "system", "content": system_prompt}]
477
+
478
+ # Adiciona mensagens anteriores da conversa (sem duplicação)
479
+ messages.extend(conversation_messages)
480
+
481
+ # Adiciona a pergunta atual
482
+ messages.append({"role": "user", "content": pergunta})
483
+
484
+ # === DEBUG: Log do que está sendo enviado ===
485
+ print(f"\n=== DEBUG SESSION {session_id} ===")
486
+ print(f"Pergunta atual: {pergunta}")
487
+ print(f"Mensagens na conversa: {len(conversation_messages)}")
488
+ print(f"Total de mensagens enviadas: {len(messages)}")
489
+ print("=" * 40)
490
+
491
+ # 5. Faz requisição usando InferenceClient
492
  inference_client = HuggingFaceInferenceClient(HF_TOKEN)
493
  model_name = MODELS[modelo]
494
+ resposta = inference_client.query_model(model_name, messages, max_tokens=1200) # Reduzido
495
 
496
+ # 6. Limpa a resposta (remove possíveis repetições)
497
+ resposta_limpa = resposta.strip()
498
 
499
+ # Remove qualquer repetição óbvia da pergunta
500
+ if pergunta.lower() in resposta_limpa.lower()[:100]: # Se a pergunta aparece no início
501
+ lines = resposta_limpa.split('\n')
502
+ # Remove linhas que são muito similares à pergunta
503
+ filtered_lines = []
504
+ for line in lines:
505
+ if not (len(line.strip()) > 0 and
506
+ any(word in line.lower() for word in pergunta.lower().split() if len(word) > 3) and
507
+ len(line.strip()) < len(pergunta) * 1.5):
508
+ filtered_lines.append(line)
509
+ resposta_limpa = '\n'.join(filtered_lines).strip()
510
+
511
+ # 7. Adiciona informação sobre modelo usado (mais discreta)
512
+ resposta_final = f"{resposta_limpa}\n\n*— {modelo}*"
513
+
514
+ # 8. Salva na memória (a resposta limpa, sem a informação do modelo)
515
+ add_to_memory(session_id, pergunta, resposta_limpa)
516
+
517
+ return resposta_final
518
 
519
  # --- Inicialização ---
520
  def inicializar_sistema():
 
555
 
556
  if status:
557
  print("\n" + "="*50)
558
+ print("TESTE DO SISTEMA CORRIGIDO")
559
  print("="*50)
560
 
561
  session_id = "teste_123"
 
565
  resposta1 = responder_como_aldo(session_id, "O que é Python?")
566
  print(f"Resposta: {resposta1[:200]}...")
567
 
568
+ # Teste 2 - Pergunta relacionada (para testar memória)
569
+ print("\n2. Testando pergunta relacionada...")
570
+ resposta2 = responder_como_aldo(session_id, "Como posso começar a aprender Python?")
571
  print(f"Resposta: {resposta2[:200]}...")
572
 
573
+ # Teste 3 - Pergunta completamente diferente
574
+ print("\n3. Testando pergunta diferente...")
575
+ resposta3 = responder_como_aldo(session_id, "Explique estruturas de dados")
576
+ print(f"Resposta: {resposta3[:200]}...")
577
+
578
  # Limpeza
579
+ print(f"\n4. {clear_memory(session_id)}")
580
 
581
  print("\n" + "="*50)
582
+ print("SISTEMA CORRIGIDO PRONTO!")
583
  print("="*50)
584
+ print("✓ Memória sem duplicação implementada")
585
+ print(" Contexto otimizado para reduzir tokens")
586
+ print(" Respostas mais limpas e diretas")
587
 
588
  else:
589
  print("\n" + "="*50)