emrd95 commited on
Commit
d14fe96
·
verified ·
1 Parent(s): 720127a

Add files using upload-large-folder tool

Browse files
Files changed (50) hide show
  1. SEMANTIC_NEIGHBORS.md +69 -0
  2. launch_semantic_neighbors.sh +4 -0
  3. neighbor_meta_armenian_western.json +11 -0
  4. neighbor_meta_bosnian.json +11 -0
  5. neighbor_meta_catalan.json +11 -0
  6. neighbor_meta_chinese_traditional.json +11 -0
  7. neighbor_meta_dutch.json +11 -0
  8. neighbor_meta_english.json +11 -0
  9. neighbor_meta_esperanto_h_sistemo.json +11 -0
  10. neighbor_meta_euskera.json +11 -0
  11. neighbor_meta_finnish.json +11 -0
  12. neighbor_meta_french.json +11 -0
  13. neighbor_meta_friulian.json +11 -0
  14. neighbor_meta_galician.json +11 -0
  15. neighbor_meta_georgian.json +11 -0
  16. neighbor_meta_greek.json +11 -0
  17. neighbor_meta_hausa.json +11 -0
  18. neighbor_meta_hawaiian.json +11 -0
  19. neighbor_meta_hebrew.json +11 -0
  20. neighbor_meta_hungarian.json +11 -0
  21. neighbor_meta_icelandic.json +11 -0
  22. neighbor_meta_indonesian.json +11 -0
  23. neighbor_meta_italian.json +11 -0
  24. neighbor_meta_japanese_romaji.json +11 -0
  25. neighbor_meta_kannada.json +11 -0
  26. neighbor_meta_kazakh.json +11 -0
  27. neighbor_meta_khmer.json +11 -0
  28. neighbor_meta_kyrgyz.json +11 -0
  29. neighbor_meta_lao.json +11 -0
  30. neighbor_meta_latin.json +11 -0
  31. neighbor_meta_lithuanian.json +11 -0
  32. neighbor_meta_macedonian.json +11 -0
  33. neighbor_meta_maltese.json +11 -0
  34. neighbor_meta_mongolian.json +11 -0
  35. neighbor_meta_oromo.json +11 -0
  36. neighbor_meta_persian.json +11 -0
  37. neighbor_meta_santali.json +11 -0
  38. neighbor_meta_serbian.json +11 -0
  39. neighbor_meta_sinhala.json +11 -0
  40. neighbor_meta_slovenian.json +11 -0
  41. neighbor_meta_swahili.json +11 -0
  42. neighbor_meta_swiss_german.json +11 -0
  43. neighbor_meta_tatar_crimean_cyrillic.json +11 -0
  44. neighbor_meta_telugu.json +11 -0
  45. neighbor_meta_thai.json +11 -0
  46. neighbor_meta_xhosa.json +11 -0
  47. neighbor_meta_yiddish.json +11 -0
  48. neighbor_meta_zulu.json +11 -0
  49. semantic_index_meta.json +17 -0
  50. semantic_neighbors_server.py +268 -0
SEMANTIC_NEIGHBORS.md ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # KeyboardRage semantic neighbors
2
+
3
+ This adds original-embedding semantic-neighbor inspection to `galaxy_fly_three.html`.
4
+
5
+ Note: I first prototyped the UI on `galaxy.html`, but the intended primary view is the Three.js fly-through view at:
6
+
7
+ ```text
8
+ http://localhost:8888/galaxy/3D_galaxy/galaxy_fly_three.html
9
+ ```
10
+
11
+ Important distinction:
12
+ - The 3D galaxy coordinates (`x/y/z`) are only the visual UMAP projection.
13
+ - Semantic neighbors are queried from original Granite definition embeddings.
14
+ - FAISS HNSW is only used for candidate retrieval.
15
+ - Final ranking/scores are exact cosine similarities against normalized float32 embeddings.
16
+
17
+ ## One-time index build
18
+
19
+ From this directory:
20
+
21
+ ```bash
22
+ ../venv/bin/python build_semantic_index.py --resume
23
+ ```
24
+
25
+ Outputs:
26
+ - `semantic_embeddings.f32.npy`
27
+ - `semantic_faiss_hnsw.index`
28
+ - `semantic_index_meta.json`
29
+
30
+ The embeddings file is large because it keeps float32 vectors for exact reranking.
31
+ For ~2.84M rows x 384 dims, expect about 4.1 GiB for the `.npy` plus the FAISS HNSW index.
32
+
33
+ ## Run the backend
34
+
35
+ ```bash
36
+ ./launch_semantic_neighbors.sh
37
+ ```
38
+
39
+ Equivalent:
40
+
41
+ ```bash
42
+ ../venv/bin/uvicorn semantic_neighbors_server:app --host 127.0.0.1 --port 8703
43
+ ```
44
+
45
+ ## Run the galaxy
46
+
47
+ From the project root:
48
+
49
+ ```bash
50
+ cd /home/ubu/Desktop/keyboardrage
51
+ python3 -m http.server 8888
52
+ ```
53
+
54
+ Open:
55
+
56
+ ```text
57
+ http://localhost:8888/galaxy/3D_galaxy/galaxy_fly_three.html
58
+ ```
59
+
60
+ Click `Inspect semantic neighbors: off` to enable the panel. Then click a point.
61
+
62
+ Controls:
63
+ - `K`: number of neighbors returned.
64
+ - `filter`: all / same language / cross-language.
65
+ - `lines`: show/hide 3D lines from selected point to semantic neighbors.
66
+ - `table`: show/hide the Atlas-style neighbor table.
67
+ - clicking a table row focuses that neighbor and queries its neighbors.
68
+
69
+ If the backend/index is not ready, the browser panel shows the exact command to start the server or build the index.
launch_semantic_neighbors.sh ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ cd "$(dirname "$0")"
4
+ exec ../venv/bin/uvicorn semantic_neighbors_server:app --host 127.0.0.1 --port 8703
neighbor_meta_armenian_western.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "armenian_western",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 437,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_bosnian.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "bosnian",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 2905,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:08Z"
11
+ }
neighbor_meta_catalan.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "catalan",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 997,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_chinese_traditional.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "chinese_traditional",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 42294,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:11Z"
11
+ }
neighbor_meta_dutch.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "dutch",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 3303,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:08Z"
11
+ }
neighbor_meta_english.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "english",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 352781,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:58Z"
11
+ }
neighbor_meta_esperanto_h_sistemo.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "esperanto_h_sistemo",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 15460,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:09Z"
11
+ }
neighbor_meta_euskera.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "euskera",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 145,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:06Z"
11
+ }
neighbor_meta_finnish.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "finnish",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 9975,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:09Z"
11
+ }
neighbor_meta_french.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "french",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 302443,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:43Z"
11
+ }
neighbor_meta_friulian.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "friulian",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 122,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:06Z"
11
+ }
neighbor_meta_galician.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "galician",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 188,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:06Z"
11
+ }
neighbor_meta_georgian.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "georgian",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 176,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:06Z"
11
+ }
neighbor_meta_greek.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "greek",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 10543,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:09Z"
11
+ }
neighbor_meta_hausa.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "hausa",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 175,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:06Z"
11
+ }
neighbor_meta_hawaiian.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "hawaiian",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 557,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_hebrew.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "hebrew",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 2921,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:08Z"
11
+ }
neighbor_meta_hungarian.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "hungarian",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 2480,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:08Z"
11
+ }
neighbor_meta_icelandic.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "icelandic",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 754,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_indonesian.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "indonesian",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 5635,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:08Z"
11
+ }
neighbor_meta_italian.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "italian",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 231321,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:33Z"
11
+ }
neighbor_meta_japanese_romaji.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "japanese_romaji",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 799,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_kannada.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "kannada",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 71,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:06Z"
11
+ }
neighbor_meta_kazakh.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "kazakh",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 728,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_khmer.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "khmer",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 291,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_kyrgyz.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "kyrgyz",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 412,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_lao.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "lao",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 325,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_latin.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "latin",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 360,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_lithuanian.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "lithuanian",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 1771,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_macedonian.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "macedonian",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 18976,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:10Z"
11
+ }
neighbor_meta_maltese.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "maltese",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 563,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_mongolian.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "mongolian",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 1298,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_oromo.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "oromo",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 430,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_persian.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "persian",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 8695,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:08Z"
11
+ }
neighbor_meta_santali.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "santali",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 64,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:06Z"
11
+ }
neighbor_meta_serbian.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "serbian",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 3022,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:08Z"
11
+ }
neighbor_meta_sinhala.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "sinhala",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 39,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:06Z"
11
+ }
neighbor_meta_slovenian.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "slovenian",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 1294,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_swahili.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "swahili",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 713,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_swiss_german.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "swiss_german",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 66,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:06Z"
11
+ }
neighbor_meta_tatar_crimean_cyrillic.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "tatar_crimean_cyrillic",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 108,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:06Z"
11
+ }
neighbor_meta_telugu.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "telugu",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 462,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_thai.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "thai",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 12901,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:09Z"
11
+ }
neighbor_meta_xhosa.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "xhosa",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 1089,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:07Z"
11
+ }
neighbor_meta_yiddish.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "yiddish",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 139,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:06Z"
11
+ }
neighbor_meta_zulu.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "language": "zulu",
3
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
4
+ "metric": "cosine_similarity_via_normalized_inner_product",
5
+ "rows": 101,
6
+ "dim": 384,
7
+ "top_k": 200,
8
+ "computation": "pytorch_gpu_per_language",
9
+ "global_total": 2250636,
10
+ "created_at": "2026-05-23T20:40:06Z"
11
+ }
semantic_index_meta.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "ibm-granite/granite-embedding-97m-multilingual-r2",
3
+ "metric": "cosine_similarity_via_normalized_inner_product",
4
+ "rows": 2250636,
5
+ "dim": 384,
6
+ "order": "sorted words_emb/*.json, skipping rows without embedding_3d; matches galaxy_data.bin and atlas_data.parquet",
7
+ "embeddings": "semantic_embeddings.f32.npy",
8
+ "faiss_index": "semantic_faiss_hnsw.index",
9
+ "faiss": {
10
+ "type": "IndexFlatIP",
11
+ "exact": true,
12
+ "candidate_search_only": false,
13
+ "final_scores": "exact cosine over normalized float32 embeddings",
14
+ "note": "Built for immediate testing after HNSW build was too hot/slow. Queries scan all vectors but ranking is exact."
15
+ },
16
+ "created_at": "2026-05-23T00:09:17Z"
17
+ }
semantic_neighbors_server.py ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Local semantic-neighbor API for KeyboardRage Galaxy.
4
+
5
+ Neighbors are fully precomputed. Global mode uses neighbor_ids.npy (all 2.25M).
6
+ Per-language mode uses neighbor_ids_{lang}.npy (within-language top-200).
7
+
8
+ Precompute with: ../venv/bin/python precompute_neighbors.py --per-language
9
+ """
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ import math
14
+ from pathlib import Path
15
+ from typing import Literal
16
+
17
+ import duckdb
18
+ import numpy as np
19
+ import pyarrow.parquet as pq
20
+ from fastapi import FastAPI, HTTPException, Query
21
+ from fastapi.middleware.cors import CORSMiddleware
22
+
23
+ HERE = Path(__file__).resolve().parent
24
+ ATLAS_PARQUET = HERE.parent / "atlas" / "atlas_data.parquet"
25
+ NEIGHBOR_IDS_PATH = HERE / "neighbor_ids.npy"
26
+ NEIGHBOR_SCORES_PATH = HERE / "neighbor_scores.npy"
27
+ NEIGHBOR_META_PATH = HERE / "neighbor_meta.json"
28
+ EMBEDDINGS_PATH = HERE / "semantic_embeddings.f32.npy"
29
+ FAISS_INDEX_PATH = HERE / "semantic_faiss_hnsw.index"
30
+ INDEX_META_PATH = HERE / "semantic_index_meta.json"
31
+
32
+ app = FastAPI(title="KeyboardRage Semantic Neighbors", version="3.0")
33
+ app.add_middleware(
34
+ CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"],
35
+ )
36
+
37
+ # Cache: {language: (ids_mmap, scores_mmap, lang_index_mmap)}
38
+ _per_lang_cache: dict[str, tuple[np.ndarray, np.ndarray, np.ndarray | None]] = {}
39
+ _global_ids: np.ndarray | None = None
40
+ _global_scores: np.ndarray | None = None
41
+ _meta_table = None
42
+ _meta_rows: int | None = None
43
+ _con = duckdb.connect(database=":memory:")
44
+
45
+
46
+ def _load_metadata_table():
47
+ global _meta_table, _meta_rows
48
+ if _meta_table is None:
49
+ if not ATLAS_PARQUET.exists():
50
+ raise RuntimeError(f"Missing {ATLAS_PARQUET}")
51
+ _meta_table = pq.read_table(
52
+ ATLAS_PARQUET, columns=["x", "y", "z", "word", "language", "definition"],
53
+ )
54
+ _meta_rows = _meta_table.num_rows
55
+ return _meta_table
56
+
57
+
58
+ def _load_global():
59
+ global _global_ids, _global_scores
60
+ if _global_ids is None:
61
+ if not NEIGHBOR_IDS_PATH.exists():
62
+ raise RuntimeError(f"Missing {NEIGHBOR_IDS_PATH.name}")
63
+ _global_ids = np.load(NEIGHBOR_IDS_PATH, mmap_mode="r")
64
+ _global_scores = np.load(NEIGHBOR_SCORES_PATH, mmap_mode="r")
65
+ return _global_ids, _global_scores
66
+
67
+
68
+ def _load_per_language(language: str):
69
+ if language in _per_lang_cache:
70
+ return _per_lang_cache[language]
71
+
72
+ ids_path = HERE / f"neighbor_ids_{language}.npy"
73
+ scores_path = HERE / f"neighbor_scores_{language}.npy"
74
+ index_path = HERE / f"lang_index_{language}.npy"
75
+
76
+ if not ids_path.exists():
77
+ # Fall back to global
78
+ return _load_global()[0], _load_global()[1], None
79
+
80
+ ids = np.load(ids_path, mmap_mode="r")
81
+ scores = np.load(scores_path, mmap_mode="r")
82
+ lang_index = np.load(index_path, mmap_mode="r") if index_path.exists() else None
83
+
84
+ _per_lang_cache[language] = (ids, scores, lang_index)
85
+ return ids, scores, lang_index
86
+
87
+
88
+ def _row(i: int) -> dict:
89
+ table = _load_metadata_table()
90
+ if i < 0 or i >= table.num_rows:
91
+ raise IndexError(i)
92
+ batch = table.slice(i, 1).to_pydict()
93
+ return {
94
+ "id": i,
95
+ "word": batch["word"][0],
96
+ "language": batch["language"][0],
97
+ "definition": batch["definition"][0],
98
+ "x": float(batch["x"][0]),
99
+ "y": float(batch["y"][0]),
100
+ "z": float(batch["z"][0]),
101
+ }
102
+
103
+
104
+ def _rows(ids: list[int]) -> list[dict]:
105
+ return [_row(i) for i in ids]
106
+
107
+
108
+ def _projected_distance(a: dict, b: dict) -> float:
109
+ dx = float(a["x"]) - float(b["x"])
110
+ dy = float(a["y"]) - float(b["y"])
111
+ dz = float(a["z"]) - float(b["z"])
112
+ return math.sqrt(dx * dx + dy * dy + dz * dz)
113
+
114
+
115
+ @app.get("/health")
116
+ def health():
117
+ status = {
118
+ "atlas_parquet": ATLAS_PARQUET.exists(),
119
+ "embeddings": EMBEDDINGS_PATH.exists(),
120
+ "precomputed_global": NEIGHBOR_IDS_PATH.exists(),
121
+ }
122
+ if ATLAS_PARQUET.exists():
123
+ status["rows"] = pq.ParquetFile(ATLAS_PARQUET).metadata.num_rows
124
+ if NEIGHBOR_META_PATH.exists():
125
+ status["neighbor_meta"] = json.loads(NEIGHBOR_META_PATH.read_text())
126
+ # List available per-language files
127
+ per_lang = sorted(
128
+ p.stem.replace("neighbor_ids_", "")
129
+ for p in HERE.glob("neighbor_ids_*.npy")
130
+ )
131
+ if per_lang:
132
+ status["per_language_available"] = per_lang
133
+ return status
134
+
135
+
136
+ @app.get("/point/{point_id}")
137
+ def point(point_id: int):
138
+ try:
139
+ return _row(point_id)
140
+ except Exception:
141
+ raise HTTPException(status_code=404, detail="point id out of range")
142
+
143
+
144
+ @app.get("/neighbors/{point_id}")
145
+ def neighbors(
146
+ point_id: int,
147
+ k: int = Query(10, ge=1, le=200),
148
+ language: str | None = Query(
149
+ None,
150
+ description="Restrict to within-language neighbors (e.g. 'french')",
151
+ ),
152
+ language_filter: Literal["all", "same", "cross"] = "all",
153
+ visible_languages: str | None = Query(None),
154
+ ):
155
+ query = _row(point_id)
156
+
157
+ if language:
158
+ # Per-language precomputed: map global_id → local_id
159
+ ids_arr, scores_arr, lang_index = _load_per_language(language)
160
+ if lang_index is not None:
161
+ local_id = int(lang_index[point_id])
162
+ if local_id < 0:
163
+ return {
164
+ "query": query, "metric": "cosine",
165
+ "space": "precomputed_per_language", "k": k,
166
+ "language": language, "neighbors": [],
167
+ }
168
+ all_ids = np.asarray(ids_arr[local_id], dtype=np.int64)
169
+ all_scores = np.asarray(scores_arr[local_id], dtype=np.float32)
170
+ else:
171
+ # No per-language file, fall back to global with same-language filter
172
+ ids_arr, scores_arr = _load_global()
173
+ all_ids = np.asarray(ids_arr[point_id], dtype=np.int64)
174
+ all_scores = np.asarray(scores_arr[point_id], dtype=np.float32)
175
+ language_filter = "same"
176
+ else:
177
+ ids_arr, scores_arr = _load_global()
178
+ all_ids = np.asarray(ids_arr[point_id], dtype=np.int64)
179
+ all_scores = np.asarray(scores_arr[point_id], dtype=np.float32)
180
+
181
+ # Drop sentinels (0 = no more neighbors)
182
+ valid = all_ids >= 0
183
+ all_ids = all_ids[valid]
184
+ all_scores = all_scores[valid]
185
+
186
+ if all_ids.size == 0:
187
+ return {
188
+ "query": query, "metric": "cosine",
189
+ "space": "precomputed", "k": k, "neighbors": [],
190
+ }
191
+
192
+ # Parse visible-language filter
193
+ visible_set = None
194
+ if visible_languages:
195
+ visible_set = {p.strip() for p in visible_languages.split(",") if p.strip()}
196
+ if not visible_set:
197
+ visible_set = None
198
+
199
+ has_filter = language_filter != "all" or visible_set is not None
200
+ rows = _rows([int(i) for i in all_ids.tolist()])
201
+
202
+ eligible_scores: list[float] = []
203
+ eligible_rows: list[dict] = []
204
+
205
+ for idx, (cid, row) in enumerate(zip(all_ids.tolist(), rows)):
206
+ if visible_set is not None and row["language"] not in visible_set:
207
+ continue
208
+ if language_filter == "same" and row["language"] != query["language"]:
209
+ continue
210
+ if language_filter == "cross" and row["language"] == query["language"]:
211
+ continue
212
+ eligible_rows.append(row)
213
+ eligible_scores.append(float(all_scores[idx]))
214
+
215
+ if has_filter and eligible_scores:
216
+ order = sorted(range(len(eligible_scores)), key=lambda i: -eligible_scores[i])[:k]
217
+ else:
218
+ order = list(range(min(k, len(eligible_scores))))
219
+
220
+ out = []
221
+ for rank, pos in enumerate(order, start=1):
222
+ row = eligible_rows[pos]
223
+ sim = eligible_scores[pos]
224
+ out.append({
225
+ **row, "rank": rank,
226
+ "cosine_similarity": sim,
227
+ "cosine_distance": float(1.0 - sim),
228
+ "projected_distance_3d": _projected_distance(query, row),
229
+ })
230
+
231
+ return {
232
+ "query": query, "metric": "cosine",
233
+ "space": "precomputed_per_language" if language else "precomputed_global",
234
+ "k": k, "language_filter": language_filter,
235
+ "visible_languages": sorted(visible_set) if visible_set else None,
236
+ "candidates_examined": int(all_ids.size),
237
+ "neighbors": out,
238
+ }
239
+
240
+
241
+ @app.get("/search")
242
+ def search(
243
+ q: str = Query(..., min_length=1),
244
+ limit: int = Query(25, ge=1, le=200),
245
+ language: str | None = Query(None, description="Filter by language"),
246
+ ):
247
+ if not ATLAS_PARQUET.exists():
248
+ raise HTTPException(status_code=500, detail="atlas_data.parquet missing")
249
+ safe_q = q.replace("'", "''")
250
+ lang_clause = ""
251
+ if language:
252
+ safe_lang = language.replace("'", "''")
253
+ lang_clause = f"AND lower(language) = lower('{safe_lang}')"
254
+ sql = f"""
255
+ WITH t AS (
256
+ SELECT row_number() OVER () - 1 AS id, word, language, x, y, z, definition
257
+ FROM read_parquet('{ATLAS_PARQUET.as_posix()}')
258
+ )
259
+ SELECT id, word, language, x, y, z, definition
260
+ FROM t
261
+ WHERE (lower(word) = lower('{safe_q}') OR lower(word) LIKE '%' || lower('{safe_q}') || '%')
262
+ {lang_clause}
263
+ ORDER BY CASE WHEN lower(word) = lower('{safe_q}') THEN 0 ELSE 1 END, word
264
+ LIMIT {int(limit)}
265
+ """
266
+ rows = _con.execute(sql).fetchall()
267
+ cols = ["id", "word", "language", "x", "y", "z", "definition"]
268
+ return {"results": [dict(zip(cols, r)) for r in rows]}