Spaces:
Running
Running
Update modules/api.py
Browse files- modules/api.py +17 -17
modules/api.py
CHANGED
|
@@ -1,10 +1,9 @@
|
|
| 1 |
"""
|
| 2 |
-
API wrapper para o serviço Akira - VERSÃO FINAL (11/2025)
|
| 3 |
-
✅
|
| 4 |
-
✅
|
| 5 |
-
✅
|
| 6 |
✅ Logs detalhados
|
| 7 |
-
✅ Gemini sem filtro rígido
|
| 8 |
"""
|
| 9 |
|
| 10 |
from typing import Any
|
|
@@ -101,10 +100,12 @@ class LLMManager:
|
|
| 101 |
temperature=temperature,
|
| 102 |
top_p=self.config.TOP_P,
|
| 103 |
)
|
| 104 |
-
text = resp
|
| 105 |
-
if text:
|
| 106 |
-
|
| 107 |
-
|
|
|
|
|
|
|
| 108 |
except Exception as e:
|
| 109 |
logger.warning(f"Mistral erro {attempt}: {e}")
|
| 110 |
|
|
@@ -129,7 +130,10 @@ class LLMManager:
|
|
| 129 |
"top_p": self.config.TOP_P,
|
| 130 |
}
|
| 131 |
)
|
| 132 |
-
text
|
|
|
|
|
|
|
|
|
|
| 133 |
if text and isinstance(text, str) and text.strip():
|
| 134 |
logger.info(f"✅ Gemini OK (tentativa {attempt})")
|
| 135 |
return self._limpar_resposta(text)
|
|
@@ -138,8 +142,8 @@ class LLMManager:
|
|
| 138 |
if "429" in str(e) or "quota" in str(e):
|
| 139 |
time.sleep(2 ** (attempt % 3))
|
| 140 |
|
| 141 |
-
logger.error("❌ Todos os provedores falharam.")
|
| 142 |
-
return self.config.
|
| 143 |
|
| 144 |
|
| 145 |
# ================================
|
|
@@ -206,7 +210,7 @@ REGRAS:
|
|
| 206 |
def akira_endpoint():
|
| 207 |
try:
|
| 208 |
raw_data = request.get_data(as_text=True)
|
| 209 |
-
logger.info(f"📩 RAW recebido ({len(raw_data)} bytes)
|
| 210 |
|
| 211 |
try:
|
| 212 |
if isinstance(request.json, dict):
|
|
@@ -218,7 +222,6 @@ REGRAS:
|
|
| 218 |
data = {}
|
| 219 |
|
| 220 |
if not isinstance(data, dict):
|
| 221 |
-
logger.warning(f"🚨 Corpo não é dict: {type(data)}")
|
| 222 |
data = {}
|
| 223 |
|
| 224 |
usuario = data.get('usuario', 'Anônimo')
|
|
@@ -228,8 +231,6 @@ REGRAS:
|
|
| 228 |
is_reply = bool(data.get('is_reply') or data.get('mensagem_original'))
|
| 229 |
mensagem_original = data.get('mensagem_original') or data.get('quoted_message') or ''
|
| 230 |
|
| 231 |
-
logger.info(f"👤 {usuario} ({numero}) disse: {mensagem}")
|
| 232 |
-
|
| 233 |
if not isinstance(mensagem, str) or not mensagem.strip():
|
| 234 |
return jsonify({'error': 'mensagem obrigatória'}), 400
|
| 235 |
|
|
@@ -238,7 +239,6 @@ REGRAS:
|
|
| 238 |
prompt = self._build_prompt(usuario, numero, mensagem, emocao, contexto, is_privileged, is_reply, mensagem_original)
|
| 239 |
|
| 240 |
resposta = self.providers.generate(prompt, max_tokens=500, temperature=0.8)
|
| 241 |
-
logger.info(f"💬 Resposta: {resposta}")
|
| 242 |
|
| 243 |
contexto.atualizar_contexto(mensagem, resposta)
|
| 244 |
self.treinador.registrar_interacao(usuario, mensagem, resposta, numero, is_reply, mensagem_original)
|
|
|
|
| 1 |
"""
|
| 2 |
+
API wrapper para o serviço Akira - VERSÃO FINAL RETIFICADA (11/2025)
|
| 3 |
+
✅ Gemini seguro (respeita ausência de Part)
|
| 4 |
+
✅ Mistral SDK compatível (novo/antigo)
|
| 5 |
+
✅ Fallback global
|
| 6 |
✅ Logs detalhados
|
|
|
|
| 7 |
"""
|
| 8 |
|
| 9 |
from typing import Any
|
|
|
|
| 100 |
temperature=temperature,
|
| 101 |
top_p=self.config.TOP_P,
|
| 102 |
)
|
| 103 |
+
text = getattr(resp, "choices", None)
|
| 104 |
+
if text and len(text) > 0 and hasattr(text[0], "message"):
|
| 105 |
+
text_val = getattr(text[0].message, "content", None)
|
| 106 |
+
if text_val:
|
| 107 |
+
logger.info(f"✅ Mistral OK (tentativa {attempt})")
|
| 108 |
+
return self._limpar_resposta(text_val)
|
| 109 |
except Exception as e:
|
| 110 |
logger.warning(f"Mistral erro {attempt}: {e}")
|
| 111 |
|
|
|
|
| 130 |
"top_p": self.config.TOP_P,
|
| 131 |
}
|
| 132 |
)
|
| 133 |
+
# Acessa text de forma segura, mesmo sem 'Part'
|
| 134 |
+
text = getattr(resp, "text", None)
|
| 135 |
+
if not text and hasattr(resp, "candidates") and len(resp.candidates) > 0:
|
| 136 |
+
text = getattr(resp.candidates[0], "content", None)
|
| 137 |
if text and isinstance(text, str) and text.strip():
|
| 138 |
logger.info(f"✅ Gemini OK (tentativa {attempt})")
|
| 139 |
return self._limpar_resposta(text)
|
|
|
|
| 142 |
if "429" in str(e) or "quota" in str(e):
|
| 143 |
time.sleep(2 ** (attempt % 3))
|
| 144 |
|
| 145 |
+
logger.error("❌ Todos os provedores falharam. Retornando fallback.")
|
| 146 |
+
return getattr(self.config, "FALLBACK_RESPONSE", "Desculpa, puto, não consegui responder.")
|
| 147 |
|
| 148 |
|
| 149 |
# ================================
|
|
|
|
| 210 |
def akira_endpoint():
|
| 211 |
try:
|
| 212 |
raw_data = request.get_data(as_text=True)
|
| 213 |
+
logger.info(f"📩 RAW recebido ({len(raw_data)} bytes)")
|
| 214 |
|
| 215 |
try:
|
| 216 |
if isinstance(request.json, dict):
|
|
|
|
| 222 |
data = {}
|
| 223 |
|
| 224 |
if not isinstance(data, dict):
|
|
|
|
| 225 |
data = {}
|
| 226 |
|
| 227 |
usuario = data.get('usuario', 'Anônimo')
|
|
|
|
| 231 |
is_reply = bool(data.get('is_reply') or data.get('mensagem_original'))
|
| 232 |
mensagem_original = data.get('mensagem_original') or data.get('quoted_message') or ''
|
| 233 |
|
|
|
|
|
|
|
| 234 |
if not isinstance(mensagem, str) or not mensagem.strip():
|
| 235 |
return jsonify({'error': 'mensagem obrigatória'}), 400
|
| 236 |
|
|
|
|
| 239 |
prompt = self._build_prompt(usuario, numero, mensagem, emocao, contexto, is_privileged, is_reply, mensagem_original)
|
| 240 |
|
| 241 |
resposta = self.providers.generate(prompt, max_tokens=500, temperature=0.8)
|
|
|
|
| 242 |
|
| 243 |
contexto.atualizar_contexto(mensagem, resposta)
|
| 244 |
self.treinador.registrar_interacao(usuario, mensagem, resposta, numero, is_reply, mensagem_original)
|