atakan Claude Opus 5 commited on
Commit
ec1d77f
·
1 Parent(s): 9e637cd

fix: Move the retrieval index out of git and onto the Hub

Browse files

The index grew 8x with the corpus bridge and no longer fits: chunks.json is
187MB, embeddings.npz 144MB, bm25.pkl 124MB. GitHub rejects any file past 100MB,
so `git push` would fail outright. chunks.json also holds the full extracted text
of 666 documents, commercial textbooks among them -- fine to keep on your own
machine, wrong to redistribute.

All three now live in the private Hub dataset repo atakankahya/controlai-rag-index.
controlai_rag/fetch_index.py (./run.sh --fetch-index) pulls them with an HF token.
It copies out of the Hub cache rather than symlinking into it, because the index
is mutated in place by uploads via HybridRetriever.add_chunks and by
scripts/repair_*.py. A clone without access has no index and builds its own from
data/user_docs/ with --build-index.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

.gitignore CHANGED
@@ -24,9 +24,12 @@ data/*
24
  # zero retrieved chunks (observed directly: /api/status reported
25
  # indexed_chunks: 0 with this excluded, since data/ is never pushed to the
26
  # Space's git repo).
27
- !data/rag_index/
28
- !data/rag_index/chunks.json
29
- !data/rag_index/bm25.pkl
 
 
 
30
 
31
  # Model checkpoints and fine-tuned weights
32
  adapters/
 
24
  # zero retrieved chunks (observed directly: /api/status reported
25
  # indexed_chunks: 0 with this excluded, since data/ is never pushed to the
26
  # Space's git repo).
27
+ # The retrieval index is NOT in git. The three artefacts total ~455MB (187MB
28
+ # chunks.json, 144MB embeddings.npz, 124MB bm25.pkl), well past GitHub's 100MB
29
+ # per-file limit, and chunks.json holds the full text of commercial textbooks,
30
+ # which is fine to keep locally and wrong to redistribute. It lives in a private
31
+ # Hub dataset repo instead -- `./run.sh --fetch-index`, or `--build-index` to
32
+ # make your own from data/user_docs/.
33
 
34
  # Model checkpoints and fine-tuned weights
35
  adapters/
controlai_rag/fetch_index.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Download the prebuilt retrieval index from the Hugging Face Hub.
2
+
3
+ The three index artefacts total ~455 MB -- far past GitHub's 100 MB per-file
4
+ limit -- so they live in a Hub dataset repo instead of in git. The repo is
5
+ private: the index carries the full extracted text of commercial textbooks,
6
+ which is fine to hold locally and wrong to redistribute. Set HF_TOKEN (or run
7
+ `huggingface-cli login`) with an account that can read it.
8
+
9
+ Without the index the retriever has nothing to search. Building one from your
10
+ own documents instead is `./run.sh --build-index`.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import argparse
16
+ import os
17
+ import sys
18
+ from pathlib import Path
19
+
20
+ from controlai_rag.index import INDEX_DIR
21
+
22
+ REPO_ID = os.environ.get("CONTROLAI_INDEX_REPO", "atakankahya/controlai-rag-index")
23
+
24
+ # chunks.json and bm25.pkl are the lexical side; embeddings.npz is the dense
25
+ # side. Missing the last one degrades retrieval to BM25 silently, so it counts
26
+ # as required here rather than optional.
27
+ FILES = ("chunks.json", "bm25.pkl", "embeddings.npz")
28
+
29
+
30
+ def fetch(index_dir: Path = INDEX_DIR, force: bool = False) -> Path:
31
+ """Place the index files in `index_dir`, downloading what is missing."""
32
+ from huggingface_hub import hf_hub_download
33
+
34
+ index_dir.mkdir(parents=True, exist_ok=True)
35
+ for name in FILES:
36
+ target = index_dir / name
37
+ if target.exists() and not force:
38
+ print(f" {name}: already present, skipping")
39
+ continue
40
+ print(f" {name}: downloading...", flush=True)
41
+ cached = hf_hub_download(
42
+ repo_id=REPO_ID,
43
+ filename=name,
44
+ repo_type="dataset",
45
+ token=os.environ.get("HF_TOKEN"),
46
+ )
47
+ # Copy rather than symlink into the cache: the index is mutated in place
48
+ # by uploads (HybridRetriever.add_chunks) and by scripts/repair_*.py.
49
+ target.write_bytes(Path(cached).read_bytes())
50
+ print(f" {name}: {target.stat().st_size / 1e6:.0f} MB")
51
+ return index_dir
52
+
53
+
54
+ def main() -> int:
55
+ parser = argparse.ArgumentParser(description=__doc__)
56
+ parser.add_argument(
57
+ "--force", action="store_true", help="re-download files that already exist"
58
+ )
59
+ args = parser.parse_args()
60
+
61
+ print(f"Fetching retrieval index from {REPO_ID}")
62
+ try:
63
+ fetch(force=args.force)
64
+ except Exception as exc: # noqa: BLE001 - the message matters more than the type
65
+ print(f"\nCould not fetch the index: {exc}", file=sys.stderr)
66
+ print(
67
+ "\nThe dataset repo is private. Authenticate with an account that can\n"
68
+ "read it (`huggingface-cli login`, or set HF_TOKEN), or build your own\n"
69
+ "index from data/user_docs/ with `./run.sh --build-index`.",
70
+ file=sys.stderr,
71
+ )
72
+ return 1
73
+ print("Index ready in", INDEX_DIR)
74
+ return 0
75
+
76
+
77
+ if __name__ == "__main__":
78
+ raise SystemExit(main())
data/rag_index/bm25.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:aec368fab52a30b88e2bc1633add98c1f6a0a8f5260ad50d73d965381c741210
3
- size 9492413
 
 
 
 
data/rag_index/chunks.json DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:939cfc3169818185b3dd60ba12b2e4799fd10755fd0fcbbff8f390567761c091
3
- size 12948944
 
 
 
 
run.sh CHANGED
@@ -1,26 +1,48 @@
1
  #!/usr/bin/env bash
2
- # ControlAI Universal Launcher
3
- set -e
4
 
5
- DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
6
  cd "$DIR"
 
7
 
8
- # Activate virtual environment if present
9
- if [ -d ".venv" ]; then
10
- source .venv/bin/activate
11
- fi
12
-
13
- # Check flags
14
- if [ "$1" == "--cli" ] || [ "$1" == "-c" ]; then
15
  shift
16
  exec python cli.py "$@"
17
- elif [ "$1" == "--help" ] || [ "$1" == "-h" ]; then
18
- echo "ControlAI Launcher Usage:"
19
- echo " ./run.sh # Launch Web UI & automatically open browser (http://127.0.0.1:8000)"
20
- echo " ./run.sh --cli # Launch interactive terminal assistant"
21
- echo " ./run.sh --cli \"<query>\" # Run single one-shot query in terminal"
22
- exit 0
23
- else
24
- # Default: Launch Web UI & automatically open browser at http://127.0.0.1:8000
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  exec python app.py
26
- fi
 
 
1
  #!/usr/bin/env bash
2
+ # ControlAI launcher.
3
+ set -euo pipefail
4
 
5
+ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
6
  cd "$DIR"
7
+ [ -d ".venv" ] && source .venv/bin/activate
8
 
9
+ case "${1:-}" in
10
+ --cli|-c)
 
 
 
 
 
11
  shift
12
  exec python cli.py "$@"
13
+ ;;
14
+ --build-index)
15
+ exec python -m controlai_rag.retriever --build
16
+ ;;
17
+ --fetch-index)
18
+ exec python -m controlai_rag.fetch_index "${@:2}"
19
+ ;;
20
+ --ingest-corpus)
21
+ exec python scripts/ingest_processed_corpus.py "${@:2}"
22
+ ;;
23
+ --calibrate)
24
+ exec python scripts/calibrate_retrieval.py "${@:2}"
25
+ ;;
26
+ --help|-h)
27
+ cat <<'USAGE'
28
+ ControlAI
29
+
30
+ ./run.sh web console at http://127.0.0.1:8000
31
+ ./run.sh --cli interactive terminal chat
32
+ ./run.sh --cli "question" one-shot question
33
+ ./run.sh --fetch-index download the prebuilt index from the HF Hub
34
+ ./run.sh --build-index rebuild the dense retrieval index
35
+ ./run.sh --ingest-corpus merge data/processed/ chunks into the index
36
+ ./run.sh --calibrate re-measure MIN_COSINE against the current corpus
37
+
38
+ Environment:
39
+ CONTROLAI_MODEL MLX model id (default mlx-community/Qwen3-14B-4bit)
40
+ CONTROLAI_ADAPTER LoRA adapter path (default none)
41
+ CONTROLAI_THINKING off | auto | on (default auto)
42
+ CONTROLAI_THINK_BUDGET max reasoning tokens (default 512)
43
+ USAGE
44
+ ;;
45
+ *)
46
  exec python app.py
47
+ ;;
48
+ esac