akra35567 commited on
Commit
410dc31
·
1 Parent(s): e83ec46

Update modules/contexto.py

Browse files
Files changed (1) hide show
  1. modules/contexto.py +95 -148
modules/contexto.py CHANGED
@@ -1,34 +1,34 @@
 
1
  import logging
2
  import re
3
  import random
4
  import time
5
  import sqlite3
6
- import json
7
- from typing import Optional, List, Dict, Tuple, Any
8
  import modules.config as config
9
  from .database import Database
10
- from .treinamento import Treinamento
11
 
12
  try:
13
- from sentence_transformers import SentenceTransformer # type: ignore[reportMissingImports]
14
  except Exception as e:
15
  logging.warning(f"sentence_transformers não disponível: {e}")
16
  SentenceTransformer = None
17
-
18
  try:
19
- import psutil # type: ignore[reportMissingImports]
20
  except Exception:
21
  psutil = None
22
-
23
  try:
24
- import structlog # type: ignore[reportMissingImports]
25
  except Exception:
26
  structlog = None
27
 
28
  logger = logging.getLogger(__name__)
29
-
30
- # Configuração do logging (fallback se structlog ausente)
31
  logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
 
32
  if structlog:
33
  structlog.configure(
34
  processors=[
@@ -45,9 +45,10 @@ if structlog:
45
  PALAVRAS_POSITIVAS = ['bom', 'ótimo', 'incrível', 'feliz', 'adorei', 'top', 'fixe', 'bué', 'show', 'legal', 'bacana']
46
  PALAVRAS_NEGATIVAS = ['ruim', 'péssimo', 'triste', 'ódio', 'raiva', 'chateado', 'merda', 'porra', 'odeio']
47
 
 
48
  class Contexto:
49
  """
50
- Classe para gerenciar o contexto da conversa, análise de intenções e aprendizado
51
  dinâmico de termos regionais/gírias para cada usuário.
52
  """
53
  def __init__(self, db: Database, usuario: Optional[str] = None):
@@ -56,30 +57,27 @@ class Contexto:
56
  self.model: Optional[SentenceTransformer] = None
57
  self.embeddings: Optional[Dict[str, Any]] = None
58
  self._treinador: Optional[Treinamento] = None
59
-
60
  # Estado de conversa
61
  self.emocao_atual = "neutra"
62
  self.espírito_crítico = False
63
  self.base_conhecimento = {}
64
-
65
  # Garante que termo_contexto seja sempre um dicionário
66
  self.termo_contexto: Dict[str, Dict] = {}
67
  self.atualizar_aprendizados_do_banco()
68
-
69
- logger.info("🟢 Inicializando Contexto (com NLP avançado, aprendizado de gírias e emoções) ...")
70
-
71
  # Cache para termos regionais e gírias
72
  self.cache_girias: Dict[str, Any] = {}
73
-
74
  def atualizar_aprendizados_do_banco(self):
75
- """
76
- Carrega todos os dados de aprendizado persistentes (termos, gírias, etc.)
77
- do banco de dados para a instância do Contexto.
78
- """
79
  try:
80
  termos_aprendidos = self.db.recuperar_girias_usuario(self.usuario) if self.usuario else []
81
  self.termo_contexto = {
82
- termo['giria']: {"significado": termo['significado'], "frequencia": termo['frequencia']}
83
  for termo in termos_aprendidos
84
  }
85
  except Exception as e:
@@ -91,88 +89,62 @@ class Contexto:
91
  if emocao_salva:
92
  emocao_dict = json.loads(emocao_salva)
93
  if isinstance(emocao_dict, dict) and 'emocao' in emocao_dict:
94
- self.emocao_atual = emocao_dict['emocao']
95
  elif isinstance(emocao_salva, str):
96
- self.emocao_atual = emocao_salva
97
  except Exception as e:
98
  logger.warning(f"Falha ao carregar emoção do DB: {e}")
99
-
100
- logger.info(f"Aprendizados de contexto carregados/recarregados para {self.usuario}.")
101
 
102
  @property
103
  def ton_predominante(self) -> Optional[str]:
104
- """
105
- [CORREÇÃO DO BUG] Retorna o tom predominante do usuário, acessando o DB.
106
- Adicionado para resolver o 'AttributeError: ton_predominante'.
107
- """
108
  if self.usuario:
109
  return self.db.obter_tom_predominante(self.usuario)
110
  return None
111
 
112
  def get_or_create_treinador(self, interval_hours: int = 24) -> Treinamento:
113
- """Retorna um treinador associado a este contexto, criando se necessário."""
114
  if self._treinador is None:
115
  self._treinador = Treinamento(self.db, contexto=self, interval_hours=interval_hours)
116
  return self._treinador
117
 
118
  def _load_model(self):
119
- """Carrega o modelo SentenceTransformer e embeddings sob demanda."""
120
  if self.model is not None:
121
  return
122
-
123
- start_time = time.time()
124
-
125
  if SentenceTransformer is None:
126
- logger.warning({"event": "Modelo SentenceTransformer não será carregado", "reason": "Biblioteca não instalada"})
127
  return
128
-
129
  try:
130
  self.model = SentenceTransformer('all-MiniLM-L6-v2')
131
- logger.info({"event": "Modelo SentenceTransformer carregado com sucesso"})
132
  except Exception as e:
133
- logger.error({"event": "Erro ao carregar modelo", "error": str(e)})
134
  self.model = None
135
-
136
  self._check_embeddings()
137
- duration = time.time() - start_time
138
- logger.info({"event": "Modelo carregado", "duration_seconds": duration})
139
 
140
  def _check_embeddings(self):
141
- """Verifica ou cria embeddings no banco de dados SQLite."""
142
  if self.model and not self.embeddings:
143
- try:
144
- self.embeddings = {"conhecimento_base": "placeholder_embedding_data"}
145
- except Exception as e:
146
- logger.warning(f"Não foi possível carregar embeddings: {e}")
147
 
148
  def analisar_emocoes_mensagem(self, mensagem: str) -> Dict[str, Any]:
149
- """
150
- Analisa o sentimento e emoção da mensagem (Heurística simples).
151
- MÉTODO ADICIONADO PARA RESOLVER O ERRO 'analisar_emocoes_mensagem'.
152
- """
153
  mensagem_lower = mensagem.strip().lower()
154
-
155
- # Análise de Sentimento (Tom Simples)
156
  pos_count = sum(mensagem_lower.count(w) for w in PALAVRAS_POSITIVAS)
157
  neg_count = sum(mensagem_lower.count(w) for w in PALAVRAS_NEGATIVAS)
158
-
159
  sentimento = "neutro"
160
  if pos_count > neg_count:
161
  sentimento = "positivo"
162
  elif neg_count > pos_count:
163
  sentimento = "negativo"
164
-
165
- # Determinar Emoção Predominante (simples)
166
- if sentimento == "positivo":
167
- emocao_predominante = "alegria"
168
- elif sentimento == "negativo":
169
- emocao_predominante = "frustração"
170
- else:
171
- emocao_predominante = "neutra"
172
-
173
- # Atualiza o estado da classe
174
  self.emocao_atual = emocao_predominante
175
-
176
  return {
177
  "sentimento_detectado": sentimento,
178
  "emocao_predominante": emocao_predominante,
@@ -180,166 +152,141 @@ class Contexto:
180
  "intensidade_negativa": neg_count,
181
  "tom_sugerido": "casual" if sentimento != "neutro" else "neutro"
182
  }
183
-
184
  def analisar_intencao_e_normalizar(self, mensagem: str, historico: List[Tuple[str, str]]) -> Dict[str, Any]:
185
- """Analisa a intenção, normaliza a mensagem e detecta sentimentos/estilo (Heurística)."""
186
  self._load_model()
187
-
188
  if not isinstance(mensagem, str):
189
  mensagem = str(mensagem)
190
  mensagem_lower = mensagem.strip().lower()
191
 
192
- # 1. Análise de Intenção
193
  intencao = "pergunta"
194
- if '?' not in mensagem_lower and ('porquê' not in mensagem_lower or 'porque' not in mensagem_lower):
195
  intencao = "afirmacao"
196
  if any(w in mensagem_lower for w in ['ola', 'oi', 'bom dia', 'boa tarde', 'boa noite', 'como vai']):
197
  intencao = "saudacao"
198
  if any(w in mensagem_lower for w in ['tchau', 'ate mais', 'adeus', 'fim', 'parar']):
199
  intencao = "despedida"
200
-
201
- # 2. Análise de Sentimento/Emoção
202
  analise_emocional = self.analisar_emocoes_mensagem(mensagem_lower)
203
-
204
- # 3. Análise de Estilo
205
  estilo = "informal"
206
  if len(re.findall(r'[A-ZÀ-Ÿ]{3,}', mensagem)) >= 2 or re.search(r'\b(Senhor|Doutor|Atenciosamente)\b', mensagem, re.IGNORECASE):
207
  estilo = "formal"
208
-
209
- # 4. Outras bandeiras
210
- ironia = False
211
- meia_frase = False
212
  usar_nome = random.random() < getattr(config, 'USAR_NOME_PROBABILIDADE', 0.7)
213
 
214
  return {
215
  "texto_normalizado": mensagem_lower,
216
  "intencao": intencao,
217
- "sentimento": analise_emocional['sentimento_detectado'],
218
  "estilo": estilo,
219
  "contexto_ajustado": self.substituir_termos_aprendidos(mensagem_lower),
220
- "ironia": ironia,
221
- "meia_frase": meia_frase,
222
  "usar_nome": usar_nome,
223
- "emocao": self.emocao_atual
224
  }
225
 
226
  def obter_historico(self, limite: int = 5) -> List[Tuple[str, str]]:
227
- """Recupera o histórico de mensagens do banco de dados (Mensagem do Usuário, Resposta da IA)."""
228
  if not self.usuario:
229
  return []
230
-
231
- raw_result = self.db.recuperar_mensagens(self.usuario, limite=limite)
232
-
233
- return raw_result if raw_result else []
 
 
 
 
 
 
 
234
 
235
  def atualizar_contexto(self, mensagem: str, resposta: str, numero: Optional[str] = None):
236
- """Salva a interação no banco de mensagens e aciona aprendizado de termos."""
237
- if not self.usuario:
238
- usuario = 'anonimo'
239
- else:
240
- usuario = self.usuario
241
-
242
- final_numero = numero if numero else self.usuario
243
-
244
  try:
245
  self.db.salvar_mensagem(usuario, mensagem, resposta, numero=final_numero)
246
-
247
  historico = self.obter_historico(limite=10)
248
- self.aprender_do_historico(mensagem, resposta, historico)
249
-
250
  self.salvar_estado_contexto_no_db(final_numero)
251
-
252
  except Exception as e:
253
- logger.warning(f'Falha ao salvar mensagem no DB: {e}')
254
 
255
  def salvar_estado_contexto_no_db(self, user_key: str):
256
- """Persiste o estado atual da classe Contexto no banco de dados."""
257
  termos_json = json.dumps(self.termo_contexto)
258
- emocao_str = self.emocao_atual
259
-
260
  try:
261
- self.db.salvar_aprendizado_detalhado(user_key, "emocao_atual", json.dumps({"emocao": emocao_str}))
262
-
263
  self.db.salvar_contexto(
264
  user_key=user_key,
265
- historico="[]",
266
- emocao_atual=emocao_str,
267
  termos=termos_json,
268
  girias=termos_json,
269
- tom=emocao_str
270
  )
271
- logger.debug(f"Contexto do usuário {user_key} salvo no DB.")
272
  except Exception as e:
273
- logger.error(f"Falha ao salvar estado do contexto no DB: {e}")
274
-
275
 
276
  def aprender_do_historico(self, mensagem: str, resposta: str, historico: List[Tuple[str, str]]):
277
- """Aprende termos do histórico de conversas e salva na tabela 'girias_aprendidas' (Downgrade/Heurística)."""
278
  if not self.usuario:
279
  return
280
-
281
  mensagem_lower = mensagem.lower()
282
-
283
- # Exemplo: Aprender gírias angolanas simples se usadas frequentemente
284
- girias_angolanas_simples = ['ya', 'bué', 'fixe', 'puto']
285
-
286
  for giria in girias_angolanas_simples:
287
  if giria in mensagem_lower:
288
  try:
289
- significado_placeholder = f'termo regional para {giria}'
290
-
291
- self.db.salvar_giria_aprendida(
292
- self.usuario,
293
- giria,
294
- significado_placeholder,
295
- mensagem[:50]
296
- )
297
-
298
- self.termo_contexto[giria] = {"significado": significado_placeholder, "frequencia": self.termo_contexto.get(giria, {}).get("frequencia", 0) + 1}
299
-
300
  except Exception as e:
301
- logger.warning(f"Erro ao salvar gíria no DB: {e}")
302
-
303
  def substituir_termos_aprendidos(self, mensagem: str) -> str:
304
- """Substitui termos aprendidos na mensagem (baseado no dicionário termo_contexto)."""
305
  for termo, info in self.termo_contexto.items():
306
  if isinstance(info, dict) and "significado" in info:
307
- # Usa regex para substituir apenas a palavra inteira (case insensitive)
308
  mensagem = re.sub(r'\b' + re.escape(termo) + r'\b', info["significado"], mensagem, flags=re.IGNORECASE)
309
  return mensagem
310
-
311
  def obter_aprendizado_detalhado(self, chave: str) -> Optional[Dict]:
312
- """Recupera aprendizados detalhados do usuário (simulação simples)."""
313
  try:
314
- raw_data = self.db.recuperar_aprendizado_detalhado(self.usuario, chave)
315
- if raw_data:
316
- return json.loads(raw_data)
317
- return None
318
  except Exception as e:
319
- logger.warning(f"Erro ao obter aprendizado detalhado: {e}")
320
  return None
321
-
322
  def obter_emocao_atual(self) -> str:
323
- """Recupera a emoção atual do usuário."""
324
  return self.emocao_atual
325
 
326
  def ativar_espírito_crítico(self):
327
- """Ativa o espírito crítico para respostas questionadoras."""
328
  self.espírito_crítico = True
329
 
330
  def obter_aprendizados(self) -> Dict[str, Any]:
331
- """Retorna os aprendizados do usuário, incluindo termos e emoções."""
332
- aprendizados = {
333
  "termos": self.termo_contexto,
334
  "emocao_preferida": self.emocao_atual,
335
- "ton_predominante": self.ton_predominante # Adicionado o novo campo de tom
336
  }
337
- return aprendizados
338
 
339
  def salvar_conhecimento_base(self, chave: str, valor: Any):
340
- """Salva uma informação na base de conhecimento."""
341
  self.base_conhecimento[chave] = valor
342
 
343
  def obter_conhecimento_base(self, chave: str) -> Optional[Any]:
344
- """Obtém uma informação da base de conhecimento."""
345
  return self.base_conhecimento.get(chave)
 
1
+ # modules/contexto.py
2
  import logging
3
  import re
4
  import random
5
  import time
6
  import sqlite3
7
+ import json
8
+ from typing import Optional, List, Dict, Tuple, Any
9
  import modules.config as config
10
  from .database import Database
11
+ from .treinamento import Treinamento
12
 
13
  try:
14
+ from sentence_transformers import SentenceTransformer
15
  except Exception as e:
16
  logging.warning(f"sentence_transformers não disponível: {e}")
17
  SentenceTransformer = None
18
+
19
  try:
20
+ import psutil
21
  except Exception:
22
  psutil = None
23
+
24
  try:
25
+ import structlog
26
  except Exception:
27
  structlog = None
28
 
29
  logger = logging.getLogger(__name__)
 
 
30
  logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
31
+
32
  if structlog:
33
  structlog.configure(
34
  processors=[
 
45
  PALAVRAS_POSITIVAS = ['bom', 'ótimo', 'incrível', 'feliz', 'adorei', 'top', 'fixe', 'bué', 'show', 'legal', 'bacana']
46
  PALAVRAS_NEGATIVAS = ['ruim', 'péssimo', 'triste', 'ódio', 'raiva', 'chateado', 'merda', 'porra', 'odeio']
47
 
48
+
49
  class Contexto:
50
  """
51
+ Classe para gerenciar o contexto da conversa, análise de intenções e aprendizado
52
  dinâmico de termos regionais/gírias para cada usuário.
53
  """
54
  def __init__(self, db: Database, usuario: Optional[str] = None):
 
57
  self.model: Optional[SentenceTransformer] = None
58
  self.embeddings: Optional[Dict[str, Any]] = None
59
  self._treinador: Optional[Treinamento] = None
60
+
61
  # Estado de conversa
62
  self.emocao_atual = "neutra"
63
  self.espírito_crítico = False
64
  self.base_conhecimento = {}
65
+
66
  # Garante que termo_contexto seja sempre um dicionário
67
  self.termo_contexto: Dict[str, Dict] = {}
68
  self.atualizar_aprendizados_do_banco()
69
+
70
+ logger.info("Inicializando Contexto (com NLP avançado, aprendizado de gírias e emoções) ...")
71
+
72
  # Cache para termos regionais e gírias
73
  self.cache_girias: Dict[str, Any] = {}
74
+
75
  def atualizar_aprendizados_do_banco(self):
76
+ """Carrega todos os dados de aprendizado persistentes do banco."""
 
 
 
77
  try:
78
  termos_aprendidos = self.db.recuperar_girias_usuario(self.usuario) if self.usuario else []
79
  self.termo_contexto = {
80
+ termo['giria']: {"significado": termo['significado'], "frequencia": termo['frequencia']}
81
  for termo in termos_aprendidos
82
  }
83
  except Exception as e:
 
89
  if emocao_salva:
90
  emocao_dict = json.loads(emocao_salva)
91
  if isinstance(emocao_dict, dict) and 'emocao' in emocao_dict:
92
+ self.emocao_atual = emocao_dict['emocao']
93
  elif isinstance(emocao_salva, str):
94
+ self.emocao_atual = emocao_salva
95
  except Exception as e:
96
  logger.warning(f"Falha ao carregar emoção do DB: {e}")
97
+
98
+ logger.info(f"Aprendizados carregados para {self.usuario}.")
99
 
100
  @property
101
  def ton_predominante(self) -> Optional[str]:
102
+ """Retorna o tom predominante do usuário (acessa o DB)."""
 
 
 
103
  if self.usuario:
104
  return self.db.obter_tom_predominante(self.usuario)
105
  return None
106
 
107
  def get_or_create_treinador(self, interval_hours: int = 24) -> Treinamento:
108
+ """Retorna um treinador associado, criando se necessário."""
109
  if self._treinador is None:
110
  self._treinador = Treinamento(self.db, contexto=self, interval_hours=interval_hours)
111
  return self._treinador
112
 
113
  def _load_model(self):
114
+ """Carrega o modelo SentenceTransformer sob demanda."""
115
  if self.model is not None:
116
  return
 
 
 
117
  if SentenceTransformer is None:
118
+ logger.warning("SentenceTransformer não instalado")
119
  return
 
120
  try:
121
  self.model = SentenceTransformer('all-MiniLM-L6-v2')
122
+ logger.info("Modelo SentenceTransformer carregado")
123
  except Exception as e:
124
+ logger.error(f"Erro ao carregar modelo: {e}")
125
  self.model = None
 
126
  self._check_embeddings()
 
 
127
 
128
  def _check_embeddings(self):
129
+ """Verifica ou cria embeddings no banco."""
130
  if self.model and not self.embeddings:
131
+ self.embeddings = {"conhecimento_base": "placeholder"}
 
 
 
132
 
133
  def analisar_emocoes_mensagem(self, mensagem: str) -> Dict[str, Any]:
134
+ """Analisa sentimento e emoção da mensagem (heurística)."""
 
 
 
135
  mensagem_lower = mensagem.strip().lower()
 
 
136
  pos_count = sum(mensagem_lower.count(w) for w in PALAVRAS_POSITIVAS)
137
  neg_count = sum(mensagem_lower.count(w) for w in PALAVRAS_NEGATIVAS)
138
+
139
  sentimento = "neutro"
140
  if pos_count > neg_count:
141
  sentimento = "positivo"
142
  elif neg_count > pos_count:
143
  sentimento = "negativo"
144
+
145
+ emocao_predominante = "alegria" if sentimento == "positivo" else "frustração" if sentimento == "negativo" else "neutra"
 
 
 
 
 
 
 
 
146
  self.emocao_atual = emocao_predominante
147
+
148
  return {
149
  "sentimento_detectado": sentimento,
150
  "emocao_predominante": emocao_predominante,
 
152
  "intensidade_negativa": neg_count,
153
  "tom_sugerido": "casual" if sentimento != "neutro" else "neutro"
154
  }
155
+
156
  def analisar_intencao_e_normalizar(self, mensagem: str, historico: List[Tuple[str, str]]) -> Dict[str, Any]:
157
+ """Analisa intenção, normaliza e detecta estilo."""
158
  self._load_model()
 
159
  if not isinstance(mensagem, str):
160
  mensagem = str(mensagem)
161
  mensagem_lower = mensagem.strip().lower()
162
 
163
+ # Intenção
164
  intencao = "pergunta"
165
+ if '?' not in mensagem_lower and 'porquê' not in mensagem_lower and 'porque' not in mensagem_lower:
166
  intencao = "afirmacao"
167
  if any(w in mensagem_lower for w in ['ola', 'oi', 'bom dia', 'boa tarde', 'boa noite', 'como vai']):
168
  intencao = "saudacao"
169
  if any(w in mensagem_lower for w in ['tchau', 'ate mais', 'adeus', 'fim', 'parar']):
170
  intencao = "despedida"
171
+
172
+ # Sentimento
173
  analise_emocional = self.analisar_emocoes_mensagem(mensagem_lower)
174
+
175
+ # Estilo
176
  estilo = "informal"
177
  if len(re.findall(r'[A-ZÀ-Ÿ]{3,}', mensagem)) >= 2 or re.search(r'\b(Senhor|Doutor|Atenciosamente)\b', mensagem, re.IGNORECASE):
178
  estilo = "formal"
179
+
 
 
 
180
  usar_nome = random.random() < getattr(config, 'USAR_NOME_PROBABILIDADE', 0.7)
181
 
182
  return {
183
  "texto_normalizado": mensagem_lower,
184
  "intencao": intencao,
185
+ "sentimento": analise_emocional['sentimento_detectado'],
186
  "estilo": estilo,
187
  "contexto_ajustado": self.substituir_termos_aprendidos(mensagem_lower),
188
+ "ironia": False,
189
+ "meia_frase": False,
190
  "usar_nome": usar_nome,
191
+ "emocao": self.emocao_atual
192
  }
193
 
194
  def obter_historico(self, limite: int = 5) -> List[Tuple[str, str]]:
195
+ """Recupera histórico do banco."""
196
  if not self.usuario:
197
  return []
198
+ raw = self.db.recuperar_mensagens(self.usuario, limite=limite)
199
+ return raw if raw else []
200
+
201
+ def obter_historico_para_llm(self) -> List[Dict]:
202
+ """Formato esperado pelo LLMManager.generate()"""
203
+ raw = self.obter_historico(limite=10)
204
+ history = []
205
+ for user_msg, bot_msg in raw:
206
+ history.append({"role": "user", "content": user_msg})
207
+ history.append({"role": "assistant", "content": bot_msg})
208
+ return history
209
 
210
  def atualizar_contexto(self, mensagem: str, resposta: str, numero: Optional[str] = None):
211
+ """Salva interação e aprende."""
212
+ usuario = self.usuario or 'anonimo'
213
+ final_numero = numero or self.usuario
214
+
 
 
 
 
215
  try:
216
  self.db.salvar_mensagem(usuario, mensagem, resposta, numero=final_numero)
 
217
  historico = self.obter_historico(limite=10)
218
+ self.aprender_do_historico(mensagem, resposta, historico)
 
219
  self.salvar_estado_contexto_no_db(final_numero)
 
220
  except Exception as e:
221
+ logger.warning(f'Falha ao salvar: {e}')
222
 
223
  def salvar_estado_contexto_no_db(self, user_key: str):
224
+ """Persiste estado no DB."""
225
  termos_json = json.dumps(self.termo_contexto)
 
 
226
  try:
227
+ self.db.salvar_aprendizado_detalhado(user_key, "emocao_atual", json.dumps({"emocao": self.emocao_atual}))
 
228
  self.db.salvar_contexto(
229
  user_key=user_key,
230
+ historico="[]",
231
+ emocao_atual=self.emocao_atual,
232
  termos=termos_json,
233
  girias=termos_json,
234
+ tom=self.emocao_atual
235
  )
 
236
  except Exception as e:
237
+ logger.error(f"Falha ao salvar contexto: {e}")
 
238
 
239
  def aprender_do_historico(self, mensagem: str, resposta: str, historico: List[Tuple[str, str]]):
240
+ """Aprende gírias do histórico."""
241
  if not self.usuario:
242
  return
 
243
  mensagem_lower = mensagem.lower()
244
+ girias_angolanas_simples = ['ya', 'bué', 'fixe', 'puto', 'kota', 'mwangolé']
245
+
 
 
246
  for giria in girias_angolanas_simples:
247
  if giria in mensagem_lower:
248
  try:
249
+ significado = f'termo regional para {giria}'
250
+ self.db.salvar_giria_aprendida(self.usuario, giria, significado, mensagem[:50])
251
+ self.termo_contexto[giria] = {
252
+ "significado": significado,
253
+ "frequencia": self.termo_contexto.get(giria, {}).get("frequencia", 0) + 1
254
+ }
 
 
 
 
 
255
  except Exception as e:
256
+ logger.warning(f"Erro ao salvar gíria: {e}")
257
+
258
  def substituir_termos_aprendidos(self, mensagem: str) -> str:
259
+ """Substitui termos aprendidos."""
260
  for termo, info in self.termo_contexto.items():
261
  if isinstance(info, dict) and "significado" in info:
 
262
  mensagem = re.sub(r'\b' + re.escape(termo) + r'\b', info["significado"], mensagem, flags=re.IGNORECASE)
263
  return mensagem
264
+
265
  def obter_aprendizado_detalhado(self, chave: str) -> Optional[Dict]:
266
+ """Recupera aprendizado detalhado."""
267
  try:
268
+ raw = self.db.recuperar_aprendizado_detalhado(self.usuario, chave)
269
+ return json.loads(raw) if raw else None
 
 
270
  except Exception as e:
271
+ logger.warning(f"Erro ao obter aprendizado: {e}")
272
  return None
273
+
274
  def obter_emocao_atual(self) -> str:
 
275
  return self.emocao_atual
276
 
277
  def ativar_espírito_crítico(self):
 
278
  self.espírito_crítico = True
279
 
280
  def obter_aprendizados(self) -> Dict[str, Any]:
281
+ """Retorna todos os aprendizados."""
282
+ return {
283
  "termos": self.termo_contexto,
284
  "emocao_preferida": self.emocao_atual,
285
+ "ton_predominante": self.ton_predominante
286
  }
 
287
 
288
  def salvar_conhecimento_base(self, chave: str, valor: Any):
 
289
  self.base_conhecimento[chave] = valor
290
 
291
  def obter_conhecimento_base(self, chave: str) -> Optional[Any]:
 
292
  return self.base_conhecimento.get(chave)