JacobLinCool Codex commited on
Commit
e493b7e
·
verified ·
1 Parent(s): 9f8766d

fix: use full embedding context

Browse files

Co-authored-by: Codex <noreply@openai.com>

README.md CHANGED
@@ -240,7 +240,7 @@ ADVISOR_REFRESH_LOCK_TTL_SECONDS=7200
240
  ADVISOR_REFRESH_EMBEDDING_TIMEOUT_SECONDS=1800
241
  ADVISOR_EMBEDDING_MODEL_REPO=ggml-org/embeddinggemma-300m-qat-q8_0-GGUF
242
  ADVISOR_EMBEDDING_MODEL_FILE=embeddinggemma-300m-qat-Q8_0.gguf
243
- ADVISOR_EMBEDDING_N_CTX=768
244
  ADVISOR_ASR_MODEL_ID=nvidia/nemotron-speech-streaming-en-0.6b
245
  ```
246
 
 
240
  ADVISOR_REFRESH_EMBEDDING_TIMEOUT_SECONDS=1800
241
  ADVISOR_EMBEDDING_MODEL_REPO=ggml-org/embeddinggemma-300m-qat-q8_0-GGUF
242
  ADVISOR_EMBEDDING_MODEL_FILE=embeddinggemma-300m-qat-Q8_0.gguf
243
+ ADVISOR_EMBEDDING_N_CTX=2048
244
  ADVISOR_ASR_MODEL_ID=nvidia/nemotron-speech-streaming-en-0.6b
245
  ```
246
 
hackathon_advisor/llama_embedding.py CHANGED
@@ -19,7 +19,7 @@ from hackathon_advisor.data import (
19
 
20
  TRUE_VALUES = {"1", "true", "yes", "on"}
21
  FALSE_VALUES = {"0", "false", "no", "off"}
22
- DEFAULT_N_CTX = 768
23
 
24
 
25
  class LlamaCppEmbedder:
 
19
 
20
  TRUE_VALUES = {"1", "true", "yes", "on"}
21
  FALSE_VALUES = {"0", "false", "no", "off"}
22
+ DEFAULT_N_CTX = 2048
23
 
24
 
25
  class LlamaCppEmbedder:
scripts/build_project_index.py CHANGED
@@ -73,7 +73,12 @@ def build_payload(
73
  data = json.loads(project_path.read_text(encoding="utf-8"))
74
  projects = [Project.from_dict(item) for item in data["projects"]]
75
  print(f"loaded {len(projects)} projects from {project_path}", flush=True)
76
- reusable_vectors = load_reusable_vectors(reuse_index_path)
 
 
 
 
 
77
  if reusable_vectors:
78
  print(f"loaded {len(reusable_vectors)} reusable vectors from {reuse_index_path}", flush=True)
79
  print(
@@ -128,10 +133,41 @@ def build_payload(
128
  )
129
 
130
 
131
- def load_reusable_vectors(reuse_index_path: Path | None) -> dict[tuple[str, str], list[float]]:
 
 
 
 
 
 
132
  if reuse_index_path is None:
133
  return {}
134
  payload = json.loads(reuse_index_path.read_text(encoding="utf-8"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  documents = payload.get("documents")
136
  if not isinstance(documents, list):
137
  return {}
 
73
  data = json.loads(project_path.read_text(encoding="utf-8"))
74
  projects = [Project.from_dict(item) for item in data["projects"]]
75
  print(f"loaded {len(projects)} projects from {project_path}", flush=True)
76
+ reusable_vectors = load_reusable_vectors(
77
+ reuse_index_path,
78
+ model_repo=model_repo,
79
+ model_file=model_file,
80
+ n_ctx=n_ctx,
81
+ )
82
  if reusable_vectors:
83
  print(f"loaded {len(reusable_vectors)} reusable vectors from {reuse_index_path}", flush=True)
84
  print(
 
133
  )
134
 
135
 
136
+ def load_reusable_vectors(
137
+ reuse_index_path: Path | None,
138
+ *,
139
+ model_repo: str,
140
+ model_file: str,
141
+ n_ctx: int,
142
+ ) -> dict[tuple[str, str], list[float]]:
143
  if reuse_index_path is None:
144
  return {}
145
  payload = json.loads(reuse_index_path.read_text(encoding="utf-8"))
146
+ embedding = payload.get("embedding")
147
+ if not isinstance(embedding, dict):
148
+ print(f"skipping reusable vectors from {reuse_index_path}: missing embedding metadata", flush=True)
149
+ return {}
150
+ expected = {
151
+ "model_repo": model_repo,
152
+ "model_file": model_file,
153
+ "n_ctx": n_ctx,
154
+ }
155
+ try:
156
+ actual_n_ctx = int(embedding.get("n_ctx") or 0)
157
+ except (TypeError, ValueError):
158
+ actual_n_ctx = 0
159
+ actual = {
160
+ "model_repo": str(embedding.get("model_repo") or ""),
161
+ "model_file": str(embedding.get("model_file") or ""),
162
+ "n_ctx": actual_n_ctx,
163
+ }
164
+ if actual != expected:
165
+ print(
166
+ f"skipping reusable vectors from {reuse_index_path}: "
167
+ f"embedding config changed from {actual} to {expected}",
168
+ flush=True,
169
+ )
170
+ return {}
171
  documents = payload.get("documents")
172
  if not isinstance(documents, list):
173
  return {}
tests/test_build_project_index.py CHANGED
@@ -33,7 +33,16 @@ def test_build_project_index_reuses_matching_digest_vectors(monkeypatch, tmp_pat
33
  encoding="utf-8",
34
  )
35
  reuse_path.write_text(
36
- json.dumps({"documents": [{"project_id": project.id, "text_digest": digest, "vector": [1.0, 0.0, 0.0]}]}),
 
 
 
 
 
 
 
 
 
37
  encoding="utf-8",
38
  )
39
 
@@ -55,3 +64,66 @@ def test_build_project_index_reuses_matching_digest_vectors(monkeypatch, tmp_pat
55
  assert payload["documents"][0]["project_id"] == project.id
56
  assert payload["documents"][0]["text_digest"] == digest
57
  assert payload["documents"][0]["vector"] == [1.0, 0.0, 0.0]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  encoding="utf-8",
34
  )
35
  reuse_path.write_text(
36
+ json.dumps(
37
+ {
38
+ "embedding": {
39
+ "model_repo": "test/repo",
40
+ "model_file": "model.gguf",
41
+ "n_ctx": build_project_index.DEFAULT_N_CTX,
42
+ },
43
+ "documents": [{"project_id": project.id, "text_digest": digest, "vector": [1.0, 0.0, 0.0]}],
44
+ }
45
+ ),
46
  encoding="utf-8",
47
  )
48
 
 
64
  assert payload["documents"][0]["project_id"] == project.id
65
  assert payload["documents"][0]["text_digest"] == digest
66
  assert payload["documents"][0]["vector"] == [1.0, 0.0, 0.0]
67
+
68
+
69
+ def test_build_project_index_rejects_vectors_when_embedding_config_changes(monkeypatch, tmp_path: Path) -> None:
70
+ project_row = {
71
+ "id": "build-small-hackathon/rebuilt-project",
72
+ "title": "Rebuilt Project",
73
+ "summary": "compact local model demo",
74
+ "tags": ["gradio"],
75
+ "models": [],
76
+ "datasets": [],
77
+ "likes": 0,
78
+ "sdk": "gradio",
79
+ "license": "",
80
+ "created_at": "",
81
+ "last_modified": "",
82
+ "host": "",
83
+ "url": "https://example.test",
84
+ }
85
+ project = Project.from_dict(project_row)
86
+ digest = sha256(project.searchable_text.encode("utf-8")).hexdigest()
87
+ project_path = tmp_path / "projects.json"
88
+ reuse_path = tmp_path / "reuse.json"
89
+ project_path.write_text(
90
+ json.dumps({"generated_at": "2026-06-08T00:00:00+00:00", "source": "test", "projects": [project_row]}),
91
+ encoding="utf-8",
92
+ )
93
+ reuse_path.write_text(
94
+ json.dumps(
95
+ {
96
+ "embedding": {
97
+ "model_repo": "test/repo",
98
+ "model_file": "model.gguf",
99
+ "n_ctx": 768,
100
+ },
101
+ "documents": [{"project_id": project.id, "text_digest": digest, "vector": [1.0, 0.0, 0.0]}],
102
+ }
103
+ ),
104
+ encoding="utf-8",
105
+ )
106
+
107
+ class FakeEmbedder:
108
+ def __init__(self, **kwargs) -> None:
109
+ assert kwargs["n_ctx"] == 2048
110
+
111
+ def embed(self, _text: str) -> list[float]:
112
+ return [0.0, 1.0, 0.0]
113
+
114
+ monkeypatch.setattr(build_project_index, "LlamaCppEmbedder", FakeEmbedder)
115
+
116
+ payload = build_project_index.build_payload(
117
+ project_path,
118
+ model_repo="test/repo",
119
+ model_file="model.gguf",
120
+ n_ctx=2048,
121
+ build_source="test",
122
+ builder="test",
123
+ reuse_index_path=reuse_path,
124
+ )
125
+
126
+ assert payload["document_count"] == 1
127
+ assert payload["documents"][0]["project_id"] == project.id
128
+ assert payload["documents"][0]["text_digest"] == digest
129
+ assert payload["documents"][0]["vector"] == [0.0, 1.0, 0.0]