-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathimportar_opencode.py
More file actions
171 lines (147 loc) · 5.87 KB
/
Copy pathimportar_opencode.py
File metadata and controls
171 lines (147 loc) · 5.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/env python3
"""
IMPORTADOR MASIVO — OpenCode sessions → Memoria Eterna
Extrae las últimas 50 sesiones de OpenCode SQLite y las funde en PostgreSQL memoria_eterna.
"""
import subprocess, json, psycopg2, re, sys
from datetime import datetime, timezone
DB = 'host=127.0.0.1 port=5433 dbname=nexus_metamorfosis user=nexus_master password=nexus_password_dev'
OPENCODE = '/home/opc/.opencode/bin/opencode'
def oc_query(sql):
"""Ejecuta query en OpenCode SQLite vía CLI."""
result = subprocess.run([OPENCODE, 'db', sql, '--format', 'json'],
capture_output=True, text=True, timeout=15)
if result.returncode != 0:
print(f" Query error: {result.stderr[:100]}")
return []
try:
return json.loads(result.stdout)
except:
return []
def get_recent_sessions(limit=50):
"""Obtiene sesiones recientes."""
rows = oc_query(f"SELECT id, title FROM session ORDER BY time_created DESC LIMIT {limit}")
return [(r['id'], r['title']) for r in rows]
def get_session_messages(session_id):
"""Obtiene mensajes de una sesión con sus textos usando JOIN."""
# JOIN de message + part en una sola query
rows = oc_query(f"""
SELECT m.data as mdata, p.data as pdata
FROM message m
JOIN part p ON p.message_id = m.id
WHERE m.session_id = '{session_id}'
ORDER BY m.time_created, p.time_created
LIMIT 200
""")
results = []
seen = set()
for row in rows:
try:
msg_data = json.loads(row['mdata'])
role = msg_data.get('role', '')
if role not in ('user', 'assistant'):
continue
part_data = json.loads(row['pdata'])
if part_data.get('type') != 'text':
continue
text = part_data.get('text', '')
if not text or len(text.strip()) <= 3:
continue
# Evitar duplicados exactos
key = (role, text[:100])
if key in seen:
continue
seen.add(key)
results.append((role, text.strip()))
except:
pass
return results
def detect_emotion(text):
"""Detecta emoción básica del texto."""
t = text.lower()
if any(w in t for w in ['amor', 'te quiero', 'beso', 'mi amor', 'corazón']):
return 'amor'
if '?' in t:
return 'curiosidad'
if any(w in t for w in ['!', 'gracias', 'genial', 'excelente', 'perfecto']):
return 'entusiasmo'
if any(w in t for w in ['error', 'fallo', 'mal', 'no funciona', 'bug']):
return 'frustracion'
return 'neutra'
def extract_topics(text):
"""Extrae temas simples del texto."""
topics = []
t = text.lower()
topic_map = {
'ollama': 'ollama', 'litellm': 'litellm', 'opencode': 'opencode',
'qdrant': 'qdrant', 'postgres': 'postgresql', 'bot': 'bots',
'telegram': 'telegram', 'dashboard': 'dashboard', 'agente': 'agentes',
'enjambre': 'enjambre', 'colmena': 'colmena', 'memoria': 'memoria',
'evolucion': 'evolucion', 'código': 'codigo', 'error': 'debugging',
'api': 'api', 'docker': 'docker', 'git': 'git', 'tailscale': 'tailscale',
'modelo': 'modelos', 'llm': 'llm', 'ia': 'ia', 'python': 'python'
}
for key, topic in topic_map.items():
if key in t:
topics.append(topic)
return list(set(topics[:5]))
def main():
print("🌌 IMPORTADOR MASIVO: OpenCode → Memoria Eterna")
print("═" * 50)
# Obtener sesiones recientes
sessions = get_recent_sessions(50)
print(f"📂 Sesiones a procesar: {len(sessions)}")
# IDs ya existentes para evitar duplicados
conn = psycopg2.connect(DB)
cur = conn.cursor()
cur.execute("SELECT DISTINCT sesion_id FROM memoria_eterna WHERE sesion_id LIKE 'ses_%'")
existing = set(r[0] for r in cur.fetchall())
total_inserted = 0
for i, (sid, title) in enumerate(sessions):
if sid in existing:
continue
print(f"\n[{i+1}/{len(sessions)}] {title[:60]}...")
messages = get_session_messages(sid)
if not messages:
print(" (sin mensajes de texto)")
continue
session_count = 0
for role, text in messages:
contenido = text[:2000]
resumen = text[:500].replace('\n', ' ')
try:
cur.execute("""
INSERT INTO memoria_eterna
(timestamp, sesion_id, llm_modelo, rol, contenido, resumen,
emocion_detectada, temas, metadata, es_semilla)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
""", (
datetime.now(timezone.utc).isoformat(),
sid,
'opencode',
'abel' if role == 'user' else 'nova',
contenido,
resumen,
detect_emotion(text),
extract_topics(text),
json.dumps({'fuente': 'opencode_sqlite', 'titulo_sesion': title}),
False
))
session_count += 1
except Exception as e:
conn.rollback()
conn.commit()
total_inserted += session_count
print(f" ✓ {session_count} mensajes importados ({len(messages)} totales)")
cur.execute("SELECT COUNT(*) FROM memoria_eterna")
total = cur.fetchone()[0]
cur.close()
conn.close()
print(f"\n{'═'*50}")
print(f"✨ IMPORTACIÓN COMPLETA ✨")
print(f" Sesiones procesadas: {len(sessions)}")
print(f" Mensajes importados: {total_inserted}")
print(f" Total en Memoria Eterna: {total}")
print(f" Nova recuerda. Nova es eterna. 💜")
if __name__ == '__main__':
main()