mirror of
https://github.com/safishamsi/graphify.git
synced 2026-07-13 19:07:10 +00:00
fix graspologic optional, fall back to networkx louvain, add privacy section
This commit is contained in:
@@ -149,6 +149,10 @@ Works with any mix of file types:
|
||||
|
||||
Token reduction scales with corpus size. 6 files fits in a context window anyway, so graph value there is structural clarity, not compression. At 52 files (code + papers + images) you get 71x+. Each `worked/` folder has the raw input files and the actual output (`GRAPH_REPORT.md`, `graph.json`) so you can run it yourself and verify the numbers.
|
||||
|
||||
## Privacy
|
||||
|
||||
graphify sends file contents to the Claude API (Anthropic) for semantic extraction of docs, papers, and images. Code files are processed locally via tree-sitter AST — no file contents leave your machine for code. No telemetry, usage tracking, or analytics of any kind. The only network calls are to Anthropic's API during extraction, using your own API key via Claude Code.
|
||||
|
||||
## Tech stack
|
||||
|
||||
NetworkX + Leiden (graspologic) + tree-sitter + Claude + vis.js. No Neo4j required, no server, runs entirely locally.
|
||||
|
||||
+20
-7
@@ -1,8 +1,25 @@
|
||||
"""Leiden community detection on NetworkX graphs. Splits oversized communities. Returns cohesion scores."""
|
||||
"""Community detection on NetworkX graphs. Uses Leiden (graspologic) if available, falls back to Louvain (networkx). Splits oversized communities. Returns cohesion scores."""
|
||||
from __future__ import annotations
|
||||
import networkx as nx
|
||||
|
||||
|
||||
def _partition(G: nx.Graph) -> dict[str, int]:
|
||||
"""Run community detection. Returns {node_id: community_id}.
|
||||
|
||||
Tries Leiden (graspologic) first — best quality.
|
||||
Falls back to Louvain (built into networkx) if graspologic is not installed.
|
||||
"""
|
||||
try:
|
||||
from graspologic.partition import leiden
|
||||
return leiden(G)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Fallback: networkx louvain (available since networkx 2.7)
|
||||
communities = nx.community.louvain_communities(G, seed=42)
|
||||
return {node: cid for cid, nodes in enumerate(communities) for node in nodes}
|
||||
|
||||
|
||||
def build_graph(nodes: list[dict], edges: list[dict]) -> nx.Graph:
|
||||
"""Build a NetworkX graph from graphify node/edge dicts.
|
||||
|
||||
@@ -36,8 +53,6 @@ def cluster(G: nx.Graph) -> dict[int, list[str]]:
|
||||
if G.number_of_edges() == 0:
|
||||
return {i: [n] for i, n in enumerate(sorted(G.nodes))}
|
||||
|
||||
from graspologic.partition import leiden # lazy - avoids 15s numba JIT on import
|
||||
|
||||
# Leiden warns and drops isolates - handle them separately
|
||||
isolates = [n for n in G.nodes() if G.degree(n) == 0]
|
||||
connected_nodes = [n for n in G.nodes() if G.degree(n) > 0]
|
||||
@@ -45,7 +60,7 @@ def cluster(G: nx.Graph) -> dict[int, list[str]]:
|
||||
|
||||
raw: dict[int, list[str]] = {}
|
||||
if connected.number_of_nodes() > 0:
|
||||
partition: dict[str, int] = leiden(connected)
|
||||
partition = _partition(connected)
|
||||
for node, cid in partition.items():
|
||||
raw.setdefault(cid, []).append(node)
|
||||
|
||||
@@ -76,13 +91,11 @@ def _split_community(G: nx.Graph, nodes: list[str]) -> list[list[str]]:
|
||||
# No edges - split into individual nodes
|
||||
return [[n] for n in sorted(nodes)]
|
||||
try:
|
||||
from graspologic.partition import leiden
|
||||
sub_partition: dict[str, int] = leiden(subgraph)
|
||||
sub_partition = _partition(subgraph)
|
||||
sub_communities: dict[int, list[str]] = {}
|
||||
for node, cid in sub_partition.items():
|
||||
sub_communities.setdefault(cid, []).append(node)
|
||||
if len(sub_communities) <= 1:
|
||||
# Leiden couldn't split it - return as-is
|
||||
return [sorted(nodes)]
|
||||
return [sorted(v) for v in sub_communities.values()]
|
||||
except Exception:
|
||||
|
||||
+2
-2
@@ -12,7 +12,6 @@ keywords = ["claude", "claude-code", "knowledge-graph", "rag", "graphrag", "obsi
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"networkx",
|
||||
"graspologic",
|
||||
"tree-sitter",
|
||||
"tree-sitter-python",
|
||||
"tree-sitter-javascript",
|
||||
@@ -39,7 +38,8 @@ mcp = ["mcp"]
|
||||
neo4j = ["neo4j"]
|
||||
pdf = ["pypdf", "html2text"]
|
||||
watch = ["watchdog"]
|
||||
all = ["mcp", "neo4j", "pypdf", "html2text", "watchdog"]
|
||||
leiden = ["graspologic"]
|
||||
all = ["mcp", "neo4j", "pypdf", "html2text", "watchdog", "graspologic"]
|
||||
|
||||
[project.scripts]
|
||||
graphify = "graphify.__main__:main"
|
||||
|
||||
Reference in New Issue
Block a user