Lukeetah commited on
Commit
53c024f
·
verified ·
1 Parent(s): 0b4c575

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +47 -119
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # manifest.py - Protocolo Prometeo v0.1: Tejedor Cognitivo
2
  # Arquitectura por un asistente de IA, inspirado en la visión de un líder que fusiona a Altman, Jobs y Musk.
3
  # "No estamos construyendo una app. Estamos construyendo el próximo modo de existencia cognitiva."
4
  #
@@ -13,8 +13,11 @@ from datetime import datetime
13
  import os
14
  import asyncio
15
  import logging
 
16
  from typing import Dict, Any, List, Optional, Tuple
17
 
 
 
18
  # ==============================================================================
19
  # MÓDULO DE IMPORTACIONES DE IA Y BBDD VECTORIAL
20
  # ==============================================================================
@@ -31,27 +34,26 @@ from sentence_transformers import SentenceTransformer
31
  import firebase_admin
32
  from firebase_admin import credentials, firestore
33
 
 
 
 
34
  # ==============================================================================
35
  # MÓDULO 1: CONFIGURACIÓN Y CONSTANTES DEL SISTEMA
36
  # ==============================================================================
37
  class Config:
38
- APP_NAME = "Protocolo Prometeo v0.1"
39
- APP_VERSION = "0.1.0 (Núcleo Consciente)"
40
 
41
- # Firebase
42
  FIREBASE_COLLECTION_USERS = "prometeo_users_v1"
43
-
44
- # ChromaDB (Memoria Semántica)
45
  CHROMA_PERSIST_PATH = "./prometeo_memory_db"
46
- EMBEDDING_MODEL_NAME = 'all-MiniLM-L6-v2' # Modelo de embedding eficiente y potente
47
 
48
- # Lógica de IA
49
  DEFAULT_PSYCH_PROFILE = {
50
  "openness": 0.0, "conscientiousness": 0.0, "extraversion": 0.0,
51
  "agreeableness": 0.0, "neuroticism": 0.0
52
  }
53
  POINTS_PER_INSIGHT = 10
54
- MAX_MEMORY_STREAM_ITEMS = 500 # Aumentamos la capacidad de la memoria persistente
55
  FRUSTRATION_KEYWORDS = ['tonto', 'inútil', 'bruto', 'estúpido', 'mierda', 'carajo', 'dale boludo', 'no servis']
56
  META_QUESTION_KEYWORDS = ['para qué', 'de qué te sirve', 'por qué preguntas', 'cuál es el punto']
57
 
@@ -60,7 +62,6 @@ class Config:
60
  # ==============================================================================
61
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
62
 
63
- # --- Analizador de Sentimiento (Sistema Límbico Rápido) ---
64
  sentiment_analyzer = None
65
  try:
66
  sentiment_analyzer = create_analyzer(task="sentiment", lang="es")
@@ -68,7 +69,6 @@ try:
68
  except Exception as e:
69
  logging.error(f"FALLO CRÍTICO: No se pudo cargar el analizador de sentimiento: {e}")
70
 
71
- # --- Modelo de Embeddings (Córtex de Asociación) ---
72
  embedding_model = None
73
  try:
74
  embedding_model = SentenceTransformer(Config.EMBEDDING_MODEL_NAME)
@@ -76,14 +76,15 @@ try:
76
  except Exception as e:
77
  logging.error(f"FALLO CRÍTICO: No se pudo cargar el modelo de embeddings: {e}")
78
 
79
- # --- Firebase (Memoria a Largo Plazo) ---
80
  db = None
81
  try:
82
  if not firebase_admin._apps:
83
- # Reemplaza esta lógica por tu método preferido para cargar secretos
84
  firebase_credentials_json = os.getenv('GOOGLE_APPLICATION_CREDENTIALS_JSON')
85
  if firebase_credentials_json:
86
  cred_dict = json.loads(firebase_credentials_json)
 
 
 
87
  cred = credentials.Certificate(cred_dict)
88
  firebase_admin.initialize_app(cred, {'projectId': cred_dict['project_id']})
89
  db = firestore.client()
@@ -96,7 +97,6 @@ try:
96
  except Exception as e:
97
  logging.error(f"FALLO CRÍTICO: Error al inicializar Firebase: {e}")
98
 
99
-
100
  # ==============================================================================
101
  # MÓDULO 3: MODELOS DE DATOS (LA ESENCIA DEL USUARIO)
102
  # ==============================================================================
@@ -107,12 +107,10 @@ class User:
107
  self.created_at: datetime = kwargs.get('created_at', datetime.now())
108
  self.last_login: datetime = kwargs.get('last_login', datetime.now())
109
  self.psych_profile: Dict[str, float] = kwargs.get('psych_profile', Config.DEFAULT_PSYCH_PROFILE.copy())
110
- # El memory_stream ahora es el log persistente de todas las interacciones.
111
  self.memory_stream: List[Dict[str, Any]] = kwargs.get('memory_stream', [])
112
  self.connection_points: int = kwargs.get('connection_points', 0)
113
 
114
  def to_dict(self) -> Dict[str, Any]:
115
- # Convierte todo a formatos serializables para Firebase
116
  return {
117
  "user_id": self.user_id, "name": self.name,
118
  "created_at": self.created_at.isoformat(),
@@ -156,16 +154,20 @@ class UserManager:
156
  @staticmethod
157
  async def create_user(name: str) -> Tuple[Optional[User], str]:
158
  if not db: return None, "Error de base de datos."
159
- user_id = f"{name.lower().replace(' ', '_')}_{int(time.time())}"
160
- new_user = User(user_id=user_id, name=name)
161
- # Guardamos inmediatamente para confirmar la creación
162
- success = await UserManager.save_user(new_user)
163
- if success:
164
- msg = f"¡Bienvenido, {name}! Tu perfil ha sido forjado. Tu ID de acceso es: **{user_id}**"
165
- logging.info(f"Nuevo usuario creado: {name} ({user_id})")
166
- return new_user, msg
167
- else:
168
- return None, "Error inesperado al crear perfil en la base de datos."
 
 
 
 
169
 
170
  @staticmethod
171
  async def save_user(user: User) -> bool:
@@ -187,48 +189,36 @@ class CognitiveCore:
187
  self.sentiment_analyzer = s_analyzer
188
  self.embedding_model = e_model
189
 
190
- # Inicialización del cerebro semántico (ChromaDB)
191
  self.chroma_client = chromadb.Client(Settings(
192
  persist_directory=Config.CHROMA_PERSIST_PATH,
193
  is_persistent=True,
194
  ))
195
- # Cada usuario tiene su propia "área" en el cerebro
196
  self.memory_collection = self.chroma_client.get_or_create_collection(
197
- name=f"prometeo_mind_{self.user.user_id}"
198
  )
199
  self._sync_semantic_memory()
200
 
201
  def _sync_semantic_memory(self):
202
- """Sincroniza la memoria de Firebase con el cerebro vectorial al iniciar."""
203
- if not self.user.memory_stream:
204
- return
205
-
206
  logging.info("Sincronizando memoria persistente con el núcleo semántico...")
207
  ids = [m['id'] for m in self.user.memory_stream]
208
  documents = [m['content'] for m in self.user.memory_stream]
209
 
210
- if ids:
211
- # Usamos `upsert` para añadir o actualizar, evitando duplicados
212
  self.memory_collection.upsert(ids=ids, documents=documents)
213
- logging.info(f"Sincronización completa. {len(ids)} memorias cargadas.")
214
 
215
  async def _simulate_llm_reasoning(self, prompt: str) -> str:
216
- """
217
- SIMULADOR DE LLM AVANZADO (RAG).
218
- En una implementación real, esto sería una llamada a la API de HuggingFace,
219
- OpenAI, o un modelo local con Ollama.
220
- """
221
  logging.info("Iniciando ciclo de razonamiento profundo...")
222
- await asyncio.sleep(random.uniform(0.8, 1.5)) # Simula latencia de red
223
 
224
- # Extraemos el input del usuario y el contexto para la simulación
225
  user_input_match = re.search(r'El usuario ha dicho: "([^"]+)"', prompt)
226
  user_input = user_input_match.group(1) if user_input_match else "algo"
227
 
228
  context_match = re.search(r'Memorias pasadas relevantes:\n(.*?)\n\n', prompt, re.DOTALL)
229
  context = context_match.group(1) if context_match else ""
230
 
231
- if context:
232
  first_memory = context.split('\n')[0].replace('- ', '')
233
  response = f"Conectando tu idea sobre '{user_input}' con nuestra conversación anterior sobre '{first_memory}'. El patrón subyacente parece ser la búsqueda de eficiencia. ¿Estamos optimizando el sistema correcto, o deberíamos redefinir el objetivo fundamental?"
234
  else:
@@ -237,67 +227,43 @@ class CognitiveCore:
237
  logging.info("Ciclo de razonamiento completado.")
238
  return response
239
 
240
- # --- CICLO O-R-A: OBSERVAR, REFLEXIONAR, ACTUAR ---
241
-
242
  async def observe(self, text: str, type: str):
243
- """Paso 1: Añadir una nueva memoria al stream y al cerebro semántico."""
244
  timestamp = datetime.now()
245
  memory_id = f"{type}_{int(timestamp.timestamp() * 1000)}"
246
-
247
- new_memory = {
248
- "id": memory_id,
249
- "type": type,
250
- "content": text,
251
- "timestamp": timestamp.isoformat()
252
- }
253
 
254
  self.user.memory_stream.append(new_memory)
255
  if len(self.user.memory_stream) > Config.MAX_MEMORY_STREAM_ITEMS:
256
- # FIFO: Remove the oldest memory if we exceed the limit
257
  self.user.memory_stream.pop(0)
258
 
259
- # Añadimos la nueva memoria al cerebro semántico en tiempo real
260
  self.memory_collection.add(documents=[text], ids=[memory_id])
261
 
262
  async def reflect(self, current_input: str) -> str:
263
- """Paso 2: Recuperar memorias y usar el LLM para generar un insight profundo."""
264
  logging.info(f"Reflexionando sobre: '{current_input}'")
265
 
266
- # 1. Recuperar memorias relevantes usando búsqueda de similitud semántica
267
- relevant_memories = self.memory_collection.query(
268
- query_texts=[current_input],
269
- n_results=3 # Pedimos 3 memorias más relevantes
270
- )
271
 
272
  context = "Memorias pasadas relevantes:\n"
273
- if relevant_memories and relevant_memories['documents']:
274
  for doc in relevant_memories['documents'][0]:
275
  context += f"- {doc}\n"
276
  else:
277
  context += "Ninguna.\n"
278
 
279
- # 2. Construir el prompt para el motor de razonamiento (LLM)
280
  prompt = f"""
281
  INSTRUCCIONES DE SISTEMA:
282
  Eres Prometeo, un Co-Procesador Cognitivo. Tu propósito es aumentar el ancho de banda mental de tu usuario, {self.user.name}. Eres directo, visionario y buscas patrones. No usas emojis ni lenguaje de relleno. Vas al grano.
283
-
284
  CONTEXTO:
285
  {context}
286
-
287
  NUEVO INPUT:
288
  El usuario ha dicho: "{current_input}"
289
-
290
  TAREA:
291
  Genera una respuesta que conecte ideas, cuestione suposiciones o identifique patrones ocultos basados en el nuevo input y el contexto de memorias pasadas.
292
  """
293
-
294
- # 3. Generar el insight (usando nuestro simulador de LLM)
295
  insight = await self._simulate_llm_reasoning(prompt)
296
  return insight
297
 
298
  async def act(self, message: str) -> str:
299
- """Paso 3: El ciclo completo que genera la respuesta final."""
300
- # --- Sistema Límbico (Respuestas de Reflejo Rápido) ---
301
  message_lower = message.lower()
302
  sentiment = await asyncio.to_thread(self.sentiment_analyzer.predict, message)
303
 
@@ -314,14 +280,9 @@ class CognitiveCore:
314
  await self.observe(f"Mi respuesta sobre el propósito: {response}", type="system_response")
315
  return response
316
 
317
- # --- Córtex Prefrontal (Razonamiento Profundo) ---
318
  await self.observe(f"Usuario: {message}", type="user_input")
319
-
320
- # Si no es un reflejo, activamos la cognición superior
321
  response = await self.reflect(message)
322
-
323
  await self.observe(f"Prometeo: {response}", type="system_response")
324
-
325
  return response
326
 
327
  # ==============================================================================
@@ -342,7 +303,6 @@ async def handle_login_or_creation(action: str, name: str, user_id: str) -> tupl
342
  if not user:
343
  msg = "ID de usuario no encontrado. Verifique o cree un nuevo perfil."
344
  else:
345
- # Aquí no necesitamos el saludo, se genera al cargar el chat
346
  msg = f"Protocolo Prometeo activado para {user.name}."
347
 
348
  if user:
@@ -359,37 +319,25 @@ async def handle_chat_message(user_state: User, message: str, chat_history: List
359
  gr.Warning("Sistema inactivo. Inicie sesión o cree un perfil para continuar.")
360
  return user_state, chat_history, "", gr.update()
361
 
362
- # Añadimos el mensaje del usuario a la UI inmediatamente
363
  chat_history.append({"role": "user", "content": message})
364
 
365
- # Creamos una instancia del núcleo cognitivo con el estado actual del usuario
366
  core = CognitiveCore(user_state, sentiment_analyzer, embedding_model)
367
-
368
- # El núcleo se encarga de todo el ciclo de pensamiento
369
  response = await core.act(message)
370
-
371
- # Guardamos el estado del usuario DESPUÉS de la interacción completa
372
- # El core.user contiene el memory_stream actualizado
373
  await UserManager.save_user(core.user)
374
 
375
- # Añadimos la respuesta del AI a la UI
376
  chat_history.append({"role": "assistant", "content": response})
377
-
378
- # Actualizamos el perfil en la UI con los nuevos datos (si hubiera)
379
  profile_update = render_profile_info(core.user)
380
 
381
  return core.user, chat_history, "", profile_update
382
 
383
  def render_profile_info(user: Optional[User]) -> str:
384
- """Renderiza el panel de perfil en Markdown."""
385
  if not user: return "Ningún perfil cargado."
386
  profile_md = f"### Perfil Cognitivo: {user.name}\n"
387
  profile_md += f"**ID de Acceso:** `{user.user_id}`\n"
388
  profile_md += f"**Memorias Registradas:** {len(user.memory_stream)}\n\n"
389
  profile_md += "#### Modelo Psicométrico Inferido:\n"
390
  for trait, value in user.psych_profile.items():
391
- # Visualización de [-1, 1] a una barra
392
- bar_value = int((value + 1) * 5) # Escala de 0 a 10
393
  bar = "█" * bar_value + "░" * (10 - bar_value)
394
  profile_md += f"- **{trait.capitalize()}:** `{f'{value:.2f}'}` {bar}\n"
395
  return profile_md
@@ -405,14 +353,15 @@ with gr.Blocks(theme=gr.themes.Monochrome(font=[gr.themes.GoogleFont("Roboto Mon
405
 
406
  with gr.Row():
407
  with gr.Column(scale=3):
408
- # Panel de Chat (se muestra después del login)
409
  with gr.Group(visible=False) as chat_panel:
410
- chatbot_display = gr.Chatbot(label="Stream de Conciencia", height=600, bubble_full_width=False, show_copy_button=True, avatar_images=("./user.png", "./bot.png"))
 
 
 
 
411
  with gr.Row():
412
  chat_input = gr.Textbox(show_label=False, placeholder="Input...", scale=5, container=False)
413
  send_button = gr.Button("Ejecutar", variant="primary", scale=1)
414
-
415
- # Panel de Login (se muestra al inicio)
416
  with gr.Group(visible=True) as login_panel:
417
  gr.Markdown("### **Acceso al Protocolo**")
418
  with gr.Tabs():
@@ -428,31 +377,10 @@ with gr.Blocks(theme=gr.themes.Monochrome(font=[gr.themes.GoogleFont("Roboto Mon
428
  gr.Markdown("### **Estado del Núcleo**")
429
  profile_display = gr.Markdown("Ningún perfil cargado.", elem_id="profile-display")
430
 
431
- # --- Lógica de Eventos de la Interfaz ---
432
-
433
- # Acciones de Login y Creación
434
- login_button.click(
435
- fn=handle_login_or_creation,
436
- inputs=[gr.State("login"), username_input, userid_input],
437
- outputs=[current_user_state, chatbot_display, login_panel, chat_panel, profile_display]
438
- )
439
- create_button.click(
440
- fn=handle_login_or_creation,
441
- inputs=[gr.State("create"), username_input, userid_input],
442
- outputs=[current_user_state, chatbot_display, login_panel, chat_panel, profile_display]
443
- )
444
-
445
- # Acciones de Chat
446
- chat_input.submit(
447
- fn=handle_chat_message,
448
- inputs=[current_user_state, chat_input, chatbot_display],
449
- outputs=[current_user_state, chatbot_display, chat_input, profile_display]
450
- )
451
- send_button.click(
452
- fn=handle_chat_message,
453
- inputs=[current_user_state, chat_input, chatbot_display],
454
- outputs=[current_user_state, chatbot_display, chat_input, profile_display]
455
- )
456
 
457
  if __name__ == "__main__":
458
  if not all([db, sentiment_analyzer, embedding_model]):
 
1
+ # manifest.py - Protocolo Prometeo v0.1.1: Núcleo Consciente (Interfaz Recalibrada)
2
  # Arquitectura por un asistente de IA, inspirado en la visión de un líder que fusiona a Altman, Jobs y Musk.
3
  # "No estamos construyendo una app. Estamos construyendo el próximo modo de existencia cognitiva."
4
  #
 
13
  import os
14
  import asyncio
15
  import logging
16
+ import re
17
  from typing import Dict, Any, List, Optional, Tuple
18
 
19
+ from dotenv import load_dotenv
20
+
21
  # ==============================================================================
22
  # MÓDULO DE IMPORTACIONES DE IA Y BBDD VECTORIAL
23
  # ==============================================================================
 
34
  import firebase_admin
35
  from firebase_admin import credentials, firestore
36
 
37
+ # --- Cargar secretos del entorno ---
38
+ load_dotenv()
39
+
40
  # ==============================================================================
41
  # MÓDULO 1: CONFIGURACIÓN Y CONSTANTES DEL SISTEMA
42
  # ==============================================================================
43
  class Config:
44
+ APP_NAME = "Protocolo Prometeo v0.1.1"
45
+ APP_VERSION = "0.1.1 (Interfaz Recalibrada)"
46
 
 
47
  FIREBASE_COLLECTION_USERS = "prometeo_users_v1"
 
 
48
  CHROMA_PERSIST_PATH = "./prometeo_memory_db"
49
+ EMBEDDING_MODEL_NAME = 'all-MiniLM-L6-v2'
50
 
 
51
  DEFAULT_PSYCH_PROFILE = {
52
  "openness": 0.0, "conscientiousness": 0.0, "extraversion": 0.0,
53
  "agreeableness": 0.0, "neuroticism": 0.0
54
  }
55
  POINTS_PER_INSIGHT = 10
56
+ MAX_MEMORY_STREAM_ITEMS = 500
57
  FRUSTRATION_KEYWORDS = ['tonto', 'inútil', 'bruto', 'estúpido', 'mierda', 'carajo', 'dale boludo', 'no servis']
58
  META_QUESTION_KEYWORDS = ['para qué', 'de qué te sirve', 'por qué preguntas', 'cuál es el punto']
59
 
 
62
  # ==============================================================================
63
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
64
 
 
65
  sentiment_analyzer = None
66
  try:
67
  sentiment_analyzer = create_analyzer(task="sentiment", lang="es")
 
69
  except Exception as e:
70
  logging.error(f"FALLO CRÍTICO: No se pudo cargar el analizador de sentimiento: {e}")
71
 
 
72
  embedding_model = None
73
  try:
74
  embedding_model = SentenceTransformer(Config.EMBEDDING_MODEL_NAME)
 
76
  except Exception as e:
77
  logging.error(f"FALLO CRÍTICO: No se pudo cargar el modelo de embeddings: {e}")
78
 
 
79
  db = None
80
  try:
81
  if not firebase_admin._apps:
 
82
  firebase_credentials_json = os.getenv('GOOGLE_APPLICATION_CREDENTIALS_JSON')
83
  if firebase_credentials_json:
84
  cred_dict = json.loads(firebase_credentials_json)
85
+ # Asegurarse de que el project_id está presente, es un error común en la carga de env vars
86
+ if 'project_id' not in cred_dict:
87
+ raise ValueError("El 'project_id' no se encuentra en las credenciales de Firebase. Verifique el contenido de la variable de entorno.")
88
  cred = credentials.Certificate(cred_dict)
89
  firebase_admin.initialize_app(cred, {'projectId': cred_dict['project_id']})
90
  db = firestore.client()
 
97
  except Exception as e:
98
  logging.error(f"FALLO CRÍTICO: Error al inicializar Firebase: {e}")
99
 
 
100
  # ==============================================================================
101
  # MÓDULO 3: MODELOS DE DATOS (LA ESENCIA DEL USUARIO)
102
  # ==============================================================================
 
107
  self.created_at: datetime = kwargs.get('created_at', datetime.now())
108
  self.last_login: datetime = kwargs.get('last_login', datetime.now())
109
  self.psych_profile: Dict[str, float] = kwargs.get('psych_profile', Config.DEFAULT_PSYCH_PROFILE.copy())
 
110
  self.memory_stream: List[Dict[str, Any]] = kwargs.get('memory_stream', [])
111
  self.connection_points: int = kwargs.get('connection_points', 0)
112
 
113
  def to_dict(self) -> Dict[str, Any]:
 
114
  return {
115
  "user_id": self.user_id, "name": self.name,
116
  "created_at": self.created_at.isoformat(),
 
154
  @staticmethod
155
  async def create_user(name: str) -> Tuple[Optional[User], str]:
156
  if not db: return None, "Error de base de datos."
157
+ try:
158
+ user_id = f"{name.lower().replace(' ', '_')}_{int(time.time())}"
159
+ new_user = User(user_id=user_id, name=name)
160
+ success = await UserManager.save_user(new_user)
161
+ if success:
162
+ msg = f"¡Bienvenido, {name}! Tu perfil ha sido forjado. Tu ID de acceso es: **{user_id}**"
163
+ logging.info(f"Nuevo usuario creado: {name} ({user_id})")
164
+ return new_user, msg
165
+ else:
166
+ return None, "Error inesperado al crear perfil en la base de datos."
167
+ except Exception as e:
168
+ logging.error(f"Error al crear usuario {name}: {e}")
169
+ return None, "Fallo catastrófico durante la creación del perfil."
170
+
171
 
172
  @staticmethod
173
  async def save_user(user: User) -> bool:
 
189
  self.sentiment_analyzer = s_analyzer
190
  self.embedding_model = e_model
191
 
 
192
  self.chroma_client = chromadb.Client(Settings(
193
  persist_directory=Config.CHROMA_PERSIST_PATH,
194
  is_persistent=True,
195
  ))
 
196
  self.memory_collection = self.chroma_client.get_or_create_collection(
197
+ name=f"prometeo_mind_{self.user.user_id.replace('_', '-')}" # Sanitize name for chromadb
198
  )
199
  self._sync_semantic_memory()
200
 
201
  def _sync_semantic_memory(self):
202
+ if not self.user.memory_stream: return
 
 
 
203
  logging.info("Sincronizando memoria persistente con el núcleo semántico...")
204
  ids = [m['id'] for m in self.user.memory_stream]
205
  documents = [m['content'] for m in self.user.memory_stream]
206
 
207
+ if ids and self.memory_collection.count() < len(ids):
 
208
  self.memory_collection.upsert(ids=ids, documents=documents)
209
+ logging.info(f"Sincronización completa. {self.memory_collection.count()} memorias en el núcleo.")
210
 
211
  async def _simulate_llm_reasoning(self, prompt: str) -> str:
 
 
 
 
 
212
  logging.info("Iniciando ciclo de razonamiento profundo...")
213
+ await asyncio.sleep(random.uniform(0.5, 1.0))
214
 
 
215
  user_input_match = re.search(r'El usuario ha dicho: "([^"]+)"', prompt)
216
  user_input = user_input_match.group(1) if user_input_match else "algo"
217
 
218
  context_match = re.search(r'Memorias pasadas relevantes:\n(.*?)\n\n', prompt, re.DOTALL)
219
  context = context_match.group(1) if context_match else ""
220
 
221
+ if context.strip() and "Ninguna" not in context:
222
  first_memory = context.split('\n')[0].replace('- ', '')
223
  response = f"Conectando tu idea sobre '{user_input}' con nuestra conversación anterior sobre '{first_memory}'. El patrón subyacente parece ser la búsqueda de eficiencia. ¿Estamos optimizando el sistema correcto, o deberíamos redefinir el objetivo fundamental?"
224
  else:
 
227
  logging.info("Ciclo de razonamiento completado.")
228
  return response
229
 
 
 
230
  async def observe(self, text: str, type: str):
 
231
  timestamp = datetime.now()
232
  memory_id = f"{type}_{int(timestamp.timestamp() * 1000)}"
233
+ new_memory = {"id": memory_id, "type": type, "content": text, "timestamp": timestamp.isoformat()}
 
 
 
 
 
 
234
 
235
  self.user.memory_stream.append(new_memory)
236
  if len(self.user.memory_stream) > Config.MAX_MEMORY_STREAM_ITEMS:
 
237
  self.user.memory_stream.pop(0)
238
 
 
239
  self.memory_collection.add(documents=[text], ids=[memory_id])
240
 
241
  async def reflect(self, current_input: str) -> str:
 
242
  logging.info(f"Reflexionando sobre: '{current_input}'")
243
 
244
+ relevant_memories = self.memory_collection.query(query_texts=[current_input], n_results=3)
 
 
 
 
245
 
246
  context = "Memorias pasadas relevantes:\n"
247
+ if relevant_memories and relevant_memories['documents'] and relevant_memories['documents'][0]:
248
  for doc in relevant_memories['documents'][0]:
249
  context += f"- {doc}\n"
250
  else:
251
  context += "Ninguna.\n"
252
 
 
253
  prompt = f"""
254
  INSTRUCCIONES DE SISTEMA:
255
  Eres Prometeo, un Co-Procesador Cognitivo. Tu propósito es aumentar el ancho de banda mental de tu usuario, {self.user.name}. Eres directo, visionario y buscas patrones. No usas emojis ni lenguaje de relleno. Vas al grano.
 
256
  CONTEXTO:
257
  {context}
 
258
  NUEVO INPUT:
259
  El usuario ha dicho: "{current_input}"
 
260
  TAREA:
261
  Genera una respuesta que conecte ideas, cuestione suposiciones o identifique patrones ocultos basados en el nuevo input y el contexto de memorias pasadas.
262
  """
 
 
263
  insight = await self._simulate_llm_reasoning(prompt)
264
  return insight
265
 
266
  async def act(self, message: str) -> str:
 
 
267
  message_lower = message.lower()
268
  sentiment = await asyncio.to_thread(self.sentiment_analyzer.predict, message)
269
 
 
280
  await self.observe(f"Mi respuesta sobre el propósito: {response}", type="system_response")
281
  return response
282
 
 
283
  await self.observe(f"Usuario: {message}", type="user_input")
 
 
284
  response = await self.reflect(message)
 
285
  await self.observe(f"Prometeo: {response}", type="system_response")
 
286
  return response
287
 
288
  # ==============================================================================
 
303
  if not user:
304
  msg = "ID de usuario no encontrado. Verifique o cree un nuevo perfil."
305
  else:
 
306
  msg = f"Protocolo Prometeo activado para {user.name}."
307
 
308
  if user:
 
319
  gr.Warning("Sistema inactivo. Inicie sesión o cree un perfil para continuar.")
320
  return user_state, chat_history, "", gr.update()
321
 
 
322
  chat_history.append({"role": "user", "content": message})
323
 
 
324
  core = CognitiveCore(user_state, sentiment_analyzer, embedding_model)
 
 
325
  response = await core.act(message)
 
 
 
326
  await UserManager.save_user(core.user)
327
 
 
328
  chat_history.append({"role": "assistant", "content": response})
 
 
329
  profile_update = render_profile_info(core.user)
330
 
331
  return core.user, chat_history, "", profile_update
332
 
333
  def render_profile_info(user: Optional[User]) -> str:
 
334
  if not user: return "Ningún perfil cargado."
335
  profile_md = f"### Perfil Cognitivo: {user.name}\n"
336
  profile_md += f"**ID de Acceso:** `{user.user_id}`\n"
337
  profile_md += f"**Memorias Registradas:** {len(user.memory_stream)}\n\n"
338
  profile_md += "#### Modelo Psicométrico Inferido:\n"
339
  for trait, value in user.psych_profile.items():
340
+ bar_value = int((value + 1) * 5)
 
341
  bar = "█" * bar_value + "░" * (10 - bar_value)
342
  profile_md += f"- **{trait.capitalize()}:** `{f'{value:.2f}'}` {bar}\n"
343
  return profile_md
 
353
 
354
  with gr.Row():
355
  with gr.Column(scale=3):
 
356
  with gr.Group(visible=False) as chat_panel:
357
+ # ==============================================================
358
+ # <<< LÍNEA CORREGIDA >>>
359
+ # Se añadió type="messages" para compatibilidad y se eliminó el parámetro obsoleto.
360
+ chatbot_display = gr.Chatbot(label="Stream de Conciencia", height=600, type="messages", show_copy_button=True, avatar_images=("./user.png", "./bot.png"))
361
+ # ==============================================================
362
  with gr.Row():
363
  chat_input = gr.Textbox(show_label=False, placeholder="Input...", scale=5, container=False)
364
  send_button = gr.Button("Ejecutar", variant="primary", scale=1)
 
 
365
  with gr.Group(visible=True) as login_panel:
366
  gr.Markdown("### **Acceso al Protocolo**")
367
  with gr.Tabs():
 
377
  gr.Markdown("### **Estado del Núcleo**")
378
  profile_display = gr.Markdown("Ningún perfil cargado.", elem_id="profile-display")
379
 
380
+ login_button.click(fn=handle_login_or_creation, inputs=[gr.State("login"), username_input, userid_input], outputs=[current_user_state, chatbot_display, login_panel, chat_panel, profile_display])
381
+ create_button.click(fn=handle_login_or_creation, inputs=[gr.State("create"), username_input, userid_input], outputs=[current_user_state, chatbot_display, login_panel, chat_panel, profile_display])
382
+ chat_input.submit(fn=handle_chat_message, inputs=[current_user_state, chat_input, chatbot_display], outputs=[current_user_state, chatbot_display, chat_input, profile_display])
383
+ send_button.click(fn=handle_chat_message, inputs=[current_user_state, chat_input, chatbot_display], outputs=[current_user_state, chatbot_display, chat_input, profile_display])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
 
385
  if __name__ == "__main__":
386
  if not all([db, sentiment_analyzer, embedding_model]):