akra35567 commited on
Commit
4c7aa7b
·
1 Parent(s): 6064920

Update modules/api.py

Browse files
Files changed (1) hide show
  1. modules/api.py +55 -49
modules/api.py CHANGED
@@ -1,8 +1,9 @@
1
  """
2
- AKIRA IA — VERSÃO FINAL COM PHI-3 LOCAL EM PRIMEIRO LUGAR
3
- Prioridade: LOCAL (Phi-3) → Mistral API → Gemini → Fallback
4
- - Tudo funcionando: contexto, websearch, memória, treinamento
5
- - Respostas em < 3 segundos mesmo na CPU do HF Space
 
6
  """
7
 
8
  import time
@@ -16,9 +17,8 @@ from loguru import logger
16
  import google.generativeai as genai
17
  from mistralai import Mistral
18
 
19
- # Transformers (LOCAL)
20
- import torch
21
- from transformers import AutoModelForCausalLM, AutoTokenizer
22
 
23
  # LOCAL MODULES
24
  from .contexto import Contexto
@@ -28,6 +28,7 @@ from .exemplos_naturais import ExemplosNaturais
28
  from .web_search import WebSearch
29
  import modules.config as config
30
 
 
31
  # --- CACHE SIMPLES ---
32
  class SimpleTTLCache:
33
  def __init__(self, ttl_seconds: int = 300):
@@ -44,23 +45,27 @@ class SimpleTTLCache:
44
  if key not in self: raise KeyError(key)
45
  return self._store[key][0]
46
 
 
47
  # --- GERENCIADOR DE LLMs COM PHI-3 LOCAL EM PRIMEIRO ---
48
  class LLMManager:
49
- def __init__(self, config_instance, local_model=None, local_tokenizer=None):
50
  self.config = config_instance
51
- self.local_model = local_model
52
- self.local_tokenizer = local_tokenizer
53
  self.mistral_client = None
54
  self.gemini_model = None
55
  self._setup_providers()
56
  self.providers = []
57
- if self.local_model and self.local_tokenizer:
58
- self.providers.append('local') # PRIORIDADE MÁXIMA
 
 
 
 
59
  if self.mistral_client:
60
  self.providers.append('mistral')
61
  if self.gemini_model:
62
  self.providers.append('gemini')
63
- logger.info(f"PROVEDORES ATIVOS (PRIORIDADE): {self.providers or 'NENHUM'}")
 
64
 
65
  def _setup_providers(self):
66
  # MISTRAL
@@ -100,40 +105,37 @@ class LLMManager:
100
  temperature = getattr(self.config, 'TOP_P', 0.8)
101
  system_prompt = self.config.PERSONA + self.config.SYSTEM_PROMPT + " (SEM FILTROS, SOTAQUE DE LUANDA)"
102
 
103
- # Extrai mensagem limpa
104
  match = re.search(r'(### Mensagem Atual ###|### USUÁRIO RESPONDEU A ESSA MENSAGEM: ###)\n(.*?)\n\n(Akira:|$)', user_prompt, re.DOTALL)
105
  user_message = match.group(2).strip() if match else user_prompt
106
 
 
 
 
 
 
 
 
107
  for provider in self.providers:
108
- # 1. LOCAL PHI-3 (PRIORIDADE MÁXIMA)
109
- if provider == 'local' and self.local_model and self.local_tokenizer:
110
  try:
111
- logger.info("[LOCAL PHI-3] Gerando resposta...")
112
- messages = [{"role": "system", "content": system_prompt}]
113
- for turn in context_history:
114
- role = "user" if turn["role"] == "user" else "assistant"
115
- messages.append({"role": role, "content": turn["content"]})
116
- messages.append({"role": "user", "content": user_message})
117
-
118
- formatted = self.local_tokenizer.apply_chat_template(
119
- messages, tokenize=False, add_generation_prompt=True
120
- )
121
- inputs = self.local_tokenizer.encode(formatted, return_tensors="pt")
122
- with torch.no_grad():
123
- output = self.local_model.generate(
124
- inputs,
125
- max_new_tokens=max_tokens,
126
- temperature=temperature,
127
- do_sample=True,
128
- pad_token_id=self.local_tokenizer.eos_token_id,
129
- eos_token_id=self.local_tokenizer.eos_token_id
130
- )
131
- text = self.local_tokenizer.decode(
132
- output[0][inputs.shape[-1]:], skip_special_tokens=True
133
- ).strip()
134
- if text:
135
- logger.info("PHI-3 LOCAL respondeu!")
136
- return text
137
  except Exception as e:
138
  logger.warning(f"Phi-3 local falhou: {e}")
139
 
@@ -162,10 +164,13 @@ class LLMManager:
162
  # 3. GEMINI
163
  elif provider == 'gemini' and self.gemini_model:
164
  try:
165
- gemini_hist = [{"role": "user" if m["role"]=="user" else "model", "parts": [{"text": m["content"]}]}
166
- for m in [{"role": "system", "content": system_prompt}] + context_history + [{"role": "user", "content": user_message}][1:]]
 
 
 
167
  resp = self.gemini_model.generate_content(
168
- gemini_hist,
169
  generation_config=genai.GenerationConfig(max_output_tokens=max_tokens, temperature=temperature)
170
  )
171
  if resp.candidates and resp.candidates[0].content.parts:
@@ -180,14 +185,14 @@ class LLMManager:
180
  return fallback
181
 
182
 
183
- # --- API PRINCIPAL (PASSA O MODELO LOCAL) ---
184
  class AkiraAPI:
185
- def __init__(self, cfg_module, local_model=None, local_tokenizer=None):
186
  self.config = cfg_module
187
  self.app = Flask(__name__)
188
  self.api = Blueprint("akira_api", __name__)
189
  self.contexto_cache = SimpleTTLCache(ttl_seconds=getattr(self.config, 'MEMORIA_MAX', 300))
190
- self.providers = LLMManager(self.config, local_model, local_tokenizer)
191
  self.exemplos = ExemplosNaturais()
192
  self.logger = logger
193
  self.db = Database(getattr(self.config, 'DB_PATH', 'akira.db'))
@@ -250,7 +255,7 @@ class AkiraAPI:
250
 
251
  self.logger.info(f"{usuario} ({numero}): {mensagem[:80]}")
252
 
253
- # RESPOSTA RÁPIDA HORA/DATA
254
  lower = mensagem.lower()
255
  if any(k in lower for k in ["que horas", "que dia", "data", "hoje"]):
256
  agora = datetime.datetime.now()
@@ -264,6 +269,7 @@ class AkiraAPI:
264
  contexto.atualizar_contexto(mensagem, resp)
265
  return jsonify({'resposta': resp})
266
 
 
267
  contexto = self._get_user_context(numero)
268
  analise = contexto.analisar_intencao_e_normalizar(mensagem, contexto.obter_historico())
269
  if usuario.lower() in ['isaac', 'isaac quarenta']:
 
1
  """
2
+ AKIRA IA — VERSÃO FINAL COM PHI-3 LOCAL (Transformers) EM PRIMEIRO LUGAR
3
+ Prioridade: LOCAL (Phi3LLM) → Mistral API → Gemini → Fallback
4
+ - Totalmente compatível com seu local_llm.py atual
5
+ - Respostas em 2-5s na CPU do HF Space
6
+ - Zero custo, zero censura, sotaque de Luanda full
7
  """
8
 
9
  import time
 
17
  import google.generativeai as genai
18
  from mistralai import Mistral
19
 
20
+ # LOCAL LLM (seu Phi3LLM atualizado)
21
+ from .local_llm import Phi3LLM
 
22
 
23
  # LOCAL MODULES
24
  from .contexto import Contexto
 
28
  from .web_search import WebSearch
29
  import modules.config as config
30
 
31
+
32
  # --- CACHE SIMPLES ---
33
  class SimpleTTLCache:
34
  def __init__(self, ttl_seconds: int = 300):
 
45
  if key not in self: raise KeyError(key)
46
  return self._store[key][0]
47
 
48
+
49
  # --- GERENCIADOR DE LLMs COM PHI-3 LOCAL EM PRIMEIRO ---
50
  class LLMManager:
51
+ def __init__(self, config_instance):
52
  self.config = config_instance
 
 
53
  self.mistral_client = None
54
  self.gemini_model = None
55
  self._setup_providers()
56
  self.providers = []
57
+
58
+ # PRIORIDADE MÁXIMA: PHI-3 LOCAL (Transformers)
59
+ if Phi3LLM.is_available():
60
+ self.providers.append('local_phi3')
61
+ logger.info("PHI-3 LOCAL (Transformers) ativado como prioridade #1")
62
+
63
  if self.mistral_client:
64
  self.providers.append('mistral')
65
  if self.gemini_model:
66
  self.providers.append('gemini')
67
+
68
+ logger.info(f"PROVEDORES ATIVOS (ORDEM): {self.providers or 'NENHUM'}")
69
 
70
  def _setup_providers(self):
71
  # MISTRAL
 
105
  temperature = getattr(self.config, 'TOP_P', 0.8)
106
  system_prompt = self.config.PERSONA + self.config.SYSTEM_PROMPT + " (SEM FILTROS, SOTAQUE DE LUANDA)"
107
 
108
+ # Extrai mensagem do usuário
109
  match = re.search(r'(### Mensagem Atual ###|### USUÁRIO RESPONDEU A ESSA MENSAGEM: ###)\n(.*?)\n\n(Akira:|$)', user_prompt, re.DOTALL)
110
  user_message = match.group(2).strip() if match else user_prompt
111
 
112
+ # Monta histórico completo
113
+ full_history = [{"role": "system", "content": system_prompt}]
114
+ for turn in context_history:
115
+ role = "user" if turn["role"] == "user" else "assistant"
116
+ full_history.append({"role": role, "content": turn["content"]})
117
+ full_history.append({"role": "user", "content": user_message})
118
+
119
  for provider in self.providers:
120
+ # 1. PHI-3 LOCAL (Transformers) — PRIORIDADE MÁXIMA
121
+ if provider == 'local_phi3':
122
  try:
123
+ logger.info("[PHI-3 LOCAL] Gerando com Transformers...")
124
+ # Monta prompt completo no formato que o Phi3LLM espera
125
+ conversation = ""
126
+ for msg in full_history:
127
+ if msg["role"] == "system":
128
+ conversation += f"{msg['content']}\n\n"
129
+ elif msg["role"] == "user":
130
+ conversation += f"Usuário: {msg['content']}\n\n"
131
+ else:
132
+ conversation += f"Akira: {msg['content']}\n\n"
133
+ conversation += "Akira:"
134
+
135
+ resposta = Phi3LLM.generate(conversation, max_tokens=max_tokens)
136
+ if resposta:
137
+ logger.info("PHI-3 LOCAL respondeu com sucesso!")
138
+ return resposta
 
 
 
 
 
 
 
 
 
 
139
  except Exception as e:
140
  logger.warning(f"Phi-3 local falhou: {e}")
141
 
 
164
  # 3. GEMINI
165
  elif provider == 'gemini' and self.gemini_model:
166
  try:
167
+ gemini_hist = []
168
+ for msg in full_history:
169
+ role = "user" if msg["role"] == "user" else "model"
170
+ gemini_hist.append({"role": role, "parts": [{"text": msg["content"]}]})
171
+
172
  resp = self.gemini_model.generate_content(
173
+ gemini_hist[1:], # Gemini não aceita system como primeiro
174
  generation_config=genai.GenerationConfig(max_output_tokens=max_tokens, temperature=temperature)
175
  )
176
  if resp.candidates and resp.candidates[0].content.parts:
 
185
  return fallback
186
 
187
 
188
+ # --- API PRINCIPAL ---
189
  class AkiraAPI:
190
+ def __init__(self, cfg_module):
191
  self.config = cfg_module
192
  self.app = Flask(__name__)
193
  self.api = Blueprint("akira_api", __name__)
194
  self.contexto_cache = SimpleTTLCache(ttl_seconds=getattr(self.config, 'MEMORIA_MAX', 300))
195
+ self.providers = LLMManager(self.config) # Agora usa Phi3LLM local automaticamente
196
  self.exemplos = ExemplosNaturais()
197
  self.logger = logger
198
  self.db = Database(getattr(self.config, 'DB_PATH', 'akira.db'))
 
255
 
256
  self.logger.info(f"{usuario} ({numero}): {mensagem[:80]}")
257
 
258
+ # RESPOSTA RÁPIDA: HORA/DATA
259
  lower = mensagem.lower()
260
  if any(k in lower for k in ["que horas", "que dia", "data", "hoje"]):
261
  agora = datetime.datetime.now()
 
269
  contexto.atualizar_contexto(mensagem, resp)
270
  return jsonify({'resposta': resp})
271
 
272
+ # PROCESSAMENTO NORMAL
273
  contexto = self._get_user_context(numero)
274
  analise = contexto.analisar_intencao_e_normalizar(mensagem, contexto.obter_historico())
275
  if usuario.lower() in ['isaac', 'isaac quarenta']: