Spaces:
Sleeping
Sleeping
| """ | |
| ingest.py β Build FAISS vector index from BGP documentation. | |
| Run this ONCE locally before deploying to HuggingFace Spaces: | |
| python ingest.py | |
| Output: faiss_index/index.faiss + faiss_index/index.pkl | |
| Commit both files to your repo β the Space loads them at startup. | |
| WHY PRE-BUILD? | |
| - Building the index requires downloading ~90MB sentence-transformers model | |
| and embedding every chunk. On HF free CPU tier this takes 3-5 minutes | |
| and risks OOM errors. Pre-building means the Space starts in ~3 seconds. | |
| - Pattern: compute expensive artifacts locally, ship the result. | |
| """ | |
| import os | |
| from pathlib import Path | |
| from langchain_community.document_loaders import TextLoader, DirectoryLoader | |
| from langchain_text_splitters import RecursiveCharacterTextSplitter | |
| from langchain_huggingface import HuggingFaceEmbeddings | |
| from langchain_community.vectorstores import FAISS | |
| # ββ Configuration ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| DATA_DIRS = ["data/docs", "data/telemetry"] | |
| INDEX_DIR = "faiss_index" | |
| EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2" | |
| CHUNK_SIZE = 500 | |
| CHUNK_OVERLAP = 50 | |
| # ββ Load documents ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def load_documents(data_dirs: list[str]) -> list: | |
| """Load all .txt files from the given directories.""" | |
| all_docs = [] | |
| for data_dir in data_dirs: | |
| if not os.path.exists(data_dir): | |
| print(f" β οΈ Directory not found, skipping: {data_dir}") | |
| continue | |
| loader = DirectoryLoader( | |
| data_dir, | |
| glob="**/*.txt", | |
| loader_cls=TextLoader, | |
| loader_kwargs={"encoding": "utf-8"}, | |
| show_progress=False, | |
| ) | |
| docs = loader.load() | |
| print(f" π {data_dir}: {len(docs)} file(s) loaded") | |
| all_docs.extend(docs) | |
| return all_docs | |
| # ββ Main ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def main(): | |
| print("=" * 60) | |
| print("BGP RAG β FAISS Index Builder") | |
| print("=" * 60) | |
| # 1. Load raw documents | |
| print("\n[1/4] Loading documents...") | |
| docs = load_documents(DATA_DIRS) | |
| if not docs: | |
| raise RuntimeError("No documents found. Check data/ directory.") | |
| print(f" β Total documents loaded: {len(docs)}") | |
| # 2. Split into chunks | |
| print(f"\n[2/4] Splitting into chunks (size={CHUNK_SIZE}, overlap={CHUNK_OVERLAP})...") | |
| splitter = RecursiveCharacterTextSplitter( | |
| chunk_size=CHUNK_SIZE, | |
| chunk_overlap=CHUNK_OVERLAP, | |
| length_function=len, | |
| separators=["\n\n", "\n", " ", ""], | |
| ) | |
| chunks = splitter.split_documents(docs) | |
| print(f" β Chunks created: {len(chunks)}") | |
| print(f" π Avg chunk size: {sum(len(c.page_content) for c in chunks) // len(chunks)} chars") | |
| # 3. Create embeddings | |
| print(f"\n[3/4] Loading embedding model: {EMBEDDING_MODEL}") | |
| print(" (First run downloads ~90MB model β subsequent runs use cache)") | |
| embeddings = HuggingFaceEmbeddings( | |
| model_name=EMBEDDING_MODEL, | |
| model_kwargs={"device": "cpu"}, | |
| encode_kwargs={"normalize_embeddings": True}, | |
| ) | |
| print(" β Embedding model loaded") | |
| # 4. Build and save FAISS index | |
| print(f"\n[4/4] Building FAISS index and saving to {INDEX_DIR}/...") | |
| os.makedirs(INDEX_DIR, exist_ok=True) | |
| vectorstore = FAISS.from_documents(chunks, embeddings) | |
| vectorstore.save_local(INDEX_DIR) | |
| # Verify files were written | |
| index_file = Path(INDEX_DIR) / "index.faiss" | |
| pkl_file = Path(INDEX_DIR) / "index.pkl" | |
| if index_file.exists() and pkl_file.exists(): | |
| size_mb = (index_file.stat().st_size + pkl_file.stat().st_size) / (1024 * 1024) | |
| print(f" β Saved: {INDEX_DIR}/index.faiss") | |
| print(f" β Saved: {INDEX_DIR}/index.pkl") | |
| print(f" π¦ Total index size: {size_mb:.2f} MB") | |
| else: | |
| raise RuntimeError("Index files not found after save β check permissions.") | |
| print("\n" + "=" * 60) | |
| print("β FAISS index built successfully!") | |
| print(f" Documents: {len(docs)}") | |
| print(f" Chunks: {len(chunks)}") | |
| print(f" Location: {INDEX_DIR}/") | |
| print("\nNext steps:") | |
| print(" 1. git add faiss_index/") | |
| print(" 2. git commit -m 'Add pre-built FAISS index'") | |
| print(" 3. Push to HuggingFace Space") | |
| print("=" * 60) | |
| if __name__ == "__main__": | |
| main() | |