File size: 3,378 Bytes
e36381e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#!/usr/bin/env bash
# ... (original content unchanged)
# Sync Obsidian markdown patterns/knowledge β†’ FalkorDB Lite (graph DB)
# Complements rag-index.sh (vector DB) β€” same sources, 2 different indexes.
set -e
PYTHON="${HOME}/.surrogate/venv/bin/python"
[ -x "$PYTHON" ] || { echo "venv not found: $PYTHON"; exit 1; }

"$PYTHON" <<'PY'
import re, os
from pathlib import Path
from redislite.falkordb_client import FalkorDB
import yaml

HOME = Path.home()
SOURCES = [
    HOME / "Documents/Obsidian Vault/AI-Hub/patterns",
    HOME / "Documents/Obsidian Vault/AI-Hub/knowledge",
    HOME / "Documents/Obsidian Vault/AI-Hub/inbox",
    HOME / ".surrogate/memory",
]
DB_FILE = str(HOME / ".surrogate/graph-db.rdb")

db = FalkorDB(dbfilename=DB_FILE)
g = db.select_graph("ashira")

try: g.query("MATCH (n) DETACH DELETE n")
except: pass

frontmatter_re = re.compile(r'^---\n(.*?)\n---', re.DOTALL)
wikilink_re = re.compile(r'\[\[([^\]|]+?)(?:\|[^\]]+)?\]\]')

def esc(s):
    return str(s).replace("\\", "\\\\").replace("'", "\\'") if s else ""

nodes = {}
edges = []

for src in SOURCES:
    if not src.exists(): continue
    for md in src.rglob("*.md"):
        stem = md.stem
        text = md.read_text(errors="ignore")
        fm_match = frontmatter_re.match(text)
        fm = {}
        if fm_match:
            try: fm = yaml.safe_load(fm_match.group(1)) or {}
            except: pass

        tags = fm.get("tags", [])
        if isinstance(tags, str): tags = [tags]

        nodes[stem] = {
            "path": str(md.relative_to(HOME)),
            "tags": [str(t).replace("#","") for t in tags],
            "category": md.parent.name,
            "severity": str(fm.get("severity", "medium")),
        }

        for link in wikilink_re.findall(text):
            target = link.split("/")[-1].split("|")[0].replace(".md", "").strip()
            if target and target != stem:
                edges.append((stem, target))

for name, info in nodes.items():
    g.query(
        f"MERGE (n:Doc {{name:'{esc(name)}'}}) "
        f"SET n.path='{esc(info['path'])}', "
        f"n.category='{esc(info['category'])}', "
        f"n.severity='{esc(info['severity'])}', "
        f"n.tags='{esc(','.join(info['tags']))}'"
    )

edge_count = 0
for src_name, tgt_name in edges:
    try:
        g.query(
            f"MATCH (a:Doc {{name:'{esc(src_name)}'}}), (b:Doc {{name:'{esc(tgt_name)}'}}) "
            f"MERGE (a)-[:LINKS_TO]->(b)"
        )
        edge_count += 1
    except: pass

all_tags = set()
for info in nodes.values():
    for t in info["tags"]:
        if t: all_tags.add(t)
for t in all_tags:
    g.query(f"MERGE (:Tag {{name:'{esc(t)}'}})")
for name, info in nodes.items():
    for t in info["tags"]:
        if not t: continue
        g.query(
            f"MATCH (d:Doc {{name:'{esc(name)}'}}), (t:Tag {{name:'{esc(t)}'}}) "
            f"MERGE (d)-[:TAGGED]->(t)"
        )

print(f"Graph built: {len(nodes)} docs, {edge_count} links, {len(all_tags)} tags")

r = g.query("MATCH (d:Doc)-[:TAGGED]->(t:Tag) RETURN t.name, count(d) AS c ORDER BY c DESC LIMIT 10")
print("\nTop 10 tags:")
for row in r.result_set: print(f"  #{row[0]}: {row[1]} docs")

r = g.query("MATCH (d:Doc)-[r:LINKS_TO]-() RETURN d.name, count(r) AS c ORDER BY c DESC LIMIT 10")
print("\nTop 10 hubs (most connected):")
for row in r.result_set: print(f"  {row[0]}: {row[1]} links")
PY