Upload 2 files
Browse files- .gitattributes +1 -0
- app.py +27 -1
- mub_chroma_db.bundle +3 -0
.gitattributes
CHANGED
|
@@ -37,3 +37,4 @@ mub_chroma_db/chroma.sqlite3 filter=lfs diff=lfs merge=lfs -text
|
|
| 37 |
chroma_db/chroma.sqlite3 filter=lfs diff=lfs merge=lfs -text
|
| 38 |
mub_chroma_db_distilbert/chroma.sqlite3 filter=lfs diff=lfs merge=lfs -text
|
| 39 |
mub_chroma_db/** -filter -diff -merge -text
|
|
|
|
|
|
| 37 |
chroma_db/chroma.sqlite3 filter=lfs diff=lfs merge=lfs -text
|
| 38 |
mub_chroma_db_distilbert/chroma.sqlite3 filter=lfs diff=lfs merge=lfs -text
|
| 39 |
mub_chroma_db/** -filter -diff -merge -text
|
| 40 |
+
mub_chroma_db.bundle filter=lfs diff=lfs merge=lfs -text
|
app.py
CHANGED
|
@@ -2,7 +2,10 @@ import logging
|
|
| 2 |
import math
|
| 3 |
import os
|
| 4 |
import re
|
|
|
|
|
|
|
| 5 |
from collections import Counter, defaultdict
|
|
|
|
| 6 |
from typing import Dict, List
|
| 7 |
|
| 8 |
os.environ.setdefault("ANONYMIZED_TELEMETRY", "False")
|
|
@@ -29,6 +32,9 @@ VECTOR_CANDIDATES = 10
|
|
| 29 |
LEXICAL_CANDIDATES = 10
|
| 30 |
CONTEXT_RESULTS = 5
|
| 31 |
RRF_K = 60
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
|
| 34 |
def normalize(text: str) -> str:
|
|
@@ -61,6 +67,20 @@ def detect_language(text: str) -> str:
|
|
| 61 |
return "ar" if total_chars and arabic_chars / total_chars > 0.3 else "en"
|
| 62 |
|
| 63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
class BM25Index:
|
| 65 |
def __init__(self, documents: List[str], k1: float = 1.5, b: float = 0.75):
|
| 66 |
self.k1 = k1
|
|
@@ -145,12 +165,18 @@ class FieldedBM25:
|
|
| 145 |
class SimpleRAG:
|
| 146 |
"""Targeted Arabert retrieval fused with field-aware BM25."""
|
| 147 |
|
| 148 |
-
def __init__(self, db_path: str =
|
|
|
|
| 149 |
logger.info("Loading Arabert embedding model...")
|
| 150 |
self.model = SentenceTransformer(EMBEDDING_MODEL)
|
| 151 |
logger.info("Loading targeted ChromaDB from %s...", db_path)
|
| 152 |
self.client = chromadb.PersistentClient(path=db_path)
|
| 153 |
self.collection = self.client.get_collection(name="mub_info")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
corpus = self.collection.get(include=["documents", "metadatas"])
|
| 155 |
self.records = []
|
| 156 |
for chroma_id, document, metadata in zip(
|
|
|
|
| 2 |
import math
|
| 3 |
import os
|
| 4 |
import re
|
| 5 |
+
import shutil
|
| 6 |
+
import zipfile
|
| 7 |
from collections import Counter, defaultdict
|
| 8 |
+
from pathlib import Path
|
| 9 |
from typing import Dict, List
|
| 10 |
|
| 11 |
os.environ.setdefault("ANONYMIZED_TELEMETRY", "False")
|
|
|
|
| 32 |
LEXICAL_CANDIDATES = 10
|
| 33 |
CONTEXT_RESULTS = 5
|
| 34 |
RRF_K = 60
|
| 35 |
+
DATABASE_BUNDLE = Path(__file__).with_name("mub_chroma_db.bundle")
|
| 36 |
+
DATABASE_RUNTIME_PATH = Path("/tmp/mub_chroma_db")
|
| 37 |
+
EXPECTED_DATABASE_RECORDS = 223
|
| 38 |
|
| 39 |
|
| 40 |
def normalize(text: str) -> str:
|
|
|
|
| 67 |
return "ar" if total_chars and arabic_chars / total_chars > 0.3 else "en"
|
| 68 |
|
| 69 |
|
| 70 |
+
def materialize_database() -> str:
|
| 71 |
+
sqlite_path = DATABASE_RUNTIME_PATH / "mub_chroma_db" / "chroma.sqlite3"
|
| 72 |
+
if not sqlite_path.exists():
|
| 73 |
+
if not DATABASE_BUNDLE.exists():
|
| 74 |
+
raise RuntimeError(f"Missing database bundle: {DATABASE_BUNDLE}")
|
| 75 |
+
shutil.rmtree(DATABASE_RUNTIME_PATH, ignore_errors=True)
|
| 76 |
+
DATABASE_RUNTIME_PATH.mkdir(parents=True)
|
| 77 |
+
with zipfile.ZipFile(DATABASE_BUNDLE) as archive:
|
| 78 |
+
archive.extractall(DATABASE_RUNTIME_PATH)
|
| 79 |
+
if sqlite_path.read_bytes()[:16] != b"SQLite format 3\x00":
|
| 80 |
+
raise RuntimeError("Bundled Chroma database is not a valid SQLite file.")
|
| 81 |
+
return str(sqlite_path.parent)
|
| 82 |
+
|
| 83 |
+
|
| 84 |
class BM25Index:
|
| 85 |
def __init__(self, documents: List[str], k1: float = 1.5, b: float = 0.75):
|
| 86 |
self.k1 = k1
|
|
|
|
| 165 |
class SimpleRAG:
|
| 166 |
"""Targeted Arabert retrieval fused with field-aware BM25."""
|
| 167 |
|
| 168 |
+
def __init__(self, db_path: str = None):
|
| 169 |
+
db_path = db_path or materialize_database()
|
| 170 |
logger.info("Loading Arabert embedding model...")
|
| 171 |
self.model = SentenceTransformer(EMBEDDING_MODEL)
|
| 172 |
logger.info("Loading targeted ChromaDB from %s...", db_path)
|
| 173 |
self.client = chromadb.PersistentClient(path=db_path)
|
| 174 |
self.collection = self.client.get_collection(name="mub_info")
|
| 175 |
+
if self.collection.count() != EXPECTED_DATABASE_RECORDS:
|
| 176 |
+
raise RuntimeError(
|
| 177 |
+
"Unexpected database record count: "
|
| 178 |
+
f"{self.collection.count()} != {EXPECTED_DATABASE_RECORDS}"
|
| 179 |
+
)
|
| 180 |
corpus = self.collection.get(include=["documents", "metadatas"])
|
| 181 |
self.records = []
|
| 182 |
for chroma_id, document, metadata in zip(
|
mub_chroma_db.bundle
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:0fbb68e81b701dcfcd3fa2839cd4b0868412db90450db86891eb7c190cf07640
|
| 3 |
+
size 1422842
|