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:
@@ -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}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user