v3.2: fp32 matrix at load (was recasting 186MB/query); add scope to split personal vs public layer
Browse files
main.py
CHANGED
|
@@ -1,8 +1,13 @@
|
|
| 1 |
-
"""OmniBrain API v3.
|
| 2 |
|
| 3 |
-
Boot: pull parquet shards from the BRAIN_REPO dataset repo, load
|
| 4 |
in RAM, serve brute-force cosine. Space disk is ephemeral, so the dataset repo
|
| 5 |
is the durable store; restarting the Space just re-pulls.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
"""
|
| 7 |
import os, glob
|
| 8 |
from collections import Counter
|
|
@@ -17,6 +22,16 @@ from sentence_transformers import SentenceTransformer
|
|
| 17 |
os.environ.setdefault("HF_HOME", "/tmp/hf")
|
| 18 |
REPO_ID = os.environ.get("BRAIN_REPO", "Fonedo/omnibrain-caleb-brain")
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
app = FastAPI(title="OmniBrain")
|
| 21 |
S = {"ready": False, "error": None}
|
| 22 |
|
|
@@ -29,39 +44,45 @@ def load():
|
|
| 29 |
for f in sorted(glob.glob(f"{d}/*.parquet")):
|
| 30 |
t = pq.read_table(f)
|
| 31 |
vecs.append(np.asarray(t["vector"].combine_chunks().flatten(),
|
| 32 |
-
dtype=np.
|
| 33 |
meta.extend(zip(t["project"].to_pylist(), t["source"].to_pylist(),
|
| 34 |
t["type"].to_pylist(), t["text"].to_pylist()))
|
| 35 |
-
|
|
|
|
| 36 |
S["M"] = meta
|
|
|
|
| 37 |
S["model"] = SentenceTransformer("nomic-ai/nomic-embed-text-v1.5",
|
| 38 |
trust_remote_code=True, device="cpu")
|
| 39 |
S["model"].max_seq_length = 512
|
| 40 |
S["ready"] = True
|
| 41 |
-
|
|
|
|
|
|
|
| 42 |
except Exception as e:
|
| 43 |
S["error"] = str(e)[:500]
|
| 44 |
print("STARTUP FAILED:", S["error"])
|
| 45 |
|
| 46 |
@app.get("/health")
|
| 47 |
def health():
|
| 48 |
-
return {"status": "online", "version": "3.
|
| 49 |
"vectors": len(S.get("M", [])), "error": S["error"]}
|
| 50 |
|
| 51 |
@app.get("/stats")
|
| 52 |
def stats():
|
| 53 |
c = Counter(m[0] for m in S.get("M", []))
|
| 54 |
t = Counter(m[2] for m in S.get("M", []))
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
"
|
| 58 |
-
"
|
|
|
|
| 59 |
|
| 60 |
class Q(BaseModel):
|
| 61 |
query: str
|
| 62 |
k: int = 8
|
| 63 |
project: str | None = None
|
| 64 |
agent: str | None = None # kimi | claude | codex — biases type
|
|
|
|
| 65 |
|
| 66 |
# each AI gets a different slice of the brain, per the OmniBrain design
|
| 67 |
AGENT_BIAS = {
|
|
@@ -70,10 +91,19 @@ AGENT_BIAS = {
|
|
| 70 |
"codex": {"code": 1.2, "doc": 1.05}, # code
|
| 71 |
}
|
| 72 |
|
| 73 |
-
def _search(q: str, k: int, project: str | None, agent: str | None
|
|
|
|
|
|
|
|
|
|
| 74 |
# asymmetric model: docs were embedded with "search_document: "
|
| 75 |
v = S["model"].encode(["search_query: " + q], normalize_embeddings=True)[0]
|
| 76 |
-
sims = S["V"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
if project:
|
| 78 |
mask = np.array([m[0] == project or m[0] == "meta" for m in S["M"]])
|
| 79 |
sims = np.where(mask, sims, -1e9)
|
|
@@ -81,7 +111,9 @@ def _search(q: str, k: int, project: str | None, agent: str | None):
|
|
| 81 |
b = AGENT_BIAS[agent]
|
| 82 |
boost = np.array([b.get(m[2], 1.0) for m in S["M"]], dtype=np.float32)
|
| 83 |
sims = np.where(sims > -1e8, sims * boost, sims)
|
| 84 |
-
|
|
|
|
|
|
|
| 85 |
idx = idx[np.argsort(-sims[idx])]
|
| 86 |
return [{"score": round(float(sims[i]), 4), "project": S["M"][i][0],
|
| 87 |
"source": S["M"][i][1], "type": S["M"][i][2],
|
|
@@ -90,12 +122,12 @@ def _search(q: str, k: int, project: str | None, agent: str | None):
|
|
| 90 |
@app.post("/search")
|
| 91 |
def search(q: Q):
|
| 92 |
if not S["ready"]: return {"error": S["error"] or "still loading"}
|
| 93 |
-
return {"results": _search(q.query, q.k, q.project, q.agent)}
|
| 94 |
|
| 95 |
@app.post("/generate_context")
|
| 96 |
def generate_context(q: Q):
|
| 97 |
if not S["ready"]: return {"error": S["error"] or "still loading"}
|
| 98 |
-
hits = _search(q.query, q.k, q.project, q.agent)
|
| 99 |
ctx = "\n\n---\n".join(
|
| 100 |
f"[{h['project']}/{h['type']}] {h['text']}" for h in hits)
|
| 101 |
return {"context": ctx, "n": len(hits)}
|
|
@@ -103,4 +135,5 @@ def generate_context(q: Q):
|
|
| 103 |
@app.get("/")
|
| 104 |
def root():
|
| 105 |
return {"message": "OmniBrain API",
|
| 106 |
-
"routes": ["/health", "/stats", "/search", "/generate_context"]
|
|
|
|
|
|
| 1 |
+
"""OmniBrain API v3.2 — real routes over the exported brain.
|
| 2 |
|
| 3 |
+
Boot: pull parquet shards from the BRAIN_REPO dataset repo, load an fp32 matrix
|
| 4 |
in RAM, serve brute-force cosine. Space disk is ephemeral, so the dataset repo
|
| 5 |
is the durable store; restarting the Space just re-pulls.
|
| 6 |
+
|
| 7 |
+
v3.2: (1) matrix kept fp32 at load — v3.1 re-cast the whole fp16 matrix to
|
| 8 |
+
fp32 on EVERY query (~186MB alloc per request). (2) `scope` splits the personal
|
| 9 |
+
layer from bulk public reference rows, which otherwise outnumber it ~7:1 and
|
| 10 |
+
crowd real answers out of the top-k.
|
| 11 |
"""
|
| 12 |
import os, glob
|
| 13 |
from collections import Counter
|
|
|
|
| 22 |
os.environ.setdefault("HF_HOME", "/tmp/hf")
|
| 23 |
REPO_ID = os.environ.get("BRAIN_REPO", "Fonedo/omnibrain-caleb-brain")
|
| 24 |
|
| 25 |
+
# Bulk public reference sets. Everything else (memories, vault, project docs,
|
| 26 |
+
# agents, skills) is Caleb's own knowledge and is what search should hit first.
|
| 27 |
+
PUBLIC_SOURCES = {
|
| 28 |
+
"teknium/OpenHermes-2.5", "openbmb/UltraFeedback",
|
| 29 |
+
"nvidia/OpenCodeReasoning", "nvidia/OpenCodeReasoning-2",
|
| 30 |
+
"ise-uiuc/Magicoder-OSS-Instruct-75K", "princeton-nlp/SWE-bench",
|
| 31 |
+
"zai-org/AgentInstruct", "markov-ai/gaming-500-hours",
|
| 32 |
+
"HuggingFaceFW/fineweb-edu",
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
app = FastAPI(title="OmniBrain")
|
| 36 |
S = {"ready": False, "error": None}
|
| 37 |
|
|
|
|
| 44 |
for f in sorted(glob.glob(f"{d}/*.parquet")):
|
| 45 |
t = pq.read_table(f)
|
| 46 |
vecs.append(np.asarray(t["vector"].combine_chunks().flatten(),
|
| 47 |
+
dtype=np.float32).reshape(-1, 768))
|
| 48 |
meta.extend(zip(t["project"].to_pylist(), t["source"].to_pylist(),
|
| 49 |
t["type"].to_pylist(), t["text"].to_pylist()))
|
| 50 |
+
# fp32 once, not per query
|
| 51 |
+
S["V"] = np.vstack(vecs) if vecs else np.zeros((0, 768), np.float32)
|
| 52 |
S["M"] = meta
|
| 53 |
+
S["IS_PUB"] = np.array([m[1] in PUBLIC_SOURCES for m in meta], dtype=bool)
|
| 54 |
S["model"] = SentenceTransformer("nomic-ai/nomic-embed-text-v1.5",
|
| 55 |
trust_remote_code=True, device="cpu")
|
| 56 |
S["model"].max_seq_length = 512
|
| 57 |
S["ready"] = True
|
| 58 |
+
n_pub = int(S["IS_PUB"].sum())
|
| 59 |
+
print(f"Loaded {len(meta):,} vectors "
|
| 60 |
+
f"({len(meta)-n_pub:,} personal / {n_pub:,} public) from {REPO_ID}")
|
| 61 |
except Exception as e:
|
| 62 |
S["error"] = str(e)[:500]
|
| 63 |
print("STARTUP FAILED:", S["error"])
|
| 64 |
|
| 65 |
@app.get("/health")
|
| 66 |
def health():
|
| 67 |
+
return {"status": "online", "version": "3.2", "ready": S["ready"],
|
| 68 |
"vectors": len(S.get("M", [])), "error": S["error"]}
|
| 69 |
|
| 70 |
@app.get("/stats")
|
| 71 |
def stats():
|
| 72 |
c = Counter(m[0] for m in S.get("M", []))
|
| 73 |
t = Counter(m[2] for m in S.get("M", []))
|
| 74 |
+
pub = int(S["IS_PUB"].sum()) if S.get("ready") else 0
|
| 75 |
+
return {"vectors": len(S.get("M", [])),
|
| 76 |
+
"personal": len(S.get("M", [])) - pub, "public": pub,
|
| 77 |
+
"by_project": dict(c), "by_type": dict(t), "dim": 768,
|
| 78 |
+
"model": "nomic-ai/nomic-embed-text-v1.5", "brain_repo": REPO_ID}
|
| 79 |
|
| 80 |
class Q(BaseModel):
|
| 81 |
query: str
|
| 82 |
k: int = 8
|
| 83 |
project: str | None = None
|
| 84 |
agent: str | None = None # kimi | claude | codex — biases type
|
| 85 |
+
scope: str = "personal" # personal | all | public
|
| 86 |
|
| 87 |
# each AI gets a different slice of the brain, per the OmniBrain design
|
| 88 |
AGENT_BIAS = {
|
|
|
|
| 91 |
"codex": {"code": 1.2, "doc": 1.05}, # code
|
| 92 |
}
|
| 93 |
|
| 94 |
+
def _search(q: str, k: int, project: str | None, agent: str | None,
|
| 95 |
+
scope: str = "personal"):
|
| 96 |
+
if not len(S["M"]):
|
| 97 |
+
return []
|
| 98 |
# asymmetric model: docs were embedded with "search_document: "
|
| 99 |
v = S["model"].encode(["search_query: " + q], normalize_embeddings=True)[0]
|
| 100 |
+
sims = S["V"] @ v.astype(np.float32)
|
| 101 |
+
|
| 102 |
+
if scope == "personal":
|
| 103 |
+
sims = np.where(S["IS_PUB"], -1e9, sims)
|
| 104 |
+
elif scope == "public":
|
| 105 |
+
sims = np.where(S["IS_PUB"], sims, -1e9)
|
| 106 |
+
|
| 107 |
if project:
|
| 108 |
mask = np.array([m[0] == project or m[0] == "meta" for m in S["M"]])
|
| 109 |
sims = np.where(mask, sims, -1e9)
|
|
|
|
| 111 |
b = AGENT_BIAS[agent]
|
| 112 |
boost = np.array([b.get(m[2], 1.0) for m in S["M"]], dtype=np.float32)
|
| 113 |
sims = np.where(sims > -1e8, sims * boost, sims)
|
| 114 |
+
|
| 115 |
+
k = max(1, min(k, len(sims)))
|
| 116 |
+
idx = np.argpartition(-sims, k - 1)[:k]
|
| 117 |
idx = idx[np.argsort(-sims[idx])]
|
| 118 |
return [{"score": round(float(sims[i]), 4), "project": S["M"][i][0],
|
| 119 |
"source": S["M"][i][1], "type": S["M"][i][2],
|
|
|
|
| 122 |
@app.post("/search")
|
| 123 |
def search(q: Q):
|
| 124 |
if not S["ready"]: return {"error": S["error"] or "still loading"}
|
| 125 |
+
return {"results": _search(q.query, q.k, q.project, q.agent, q.scope)}
|
| 126 |
|
| 127 |
@app.post("/generate_context")
|
| 128 |
def generate_context(q: Q):
|
| 129 |
if not S["ready"]: return {"error": S["error"] or "still loading"}
|
| 130 |
+
hits = _search(q.query, q.k, q.project, q.agent, q.scope)
|
| 131 |
ctx = "\n\n---\n".join(
|
| 132 |
f"[{h['project']}/{h['type']}] {h['text']}" for h in hits)
|
| 133 |
return {"context": ctx, "n": len(hits)}
|
|
|
|
| 135 |
@app.get("/")
|
| 136 |
def root():
|
| 137 |
return {"message": "OmniBrain API",
|
| 138 |
+
"routes": ["/health", "/stats", "/search", "/generate_context"],
|
| 139 |
+
"scopes": ["personal (default)", "all", "public"]}
|