akra35567 commited on
Commit
5ab2f61
·
1 Parent(s): 59f3a55

Update modules/api.py

Browse files
Files changed (1) hide show
  1. modules/api.py +55 -20
modules/api.py CHANGED
@@ -10,10 +10,12 @@ import datetime
10
  from typing import Dict, Optional, Any, List
11
  from flask import Flask, Blueprint, request, jsonify
12
  from loguru import logger
 
13
  # LLM PROVIDERS
14
  import google.generativeai as genai
15
  from mistralai import Mistral
16
- from .local_llm import HermesLLM # ← HERMES 7B LOCAL
 
17
  # LOCAL MODULES
18
  from .contexto import Contexto
19
  from .database import Database
@@ -21,45 +23,65 @@ from .treinamento import Treinamento
21
  from .exemplos_naturais import ExemplosNaturais
22
  import modules.config as config
23
 
 
24
  # --- CACHE SIMPLES COM TTL ---
25
  class SimpleTTLCache:
26
  def __init__(self, ttl_seconds: int = 300):
27
  self.ttl = ttl_seconds
28
  self._store = {}
 
29
  def __contains__(self, key):
30
- if key not in self._store: return False
 
31
  _, expires = self._store[key]
32
- if time.time() > expires: del self._store[key]; return False
 
 
33
  return True
 
34
  def __setitem__(self, key, value):
35
  self._store[key] = (value, time.time() + self.ttl)
 
36
  def __getitem__(self, key):
37
- if key not in self: raise KeyError(key)
 
38
  return self._store[key][0]
39
 
 
40
  # --- GERENCIADOR DE LLMs ---
41
  class LLMManager:
42
  def __init__(self, config_instance):
43
  self.config = config_instance
44
  self.mistral_client: Optional[Mistral] = None
45
  self.gemini_model: Optional[genai.GenerativeModel] = None
46
- self.hermes_llm = self._import_hermes() # ← HERMES
47
  self._setup_providers()
 
48
  # PRIORIDADE: HERMES LOCAL → MISTRAL → GEMINI
49
  self.providers = []
50
  if self.hermes_llm and self.hermes_llm.is_available():
51
  self.providers.append('hermes')
 
52
  if self.mistral_client:
53
  self.providers.append('mistral')
54
  if self.gemini_model:
55
  self.providers.append('gemini')
 
56
  logger.info(f"Provedores ativos (ordem): {self.providers or 'NENHUM'}")
57
 
58
  def _import_hermes(self):
 
59
  try:
60
- return HermesLLM() # ← HERMES 7B LOCAL
 
 
 
 
 
61
  except Exception as e:
62
- logger.warning(f"Hermes 7B local não carregado: {e}")
 
 
63
  return None
64
 
65
  def _setup_providers(self):
@@ -103,11 +125,16 @@ class LLMManager:
103
 
104
  for provider in self.providers:
105
  # 1. HERMES LOCAL (PRIORIDADE MÁXIMA)
106
- if provider == 'hermes' and self.hermes_llm:
107
  try:
108
- text = self.hermes_llm.generate(user_prompt, max_tokens=self.config.MAX_TOKENS, temperature=self.config.TOP_P)
109
- if text:
110
- logger.info("Hermes 7B local respondeu")
 
 
 
 
 
111
  return text.strip()
112
  except Exception as e:
113
  logger.warning(f"Hermes local falhou: {e}")
@@ -149,7 +176,11 @@ class LLMManager:
149
  except Exception as e:
150
  logger.warning(f"Gemini falhou: {e}")
151
 
152
- return getattr(self.config, 'FALLBACK_RESPONSE', 'Desculpa, puto, to off hoje.')
 
 
 
 
153
 
154
  # --- API PRINCIPAL ---
155
  class AkiraAPI:
@@ -177,11 +208,11 @@ class AkiraAPI:
177
  try:
178
  data = request.get_json(force=True, silent=True) or {}
179
  usuario = data.get('usuario', 'anonimo')
180
- numero = data.get('numero', '') # ← JID COMPLETO (2449...@s.whatsapp.net)
181
  mensagem = data.get('mensagem', '').strip()
182
- mensagem_citada = data.get('mensagem_citada', '').strip() # ← DO index.js
183
  is_reply = bool(mensagem_citada)
184
- mensagem_original = mensagem_citada # ← pra compatibilidade
185
 
186
  if not mensagem and not mensagem_citada:
187
  return jsonify({'error': 'mensagem obrigatória'}), 400
@@ -190,6 +221,7 @@ class AkiraAPI:
190
 
191
  contexto = self._get_user_context(usuario)
192
  analise = contexto.analisar_intencao_e_normalizar(mensagem, contexto.obter_historico())
 
193
  if usuario.lower() in ['isaac', 'isaac quarenta']:
194
  analise['usar_nome'] = False
195
 
@@ -202,6 +234,7 @@ class AkiraAPI:
202
  )
203
 
204
  resposta = self._generate_response(prompt, contexto.obter_historico_para_llm(), is_privileged)
 
205
  contexto.atualizar_contexto(mensagem, resposta)
206
 
207
  # REGISTRA NO TREINAMENTO
@@ -210,7 +243,7 @@ class AkiraAPI:
210
  trainer = Treinamento(db)
211
  trainer.registrar_interacao(usuario, mensagem, resposta, numero, is_reply, mensagem_original)
212
  except Exception as e:
213
- self.logger.warning(f"Registro falhou: {e}")
214
 
215
  response_data = {'resposta': resposta}
216
  try:
@@ -254,8 +287,10 @@ class AkiraAPI:
254
  f"- Número do bot: 244952786417.\n"
255
  )
256
  system_part = strict_override + f"\n{self.config.SYSTEM_PROMPT}\n{self.config.PERSONA}\n"
257
- if is_privileged: system_part += "- Tom formal com Isaac.\n"
258
- if is_blocking: system_part += "\n# BLOQUEIO: Xingue (vai pra merda, etc).\n"
 
 
259
 
260
  usar_nome = analise.get('usar_nome', False)
261
  parts = [
@@ -263,7 +298,6 @@ class AkiraAPI:
263
  f"### Contexto ###\n{historico_texto}\n\n",
264
  ]
265
 
266
- # REPLY INTELIGENTE: INCLUI MENSAGEM CITADA
267
  if is_reply and mensagem_citada:
268
  parts.append(f"### MENSAGEM CITADA (Akira disse): ###\n{mensagem_citada}\n\n")
269
  parts.append(f"### USUÁRIO RESPONDEU A ESSA MENSAGEM: ###\n{mensagem or '(sem texto, só reply)'}\n\n")
@@ -283,7 +317,8 @@ class AkiraAPI:
283
  return getattr(self.config, 'FALLBACK_RESPONSE', 'Desculpa, estou off.')
284
 
285
  def _clean_response(self, text: Optional[str], prompt: Optional[str] = None) -> str:
286
- if not text: return ''
 
287
  cleaned = text.strip()
288
  for prefix in ['akira:', 'Resposta:', 'resposta:', '### Resposta:']:
289
  if cleaned.lower().startswith(prefix.lower()):
 
10
  from typing import Dict, Optional, Any, List
11
  from flask import Flask, Blueprint, request, jsonify
12
  from loguru import logger
13
+
14
  # LLM PROVIDERS
15
  import google.generativeai as genai
16
  from mistralai import Mistral
17
+ from .local_llm import HermesLLM # ← HERMES 7B LOCAL (com generate(max_tokens, temp))
18
+
19
  # LOCAL MODULES
20
  from .contexto import Contexto
21
  from .database import Database
 
23
  from .exemplos_naturais import ExemplosNaturais
24
  import modules.config as config
25
 
26
+
27
  # --- CACHE SIMPLES COM TTL ---
28
  class SimpleTTLCache:
29
  def __init__(self, ttl_seconds: int = 300):
30
  self.ttl = ttl_seconds
31
  self._store = {}
32
+
33
  def __contains__(self, key):
34
+ if key not in self._store:
35
+ return False
36
  _, expires = self._store[key]
37
+ if time.time() > expires:
38
+ del self._store[key]
39
+ return False
40
  return True
41
+
42
  def __setitem__(self, key, value):
43
  self._store[key] = (value, time.time() + self.ttl)
44
+
45
  def __getitem__(self, key):
46
+ if key not in self:
47
+ raise KeyError(key)
48
  return self._store[key][0]
49
 
50
+
51
  # --- GERENCIADOR DE LLMs ---
52
  class LLMManager:
53
  def __init__(self, config_instance):
54
  self.config = config_instance
55
  self.mistral_client: Optional[Mistral] = None
56
  self.gemini_model: Optional[genai.GenerativeModel] = None
57
+ self.hermes_llm = self._import_hermes()
58
  self._setup_providers()
59
+
60
  # PRIORIDADE: HERMES LOCAL → MISTRAL → GEMINI
61
  self.providers = []
62
  if self.hermes_llm and self.hermes_llm.is_available():
63
  self.providers.append('hermes')
64
+ logger.info("HERMES 7B LOCAL ATIVO → PRIORIDADE MÁXIMA")
65
  if self.mistral_client:
66
  self.providers.append('mistral')
67
  if self.gemini_model:
68
  self.providers.append('gemini')
69
+
70
  logger.info(f"Provedores ativos (ordem): {self.providers or 'NENHUM'}")
71
 
72
  def _import_hermes(self):
73
+ """Tenta carregar Hermes 7B local"""
74
  try:
75
+ hermes = HermesLLM()
76
+ if hermes.is_available():
77
+ logger.info("Hermes 7B local carregado com sucesso!")
78
+ else:
79
+ logger.warning("Hermes 7B local carregado, mas não disponível (shards faltando?)")
80
+ return hermes
81
  except Exception as e:
82
+ logger.error(f"Falha ao instanciar HermesLLM: {e}")
83
+ import traceback
84
+ logger.error(traceback.format_exc())
85
  return None
86
 
87
  def _setup_providers(self):
 
125
 
126
  for provider in self.providers:
127
  # 1. HERMES LOCAL (PRIORIDADE MÁXIMA)
128
+ if provider == 'hermes' and self.hermes_llm and self.hermes_llm.is_available():
129
  try:
130
+ logger.info(f"[HERMES] Gerando com max_tokens={self.config.MAX_TOKENS}, temp={self.config.TOP_P}")
131
+ text = self.hermes_llm.generate(
132
+ user_prompt,
133
+ max_tokens=self.config.MAX_TOKENS,
134
+ temperature=self.config.TOP_P
135
+ )
136
+ if text and text.strip():
137
+ logger.info("Hermes 7B local respondeu com sucesso")
138
  return text.strip()
139
  except Exception as e:
140
  logger.warning(f"Hermes local falhou: {e}")
 
176
  except Exception as e:
177
  logger.warning(f"Gemini falhou: {e}")
178
 
179
+ # Fallback
180
+ fallback = getattr(self.config, 'FALLBACK_RESPONSE', 'Desculpa, puto, tô off hoje.')
181
+ logger.warning(f"TODOS LLMs FALHARAM → Usando fallback: {fallback}")
182
+ return fallback
183
+
184
 
185
  # --- API PRINCIPAL ---
186
  class AkiraAPI:
 
208
  try:
209
  data = request.get_json(force=True, silent=True) or {}
210
  usuario = data.get('usuario', 'anonimo')
211
+ numero = data.get('numero', '')
212
  mensagem = data.get('mensagem', '').strip()
213
+ mensagem_citada = data.get('mensagem_citada', '').strip()
214
  is_reply = bool(mensagem_citada)
215
+ mensagem_original = mensagem_citada
216
 
217
  if not mensagem and not mensagem_citada:
218
  return jsonify({'error': 'mensagem obrigatória'}), 400
 
221
 
222
  contexto = self._get_user_context(usuario)
223
  analise = contexto.analisar_intencao_e_normalizar(mensagem, contexto.obter_historico())
224
+
225
  if usuario.lower() in ['isaac', 'isaac quarenta']:
226
  analise['usar_nome'] = False
227
 
 
234
  )
235
 
236
  resposta = self._generate_response(prompt, contexto.obter_historico_para_llm(), is_privileged)
237
+
238
  contexto.atualizar_contexto(mensagem, resposta)
239
 
240
  # REGISTRA NO TREINAMENTO
 
243
  trainer = Treinamento(db)
244
  trainer.registrar_interacao(usuario, mensagem, resposta, numero, is_reply, mensagem_original)
245
  except Exception as e:
246
+ self.logger.warning(f"Registro de interação falhou: {e}")
247
 
248
  response_data = {'resposta': resposta}
249
  try:
 
287
  f"- Número do bot: 244952786417.\n"
288
  )
289
  system_part = strict_override + f"\n{self.config.SYSTEM_PROMPT}\n{self.config.PERSONA}\n"
290
+ if is_privileged:
291
+ system_part += "- Tom formal com Isaac.\n"
292
+ if is_blocking:
293
+ system_part += "\n# BLOQUEIO: Xingue (vai pra merda, etc).\n"
294
 
295
  usar_nome = analise.get('usar_nome', False)
296
  parts = [
 
298
  f"### Contexto ###\n{historico_texto}\n\n",
299
  ]
300
 
 
301
  if is_reply and mensagem_citada:
302
  parts.append(f"### MENSAGEM CITADA (Akira disse): ###\n{mensagem_citada}\n\n")
303
  parts.append(f"### USUÁRIO RESPONDEU A ESSA MENSAGEM: ###\n{mensagem or '(sem texto, só reply)'}\n\n")
 
317
  return getattr(self.config, 'FALLBACK_RESPONSE', 'Desculpa, estou off.')
318
 
319
  def _clean_response(self, text: Optional[str], prompt: Optional[str] = None) -> str:
320
+ if not text:
321
+ return ''
322
  cleaned = text.strip()
323
  for prefix in ['akira:', 'Resposta:', 'resposta:', '### Resposta:']:
324
  if cleaned.lower().startswith(prefix.lower()):