graph-mind-memory 0.3.3__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {graph_mind_memory-0.3.3/graph_mind_memory.egg-info → graph_mind_memory-0.4.0}/PKG-INFO +14 -12
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/README.md +10 -8
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/graph_mind_mcp_server.py +11 -1
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0/graph_mind_memory.egg-info}/PKG-INFO +14 -12
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/graph_mind_memory.egg-info/requires.txt +3 -3
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/install.py +12 -15
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/local_embedder.py +69 -20
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/pyproject.toml +4 -4
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/LICENSE +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/associative_memory.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/automatic_capture.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/automatic_capture_cli.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/brain_log.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/clock.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/coding_memory.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/conversation_memory.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/development_memory.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/development_paths.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/embedding_warmup.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/entity_timeline.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/forget.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/graph_mind_memory.egg-info/SOURCES.txt +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/graph_mind_memory.egg-info/dependency_links.txt +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/graph_mind_memory.egg-info/entry_points.txt +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/graph_mind_memory.egg-info/top_level.txt +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/local_brain.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/semantic_llm_extractor.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/semantic_memory.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/semantic_recall.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/setup.cfg +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/temporal_resolver.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/universal_personal_memory.py +0 -0
- {graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/vector_cache.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graph-mind-memory
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Local-first memory for AI coding assistants: verbatim, on your own PC, no LLM calls at write time.
|
|
5
5
|
Author-email: Yohan Ko <goyohan0611@gmail.com>
|
|
6
6
|
License-Expression: AGPL-3.0-only
|
|
@@ -13,11 +13,11 @@ Classifier: Operating System :: OS Independent
|
|
|
13
13
|
Requires-Python: >=3.10
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
License-File: LICENSE
|
|
16
|
-
Requires-Dist: torch<3,>=2.2
|
|
17
16
|
Requires-Dist: mcp<3,>=2
|
|
18
17
|
Requires-Dist: numpy
|
|
19
|
-
Requires-Dist:
|
|
20
|
-
Requires-Dist:
|
|
18
|
+
Requires-Dist: onnxruntime>=1.17
|
|
19
|
+
Requires-Dist: tokenizers>=0.15
|
|
20
|
+
Requires-Dist: huggingface_hub>=0.20
|
|
21
21
|
Requires-Dist: pgserver; python_version < "3.13"
|
|
22
22
|
Requires-Dist: psycopg[binary]
|
|
23
23
|
Requires-Dist: psutil
|
|
@@ -48,8 +48,9 @@ Local-first memory for AI coding assistants. Verbatim storage, on your own PC:
|
|
|
48
48
|
</div>
|
|
49
49
|
|
|
50
50
|
> [!NOTE]
|
|
51
|
-
> **Alpha.**
|
|
52
|
-
>
|
|
51
|
+
> **Alpha.** Windows: used daily, with full end-to-end checks (fresh install, two PCs, real
|
|
52
|
+
> Claude and Codex). macOS and Linux: tests and a clean install from PyPI pass in CI on every
|
|
53
|
+
> release and every day, but nobody has used them day to day yet; consider them experimental.
|
|
53
54
|
|
|
54
55
|
---
|
|
55
56
|
|
|
@@ -125,8 +126,8 @@ graph-mind-install
|
|
|
125
126
|
|
|
126
127
|
If `graph-mind-install` is "not recognized", pip put it in a Scripts folder that is not on your
|
|
127
128
|
PATH (common with the Windows Python install manager). `python -m install` runs the same thing.
|
|
128
|
-
If it stops with
|
|
129
|
-
runtime
|
|
129
|
+
If it stops with a DLL load error, Windows is missing the Microsoft Visual C++ runtime that the
|
|
130
|
+
embedding runtime needs: install [vc_redist.x64.exe](https://aka.ms/vs/17/release/vc_redist.x64.exe),
|
|
130
131
|
restart, and run the installer again.
|
|
131
132
|
|
|
132
133
|
or from source:
|
|
@@ -139,12 +140,12 @@ python install.py
|
|
|
139
140
|
|
|
140
141
|
The installer:
|
|
141
142
|
|
|
142
|
-
- installs the packages (PyTorch
|
|
143
|
+
- installs the packages (no PyTorch: the embedding model runs on ONNX Runtime);
|
|
143
144
|
- registers the MCP server with every app it finds: Claude Code, Claude Desktop (including the
|
|
144
145
|
Microsoft Store build) and Codex;
|
|
145
146
|
- starts the capture service at login (Windows Startup folder, a macOS LaunchAgent, or an XDG
|
|
146
147
|
autostart entry on Linux);
|
|
147
|
-
- downloads the embedding model.
|
|
148
|
+
- downloads the embedding model (about 470 MB, once).
|
|
148
149
|
|
|
149
150
|
Then restart your AI apps. The server is also listed in the
|
|
150
151
|
[MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.goyohan0611-png/graph-mind`. Running the installer again is safe. Run it again if you move the folder.
|
|
@@ -258,8 +259,9 @@ python -m unittest discover -p "test_*.py"
|
|
|
258
259
|
|
|
259
260
|
## Known limits
|
|
260
261
|
|
|
261
|
-
- **
|
|
262
|
-
|
|
262
|
+
- **For the first few seconds after an AI app starts, answers use word search only** while the
|
|
263
|
+
embedding model loads in the background (6-9 s on a slow, synced disk; it was 50-70 s before
|
|
264
|
+
0.4). The first answer never waits for it; later answers take well under a second.
|
|
263
265
|
- **Daily use on Windows only so far.** macOS and Linux pass the tests in CI but have not seen real
|
|
264
266
|
use.
|
|
265
267
|
- **Capture follows each app's transcript format,** which is not a public interface. An app update
|
|
@@ -22,8 +22,9 @@ Local-first memory for AI coding assistants. Verbatim storage, on your own PC:
|
|
|
22
22
|
</div>
|
|
23
23
|
|
|
24
24
|
> [!NOTE]
|
|
25
|
-
> **Alpha.**
|
|
26
|
-
>
|
|
25
|
+
> **Alpha.** Windows: used daily, with full end-to-end checks (fresh install, two PCs, real
|
|
26
|
+
> Claude and Codex). macOS and Linux: tests and a clean install from PyPI pass in CI on every
|
|
27
|
+
> release and every day, but nobody has used them day to day yet; consider them experimental.
|
|
27
28
|
|
|
28
29
|
---
|
|
29
30
|
|
|
@@ -99,8 +100,8 @@ graph-mind-install
|
|
|
99
100
|
|
|
100
101
|
If `graph-mind-install` is "not recognized", pip put it in a Scripts folder that is not on your
|
|
101
102
|
PATH (common with the Windows Python install manager). `python -m install` runs the same thing.
|
|
102
|
-
If it stops with
|
|
103
|
-
runtime
|
|
103
|
+
If it stops with a DLL load error, Windows is missing the Microsoft Visual C++ runtime that the
|
|
104
|
+
embedding runtime needs: install [vc_redist.x64.exe](https://aka.ms/vs/17/release/vc_redist.x64.exe),
|
|
104
105
|
restart, and run the installer again.
|
|
105
106
|
|
|
106
107
|
or from source:
|
|
@@ -113,12 +114,12 @@ python install.py
|
|
|
113
114
|
|
|
114
115
|
The installer:
|
|
115
116
|
|
|
116
|
-
- installs the packages (PyTorch
|
|
117
|
+
- installs the packages (no PyTorch: the embedding model runs on ONNX Runtime);
|
|
117
118
|
- registers the MCP server with every app it finds: Claude Code, Claude Desktop (including the
|
|
118
119
|
Microsoft Store build) and Codex;
|
|
119
120
|
- starts the capture service at login (Windows Startup folder, a macOS LaunchAgent, or an XDG
|
|
120
121
|
autostart entry on Linux);
|
|
121
|
-
- downloads the embedding model.
|
|
122
|
+
- downloads the embedding model (about 470 MB, once).
|
|
122
123
|
|
|
123
124
|
Then restart your AI apps. The server is also listed in the
|
|
124
125
|
[MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.goyohan0611-png/graph-mind`. Running the installer again is safe. Run it again if you move the folder.
|
|
@@ -232,8 +233,9 @@ python -m unittest discover -p "test_*.py"
|
|
|
232
233
|
|
|
233
234
|
## Known limits
|
|
234
235
|
|
|
235
|
-
- **
|
|
236
|
-
|
|
236
|
+
- **For the first few seconds after an AI app starts, answers use word search only** while the
|
|
237
|
+
embedding model loads in the background (6-9 s on a slow, synced disk; it was 50-70 s before
|
|
238
|
+
0.4). The first answer never waits for it; later answers take well under a second.
|
|
237
239
|
- **Daily use on Windows only so far.** macOS and Linux pass the tests in CI but have not seen real
|
|
238
240
|
use.
|
|
239
241
|
- **Capture follows each app's transcript format,** which is not a public interface. An app update
|
|
@@ -218,7 +218,15 @@ def semantic_turns(database, query, *, scopes=None, since=None, until=None, limi
|
|
|
218
218
|
# new pieces are embedded inline; a backlog is filled in the background while this question
|
|
219
219
|
# is answered from what is already embedded (word search covers the rest meanwhile).
|
|
220
220
|
missing = [p for p in pieces if embedder._key(p.strip()[:2000]) not in embedder.cache]
|
|
221
|
-
|
|
221
|
+
# Nor wait for the model itself: an app's first question used to sit through the torch import
|
|
222
|
+
# (38.8 s measured). If it is not loaded within WAIT_FOR_MODEL seconds, this question is
|
|
223
|
+
# answered from word search plus what is embedded already, and loading carries on.
|
|
224
|
+
asked = embedder._key(query.strip()[:2000]) in embedder.cache
|
|
225
|
+
wait = getattr(embedder, "WAIT_FOR_MODEL", None)
|
|
226
|
+
loading = (wait is not None and (missing or not asked) and not embedder.ready(wait))
|
|
227
|
+
if loading and not asked:
|
|
228
|
+
return []
|
|
229
|
+
if len(missing) > INLINE_EMBED_LIMIT or (loading and missing):
|
|
222
230
|
embed_in_background(embedder, missing)
|
|
223
231
|
keep = [i for i, p in enumerate(pieces)
|
|
224
232
|
if embedder._key(p.strip()[:2000]) in embedder.cache]
|
|
@@ -741,6 +749,8 @@ def preload(database):
|
|
|
741
749
|
|
|
742
750
|
|
|
743
751
|
def main():
|
|
752
|
+
from local_embedder import LocalEmbedder
|
|
753
|
+
LocalEmbedder.WAIT_FOR_MODEL = 0.5 # an app's question never waits out a model load
|
|
744
754
|
preload(configured_db_path())
|
|
745
755
|
server.run(transport="stdio")
|
|
746
756
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graph-mind-memory
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Local-first memory for AI coding assistants: verbatim, on your own PC, no LLM calls at write time.
|
|
5
5
|
Author-email: Yohan Ko <goyohan0611@gmail.com>
|
|
6
6
|
License-Expression: AGPL-3.0-only
|
|
@@ -13,11 +13,11 @@ Classifier: Operating System :: OS Independent
|
|
|
13
13
|
Requires-Python: >=3.10
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
License-File: LICENSE
|
|
16
|
-
Requires-Dist: torch<3,>=2.2
|
|
17
16
|
Requires-Dist: mcp<3,>=2
|
|
18
17
|
Requires-Dist: numpy
|
|
19
|
-
Requires-Dist:
|
|
20
|
-
Requires-Dist:
|
|
18
|
+
Requires-Dist: onnxruntime>=1.17
|
|
19
|
+
Requires-Dist: tokenizers>=0.15
|
|
20
|
+
Requires-Dist: huggingface_hub>=0.20
|
|
21
21
|
Requires-Dist: pgserver; python_version < "3.13"
|
|
22
22
|
Requires-Dist: psycopg[binary]
|
|
23
23
|
Requires-Dist: psutil
|
|
@@ -48,8 +48,9 @@ Local-first memory for AI coding assistants. Verbatim storage, on your own PC:
|
|
|
48
48
|
</div>
|
|
49
49
|
|
|
50
50
|
> [!NOTE]
|
|
51
|
-
> **Alpha.**
|
|
52
|
-
>
|
|
51
|
+
> **Alpha.** Windows: used daily, with full end-to-end checks (fresh install, two PCs, real
|
|
52
|
+
> Claude and Codex). macOS and Linux: tests and a clean install from PyPI pass in CI on every
|
|
53
|
+
> release and every day, but nobody has used them day to day yet; consider them experimental.
|
|
53
54
|
|
|
54
55
|
---
|
|
55
56
|
|
|
@@ -125,8 +126,8 @@ graph-mind-install
|
|
|
125
126
|
|
|
126
127
|
If `graph-mind-install` is "not recognized", pip put it in a Scripts folder that is not on your
|
|
127
128
|
PATH (common with the Windows Python install manager). `python -m install` runs the same thing.
|
|
128
|
-
If it stops with
|
|
129
|
-
runtime
|
|
129
|
+
If it stops with a DLL load error, Windows is missing the Microsoft Visual C++ runtime that the
|
|
130
|
+
embedding runtime needs: install [vc_redist.x64.exe](https://aka.ms/vs/17/release/vc_redist.x64.exe),
|
|
130
131
|
restart, and run the installer again.
|
|
131
132
|
|
|
132
133
|
or from source:
|
|
@@ -139,12 +140,12 @@ python install.py
|
|
|
139
140
|
|
|
140
141
|
The installer:
|
|
141
142
|
|
|
142
|
-
- installs the packages (PyTorch
|
|
143
|
+
- installs the packages (no PyTorch: the embedding model runs on ONNX Runtime);
|
|
143
144
|
- registers the MCP server with every app it finds: Claude Code, Claude Desktop (including the
|
|
144
145
|
Microsoft Store build) and Codex;
|
|
145
146
|
- starts the capture service at login (Windows Startup folder, a macOS LaunchAgent, or an XDG
|
|
146
147
|
autostart entry on Linux);
|
|
147
|
-
- downloads the embedding model.
|
|
148
|
+
- downloads the embedding model (about 470 MB, once).
|
|
148
149
|
|
|
149
150
|
Then restart your AI apps. The server is also listed in the
|
|
150
151
|
[MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.goyohan0611-png/graph-mind`. Running the installer again is safe. Run it again if you move the folder.
|
|
@@ -258,8 +259,9 @@ python -m unittest discover -p "test_*.py"
|
|
|
258
259
|
|
|
259
260
|
## Known limits
|
|
260
261
|
|
|
261
|
-
- **
|
|
262
|
-
|
|
262
|
+
- **For the first few seconds after an AI app starts, answers use word search only** while the
|
|
263
|
+
embedding model loads in the background (6-9 s on a slow, synced disk; it was 50-70 s before
|
|
264
|
+
0.4). The first answer never waits for it; later answers take well under a second.
|
|
263
265
|
- **Daily use on Windows only so far.** macOS and Linux pass the tests in CI but have not seen real
|
|
264
266
|
use.
|
|
265
267
|
- **Capture follows each app's transcript format,** which is not a public interface. An app update
|
|
@@ -180,35 +180,32 @@ def capture_service(start: bool) -> str:
|
|
|
180
180
|
|
|
181
181
|
def embedding_model():
|
|
182
182
|
sys.path.insert(0, str(HERE))
|
|
183
|
-
from local_embedder import LOCAL_MODEL, own_hf_home
|
|
183
|
+
from local_embedder import LOCAL_MODEL, MODEL_FILES, model_paths, own_hf_home
|
|
184
184
|
try:
|
|
185
|
-
|
|
186
|
-
except
|
|
187
|
-
if "
|
|
185
|
+
import onnxruntime # noqa: F401 (a DLL failure here would leave search on words only)
|
|
186
|
+
except ImportError as error:
|
|
187
|
+
if platform.system() != "Windows":
|
|
188
188
|
raise
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
sys.exit(f"\n{error}\n\nPyTorch could not load. Install the Microsoft Visual C++ "
|
|
192
|
-
"Redistributable (x64), restart, and run this again:\n"
|
|
189
|
+
sys.exit(f"\n{error}\n\nThe embedding runtime could not load. Install the Microsoft "
|
|
190
|
+
"Visual C++ Redistributable (x64), restart, and run this again:\n"
|
|
193
191
|
" https://aka.ms/vs/17/release/vc_redist.x64.exe\n"
|
|
194
192
|
"The apps are already connected; until then recall works by word search only.")
|
|
195
|
-
|
|
196
193
|
try:
|
|
197
|
-
|
|
198
|
-
AutoModel.from_pretrained(LOCAL_MODEL)
|
|
194
|
+
model_paths()
|
|
199
195
|
except OSError as error:
|
|
200
196
|
# ~/.cache refused (access denied): move Hugging Face's whole home under ~/.graph-mind,
|
|
201
197
|
# where every Graph-MIND process looks from now on (local_embedder.use_own_hf_home)
|
|
202
|
-
if "PermissionError" not in str(error) and not isinstance(error.__cause__, PermissionError)
|
|
198
|
+
if "PermissionError" not in str(error) and not isinstance(error.__cause__, PermissionError) \
|
|
199
|
+
and not isinstance(error, PermissionError):
|
|
203
200
|
raise
|
|
204
201
|
own = own_hf_home()
|
|
205
202
|
own.mkdir(parents=True, exist_ok=True)
|
|
206
203
|
step(f"the usual model folder is not writable; using {own}")
|
|
207
204
|
# huggingface_hub fixed its folders when it was imported: download in a fresh process
|
|
208
205
|
subprocess.run([sys.executable, "-c",
|
|
209
|
-
"from
|
|
210
|
-
|
|
211
|
-
|
|
206
|
+
"from huggingface_hub import hf_hub_download; "
|
|
207
|
+
+ "; ".join(f"hf_hub_download({LOCAL_MODEL!r}, {name!r})"
|
|
208
|
+
for name in MODEL_FILES)],
|
|
212
209
|
env={**os.environ, "HF_HOME": str(own),
|
|
213
210
|
"HF_HUB_DISABLE_SYMLINKS_WARNING": "1"}, check=True)
|
|
214
211
|
|
|
@@ -36,20 +36,43 @@ def use_own_hf_home() -> None:
|
|
|
36
36
|
use_own_hf_home()
|
|
37
37
|
|
|
38
38
|
|
|
39
|
+
MODEL_FILES = ("tokenizer.json", "onnx/model.onnx")
|
|
40
|
+
|
|
41
|
+
|
|
39
42
|
def model_on_disk() -> bool:
|
|
43
|
+
"""Both files the embedder reads are already downloaded (an install from before 0.4 has the
|
|
44
|
+
torch weights in the same folder, but not the ONNX file)."""
|
|
40
45
|
hf_home = Path(os.environ.get("HF_HOME") or Path.home() / ".cache" / "huggingface")
|
|
41
|
-
|
|
46
|
+
snapshots = hf_home / "hub" / ("models--" + LOCAL_MODEL.replace("/", "--")) / "snapshots"
|
|
47
|
+
return any(all((snapshot / name).exists() for name in MODEL_FILES)
|
|
48
|
+
for snapshot in (snapshots.iterdir() if snapshots.is_dir() else []))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def model_paths(model=LOCAL_MODEL) -> tuple:
|
|
52
|
+
"""Local paths of the tokenizer and the ONNX model, downloaded on first use."""
|
|
53
|
+
from huggingface_hub import hf_hub_download
|
|
54
|
+
return tuple(hf_hub_download(model, name) for name in MODEL_FILES)
|
|
42
55
|
|
|
43
56
|
|
|
44
57
|
class LocalEmbedder:
|
|
45
|
-
"""On-device multilingual embeddings
|
|
46
|
-
No text leaves the machine
|
|
58
|
+
"""On-device multilingual embeddings: the model's own ONNX export run by ONNX Runtime,
|
|
59
|
+
mean pooling, L2-normalized. No text leaves the machine.
|
|
60
|
+
|
|
61
|
+
Until 0.4 this ran on torch + transformers: same model, same vectors (on 1,000 texts the
|
|
62
|
+
largest difference was 2.4e-7, cosine 1.000000), but a 2 GB install, the Visual C++ runtime,
|
|
63
|
+
and 48-71 s to load on a OneDrive-synced Windows PC against 6-9 s now."""
|
|
47
64
|
|
|
48
|
-
_model = None
|
|
49
|
-
_tok = None
|
|
65
|
+
_model = None # an onnxruntime.InferenceSession
|
|
66
|
+
_tok = None # a tokenizers.Tokenizer
|
|
50
67
|
_lock = threading.RLock() # model load + cache writes are not thread-safe
|
|
51
68
|
|
|
52
69
|
FLUSH_EVERY = 5000 # vectors between writes: bounds lost work without rewriting per call
|
|
70
|
+
# Seconds a question may wait for the model to load before it is answered by word search
|
|
71
|
+
# alone. None waits (benchmarks, tests, the capture service); the MCP server sets 0.5: loading
|
|
72
|
+
# torch took 38.8 s for an app's first question on a OneDrive-synced Windows PC; now 2.4 s.
|
|
73
|
+
WAIT_FOR_MODEL = None
|
|
74
|
+
_loaded = threading.Event()
|
|
75
|
+
_loading = threading.Lock()
|
|
53
76
|
|
|
54
77
|
def __init__(self, cache_path, model=LOCAL_MODEL):
|
|
55
78
|
# float32 rows in a sibling directory: the old JSON cache turned 1.1GB on disk into 3-4GB
|
|
@@ -63,26 +86,52 @@ class LocalEmbedder:
|
|
|
63
86
|
|
|
64
87
|
def _load(self):
|
|
65
88
|
if LocalEmbedder._model is None:
|
|
66
|
-
import
|
|
67
|
-
from
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
89
|
+
import onnxruntime
|
|
90
|
+
from tokenizers import Tokenizer
|
|
91
|
+
tokenizer_file, model_file = model_paths(self.model_name)
|
|
92
|
+
tokenizer = Tokenizer.from_file(tokenizer_file)
|
|
93
|
+
tokenizer.enable_truncation(256) # as transformers did: max_length=256
|
|
94
|
+
tokenizer.enable_padding()
|
|
95
|
+
options = onnxruntime.SessionOptions()
|
|
96
|
+
options.log_severity_level = 3 # warnings about unused initializers: noise
|
|
97
|
+
LocalEmbedder._tok = tokenizer
|
|
98
|
+
LocalEmbedder._model = onnxruntime.InferenceSession(
|
|
99
|
+
model_file, options, providers=["CPUExecutionProvider"])
|
|
100
|
+
LocalEmbedder._loaded.set()
|
|
101
|
+
|
|
102
|
+
def ready(self, timeout) -> bool:
|
|
103
|
+
"""Whether the model is loaded, waiting at most `timeout` seconds. The first call starts
|
|
104
|
+
loading it in the background, so a later question finds it ready."""
|
|
105
|
+
if LocalEmbedder._model is not None:
|
|
106
|
+
return True
|
|
107
|
+
if LocalEmbedder._loading.acquire(blocking=False):
|
|
108
|
+
def load():
|
|
109
|
+
try:
|
|
110
|
+
with LocalEmbedder._lock:
|
|
111
|
+
self._load()
|
|
112
|
+
except Exception:
|
|
113
|
+
pass # no model on disk: word search keeps answering
|
|
114
|
+
finally:
|
|
115
|
+
LocalEmbedder._loading.release()
|
|
116
|
+
threading.Thread(target=load, name="graph-mind-model", daemon=True).start()
|
|
117
|
+
return LocalEmbedder._loaded.wait(timeout)
|
|
71
118
|
|
|
72
119
|
def _key(self, text):
|
|
73
120
|
return hashlib.sha256((self.model_name + "\0" + text).encode("utf-8")).hexdigest()
|
|
74
121
|
|
|
75
122
|
def _encode(self, texts):
|
|
76
|
-
import
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
123
|
+
import numpy as np
|
|
124
|
+
encoded = LocalEmbedder._tok.encode_batch(texts)
|
|
125
|
+
ids = np.array([e.ids for e in encoded], dtype=np.int64)
|
|
126
|
+
mask = np.array([e.attention_mask for e in encoded], dtype=np.int64)
|
|
127
|
+
feed = {"input_ids": ids, "attention_mask": mask}
|
|
128
|
+
if "token_type_ids" in {i.name for i in LocalEmbedder._model.get_inputs()}:
|
|
129
|
+
feed["token_type_ids"] = np.zeros_like(ids)
|
|
130
|
+
hidden = LocalEmbedder._model.run(None, feed)[0]
|
|
131
|
+
weights = mask[..., None].astype(np.float32)
|
|
132
|
+
pooled = (hidden * weights).sum(1) / np.clip(weights.sum(1), 1e-9, None)
|
|
133
|
+
pooled /= np.clip(np.linalg.norm(pooled, axis=1, keepdims=True), 1e-12, None)
|
|
134
|
+
return pooled.tolist()
|
|
86
135
|
|
|
87
136
|
def embed(self, texts):
|
|
88
137
|
texts = [t.strip()[:2000] for t in texts]
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "graph-mind-memory"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "Local-first memory for AI coding assistants: verbatim, on your own PC, no LLM calls at write time."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -18,11 +18,11 @@ classifiers = [
|
|
|
18
18
|
"Operating System :: OS Independent",
|
|
19
19
|
]
|
|
20
20
|
dependencies = [
|
|
21
|
-
"torch>=2.2,<3",
|
|
22
21
|
"mcp>=2,<3",
|
|
23
22
|
"numpy",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
23
|
+
"onnxruntime>=1.17",
|
|
24
|
+
"tokenizers>=0.15",
|
|
25
|
+
"huggingface_hub>=0.20",
|
|
26
26
|
# hosts the shared brain's Postgres; built for Python 3.9-3.12 only. Joining another PC's
|
|
27
27
|
# brain (psycopg) and everything else work on any supported Python.
|
|
28
28
|
"pgserver; python_version < '3.13'",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/graph_mind_memory.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/graph_mind_memory.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{graph_mind_memory-0.3.3 → graph_mind_memory-0.4.0}/graph_mind_memory.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|