akra35567 commited on
Commit
46bbe71
·
1 Parent(s): 6921978

Update modules/api.py

Browse files
Files changed (1) hide show
  1. modules/api.py +46 -23
modules/api.py CHANGED
@@ -1,4 +1,3 @@
1
- # modules/api.py — VERSÃO FINAL OFICIAL: Contexto Fixo, Web Search Ativo, Akira Viva!
2
  """
3
  API wrapper Akira IA.
4
  Prioridade: Mistral API (Phi-3 Mini) → Gemini → Fallback
@@ -19,7 +18,7 @@ import google.generativeai as genai
19
  from mistralai import Mistral
20
 
21
  # LOCAL MODULES
22
- # from .local_llm import HermesLLM # ← REMOVIDO: Era o modelo que causava a carga de 101% CPU
23
  from .contexto import Contexto
24
  from .database import Database
25
  from .treinamento import Treinamento
@@ -64,11 +63,6 @@ class LLMManager:
64
  self.providers = []
65
 
66
  # PRIORIDADE MÁXIMA AGORA É O MISTRAL (PHI-3 MINI)
67
- # if HermesLLM.is_available(): # REMOVIDO PELA CARGA DE CPU
68
- # self.hermes_available = True
69
- # self.providers.append('hermes')
70
- # logger.info("HERMES 7B LOCAL (GGUF + LoRA ANGOLANO) ATIVO → PRIORIDADE MÁXIMA → 8-12s RESPOSTA!")
71
-
72
  if self.mistral_client:
73
  self.providers.append('mistral') # Mistral (usando Phi-3) é o novo principal
74
  if self.gemini_model:
@@ -127,11 +121,16 @@ class LLMManager:
127
  messages.append({"role": role, "content": turn["content"]})
128
 
129
  # Extrai a mensagem limpa do prompt (necessário para APIs)
130
- user_message_clean_match = re.search(r'### Mensagem Atual ###\n(.*?)\n\nAkira:', user_prompt, re.DOTALL)
 
 
 
131
  if user_message_clean_match:
132
- user_message_clean = user_message_clean_match.group(1).strip()
 
133
  else:
134
- user_message_clean = user_prompt # Fallback
 
135
 
136
  messages.append({"role": "user", "content": user_message_clean})
137
 
@@ -140,10 +139,6 @@ class LLMManager:
140
 
141
 
142
  for provider in self.providers:
143
- # 1. HERMES LOCAL → PULADO (REMOVIDO DO __init__)
144
- # if provider == 'hermes' and self.hermes_available:
145
- # ...
146
-
147
  # 1. MISTRAL API (AGORA PRIORIDADE MÁXIMA)
148
  if provider == 'mistral' and self.mistral_client:
149
  try:
@@ -171,6 +166,7 @@ class LLMManager:
171
  if getattr(self.config, 'GEMINI_API_KEY', '').startswith('AIza'):
172
  genai.configure(api_key=self.config.GEMINI_API_KEY)
173
 
 
174
  gemini_hist = []
175
  for msg in messages[1:]:
176
  role = "user" if msg["role"] == "user" else "model"
@@ -245,15 +241,38 @@ class AkiraAPI:
245
 
246
  # CORREÇÃO: Verifica se o método existe antes de chamar
247
  if hasattr(trainer, 'start_periodic_training'):
248
- trainer.start_periodic_training()
249
- self.logger.info("Treinamento periódico (start_periodic_training) iniciado com sucesso.")
250
  else:
251
- self.logger.info("Treinamento periódico (via __init__) iniciado.")
252
-
253
  except Exception as e:
254
  self.logger.exception(f"Treinador periódico falhou ao iniciar: {e}")
255
 
256
  def _setup_routes(self):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  @self.api.route('/akira', methods=['POST'])
258
  def akira_endpoint():
259
  try:
@@ -272,14 +291,17 @@ class AkiraAPI:
272
 
273
  # --- CORREÇÃO: Resposta rápida para "Que dia é hoje?" ---
274
  prompt_lower = mensagem.lower().strip()
275
- if any(keyword in prompt_lower for keyword in ["que dia é hoje", "qual é a data", "dia da semana"]):
276
  hoje = datetime.datetime.now()
277
  dia_semana = hoje.strftime("%A")
278
  dia_mes = hoje.day
279
  mes = hoje.strftime("%B")
280
  ano = hoje.year
 
281
 
282
- if any(k in prompt_lower for k in ["que dia", "hoje é que dia", "dia da semana"]) and not any(k in prompt_lower for k in ["mês", "ano", "data", "completa"]):
 
 
283
  resposta = f"Hoje é {dia_semana.capitalize()}, {dia_mes}, meu."
284
  else:
285
  resposta = f"Hoje é {dia_semana.capitalize()}, {dia_mes} de {mes.capitalize()} de {ano}, meu."
@@ -373,7 +395,7 @@ class AkiraAPI:
373
  web_search_context = ""
374
 
375
  # Palavras-chave que sugerem necessidade de informação em tempo real ou muito específica
376
- trigger_keywords = ['hoje', 'agora', 'recente', 'notícias', 'busca na web', 'pesquisa', 'investiga']
377
 
378
  search_query = f"{mensagem} {mensagem_citada}".strip().lower()
379
 
@@ -443,9 +465,10 @@ class AkiraAPI:
443
  temperature = getattr(self.config, 'TOP_P', 0.8)
444
 
445
  # Extrai a mensagem limpa do prompt (necessário para APIs)
446
- user_prompt_clean_match = re.search(r'### Mensagem Atual ###\n(.*?)\n\nAkira:', prompt, re.DOTALL)
 
447
  if user_prompt_clean_match:
448
- user_prompt_clean = user_prompt_clean_match.group(1).strip()
449
  else:
450
  user_prompt_clean = prompt # Fallback
451
 
 
 
1
  """
2
  API wrapper Akira IA.
3
  Prioridade: Mistral API (Phi-3 Mini) → Gemini → Fallback
 
18
  from mistralai import Mistral
19
 
20
  # LOCAL MODULES
21
+ # from .local_llm import HermesLLM # ← REMOVIDO: Era o modelo que causava a carga de 101% CPU
22
  from .contexto import Contexto
23
  from .database import Database
24
  from .treinamento import Treinamento
 
63
  self.providers = []
64
 
65
  # PRIORIDADE MÁXIMA AGORA É O MISTRAL (PHI-3 MINI)
 
 
 
 
 
66
  if self.mistral_client:
67
  self.providers.append('mistral') # Mistral (usando Phi-3) é o novo principal
68
  if self.gemini_model:
 
121
  messages.append({"role": role, "content": turn["content"]})
122
 
123
  # Extrai a mensagem limpa do prompt (necessário para APIs)
124
+ # O prompt completo é formatado em _build_prompt, mas as APIs usam o formato de messages.
125
+ # Precisamos extrair apenas a última mensagem do usuário do prompt longo para garantir que
126
+ # o histórico (que já está em context_history) não seja duplicado.
127
+ user_message_clean_match = re.search(r'(### Mensagem Atual ###|### USUÁRIO RESPONDEU A ESSA MENSAGEM: ###)\n(.*?)\n\n(Akira:|$)', user_prompt, re.DOTALL)
128
  if user_message_clean_match:
129
+ # Captura o grupo 2 (o conteúdo da mensagem)
130
+ user_message_clean = user_message_clean_match.group(2).strip()
131
  else:
132
+ # Fallback (caso o formato do prompt mude)
133
+ user_message_clean = user_prompt
134
 
135
  messages.append({"role": "user", "content": user_message_clean})
136
 
 
139
 
140
 
141
  for provider in self.providers:
 
 
 
 
142
  # 1. MISTRAL API (AGORA PRIORIDADE MÁXIMA)
143
  if provider == 'mistral' and self.mistral_client:
144
  try:
 
166
  if getattr(self.config, 'GEMINI_API_KEY', '').startswith('AIza'):
167
  genai.configure(api_key=self.config.GEMINI_API_KEY)
168
 
169
+ # Cria o histórico no formato esperado pelo Gemini (list of Content)
170
  gemini_hist = []
171
  for msg in messages[1:]:
172
  role = "user" if msg["role"] == "user" else "model"
 
241
 
242
  # CORREÇÃO: Verifica se o método existe antes de chamar
243
  if hasattr(trainer, 'start_periodic_training'):
244
+ trainer.start_periodic_training()
245
+ self.logger.info("Treinamento periódico (start_periodic_training) iniciado com sucesso.")
246
  else:
247
+ self.logger.info("Treinamento periódico (via __init__) iniciado.")
248
+
249
  except Exception as e:
250
  self.logger.exception(f"Treinador periódico falhou ao iniciar: {e}")
251
 
252
  def _setup_routes(self):
253
+ """
254
+ Configura as rotas da API, incluindo o tratamento de CORS.
255
+ """
256
+ # --- CORREÇÃO: Adiciona suporte manual a CORS ---
257
+ # 1. CORS Preflight Handler (Responde a requests OPTIONS)
258
+ @self.api.before_request
259
+ def handle_options():
260
+ if request.method == 'OPTIONS':
261
+ response = self.app.make_response('')
262
+ response.headers.add('Access-Control-Allow-Origin', '*')
263
+ response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization')
264
+ response.headers.add('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
265
+ return response
266
+
267
+ # 2. CORS Post-Request Header Addition (Adiciona headers em toda resposta)
268
+ @self.api.after_request
269
+ def add_cors_headers(response):
270
+ response.headers.add('Access-Control-Allow-Origin', '*')
271
+ response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization')
272
+ response.headers.add('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
273
+ return response
274
+ # ------------------------------------------------
275
+
276
  @self.api.route('/akira', methods=['POST'])
277
  def akira_endpoint():
278
  try:
 
291
 
292
  # --- CORREÇÃO: Resposta rápida para "Que dia é hoje?" ---
293
  prompt_lower = mensagem.lower().strip()
294
+ if any(keyword in prompt_lower for keyword in ["que dia é hoje", "qual é a data", "dia da semana", "que horas"]):
295
  hoje = datetime.datetime.now()
296
  dia_semana = hoje.strftime("%A")
297
  dia_mes = hoje.day
298
  mes = hoje.strftime("%B")
299
  ano = hoje.year
300
+ hora_minuto = hoje.strftime("%H:%M")
301
 
302
+ if "que horas" in prompt_lower:
303
+ resposta = f"São {hora_minuto} agora, meu."
304
+ elif any(k in prompt_lower for k in ["que dia", "hoje é que dia", "dia da semana"]) and not any(k in prompt_lower for k in ["mês", "ano", "data", "completa"]):
305
  resposta = f"Hoje é {dia_semana.capitalize()}, {dia_mes}, meu."
306
  else:
307
  resposta = f"Hoje é {dia_semana.capitalize()}, {dia_mes} de {mes.capitalize()} de {ano}, meu."
 
395
  web_search_context = ""
396
 
397
  # Palavras-chave que sugerem necessidade de informação em tempo real ou muito específica
398
+ trigger_keywords = ['hoje', 'agora', 'recente', 'notícias', 'busca na web', 'pesquisa', 'investiga', 'último']
399
 
400
  search_query = f"{mensagem} {mensagem_citada}".strip().lower()
401
 
 
465
  temperature = getattr(self.config, 'TOP_P', 0.8)
466
 
467
  # Extrai a mensagem limpa do prompt (necessário para APIs)
468
+ # Usa o mesmo regex do LLMManager.generate para manter a consistência
469
+ user_prompt_clean_match = re.search(r'(### Mensagem Atual ###|### USUÁRIO RESPONDEU A ESSA MENSAGEM: ###)\n(.*?)\n\n(Akira:|$)', prompt, re.DOTALL)
470
  if user_prompt_clean_match:
471
+ user_prompt_clean = user_prompt_clean_match.group(2).strip()
472
  else:
473
  user_prompt_clean = prompt # Fallback
474