add vector_store.py
This commit is contained in:
+43
-33
@@ -1,54 +1,64 @@
|
|||||||
"""
|
"""
|
||||||
Vector store abstraction using ChromaDB.
|
Vector store implementation using ChromaDB.
|
||||||
|
|
||||||
Provides methods to add documents with embeddings and perform similarity search.
|
Provides methods to add documents and perform similarity search.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Dict, Any
|
from typing import List, Dict
|
||||||
|
|
||||||
from chromadb import Client as ChromaClient
|
from chromadb import Client as ChromadbClient
|
||||||
from chromadb.config import Settings
|
from chromadb.config import Settings
|
||||||
|
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
||||||
from langchain_ollama import OllamaEmbeddings
|
from langchain_ollama import OllamaEmbeddings
|
||||||
|
|
||||||
# Initialize global client (in-memory for simplicity)
|
# Ensure persistent directory exists
|
||||||
client = ChromaClient(Settings(chroma_db_impl="duckdb+parquet", persist_directory=None))
|
CHROMA_DIR = Path("./chroma_db")
|
||||||
collection_name = "rag_collection"
|
CHROMA_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
# Ensure collection exists
|
# Embedding model via Ollama
|
||||||
|
embeddings = OllamaEmbeddings(model="nomic-embed-text")
|
||||||
|
|
||||||
|
# Chroma client with persistence
|
||||||
|
client = ChromadbClient(Settings(persist_directory=str(CHROMA_DIR)))
|
||||||
|
collection_name = "knowledge"
|
||||||
if collection_name not in client.list_collections():
|
if collection_name not in client.list_collections():
|
||||||
client.create_collection(name=collection_name)
|
client.create_collection(name=collection_name)
|
||||||
col = client.get_or_create_collection(name=collection_name)
|
col = client.get_or_create_collection(name=collection_name)
|
||||||
|
|
||||||
embeddings = OllamaEmbeddings(model="nomic-embed-text")
|
# Chunker from chunker.py
|
||||||
|
from chunker import chunker
|
||||||
|
|
||||||
class ChromaVectorStore:
|
class VectorStore:
|
||||||
"""Wrapper around a Chroma collection."""
|
def add_documents(self, docs: List[str], metadatas: List[Dict]):
|
||||||
|
"""Add documents to the collection.
|
||||||
|
|
||||||
def __init__(self, collection):
|
Parameters
|
||||||
self.collection = collection
|
----------
|
||||||
|
docs: list of raw text strings.
|
||||||
|
metadatas: list of metadata dicts corresponding to each doc.
|
||||||
|
"""
|
||||||
|
# Split into chunks and embed
|
||||||
|
all_chunks = []
|
||||||
|
all_metadatas = []
|
||||||
|
for doc, meta in zip(docs, metadatas):
|
||||||
|
chunks = chunker.split_text(doc)
|
||||||
|
all_chunks.extend(chunks)
|
||||||
|
all_metadatas.extend([meta] * len(chunks))
|
||||||
|
|
||||||
def add_documents(self, documents: List[Dict[str, Any]]):
|
# Generate embeddings via Ollama
|
||||||
ids = []
|
embeds = embeddings.embed_documents(all_chunks)
|
||||||
texts = []
|
ids = [f"chunk_{i}" for i in range(len(all_chunks))]
|
||||||
metadatas = []
|
col.add(ids=ids, documents=all_chunks, metadatas=all_metadatas, embeddings=embeds)
|
||||||
for doc in documents:
|
|
||||||
ids.append(doc.get("id", os.urandom(8).hex()))
|
|
||||||
texts.append(doc["content"])
|
|
||||||
metadatas.append(doc.get("metadata", {}))
|
|
||||||
embeddings_list = embeddings.embed_documents(texts)
|
|
||||||
self.collection.add(ids=ids, documents=texts, embeddings=embeddings_list, metadatas=metadatas)
|
|
||||||
|
|
||||||
def similarity_search(self, query: str, k: int = 5) -> List[Dict[str, Any]]:
|
def similarity_search(self, query: str, k: int = 5) -> List[Dict]:
|
||||||
results = self.collection.query(
|
"""Return top-k similar chunks with metadata."""
|
||||||
|
results = col.query(
|
||||||
query_texts=[query],
|
query_texts=[query],
|
||||||
n_results=k,
|
n_results=k,
|
||||||
include=['documents', 'distances', 'metadatas'],
|
include=['documents', 'metadatas'],
|
||||||
)
|
)
|
||||||
docs = []
|
# results is dict with keys documents, metadatas
|
||||||
for doc, dist, meta in zip(results["documents"][0], results["distances"][0], results["metadatas"][0]):
|
docs = results["documents"][0]
|
||||||
docs.append({"content": doc, "distance": dist, "metadata": meta})
|
metas = results["metadatas"][0]
|
||||||
return docs
|
return [{"content": d, "metadata": m} for d, m in zip(docs, metas)]
|
||||||
|
|
||||||
# Singleton instance
|
|
||||||
vector_store = ChromaVectorStore(col)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user