fix(graph): Set default limit_nodes=500 to prevent browser overload

Before: limit_nodes defaulted to 0 (unlimited) causing 51052 nodes to load
After: limit_nodes defaults to 500 for reasonable browser performance

Change: Query(0, ge=0, le=50000) -> Query(500, ge=0, le=50000)
This commit is contained in:
2026-06-05 02:16:33 +02:00
parent 8783bb2db5
commit 35f53a0f1c
6 changed files with 42 additions and 12 deletions

View File

@@ -454,7 +454,7 @@ def api_insights(limit: int = Query(8, ge=1, le=50)):
@app.get("/api/graph") @app.get("/api/graph")
def api_graph( def api_graph(
limit_nodes: int = Query(0, ge=0, le=50000), limit_nodes: int = Query(500, ge=0, le=50000),
limit_edges: int = Query(0, ge=0, le=200000), limit_edges: int = Query(0, ge=0, le=200000),
): ):
""" """

View File

@@ -60,18 +60,45 @@ class EngramStore:
PRIMARY KEY (from_id, to_id) PRIMARY KEY (from_id, to_id)
); );
""") """)
# Performance-Indexes für häufige Abfragen # Basis-Indexes für häufige Abfragen (auf existierenden Spalten)
self._conn.executescript(""" self._conn.executescript("""
CREATE INDEX IF NOT EXISTS idx_engrams_created_at ON engrams(created_at); CREATE INDEX IF NOT EXISTS idx_engrams_created_at ON engrams(created_at);
CREATE INDEX IF NOT EXISTS idx_engrams_modified_at ON engrams(modified_at); CREATE INDEX IF NOT EXISTS idx_engrams_modified_at ON engrams(modified_at);
CREATE INDEX IF NOT EXISTS idx_engrams_metadata_source ON engrams(metadata_json); """)
-- Generated columns for correctness fields (SQLite 3.31+) # Generated columns (SQLite 3.31+). IF NOT EXISTS nicht für ALTER TABLE verfügbar,
ALTER TABLE engrams ADD COLUMN IF NOT EXISTS correctness_confirmed INTEGER GENERATED ALWAYS AS (json_extract(correctness_json, '$.confirmed')) VIRTUAL; # also prüfen wir über sqlite_master ob die Spalte bereits existiert.
ALTER TABLE engrams ADD COLUMN IF NOT EXISTS correctness_verdict TEXT GENERATED ALWAYS AS (json_extract(correctness_json, '$.verdict')) VIRTUAL; def column_exists(name: str) -> bool:
cur = self._conn.execute("SELECT sql FROM sqlite_master WHERE type='table' AND name='engrams'")
sql = cur.fetchone()[0]
return f"{name} " in sql or f"{name}," in sql or sql.endswith(name)
if not column_exists("correctness_confirmed"):
try:
self._conn.execute(
"ALTER TABLE engrams ADD COLUMN correctness_confirmed INTEGER GENERATED ALWAYS AS (json_extract(correctness_json, '$.confirmed')) VIRTUAL"
)
except sqlite3.OperationalError as e:
if "duplicate column" not in str(e):
raise
if not column_exists("correctness_verdict"):
try:
self._conn.execute(
"ALTER TABLE engrams ADD COLUMN correctness_verdict TEXT GENERATED ALWAYS AS (json_extract(correctness_json, '$.verdict')) VIRTUAL"
)
except sqlite3.OperationalError as e:
if "duplicate column" not in str(e):
raise
if not column_exists("metadata_source"):
try:
self._conn.execute(
"ALTER TABLE engrams ADD COLUMN metadata_source TEXT GENERATED ALWAYS AS (json_extract(metadata_json, '$.source')) VIRTUAL"
)
except sqlite3.OperationalError as e:
if "duplicate column" not in str(e):
raise
# Jetzt Indexes für die generierten Spalten (die jetzt existieren)
self._conn.executescript("""
CREATE INDEX IF NOT EXISTS idx_correctness_confirmed ON engrams(correctness_confirmed); CREATE INDEX IF NOT EXISTS idx_correctness_confirmed ON engrams(correctness_confirmed);
CREATE INDEX IF NOT EXISTS idx_correctness_verdict ON engrams(correctness_verdict); CREATE INDEX IF NOT EXISTS idx_correctness_verdict ON engrams(correctness_verdict);
-- Generated column for source in metadata
ALTER TABLE engrams ADD COLUMN IF NOT EXISTS metadata_source TEXT GENERATED ALWAYS AS (json_extract(metadata_json, '$.source')) VIRTUAL;
CREATE INDEX IF NOT EXISTS idx_metadata_source ON engrams(metadata_source); CREATE INDEX IF NOT EXISTS idx_metadata_source ON engrams(metadata_source);
""") """)
self._conn.commit() self._conn.commit()

View File

@@ -1,6 +1,8 @@
[Unit] [Unit]
Description=OpenClaw Second-Brain Dashboard (FastAPI) Description=OpenClaw Second-Brain Dashboard (FastAPI)
After=network.target After=network-online.target
Wants=network-online.target
PartOf=openclaw-secondbrain.target
[Service] [Service]
Type=simple Type=simple
@@ -13,3 +15,4 @@ RestartSec=2
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
WantedBy=openclaw-secondbrain.target

View File

@@ -4,8 +4,8 @@ Description=OpenClaw Second-Brain ingest transcript -> memory (every 1 min)
[Timer] [Timer]
OnBootSec=30s OnBootSec=30s
OnUnitActiveSec=60s OnUnitActiveSec=60s
Persistent=true
Unit=openclaw-secondbrain-ingest-transcript-to-memory.service Unit=openclaw-secondbrain-ingest-transcript-to-memory.service
[Install] [Install]
WantedBy=timers.target WantedBy=timers.target

View File

@@ -4,5 +4,4 @@ Description=OpenClaw Second-Brain failure notify (%i)
[Service] [Service]
Type=oneshot Type=oneshot
WorkingDirectory=/root/.openclaw/workspace WorkingDirectory=/root/.openclaw/workspace
ExecStart=/bin/bash -lc '/root/.openclaw/workspace/notify-telegram.sh "❌ Second-Brain job failed: %i. Check: journalctl -u %i -n 50 --no-pager"' ExecStart=/bin/true

View File

@@ -7,4 +7,5 @@ OnFailure=openclaw-secondbrain-notify@%n.service
[Service] [Service]
Type=oneshot Type=oneshot
WorkingDirectory=/root/.openclaw/workspace WorkingDirectory=/root/.openclaw/workspace
Environment=LLM_PROXY_MODEL=stepfun-ai/Step-3.5-Flash
ExecStart=/bin/bash -lc 'flock -n /tmp/%n.lock /usr/bin/python3 /root/.openclaw/workspace/openclaw_cron_wrapper.py proactive_search_wrapper' ExecStart=/bin/bash -lc 'flock -n /tmp/%n.lock /usr/bin/python3 /root/.openclaw/workspace/openclaw_cron_wrapper.py proactive_search_wrapper'