Madras1 commited on
Commit
02091cf
·
verified ·
1 Parent(s): b95c170

Update jade/core.py

Browse files
Files changed (1) hide show
  1. jade/core.py +168 -168
jade/core.py CHANGED
@@ -1,168 +1,168 @@
1
- import json
2
- import logging
3
- import os
4
- import sys
5
- import time
6
- import uuid
7
-
8
- from groq import Groq
9
-
10
- # Importa nossos módulos customizados
11
- from .handlers import ImageHandler
12
- from .tts import TTSPlayer
13
- from .utils import slim_history
14
- from .shorestone import ShoreStoneMemory
15
- from .curator_heuristic import MemoryCuratorHeuristic
16
- from .web_search import WebSearchHandler
17
-
18
- # Configura o logger principal
19
- logging.basicConfig(level=logging.INFO, format="%(asctime)s - JADE - %(levelname)s - %(message)s")
20
-
21
- class JadeAgent:
22
- def __init__(self, config_path="jade/config.json"):
23
- # Carrega configurações
24
- # Try to load from absolute path first, then relative
25
- try:
26
- with open(config_path) as f:
27
- self.cfg = json.load(f)
28
- except FileNotFoundError:
29
- # Fallback: try to find it relative to this file
30
- base_dir = os.path.dirname(os.path.abspath(__file__))
31
- config_path = os.path.join(base_dir, "config.json")
32
- with open(config_path) as f:
33
- self.cfg = json.load(f)
34
-
35
- # --- Configuração da API Groq ---
36
- logging.info("Iniciando J.A.D.E. em modo API (Groq)...")
37
- self.api_key = self._get_api_key()
38
- self.client = Groq(api_key=self.api_key)
39
- self.model_name = self.cfg.get("groq_model", "meta-llama/llama-4-maverick-17b-128e-instruct")
40
-
41
- # System Prompt Base
42
- 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."}
43
-
44
- # --- Inicialização dos Módulos ---
45
- logging.info("Carregando módulos de percepção e memória...")
46
-
47
- # Visão e Fala
48
- self.image_handler = ImageHandler(self.cfg.get("caption_model", "Salesforce/blip-image-captioning-large"))
49
- self.tts = TTSPlayer(lang=self.cfg.get("language", "pt"))
50
-
51
- # 1. Memória ShoreStone (Persistente)
52
- self.memory = ShoreStoneMemory()
53
- # Inicializa com sessão padrão, mas será trocada dinamicamente no respond()
54
- self.memory.load_or_create_session("sessao_padrao_gabriel")
55
-
56
- # 2. Curador Heurístico (Manutenção Automática)
57
- self.curator = MemoryCuratorHeuristic(shorestone_memory=self.memory)
58
- self.response_count = 0
59
- self.maintenance_interval = 10 # Executar a manutenção a cada 10 interações
60
-
61
- # 3. Web Search (Tavily)
62
- self.web_search_handler = WebSearchHandler()
63
-
64
- logging.info(f"J.A.D.E. pronta e conectada ao modelo {self.model_name}.")
65
-
66
- def _get_api_key(self):
67
- """Recupera a chave da API do ambiente de forma segura."""
68
- key = os.getenv("GROQ_API_KEY")
69
- if not key:
70
- logging.error("Chave GROQ_API_KEY não encontrada nas variáveis de ambiente.")
71
- # For development, try to warn but not crash if possible, but Groq needs it.
72
- # raise RuntimeError("❌ GROQ_API_KEY não encontrada. Defina a variável de ambiente.")
73
- print("WARNING: GROQ_API_KEY not found.")
74
- return key
75
-
76
- def _chat(self, messages):
77
- """Envia as mensagens para a Groq e retorna a resposta."""
78
- try:
79
- chat = self.client.chat.completions.create(
80
- messages=messages,
81
- model=self.model_name,
82
- temperature=0.7, # Criatividade balanceada
83
- max_tokens=1024 # Limite de resposta razoável
84
- )
85
- return chat.choices[0].message.content.strip()
86
- except Exception as e:
87
- logging.error(f"Erro na comunicação com a Groq: {e}")
88
- return "Desculpe, tive um problema ao me conectar com meu cérebro na nuvem."
89
-
90
- def respond(self, history, user_input, user_id="default", vision_context=None, web_search=False, thinking_mode=False):
91
- """Processo principal de raciocínio: Buscar -> Lembrar -> Ver -> Pensar -> Responder -> Memorizar -> Manter."""
92
-
93
- # TROCA A SESSÃO DA MEMÓRIA PARA O USUÁRIO ATUAL
94
- session_name = f"user_{user_id}"
95
- self.memory.load_or_create_session(session_name)
96
-
97
- messages = history[:]
98
-
99
- # 0. Thinking Mode - Adiciona instrução de CoT
100
- if thinking_mode:
101
- thinking_prompt = {
102
- "role": "system",
103
- "content": """MODO THINKING ATIVADO: Antes de dar sua resposta final, pense passo a passo.
104
- Coloque todo seu raciocínio dentro de tags <thinking>...</thinking>.
105
- Após fechar a tag </thinking>, dê sua resposta final de forma clara e direta.
106
- Exemplo:
107
- <thinking>
108
- 1. Primeiro, vou analisar...
109
- 2. Considerando que...
110
- 3. Portanto...
111
- </thinking>
112
-
113
- [Sua resposta final aqui]"""
114
- }
115
- messages.append(thinking_prompt)
116
-
117
- # 0. Buscar na Web (se habilitado)
118
- if web_search and self.web_search_handler.is_available():
119
- search_results = self.web_search_handler.search(user_input)
120
- if search_results:
121
- search_context = f"--- RESULTADOS DA BUSCA WEB ---\n{search_results}\n--- FIM DA BUSCA ---"
122
- messages.append({"role": "system", "content": search_context})
123
-
124
- # 1. Lembrar (Recuperação de Contexto)
125
- memories = self.memory.remember(user_input)
126
- if memories:
127
- memory_context = f"--- MEMÓRIAS RELEVANTES (ShoreStone) ---\n{memories}\n--- FIM DAS MEMÓRIAS ---"
128
- # Inserimos as memórias como contexto de sistema para guiar a resposta
129
- messages.append({"role": "system", "content": memory_context})
130
-
131
- # 2. Ver (Contexto Visual)
132
- if vision_context:
133
- messages.append({"role": "system", "content": f"Contexto visual da imagem que o usuário enviou: {vision_context}"})
134
-
135
- # Adiciona a pergunta atual ao histórico temporário e ao prompt
136
- history.append({"role": "user", "content": user_input})
137
- messages.append({"role": "user", "content": user_input})
138
-
139
- # 3. Responder (Geração)
140
- resposta = self._chat(messages)
141
-
142
- # Atualiza histórico
143
- history.append({"role": "assistant", "content": resposta})
144
- history = slim_history(history, keep=self.cfg.get("max_context", 12))
145
-
146
- # 4. Memorizar (Armazenamento Persistente)
147
- self.memory.memorize(user_input, resposta)
148
-
149
- print(f"\n🤖 J.A.D.E.: {resposta}")
150
-
151
- # Falar (TTS) - Modified for Backend compatibility
152
- audio_path = None
153
- try:
154
- # Uses the TTSPlayer from tts.py which has save_audio_to_file
155
- audio_path = self.tts.save_audio_to_file(resposta)
156
- except Exception as e:
157
- logging.warning(f"TTS falhou (silenciado): {e}")
158
-
159
- # 5. Manter (Ciclo de Curadoria Automática)
160
- self.response_count += 1
161
- if self.response_count % self.maintenance_interval == 0:
162
- logging.info(f"Ciclo de manutenção agendado (interação {self.response_count}). Verificando saúde da memória...")
163
- try:
164
- self.curator.run_maintenance_cycle()
165
- except Exception as e:
166
- logging.error(f"Erro no Curador de Memória: {e}")
167
-
168
- return resposta, audio_path, history
 
1
+ import json
2
+ import logging
3
+ import os
4
+ import sys
5
+ import time
6
+ import uuid
7
+
8
+ from groq import Groq
9
+
10
+ # Importa nossos módulos customizados
11
+ from .handlers import ImageHandler
12
+ from .tts import TTSPlayer
13
+ from .utils import slim_history
14
+ from .shorestone import ShoreStoneMemory
15
+ from .curator_heuristic import MemoryCuratorHeuristic
16
+ from .web_search import WebSearchHandler
17
+
18
+ # Configura o logger principal
19
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s - JADE - %(levelname)s - %(message)s")
20
+
21
+ class JadeAgent:
22
+ def __init__(self, config_path="jade/config.json"):
23
+ # Carrega configurações
24
+ # Try to load from absolute path first, then relative
25
+ try:
26
+ with open(config_path) as f:
27
+ self.cfg = json.load(f)
28
+ except FileNotFoundError:
29
+ # Fallback: try to find it relative to this file
30
+ base_dir = os.path.dirname(os.path.abspath(__file__))
31
+ config_path = os.path.join(base_dir, "config.json")
32
+ with open(config_path) as f:
33
+ self.cfg = json.load(f)
34
+
35
+ # --- Configuração da API Groq ---
36
+ logging.info("Iniciando J.A.D.E. em modo API (Groq)...")
37
+ self.api_key = self._get_api_key()
38
+ self.client = Groq(api_key=self.api_key)
39
+ self.model_name = self.cfg.get("groq_model", "moonshotai/kimi-k2-instruct-0905")
40
+
41
+ # System Prompt Base
42
+ 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."}
43
+
44
+ # --- Inicialização dos Módulos ---
45
+ logging.info("Carregando módulos de percepção e memória...")
46
+
47
+ # Visão e Fala
48
+ self.image_handler = ImageHandler(self.cfg.get("caption_model", "Salesforce/blip-image-captioning-large"))
49
+ self.tts = TTSPlayer(lang=self.cfg.get("language", "pt"))
50
+
51
+ # 1. Memória ShoreStone (Persistente)
52
+ self.memory = ShoreStoneMemory()
53
+ # Inicializa com sessão padrão, mas será trocada dinamicamente no respond()
54
+ self.memory.load_or_create_session("sessao_padrao_gabriel")
55
+
56
+ # 2. Curador Heurístico (Manutenção Automática)
57
+ self.curator = MemoryCuratorHeuristic(shorestone_memory=self.memory)
58
+ self.response_count = 0
59
+ self.maintenance_interval = 10 # Executar a manutenção a cada 10 interações
60
+
61
+ # 3. Web Search (Tavily)
62
+ self.web_search_handler = WebSearchHandler()
63
+
64
+ logging.info(f"J.A.D.E. pronta e conectada ao modelo {self.model_name}.")
65
+
66
+ def _get_api_key(self):
67
+ """Recupera a chave da API do ambiente de forma segura."""
68
+ key = os.getenv("GROQ_API_KEY")
69
+ if not key:
70
+ logging.error("Chave GROQ_API_KEY não encontrada nas variáveis de ambiente.")
71
+ # For development, try to warn but not crash if possible, but Groq needs it.
72
+ # raise RuntimeError("❌ GROQ_API_KEY não encontrada. Defina a variável de ambiente.")
73
+ print("WARNING: GROQ_API_KEY not found.")
74
+ return key
75
+
76
+ def _chat(self, messages):
77
+ """Envia as mensagens para a Groq e retorna a resposta."""
78
+ try:
79
+ chat = self.client.chat.completions.create(
80
+ messages=messages,
81
+ model=self.model_name,
82
+ temperature=0.7, # Criatividade balanceada
83
+ max_tokens=1024 # Limite de resposta razoável
84
+ )
85
+ return chat.choices[0].message.content.strip()
86
+ except Exception as e:
87
+ logging.error(f"Erro na comunicação com a Groq: {e}")
88
+ return "Desculpe, tive um problema ao me conectar com meu cérebro na nuvem."
89
+
90
+ def respond(self, history, user_input, user_id="default", vision_context=None, web_search=False, thinking_mode=False):
91
+ """Processo principal de raciocínio: Buscar -> Lembrar -> Ver -> Pensar -> Responder -> Memorizar -> Manter."""
92
+
93
+ # TROCA A SESSÃO DA MEMÓRIA PARA O USUÁRIO ATUAL
94
+ session_name = f"user_{user_id}"
95
+ self.memory.load_or_create_session(session_name)
96
+
97
+ messages = history[:]
98
+
99
+ # 0. Thinking Mode - Adiciona instrução de CoT
100
+ if thinking_mode:
101
+ thinking_prompt = {
102
+ "role": "system",
103
+ "content": """MODO THINKING ATIVADO: Antes de dar sua resposta final, pense passo a passo.
104
+ Coloque todo seu raciocínio dentro de tags <thinking>...</thinking>.
105
+ Após fechar a tag </thinking>, dê sua resposta final de forma clara e direta.
106
+ Exemplo:
107
+ <thinking>
108
+ 1. Primeiro, vou analisar...
109
+ 2. Considerando que...
110
+ 3. Portanto...
111
+ </thinking>
112
+
113
+ [Sua resposta final aqui]"""
114
+ }
115
+ messages.append(thinking_prompt)
116
+
117
+ # 0. Buscar na Web (se habilitado)
118
+ if web_search and self.web_search_handler.is_available():
119
+ search_results = self.web_search_handler.search(user_input)
120
+ if search_results:
121
+ search_context = f"--- RESULTADOS DA BUSCA WEB ---\n{search_results}\n--- FIM DA BUSCA ---"
122
+ messages.append({"role": "system", "content": search_context})
123
+
124
+ # 1. Lembrar (Recuperação de Contexto)
125
+ memories = self.memory.remember(user_input)
126
+ if memories:
127
+ memory_context = f"--- MEMÓRIAS RELEVANTES (ShoreStone) ---\n{memories}\n--- FIM DAS MEMÓRIAS ---"
128
+ # Inserimos as memórias como contexto de sistema para guiar a resposta
129
+ messages.append({"role": "system", "content": memory_context})
130
+
131
+ # 2. Ver (Contexto Visual)
132
+ if vision_context:
133
+ messages.append({"role": "system", "content": f"Contexto visual da imagem que o usuário enviou: {vision_context}"})
134
+
135
+ # Adiciona a pergunta atual ao histórico temporário e ao prompt
136
+ history.append({"role": "user", "content": user_input})
137
+ messages.append({"role": "user", "content": user_input})
138
+
139
+ # 3. Responder (Geração)
140
+ resposta = self._chat(messages)
141
+
142
+ # Atualiza histórico
143
+ history.append({"role": "assistant", "content": resposta})
144
+ history = slim_history(history, keep=self.cfg.get("max_context", 12))
145
+
146
+ # 4. Memorizar (Armazenamento Persistente)
147
+ self.memory.memorize(user_input, resposta)
148
+
149
+ print(f"\n🤖 J.A.D.E.: {resposta}")
150
+
151
+ # Falar (TTS) - Modified for Backend compatibility
152
+ audio_path = None
153
+ try:
154
+ # Uses the TTSPlayer from tts.py which has save_audio_to_file
155
+ audio_path = self.tts.save_audio_to_file(resposta)
156
+ except Exception as e:
157
+ logging.warning(f"TTS falhou (silenciado): {e}")
158
+
159
+ # 5. Manter (Ciclo de Curadoria Automática)
160
+ self.response_count += 1
161
+ if self.response_count % self.maintenance_interval == 0:
162
+ logging.info(f"Ciclo de manutenção agendado (interação {self.response_count}). Verificando saúde da memória...")
163
+ try:
164
+ self.curator.run_maintenance_cycle()
165
+ except Exception as e:
166
+ logging.error(f"Erro no Curador de Memória: {e}")
167
+
168
+ return resposta, audio_path, history