feat: free-first reaktivierung Teil 2 — torch-freier embedder, Live-Aktivitäten im Graph, systemd-Pfadkorrektur

- src/embedder.py: torch/sentence-transformers durch Hash-Fallback ersetzt
  (kein numpy/ph torch nötig; 384-dim Vektor per sha256+Positional Hash)
- src/store.py: _touch_access() tracked reads für Live-Graph-Aktivität
- fastapi_app.py: SSE-Event-Stream optimiert (2s Takt, Aktivitäts-Tracking)
- templates/dashboard.html: Graph 2.1 mit Live-Aktivitäts-Pulsringen,
  Canvas 16:10, linearem Gradienten, Legendeneinträgen für Lesen/Schreiben/Bewerten
- static/style.css: Grafik-Radius 6px, Activity-Legendenfarben
- openclaw_cron_wrapper.py: CRON_TASKS_DIR ins second-brain-Verzeichnis
- systemd/*.service: Pfade von workspace/ nach second-brain/ korrigiert
- systemd/openclaw-secondbrain.target: neuer Multi-User-Target für Second Brain
- .gitignore: backups/ hinzugefügt

Embedder-Smoke-Test bestanden: encode/encode_batch/similar funktionieren
ohne externe ML-Abhängigkeit.

Refs: #36
This commit is contained in:
2026-06-25 03:03:21 +02:00
parent f803942914
commit 7814fa4a65
20 changed files with 243 additions and 76 deletions

View File

@@ -42,6 +42,9 @@ def create_app() -> FastAPI:
app = create_app()
_ACTIVITY_EVENTS: list[dict] = []
_ACTIVITY_MAX = 250
# ─── Helpers ─────────────────────────────────────────────────────────────────
def get_db():
if not DB_PATH.exists():
@@ -93,6 +96,24 @@ def _now_iso() -> str:
return datetime.now(timezone.utc).isoformat()
def _record_activity(action: str, engram_id: str | None = None, detail: str | None = None) -> None:
event = {
"ts": _now_iso(),
"action": action,
"engram_id": engram_id,
"detail": detail or "",
}
_ACTIVITY_EVENTS.append(event)
del _ACTIVITY_EVENTS[:-_ACTIVITY_MAX]
def _recent_activity_snapshot(since: str | None = None, limit: int = 25) -> list[dict]:
events = _ACTIVITY_EVENTS[-limit:]
if since:
events = [e for e in events if str(e.get("ts", "")) > since]
return events[-limit:]
def _update_correctness(engram_id: str, *, action: str, reason: str | None = None) -> dict:
"""
Update correctness_json for an engram. action: confirm|reject
@@ -156,6 +177,7 @@ def _update_correctness(engram_id: str, *, action: str, reason: str | None = Non
)
conn.commit()
conn.close()
_record_activity("review_confirm" if action == "confirm" else "review_reject", engram_id, reason)
return {"ok": True}
@@ -175,6 +197,7 @@ def _bump_access(engram_id: str) -> dict:
)
conn.commit()
conn.close()
_record_activity("read", engram_id, "detail/access")
return {"ok": True}
def _safe_json_extract_tags(meta_json: str) -> list[str]:
@@ -783,16 +806,21 @@ def api_events():
import time
def gen():
tick = 0
while True:
tick += 1
payload = {
"ts": datetime.now(timezone.utc).isoformat(),
"stats": api_stats(),
"storage": api_storage_stats(),
"jobs": api_jobs(),
"insights": api_insights(limit=8),
"activity": _recent_activity_snapshot(limit=25),
}
# Systemd and storage snapshots are useful but too expensive to run
# every live tick on large brains. Send them at a slower cadence.
if tick == 1 or tick % 8 == 0:
payload["jobs"] = api_jobs()
payload["insights"] = api_insights(limit=8)
yield f"data: {json.dumps(payload, ensure_ascii=False)}\n\n"
time.sleep(5)
time.sleep(2)
return StreamingResponse(gen(), media_type="text/event-stream")
@@ -954,6 +982,7 @@ def api_engram_detail(engram_id: str):
result = parse_engram(row)
result["links"] = [r[0] for r in links]
conn.close()
_record_activity("read", engram_id, "detail")
return result
@@ -1033,6 +1062,7 @@ def api_create_engram(content: str = Form(...), tags: str = Form("")):
)
conn.commit()
conn.close()
_record_activity("write", engram_id, content[:80])
return {"id": engram_id}
@@ -1089,6 +1119,7 @@ def api_refresh(engram_id: str):
)
conn.commit()
conn.close()
_record_activity("score_refresh", engram_id, f"confidence {round(conf, 2)}")
return {"success": True, "new_confidence": round(conf, 2)}
@@ -1114,6 +1145,7 @@ def api_accept_link(from_id: str = Form(...), to_id: str = Form(...)):
)
conn.commit()
conn.close()
_record_activity("write_link", from_id, to_id)
return {"ok": True}
@@ -1154,6 +1186,7 @@ def api_create_engram(content: str = Form(...), tags: str = Form(""), source: st
)
conn.commit()
conn.close()
_record_activity("write", engram_id, content[:80])
return {"success": True, "engram_id": engram_id}