akra35567 commited on
Commit
5d0a22a
·
verified ·
1 Parent(s): fa34f3f

Update modules/treinamento.py

Browse files
Files changed (1) hide show
  1. modules/treinamento.py +199 -50
modules/treinamento.py CHANGED
@@ -6,6 +6,7 @@
6
  ✅ Detecção de padrões de conversa
7
  ✅ Compatível com STT/TTS
8
  ✅ Otimizado para produção
 
9
  """
10
 
11
  import json
@@ -54,7 +55,7 @@ class Treinamento:
54
  logger.info(f"✅ Treinamento inicializado (intervalo: {interval_hours}h)")
55
 
56
  # ========================================================================
57
- # 📝 REGISTRO DE INTERAÇÕES (ADAPTADO AO INDEX.JS)
58
  # ========================================================================
59
 
60
  def registrar_interacao(
@@ -69,7 +70,8 @@ class Treinamento:
69
  tipo_conversa: str = 'pv',
70
  tipo_mensagem: str = 'texto',
71
  reply_to_bot: bool = False,
72
- reply_metadata: Optional[Dict] = None
 
73
  ):
74
  """
75
  Registra interação para treinamento - TOTALMENTE COMPATÍVEL
@@ -86,6 +88,7 @@ class Treinamento:
86
  tipo_mensagem: 'texto', 'audio', etc
87
  reply_to_bot: Se é reply ao bot
88
  reply_metadata: Metadata do reply (do index.js)
 
89
  """
90
  try:
91
  numero = str(numero).strip()
@@ -98,11 +101,14 @@ class Treinamento:
98
  if reply_metadata and reply_metadata.get('reply_to_bot') is not None:
99
  reply_to_bot = reply_metadata.get('reply_to_bot', False)
100
 
 
 
 
101
  # Determina emoção e qualidade
102
  emocao_detectada, confianca_emocao = self._detectar_emocao(mensagem)
103
  qualidade = self._calcular_qualidade_resposta(mensagem, resposta, tipo_mensagem)
104
 
105
- # Salva no banco usando método CORRETO
106
  self.db.salvar_mensagem(
107
  usuario=usuario,
108
  mensagem=mensagem,
@@ -115,12 +121,25 @@ class Treinamento:
115
  modo_resposta=contexto.get('modo_resposta', 'normal_ironico'),
116
  emocao_detectada=emocao_detectada,
117
  confianca_emocao=confianca_emocao,
 
 
118
  tipo_mensagem=tipo_mensagem,
119
  usuario_nome=usuario,
120
  tipo_conversa=tipo_conversa,
121
  reply_info_json=json.dumps(reply_metadata) if reply_metadata else None
122
  )
123
 
 
 
 
 
 
 
 
 
 
 
 
124
  # Adiciona ao dataset se qualidade boa
125
  if qualidade >= QUALIDADE_MINIMA:
126
  self._adicionar_ao_dataset(
@@ -136,16 +155,18 @@ class Treinamento:
136
  tipo_conversa=tipo_conversa,
137
  is_reply=is_reply,
138
  reply_to_bot=reply_to_bot,
139
- reply_metadata=reply_metadata
 
140
  )
141
 
142
- # Salva exemplo de treinamento
143
  if tipo_mensagem == 'texto' and len(resposta) > 10:
144
  self.db.salvar_training_example(
145
  input_text=mensagem,
146
  output_text=resposta,
147
  humor=contexto.get('humor_atualizado', 'normal_ironico'),
148
  modo_resposta=contexto.get('modo_resposta', 'normal_ironico'),
 
149
  emocao_contexto=emocao_detectada,
150
  qualidade_score=qualidade,
151
  contexto_super_claro={
@@ -153,10 +174,26 @@ class Treinamento:
153
  'reply_to_bot': reply_to_bot,
154
  'tipo_conversa': tipo_conversa,
155
  'tipo_mensagem': tipo_mensagem,
156
- 'reply_metadata': reply_metadata
 
 
157
  }
158
  )
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  # Analisa padrões
161
  self._analisar_padroes_usuario(
162
  numero=numero,
@@ -168,10 +205,11 @@ class Treinamento:
168
  tipo_conversa=tipo_conversa,
169
  is_reply=is_reply,
170
  reply_to_bot=reply_to_bot,
171
- reply_metadata=reply_metadata
 
172
  )
173
 
174
- logger.debug(f"✅ Interação registrada: {usuario[:10]} | reply: {is_reply} | reply_to_bot: {reply_to_bot}")
175
 
176
  except Exception as e:
177
  logger.error(f"❌ Erro ao registrar interação: {e}")
@@ -258,7 +296,7 @@ class Treinamento:
258
  return round(qualidade, 2)
259
 
260
  # ========================================================================
261
- # 💾 ADICIONAR AO DATASET
262
  # ========================================================================
263
 
264
  def _adicionar_ao_dataset(
@@ -275,10 +313,11 @@ class Treinamento:
275
  tipo_conversa: str,
276
  is_reply: bool,
277
  reply_to_bot: bool,
278
- reply_metadata: Optional[Dict] = None
 
279
  ):
280
  """
281
- Adiciona exemplo ao dataset de treinamento
282
 
283
  Args:
284
  mensagem: Mensagem do usuário
@@ -294,6 +333,7 @@ class Treinamento:
294
  is_reply: Se é reply
295
  reply_to_bot: Se é reply ao bot
296
  reply_metadata: Metadata do reply
 
297
  """
298
  try:
299
  humor = contexto.get("humor_atualizado", "normal_ironico")
@@ -312,12 +352,13 @@ class Treinamento:
312
  if modo == "casual_amigavel":
313
  modo = "normal_ironico"
314
 
315
- # Prepara metadados com reply_metadata
316
  metadata = {
317
  "usuario": usuario[:20],
318
  "numero_hash": hashlib.md5(numero.encode()).hexdigest()[:8],
319
  "humor": humor,
320
  "modo_resposta": modo,
 
321
  "emocao_detectada": emocao_detectada,
322
  "confianca_emocao": confianca_emocao,
323
  "qualidade_score": qualidade,
@@ -337,6 +378,15 @@ class Treinamento:
337
  "reply_metadata_context": reply_metadata.get('context_hint', '')
338
  })
339
 
 
 
 
 
 
 
 
 
 
340
  entry = {
341
  "input": mensagem.strip(),
342
  "output": resposta.strip(),
@@ -369,13 +419,13 @@ class Treinamento:
369
  with open(DATASET_PATH, "w", encoding="utf-8") as f:
370
  json.dump(dataset, f, ensure_ascii=False, indent=2)
371
 
372
- logger.debug(f"✅ Exemplo adicionado ao dataset | qualidade: {qualidade:.2f}")
373
 
374
  except Exception as e:
375
  logger.warning(f"⚠️ Erro ao adicionar ao dataset: {e}")
376
 
377
  # ========================================================================
378
- # 🔍 ANÁLISE DE PADRÕES
379
  # ========================================================================
380
 
381
  def _analisar_padroes_usuario(
@@ -389,10 +439,11 @@ class Treinamento:
389
  tipo_conversa: str,
390
  is_reply: bool,
391
  reply_to_bot: bool,
392
- reply_metadata: Optional[Dict] = None
 
393
  ):
394
  """
395
- Analisa padrões de comunicação do usuário
396
 
397
  Args:
398
  numero: Número do usuário
@@ -405,6 +456,7 @@ class Treinamento:
405
  is_reply: Se é reply
406
  reply_to_bot: Se é reply ao bot
407
  reply_metadata: Metadata do reply
 
408
  """
409
  try:
410
  # 1. REGISTRAR TOM
@@ -425,22 +477,25 @@ class Treinamento:
425
  except Exception as e:
426
  logger.warning(f"Erro ao salvar gíria: {e}")
427
 
428
- # 3. REGISTRAR HUMOR
429
  if "humor_atualizado" in contexto:
430
  humor = contexto["humor_atualizado"]
431
  humor_atual = self.db.recuperar_humor_atual(numero)
432
- if humor != humor_atual:
 
 
433
  self.db.salvar_transicao_humor(
434
  numero=numero,
435
  humor_anterior=humor_atual,
436
  humor_novo=humor,
 
 
437
  emocao_trigger=emocao_detectada,
438
  confianca_emocao=contexto.get('confianca_emocao', 0.5),
439
- nivel_transicao=contexto.get('nivel_transicao', 0),
440
- razao=f"Interação {tipo_conversa}"
441
  )
442
 
443
- # 4. APRENDER PADRÕES DE REPLY
444
  if is_reply:
445
  self._aprender_padrao_reply(
446
  numero=numero,
@@ -449,7 +504,18 @@ class Treinamento:
449
  resposta=resposta,
450
  reply_to_bot=reply_to_bot,
451
  tipo_conversa=tipo_conversa,
452
- reply_metadata=reply_metadata
 
 
 
 
 
 
 
 
 
 
 
453
  )
454
 
455
  except Exception as e:
@@ -525,10 +591,11 @@ class Treinamento:
525
  resposta: str,
526
  reply_to_bot: bool,
527
  tipo_conversa: str,
528
- reply_metadata: Optional[Dict] = None
 
529
  ):
530
  """
531
- Aprende padrões de reply
532
 
533
  Args:
534
  numero: Número do usuário
@@ -538,6 +605,7 @@ class Treinamento:
538
  reply_to_bot: Se é reply ao bot
539
  tipo_conversa: Tipo da conversa
540
  reply_metadata: Metadata do reply
 
541
  """
542
  try:
543
  # Define padrão com base no reply_metadata
@@ -561,10 +629,13 @@ class Treinamento:
561
  tipo = "conversa_alheia"
562
  contexto_extra = ""
563
 
 
 
 
564
  # Prepara texto com contexto
565
- input_text_com_contexto = f"[CONTEXTO: {padrao.upper()}] {contexto_extra} {mensagem}"
566
 
567
- # Salva aprendizado
568
  self.db.salvar_aprendizado_detalhado(
569
  input_text=input_text_com_contexto,
570
  output_text=resposta,
@@ -575,17 +646,64 @@ class Treinamento:
575
  'reply_to_bot': reply_to_bot,
576
  'tipo_conversa': tipo_conversa,
577
  'tipo': tipo,
578
- 'reply_metadata': reply_metadata
 
579
  },
580
  qualidade_score=0.8,
581
- tipo_aprendizado=f"reply_{tipo}"
582
  )
583
 
584
- logger.debug(f"��� Padrão de reply aprendido: {padrao}")
585
 
586
  except Exception as e:
587
  logger.warning(f"⚠️ Erro ao aprender padrão de reply: {e}")
588
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
  # ========================================================================
590
  # 🔄 TREINAMENTO PERIÓDICO
591
  # ========================================================================
@@ -636,7 +754,7 @@ class Treinamento:
636
  logger.warning("⚠️ Nenhum exemplo com qualidade suficiente")
637
  return
638
 
639
- # Gera arquivo JSONL
640
  with open("training_dataset_akira_v21.jsonl", "w", encoding="utf-8") as f:
641
  for ex in exemplos[:500]:
642
  if ex.get("score", 0) >= 0.7:
@@ -645,6 +763,7 @@ class Treinamento:
645
  "output": ex.get("output", ""),
646
  "humor": ex.get("humor", "normal_ironico"),
647
  "modo": ex.get("modo", "normal_ironico"),
 
648
  "metadata": {
649
  "score": ex.get("score", 0.5),
650
  "timestamp": time.time(),
@@ -652,7 +771,7 @@ class Treinamento:
652
  }
653
  }, ensure_ascii=False) + "\n")
654
 
655
- logger.info(f"✅ Dataset gerado: {len(exemplos)} exemplos")
656
  self.db.marcar_examples_como_usados()
657
 
658
  except Exception as e:
@@ -667,7 +786,7 @@ class Treinamento:
667
  with open(DATASET_PATH, "r", encoding="utf-8") as f:
668
  dataset = json.load(f)
669
 
670
- # Análise estatística
671
  padroes = {
672
  "total": len(dataset),
673
  "reply_to_bot": 0,
@@ -676,7 +795,11 @@ class Treinamento:
676
  "grupo": 0,
677
  "pv": 0,
678
  "audio": 0,
679
- "texto": 0
 
 
 
 
680
  }
681
 
682
  for e in dataset:
@@ -698,6 +821,17 @@ class Treinamento:
698
  padroes["audio"] += 1
699
  else:
700
  padroes["texto"] += 1
 
 
 
 
 
 
 
 
 
 
 
701
 
702
  # Log estatísticas
703
  logger.info(f"📊 Estatísticas do dataset:")
@@ -707,6 +841,7 @@ class Treinamento:
707
  logger.info(f" Com reply_metadata: {padroes['reply_with_metadata']}")
708
  logger.info(f" Grupo: {padroes['grupo']} | PV: {padroes['pv']}")
709
  logger.info(f" Áudio: {padroes['audio']} | Texto: {padroes['texto']}")
 
710
 
711
  except Exception as e:
712
  logger.error(f"❌ Erro na análise global: {e}")
@@ -721,12 +856,12 @@ class Treinamento:
721
  logger.warning(f"⚠️ Erro na otimização: {e}")
722
 
723
  # ========================================================================
724
- # 🔧 FUNÇÃO PARA USO DIRETO DA API
725
  # ========================================================================
726
 
727
  def processar_interacao_api(self, payload: Dict, resposta: str) -> Dict:
728
  """
729
- Processa interação da API para treinamento
730
 
731
  Args:
732
  payload: Payload da requisição
@@ -753,10 +888,11 @@ class Treinamento:
753
 
754
  is_reply = bool(payload.get('mensagem_citada')) or bool(reply_metadata)
755
 
756
- # Contexto da análise
757
  contexto_analise = payload.get('analise', {})
 
758
 
759
- # Registra interação
760
  self.registrar_interacao(
761
  usuario=usuario,
762
  mensagem=mensagem,
@@ -768,13 +904,15 @@ class Treinamento:
768
  tipo_conversa=tipo_conversa,
769
  tipo_mensagem=tipo_mensagem,
770
  reply_to_bot=reply_to_bot,
771
- reply_metadata=reply_metadata
 
772
  )
773
 
774
  return {
775
  'status': 'success',
776
  'message': 'Interação registrada',
777
  'usuario': usuario,
 
778
  'timestamp': time.time()
779
  }
780
 
@@ -809,7 +947,7 @@ def get_treinamento_instance(db: Database = None):
809
  return _treinamento_instance
810
 
811
  # ============================================================================
812
- # 🎯 FUNÇÃO DE INTEGRAÇÃO RÁPIDA
813
  # ============================================================================
814
  def registrar_interacao_rapida(
815
  usuario: str,
@@ -821,10 +959,11 @@ def registrar_interacao_rapida(
821
  tipo_conversa: str = 'pv',
822
  tipo_mensagem: str = 'texto',
823
  contexto: Dict = None,
824
- reply_metadata: Optional[Dict] = None
 
825
  ) -> bool:
826
  """
827
- Registra interação rapidamente
828
 
829
  Args:
830
  usuario: Nome do usuário
@@ -837,6 +976,7 @@ def registrar_interacao_rapida(
837
  tipo_mensagem: Tipo da mensagem
838
  contexto: Contexto da conversa
839
  reply_metadata: Metadata do reply
 
840
 
841
  Returns:
842
  True se sucesso, False caso contrário
@@ -853,9 +993,10 @@ def registrar_interacao_rapida(
853
  tipo_conversa=tipo_conversa,
854
  tipo_mensagem=tipo_mensagem,
855
  contexto=contexto,
856
- reply_metadata=reply_metadata
 
857
  )
858
- logger.debug(f"✅ Interação rápida registrada: {usuario[:10]}")
859
  return True
860
  except Exception as e:
861
  logger.error(f"❌ Erro no registro rápido: {e}")
@@ -866,7 +1007,7 @@ def registrar_interacao_rapida(
866
  # ============================================================================
867
  if __name__ == "__main__":
868
  print("=" * 80)
869
- print("TESTANDO TREINAMENTO.PY - CORRIGIDO E COMPLETO")
870
  print("=" * 80)
871
 
872
  from .database import Database
@@ -876,7 +1017,7 @@ if __name__ == "__main__":
876
  db = Database(":memory:")
877
  treinamento = Treinamento(db)
878
 
879
- # Simula payload do api.py com reply_metadata
880
  payload_teste = {
881
  "usuario": "Isaac Teste",
882
  "numero": "244978787009",
@@ -891,20 +1032,27 @@ if __name__ == "__main__":
891
  },
892
  "analise": {
893
  "humor_atualizado": "normal_ironico",
894
- "modo_resposta": "normal_ironico"
 
 
 
 
 
 
895
  }
896
  }
897
 
898
  resposta_teste = "Tudo e tu, puto?"
899
 
900
- # Processa interação
901
  resultado = treinamento.processar_interacao_api(payload_teste, resposta_teste)
902
 
903
  print(f"✅ Teste OK: {resultado}")
904
  print(f"📝 Mensagem: {payload_teste['mensagem']}")
905
  print(f"💬 Resposta: {resposta_teste}")
 
906
 
907
- # Teste com registro rápido
908
  sucesso = registrar_interacao_rapida(
909
  usuario="Teste 2",
910
  numero="244000000000",
@@ -912,7 +1060,8 @@ if __name__ == "__main__":
912
  resposta="Nada, cota.",
913
  is_reply=True,
914
  reply_to_bot=True,
915
- reply_metadata={"quoted_author_name": "Akira", "is_reply": True}
 
916
  )
917
 
918
  print(f"✅ Registro rápido: {'Sucesso' if sucesso else 'Falhou'}")
@@ -923,5 +1072,5 @@ if __name__ == "__main__":
923
  traceback.print_exc()
924
 
925
  print("\n" + "=" * 80)
926
- print("TREINAMENTO.PY - COMPLETO E PRONTO PARA USO")
927
  print("=" * 80)
 
6
  ✅ Detecção de padrões de conversa
7
  ✅ Compatível com STT/TTS
8
  ✅ Otimizado para produção
9
+ ✅ CORREÇÃO: Suporte para nivel_transicao adicionado
10
  """
11
 
12
  import json
 
55
  logger.info(f"✅ Treinamento inicializado (intervalo: {interval_hours}h)")
56
 
57
  # ========================================================================
58
+ # 📝 REGISTRO DE INTERAÇÕES (ADAPTADO AO INDEX.JS) - CORRIGIDO
59
  # ========================================================================
60
 
61
  def registrar_interacao(
 
70
  tipo_conversa: str = 'pv',
71
  tipo_mensagem: str = 'texto',
72
  reply_to_bot: bool = False,
73
+ reply_metadata: Optional[Dict] = None,
74
+ nivel_transicao: int = 0 # NOVO PARÂMETRO ADICIONADO
75
  ):
76
  """
77
  Registra interação para treinamento - TOTALMENTE COMPATÍVEL
 
88
  tipo_mensagem: 'texto', 'audio', etc
89
  reply_to_bot: Se é reply ao bot
90
  reply_metadata: Metadata do reply (do index.js)
91
+ nivel_transicao: Nível de transição do usuário privilegiado
92
  """
93
  try:
94
  numero = str(numero).strip()
 
101
  if reply_metadata and reply_metadata.get('reply_to_bot') is not None:
102
  reply_to_bot = reply_metadata.get('reply_to_bot', False)
103
 
104
+ # Extrai info_transicao do contexto
105
+ info_transicao = contexto.get('info_transicao', {})
106
+
107
  # Determina emoção e qualidade
108
  emocao_detectada, confianca_emocao = self._detectar_emocao(mensagem)
109
  qualidade = self._calcular_qualidade_resposta(mensagem, resposta, tipo_mensagem)
110
 
111
+ # Salva no banco usando método CORRETO com nivel_transicao
112
  self.db.salvar_mensagem(
113
  usuario=usuario,
114
  mensagem=mensagem,
 
121
  modo_resposta=contexto.get('modo_resposta', 'normal_ironico'),
122
  emocao_detectada=emocao_detectada,
123
  confianca_emocao=confianca_emocao,
124
+ nivel_transicao=nivel_transicao, # PARÂMETRO ADICIONADO
125
+ info_transicao=info_transicao, # INFO DE TRANSIÇÃO
126
  tipo_mensagem=tipo_mensagem,
127
  usuario_nome=usuario,
128
  tipo_conversa=tipo_conversa,
129
  reply_info_json=json.dumps(reply_metadata) if reply_metadata else None
130
  )
131
 
132
+ # Atualiza contexto com nivel_transicao
133
+ self.db.atualizar_contexto(
134
+ numero=numero,
135
+ humor_atual=contexto.get('humor_atualizado', 'normal_ironico'),
136
+ modo_resposta=contexto.get('modo_resposta', 'normal_ironico'),
137
+ nivel_transicao=nivel_transicao,
138
+ info_transicao=info_transicao,
139
+ tom=contexto.get('tom', 'normal'),
140
+ emocao_tendencia=emocao_detectada
141
+ )
142
+
143
  # Adiciona ao dataset se qualidade boa
144
  if qualidade >= QUALIDADE_MINIMA:
145
  self._adicionar_ao_dataset(
 
155
  tipo_conversa=tipo_conversa,
156
  is_reply=is_reply,
157
  reply_to_bot=reply_to_bot,
158
+ reply_metadata=reply_metadata,
159
+ nivel_transicao=nivel_transicao # ADICIONADO
160
  )
161
 
162
+ # Salva exemplo de treinamento com nivel_transicao
163
  if tipo_mensagem == 'texto' and len(resposta) > 10:
164
  self.db.salvar_training_example(
165
  input_text=mensagem,
166
  output_text=resposta,
167
  humor=contexto.get('humor_atualizado', 'normal_ironico'),
168
  modo_resposta=contexto.get('modo_resposta', 'normal_ironico'),
169
+ nivel_transicao=nivel_transicao, # ADICIONADO
170
  emocao_contexto=emocao_detectada,
171
  qualidade_score=qualidade,
172
  contexto_super_claro={
 
174
  'reply_to_bot': reply_to_bot,
175
  'tipo_conversa': tipo_conversa,
176
  'tipo_mensagem': tipo_mensagem,
177
+ 'reply_metadata': reply_metadata,
178
+ 'nivel_transicao': nivel_transicao,
179
+ 'info_transicao': info_transicao
180
  }
181
  )
182
 
183
+ # Registra interação para treinamento
184
+ self.db.registrar_interacao(
185
+ numero=numero,
186
+ mensagem=mensagem,
187
+ resposta=resposta,
188
+ humor=contexto.get('humor_atualizado', 'normal_ironico'),
189
+ modo_resposta=contexto.get('modo_resposta', 'normal_ironico'),
190
+ nivel_transicao=nivel_transicao, # PARÂMETRO ADICIONADO
191
+ emocao_detectada=emocao_detectada,
192
+ tipo_conversa=tipo_conversa,
193
+ reply_info_json=json.dumps(reply_metadata) if reply_metadata else None,
194
+ qualidade_score=qualidade
195
+ )
196
+
197
  # Analisa padrões
198
  self._analisar_padroes_usuario(
199
  numero=numero,
 
205
  tipo_conversa=tipo_conversa,
206
  is_reply=is_reply,
207
  reply_to_bot=reply_to_bot,
208
+ reply_metadata=reply_metadata,
209
+ nivel_transicao=nivel_transicao # ADICIONADO
210
  )
211
 
212
+ logger.debug(f"✅ Interação registrada: {usuario[:10]} | Nível: {nivel_transicao} | reply: {is_reply}")
213
 
214
  except Exception as e:
215
  logger.error(f"❌ Erro ao registrar interação: {e}")
 
296
  return round(qualidade, 2)
297
 
298
  # ========================================================================
299
+ # 💾 ADICIONAR AO DATASET (ATUALIZADO)
300
  # ========================================================================
301
 
302
  def _adicionar_ao_dataset(
 
313
  tipo_conversa: str,
314
  is_reply: bool,
315
  reply_to_bot: bool,
316
+ reply_metadata: Optional[Dict] = None,
317
+ nivel_transicao: int = 0 # NOVO PARÂMETRO
318
  ):
319
  """
320
+ Adiciona exemplo ao dataset de treinamento - ATUALIZADO
321
 
322
  Args:
323
  mensagem: Mensagem do usuário
 
333
  is_reply: Se é reply
334
  reply_to_bot: Se é reply ao bot
335
  reply_metadata: Metadata do reply
336
+ nivel_transicao: Nível de transição do usuário
337
  """
338
  try:
339
  humor = contexto.get("humor_atualizado", "normal_ironico")
 
352
  if modo == "casual_amigavel":
353
  modo = "normal_ironico"
354
 
355
+ # Prepara metadados com reply_metadata e nivel_transicao
356
  metadata = {
357
  "usuario": usuario[:20],
358
  "numero_hash": hashlib.md5(numero.encode()).hexdigest()[:8],
359
  "humor": humor,
360
  "modo_resposta": modo,
361
+ "nivel_transicao": nivel_transicao, # ADICIONADO
362
  "emocao_detectada": emocao_detectada,
363
  "confianca_emocao": confianca_emocao,
364
  "qualidade_score": qualidade,
 
378
  "reply_metadata_context": reply_metadata.get('context_hint', '')
379
  })
380
 
381
+ # Adiciona info_transicao se disponível
382
+ info_transicao = contexto.get('info_transicao', {})
383
+ if info_transicao:
384
+ metadata.update({
385
+ "info_transicao_desc": info_transicao.get('desc', ''),
386
+ "info_transicao_modo": info_transicao.get('modo', ''),
387
+ "info_transicao_deve_transicionar": info_transicao.get('deve_transicionar', False)
388
+ })
389
+
390
  entry = {
391
  "input": mensagem.strip(),
392
  "output": resposta.strip(),
 
419
  with open(DATASET_PATH, "w", encoding="utf-8") as f:
420
  json.dump(dataset, f, ensure_ascii=False, indent=2)
421
 
422
+ logger.debug(f"✅ Exemplo adicionado ao dataset | nível: {nivel_transicao} | qualidade: {qualidade:.2f}")
423
 
424
  except Exception as e:
425
  logger.warning(f"⚠️ Erro ao adicionar ao dataset: {e}")
426
 
427
  # ========================================================================
428
+ # 🔍 ANÁLISE DE PADRÕES (ATUALIZADA)
429
  # ========================================================================
430
 
431
  def _analisar_padroes_usuario(
 
439
  tipo_conversa: str,
440
  is_reply: bool,
441
  reply_to_bot: bool,
442
+ reply_metadata: Optional[Dict] = None,
443
+ nivel_transicao: int = 0 # NOVO PARÂMETRO
444
  ):
445
  """
446
+ Analisa padrões de comunicação do usuário - ATUALIZADA
447
 
448
  Args:
449
  numero: Número do usuário
 
456
  is_reply: Se é reply
457
  reply_to_bot: Se é reply ao bot
458
  reply_metadata: Metadata do reply
459
+ nivel_transicao: Nível de transição do usuário
460
  """
461
  try:
462
  # 1. REGISTRAR TOM
 
477
  except Exception as e:
478
  logger.warning(f"Erro ao salvar gíria: {e}")
479
 
480
+ # 3. REGISTRAR TRANSIÇÃO DE HUMOR COM nivel_transicao
481
  if "humor_atualizado" in contexto:
482
  humor = contexto["humor_atualizado"]
483
  humor_atual = self.db.recuperar_humor_atual(numero)
484
+ nivel_atual = self.db.recuperar_nivel_transicao(numero)
485
+
486
+ if humor != humor_atual or nivel_transicao != nivel_atual:
487
  self.db.salvar_transicao_humor(
488
  numero=numero,
489
  humor_anterior=humor_atual,
490
  humor_novo=humor,
491
+ nivel_transicao_anterior=nivel_atual,
492
+ nivel_transicao_novo=nivel_transicao,
493
  emocao_trigger=emocao_detectada,
494
  confianca_emocao=contexto.get('confianca_emocao', 0.5),
495
+ razao=f"Transição nível {nivel_atual}→{nivel_transicao} | {tipo_conversa}"
 
496
  )
497
 
498
+ # 4. APRENDER PADRÕES DE REPLY COM nivel_transicao
499
  if is_reply:
500
  self._aprender_padrao_reply(
501
  numero=numero,
 
504
  resposta=resposta,
505
  reply_to_bot=reply_to_bot,
506
  tipo_conversa=tipo_conversa,
507
+ reply_metadata=reply_metadata,
508
+ nivel_transicao=nivel_transicao # ADICIONADO
509
+ )
510
+
511
+ # 5. ANALISAR TRANSIÇÕES DE USUÁRIOS PRIVILEGIADOS
512
+ if nivel_transicao > 0:
513
+ self._analisar_transicao_privilegiado(
514
+ numero=numero,
515
+ usuario=usuario,
516
+ nivel_transicao=nivel_transicao,
517
+ mensagem=mensagem,
518
+ contexto=contexto
519
  )
520
 
521
  except Exception as e:
 
591
  resposta: str,
592
  reply_to_bot: bool,
593
  tipo_conversa: str,
594
+ reply_metadata: Optional[Dict] = None,
595
+ nivel_transicao: int = 0 # NOVO PARÂMETRO
596
  ):
597
  """
598
+ Aprende padrões de reply - ATUALIZADO
599
 
600
  Args:
601
  numero: Número do usuário
 
605
  reply_to_bot: Se é reply ao bot
606
  tipo_conversa: Tipo da conversa
607
  reply_metadata: Metadata do reply
608
+ nivel_transicao: Nível de transição do usuário
609
  """
610
  try:
611
  # Define padrão com base no reply_metadata
 
629
  tipo = "conversa_alheia"
630
  contexto_extra = ""
631
 
632
+ # Adiciona info de transição se disponível
633
+ transicao_info = f"[Nível transição: {nivel_transicao}]" if nivel_transicao > 0 else ""
634
+
635
  # Prepara texto com contexto
636
+ input_text_com_contexto = f"[CONTEXTO: {padrao.upper()}] {transicao_info} {contexto_extra} {mensagem}"
637
 
638
+ # Salva aprendizado com nivel_transicao
639
  self.db.salvar_aprendizado_detalhado(
640
  input_text=input_text_com_contexto,
641
  output_text=resposta,
 
646
  'reply_to_bot': reply_to_bot,
647
  'tipo_conversa': tipo_conversa,
648
  'tipo': tipo,
649
+ 'reply_metadata': reply_metadata,
650
+ 'nivel_transicao': nivel_transicao # ADICIONADO
651
  },
652
  qualidade_score=0.8,
653
+ tipo_aprendizado=f"reply_{tipo}_nivel_{nivel_transicao}"
654
  )
655
 
656
+ logger.debug(f" Padrão de reply aprendido: {padrao} | Nível: {nivel_transicao}")
657
 
658
  except Exception as e:
659
  logger.warning(f"⚠️ Erro ao aprender padrão de reply: {e}")
660
 
661
+ def _analisar_transicao_privilegiado(
662
+ self,
663
+ numero: str,
664
+ usuario: str,
665
+ nivel_transicao: int,
666
+ mensagem: str,
667
+ contexto: Dict
668
+ ):
669
+ """
670
+ Analisa transições de usuários privilegiados
671
+
672
+ Args:
673
+ numero: Número do usuário
674
+ usuario: Nome do usuário
675
+ nivel_transicao: Nível atual de transição
676
+ mensagem: Mensagem enviada
677
+ contexto: Contexto da conversa
678
+ """
679
+ try:
680
+ # Recupera histórico de transições
681
+ transicoes = self.db._execute_with_retry(
682
+ """
683
+ SELECT nivel_transicao_anterior, nivel_transicao_novo, timestamp, razao
684
+ FROM transicoes_humor
685
+ WHERE numero = ?
686
+ ORDER BY timestamp DESC
687
+ LIMIT 10
688
+ """,
689
+ (numero,),
690
+ fetch=True
691
+ )
692
+
693
+ # Analisa padrão de transição
694
+ if len(transicoes) >= 3:
695
+ niveis = [t[1] for t in transicoes] # Últimos níveis novos
696
+ mudancas = sum(1 for i in range(len(niveis)-1) if niveis[i] != niveis[i+1])
697
+
698
+ # Se muitas mudanças, usuário é volátil
699
+ if mudancas >= 2:
700
+ logger.info(f"⚠️ Usuário {usuario} é volátil em transições: {mudancas} mudanças")
701
+
702
+ logger.debug(f"📊 Transição privilegiado: {usuario} → Nível {nivel_transicao}")
703
+
704
+ except Exception as e:
705
+ logger.warning(f"⚠️ Erro na análise de transição: {e}")
706
+
707
  # ========================================================================
708
  # 🔄 TREINAMENTO PERIÓDICO
709
  # ========================================================================
 
754
  logger.warning("⚠️ Nenhum exemplo com qualidade suficiente")
755
  return
756
 
757
+ # Gera arquivo JSONL com nivel_transicao
758
  with open("training_dataset_akira_v21.jsonl", "w", encoding="utf-8") as f:
759
  for ex in exemplos[:500]:
760
  if ex.get("score", 0) >= 0.7:
 
763
  "output": ex.get("output", ""),
764
  "humor": ex.get("humor", "normal_ironico"),
765
  "modo": ex.get("modo", "normal_ironico"),
766
+ "nivel_transicao": ex.get("nivel_transicao", 0), # ADICIONADO
767
  "metadata": {
768
  "score": ex.get("score", 0.5),
769
  "timestamp": time.time(),
 
771
  }
772
  }, ensure_ascii=False) + "\n")
773
 
774
+ logger.info(f"✅ Dataset gerado: {len(exemplos)} exemplos (com nível transição)")
775
  self.db.marcar_examples_como_usados()
776
 
777
  except Exception as e:
 
786
  with open(DATASET_PATH, "r", encoding="utf-8") as f:
787
  dataset = json.load(f)
788
 
789
+ # Análise estatística com nivel_transicao
790
  padroes = {
791
  "total": len(dataset),
792
  "reply_to_bot": 0,
 
795
  "grupo": 0,
796
  "pv": 0,
797
  "audio": 0,
798
+ "texto": 0,
799
+ "transicao_nivel_0": 0,
800
+ "transicao_nivel_1": 0,
801
+ "transicao_nivel_2": 0,
802
+ "transicao_nivel_3": 0
803
  }
804
 
805
  for e in dataset:
 
821
  padroes["audio"] += 1
822
  else:
823
  padroes["texto"] += 1
824
+
825
+ # Analisa nível de transição
826
+ nivel = meta.get("nivel_transicao", 0)
827
+ if nivel == 0:
828
+ padroes["transicao_nivel_0"] += 1
829
+ elif nivel == 1:
830
+ padroes["transicao_nivel_1"] += 1
831
+ elif nivel == 2:
832
+ padroes["transicao_nivel_2"] += 1
833
+ elif nivel == 3:
834
+ padroes["transicao_nivel_3"] += 1
835
 
836
  # Log estatísticas
837
  logger.info(f"📊 Estatísticas do dataset:")
 
841
  logger.info(f" Com reply_metadata: {padroes['reply_with_metadata']}")
842
  logger.info(f" Grupo: {padroes['grupo']} | PV: {padroes['pv']}")
843
  logger.info(f" Áudio: {padroes['audio']} | Texto: {padroes['texto']}")
844
+ logger.info(f" Níveis transição: 0={padroes['transicao_nivel_0']} | 1={padroes['transicao_nivel_1']} | 2={padroes['transicao_nivel_2']} | 3={padroes['transicao_nivel_3']}")
845
 
846
  except Exception as e:
847
  logger.error(f"❌ Erro na análise global: {e}")
 
856
  logger.warning(f"⚠️ Erro na otimização: {e}")
857
 
858
  # ========================================================================
859
+ # 🔧 FUNÇÃO PARA USO DIRETO DA API (ATUALIZADA)
860
  # ========================================================================
861
 
862
  def processar_interacao_api(self, payload: Dict, resposta: str) -> Dict:
863
  """
864
+ Processa interação da API para treinamento - ATUALIZADA
865
 
866
  Args:
867
  payload: Payload da requisição
 
888
 
889
  is_reply = bool(payload.get('mensagem_citada')) or bool(reply_metadata)
890
 
891
+ # Contexto da análise com nivel_transicao
892
  contexto_analise = payload.get('analise', {})
893
+ nivel_transicao = contexto_analise.get('nivel_transicao', 0)
894
 
895
+ # Registra interação com nivel_transicao
896
  self.registrar_interacao(
897
  usuario=usuario,
898
  mensagem=mensagem,
 
904
  tipo_conversa=tipo_conversa,
905
  tipo_mensagem=tipo_mensagem,
906
  reply_to_bot=reply_to_bot,
907
+ reply_metadata=reply_metadata,
908
+ nivel_transicao=nivel_transicao # ADICIONADO
909
  )
910
 
911
  return {
912
  'status': 'success',
913
  'message': 'Interação registrada',
914
  'usuario': usuario,
915
+ 'nivel_transicao': nivel_transicao,
916
  'timestamp': time.time()
917
  }
918
 
 
947
  return _treinamento_instance
948
 
949
  # ============================================================================
950
+ # 🎯 FUNÇÃO DE INTEGRAÇÃO RÁPIDA (ATUALIZADA)
951
  # ============================================================================
952
  def registrar_interacao_rapida(
953
  usuario: str,
 
959
  tipo_conversa: str = 'pv',
960
  tipo_mensagem: str = 'texto',
961
  contexto: Dict = None,
962
+ reply_metadata: Optional[Dict] = None,
963
+ nivel_transicao: int = 0 # NOVO PARÂMETRO
964
  ) -> bool:
965
  """
966
+ Registra interação rapidamente - ATUALIZADA
967
 
968
  Args:
969
  usuario: Nome do usuário
 
976
  tipo_mensagem: Tipo da mensagem
977
  contexto: Contexto da conversa
978
  reply_metadata: Metadata do reply
979
+ nivel_transicao: Nível de transição do usuário
980
 
981
  Returns:
982
  True se sucesso, False caso contrário
 
993
  tipo_conversa=tipo_conversa,
994
  tipo_mensagem=tipo_mensagem,
995
  contexto=contexto,
996
+ reply_metadata=reply_metadata,
997
+ nivel_transicao=nivel_transicao # ADICIONADO
998
  )
999
+ logger.debug(f"✅ Interação rápida registrada: {usuario[:10]} | Nível: {nivel_transicao}")
1000
  return True
1001
  except Exception as e:
1002
  logger.error(f"❌ Erro no registro rápido: {e}")
 
1007
  # ============================================================================
1008
  if __name__ == "__main__":
1009
  print("=" * 80)
1010
+ print("TESTANDO TREINAMENTO.PY - COMPLETO COM nivel_transicao")
1011
  print("=" * 80)
1012
 
1013
  from .database import Database
 
1017
  db = Database(":memory:")
1018
  treinamento = Treinamento(db)
1019
 
1020
+ # Simula payload do api.py com reply_metadata e nivel_transicao
1021
  payload_teste = {
1022
  "usuario": "Isaac Teste",
1023
  "numero": "244978787009",
 
1032
  },
1033
  "analise": {
1034
  "humor_atualizado": "normal_ironico",
1035
+ "modo_resposta": "normal_ironico",
1036
+ "nivel_transicao": 2,
1037
+ "info_transicao": {
1038
+ "desc": "Nível 2 - Formal Relaxado",
1039
+ "modo": "tecnico_formal",
1040
+ "deve_transicionar": False
1041
+ }
1042
  }
1043
  }
1044
 
1045
  resposta_teste = "Tudo e tu, puto?"
1046
 
1047
+ # Processa interação com nivel_transicao
1048
  resultado = treinamento.processar_interacao_api(payload_teste, resposta_teste)
1049
 
1050
  print(f"✅ Teste OK: {resultado}")
1051
  print(f"📝 Mensagem: {payload_teste['mensagem']}")
1052
  print(f"💬 Resposta: {resposta_teste}")
1053
+ print(f"🎯 Nível transição: {payload_teste['analise']['nivel_transicao']}")
1054
 
1055
+ # Teste com registro rápido com nivel_transicao
1056
  sucesso = registrar_interacao_rapida(
1057
  usuario="Teste 2",
1058
  numero="244000000000",
 
1060
  resposta="Nada, cota.",
1061
  is_reply=True,
1062
  reply_to_bot=True,
1063
+ reply_metadata={"quoted_author_name": "Akira", "is_reply": True},
1064
+ nivel_transicao=3
1065
  )
1066
 
1067
  print(f"✅ Registro rápido: {'Sucesso' if sucesso else 'Falhou'}")
 
1072
  traceback.print_exc()
1073
 
1074
  print("\n" + "=" * 80)
1075
+ print("TREINAMENTO.PY - COMPLETO COM SUPORTE A nivel_transicao")
1076
  print("=" * 80)