CoolFace
Apppublic

AabhavAmitabh/document-intelligence-chatbot

sourceHugging Facemitupdated 5mo agoView on Hugging Face
0likes
embedder.py133 linesDownload Raw Back to root
1# embedder.py
2# This file has ONE job: take text chunks and store them in ChromaDB
3# as embeddings so we can search them by meaning later.
4
5from sentence_transformers import SentenceTransformer
6import chromadb
7from ingestor import ingest_pdf
8
9
10# We use a small but powerful open-source embedding model.
11# It runs entirely on your machine — no API key needed for this step.
12# "all-MiniLM-L6-v2" is fast, accurate, and used in real production systems.
13EMBEDDING_MODEL = "all-MiniLM-L6-v2"
14
15# This is the folder where ChromaDB will save your vector database.
16# It will be created automatically the first time you run this.
17CHROMA_PATH = "chroma_db"
18
19# We give our collection of document chunks a name inside ChromaDB.
20COLLECTION_NAME = "documents"
21
22
23def get_embedding_model():
24    """
25    Loads the embedding model.
26    The first time this runs it downloads ~90MB from the internet.
27    After that it's cached locally and loads in seconds.
28    """
29    print("Loading embedding model...")
30    model = SentenceTransformer(EMBEDDING_MODEL)
31    print("Model ready.")
32    return model
33
34
35def embed_and_store(chunks: list, doc_name: str = "document") -> chromadb.Collection:
36    """
37    Takes a list of text chunks, converts each one to an embedding,
38    and stores everything in ChromaDB.
39
40    doc_name: a label so you know which document these chunks came from.
41               Useful later when you support multiple documents.
42    """
43    model = get_embedding_model()
44
45    # Create (or connect to) the ChromaDB database on disk
46    client = chromadb.PersistentClient(path=CHROMA_PATH)
47
48    # Delete the collection if it already exists so we start fresh.
49    # This prevents duplicate chunks if you run the script twice.
50    existing = [c.name for c in client.list_collections()]
51    if COLLECTION_NAME in existing:
52        client.delete_collection(COLLECTION_NAME)
53        print("Cleared existing collection.")
54
55    collection = client.create_collection(COLLECTION_NAME)
56
57    print(f"Embedding {len(chunks)} chunks — this may take 30-60 seconds...")
58    if not chunks:
59        raise ValueError(
60            "No text could be extracted from this PDF. "
61            "It may be a scanned image. Try a text-based PDF instead."
62        )
63
64    # Convert all chunks to embeddings in one batch (faster than one at a time)
65    embeddings = model.encode(chunks, show_progress_bar=True)
66
67    # Store each chunk in ChromaDB with:
68    # - a unique ID
69    # - the embedding (the numbers)
70    # - the original text (so we can retrieve it later)
71    # - metadata (which document it came from)
72    collection.add(
73        ids=[f"{doc_name}_chunk_{i}" for i in range(len(chunks))],
74        embeddings=embeddings.tolist(),
75        documents=chunks,
76        metadatas=[{"source": doc_name, "chunk_index": i} for i in range(len(chunks))]
77    )
78
79    print(f"Stored {collection.count()} chunks in ChromaDB.")
80    return collection
81
82
83def load_collection() -> chromadb.Collection:
84    """
85    Connects to an existing ChromaDB database and returns the collection.
86    This is what the rest of the app calls when answering questions —
87    it doesn't re-embed, it just opens what's already saved on disk.
88    """
89    client = chromadb.PersistentClient(path=CHROMA_PATH)
90    collection = client.get_collection(COLLECTION_NAME)
91    return collection
92
93
94# Test it directly when you run this file
95if __name__ == "__main__":
96    import sys
97
98    if len(sys.argv) < 2:
99        print("Usage: python embedder.py path/to/your/file.pdf")
100        sys.exit(1)
101
102    pdf_path = sys.argv[1]
103
104    # Get a clean name for the document (just the filename, no path)
105    import os
106    doc_name = os.path.splitext(os.path.basename(pdf_path))[0]
107
108    # Step 1: ingest the PDF into chunks
109    chunks = ingest_pdf(pdf_path)
110
111    # Step 2: embed and store
112    collection = embed_and_store(chunks, doc_name=doc_name)
113
114    # Step 3: do a quick test search to prove it's working
115    print("\n--- TEST SEARCH ---")
116    test_query = "Who is this document about?"
117    print(f"Query: '{test_query}'")
118
119    model = SentenceTransformer(EMBEDDING_MODEL)
120    query_embedding = model.encode([test_query]).tolist()
121
122    results = collection.query(
123        query_embeddings=query_embedding,
124        n_results=2
125    )
126
127    print("\nTop 2 most relevant chunks found:")
128    for i, doc in enumerate(results["documents"][0]):
129        print(f"\nResult {i+1}:\n{doc[:300]}...")
130        print("-" * 40)
131
132    print("\nPhase 3 complete. ChromaDB is populated and searchable.")
133