|
|
import json |
|
|
import logging |
|
|
import os |
|
|
import sys |
|
|
import time |
|
|
import uuid |
|
|
|
|
|
from groq import Groq |
|
|
|
|
|
|
|
|
from .handlers import ImageHandler |
|
|
from .tts import TTSPlayer |
|
|
from .utils import slim_history |
|
|
from .shorestone import ShoreStoneMemory |
|
|
from .curator_heuristic import MemoryCuratorHeuristic |
|
|
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s - JADE - %(levelname)s - %(message)s") |
|
|
|
|
|
class JadeAgent: |
|
|
def __init__(self, config_path="jade/config.json"): |
|
|
|
|
|
|
|
|
try: |
|
|
with open(config_path) as f: |
|
|
self.cfg = json.load(f) |
|
|
except FileNotFoundError: |
|
|
|
|
|
base_dir = os.path.dirname(os.path.abspath(__file__)) |
|
|
config_path = os.path.join(base_dir, "config.json") |
|
|
with open(config_path) as f: |
|
|
self.cfg = json.load(f) |
|
|
|
|
|
|
|
|
logging.info("Iniciando J.A.D.E. em modo API (Groq)...") |
|
|
self.api_key = self._get_api_key() |
|
|
self.client = Groq(api_key=self.api_key) |
|
|
self.model_name = self.cfg.get("groq_model", "meta-llama/llama-4-maverick-17b-128e-instruct") |
|
|
|
|
|
|
|
|
self.system_prompt = {"role": "system", "content": "Você é J.A.D.E., uma IA multimodal calma e inteligente. Seja direta. Responda de forma concisa e natural. NÃO explique seu processo de pensamento. Apenas responda à pergunta."} |
|
|
|
|
|
|
|
|
logging.info("Carregando módulos de percepção e memória...") |
|
|
|
|
|
|
|
|
self.image_handler = ImageHandler(self.cfg.get("caption_model", "Salesforce/blip-image-captioning-large")) |
|
|
self.tts = TTSPlayer(lang=self.cfg.get("language", "pt")) |
|
|
|
|
|
|
|
|
self.memory = ShoreStoneMemory() |
|
|
|
|
|
self.memory.load_or_create_session("sessao_padrao_gabriel") |
|
|
|
|
|
|
|
|
self.curator = MemoryCuratorHeuristic(shorestone_memory=self.memory) |
|
|
self.response_count = 0 |
|
|
self.maintenance_interval = 10 |
|
|
|
|
|
logging.info(f"J.A.D.E. pronta e conectada ao modelo {self.model_name}.") |
|
|
|
|
|
def _get_api_key(self): |
|
|
"""Recupera a chave da API do ambiente de forma segura.""" |
|
|
key = os.getenv("GROQ_API_KEY") |
|
|
if not key: |
|
|
logging.error("Chave GROQ_API_KEY não encontrada nas variáveis de ambiente.") |
|
|
|
|
|
|
|
|
print("WARNING: GROQ_API_KEY not found.") |
|
|
return key |
|
|
|
|
|
def _chat(self, messages): |
|
|
"""Envia as mensagens para a Groq e retorna a resposta.""" |
|
|
try: |
|
|
chat = self.client.chat.completions.create( |
|
|
messages=messages, |
|
|
model=self.model_name, |
|
|
temperature=0.7, |
|
|
max_tokens=1024 |
|
|
) |
|
|
return chat.choices[0].message.content.strip() |
|
|
except Exception as e: |
|
|
logging.error(f"Erro na comunicação com a Groq: {e}") |
|
|
return "Desculpe, tive um problema ao me conectar com meu cérebro na nuvem." |
|
|
|
|
|
def respond(self, history, user_input, user_id="default", vision_context=None): |
|
|
"""Processo principal de raciocínio: Lembrar -> Ver -> Responder -> Memorizar -> Manter.""" |
|
|
|
|
|
|
|
|
session_name = f"user_{user_id}" |
|
|
self.memory.load_or_create_session(session_name) |
|
|
|
|
|
messages = history[:] |
|
|
|
|
|
|
|
|
memories = self.memory.remember(user_input) |
|
|
if memories: |
|
|
memory_context = f"--- MEMÓRIAS RELEVANTES (ShoreStone) ---\n{memories}\n--- FIM DAS MEMÓRIAS ---" |
|
|
|
|
|
messages.append({"role": "system", "content": memory_context}) |
|
|
|
|
|
|
|
|
if vision_context: |
|
|
messages.append({"role": "system", "content": f"Contexto visual da imagem que o usuário enviou: {vision_context}"}) |
|
|
|
|
|
|
|
|
history.append({"role": "user", "content": user_input}) |
|
|
messages.append({"role": "user", "content": user_input}) |
|
|
|
|
|
|
|
|
resposta = self._chat(messages) |
|
|
|
|
|
|
|
|
history.append({"role": "assistant", "content": resposta}) |
|
|
history = slim_history(history, keep=self.cfg.get("max_context", 12)) |
|
|
|
|
|
|
|
|
self.memory.memorize(user_input, resposta) |
|
|
|
|
|
print(f"\n🤖 J.A.D.E.: {resposta}") |
|
|
|
|
|
|
|
|
audio_path = None |
|
|
try: |
|
|
|
|
|
audio_path = self.tts.save_audio_to_file(resposta) |
|
|
except Exception as e: |
|
|
logging.warning(f"TTS falhou (silenciado): {e}") |
|
|
|
|
|
|
|
|
self.response_count += 1 |
|
|
if self.response_count % self.maintenance_interval == 0: |
|
|
logging.info(f"Ciclo de manutenção agendado (interação {self.response_count}). Verificando saúde da memória...") |
|
|
try: |
|
|
self.curator.run_maintenance_cycle() |
|
|
except Exception as e: |
|
|
logging.error(f"Erro no Curador de Memória: {e}") |
|
|
|
|
|
return resposta, audio_path, history |
|
|
|