Aurora / vectorstore.py
Kannan Priyadharshan
Upload folder using huggingface_hub
f231844 verified
Raw History Blame Contribute Delete
7.1 kB
"""
Qdrant vector store abstraction for Aurora backend.
Provides a simple interface for Qdrant operations with proper embedding initialization.
"""
import os
from typing import List, Optional, Dict, Any
from qdrant_client import QdrantClient
from qdrant_client.http import models
# Try preferred import first, fallback to community
try:
from langchain_qdrant import Qdrant
QDRANT_AVAILABLE = True
except ImportError:
try:
from langchain_community.vectorstores import Qdrant
QDRANT_AVAILABLE = True
except ImportError:
QDRANT_AVAILABLE = False
Qdrant = None
def init_vector_store(embeddings) -> Optional[Qdrant]:
"""
Initialize Qdrant vector store with the given embedding function.
Args:
embeddings: The embedding function (e.g., HuggingFaceEmbeddings)
Returns:
Qdrant vector store instance or None if initialization fails
"""
if not QDRANT_AVAILABLE:
print("❌ Qdrant dependencies not available")
return None
try:
# Get configuration from environment
qdrant_url = os.getenv("QDRANT_URL")
qdrant_api_key = os.getenv("QDRANT_API_KEY")
collection_name = os.getenv("QDRANT_COLLECTION", "aurora")
if not qdrant_url:
print("❌ QDRANT_URL not configured")
return None
# Initialize Qdrant client
client_kwargs = {
"url": qdrant_url,
"prefer_grpc": False
}
if qdrant_api_key:
client_kwargs["api_key"] = qdrant_api_key
client = QdrantClient(**client_kwargs)
# Ensure collection exists with dimension inference
try:
# Try to get collection info to check if it exists
client.get_collection(collection_name)
print(f"βœ… Using existing Qdrant collection: {collection_name}")
except Exception:
# Collection doesn't exist, create it
print(f"πŸ”„ Creating Qdrant collection: {collection_name}")
# Get embedding dimension
try:
test_embedding = embeddings.embed_query("dimension probe")
embedding_dim = len(test_embedding)
print(f"πŸ“ Embedding dimension: {embedding_dim}")
except Exception as e:
print(f"⚠️ Could not get embedding dimension: {e}")
# Fallback to common dimension for sentence-transformers
embedding_dim = 384 # Default for all-MiniLM-L6-v2
print(f"πŸ“ Using fallback embedding dimension: {embedding_dim}")
# Create collection with cosine distance
client.create_collection(
collection_name=collection_name,
vectors_config=models.VectorParams(
size=embedding_dim,
distance=models.Distance.COSINE
)
)
print(f"βœ… Created Qdrant collection: {collection_name}")
# Initialize vector store with embeddings
vector_store = None
# Try different initialization methods
init_methods = [
("embeddings", lambda: Qdrant(client=client, collection_name=collection_name, embeddings=embeddings)),
("embedding", lambda: Qdrant(client=client, collection_name=collection_name, embedding=embeddings)),
]
for method_name, init_func in init_methods:
try:
vector_store = init_func()
print(f"βœ… Initialized with '{method_name}' parameter")
break
except Exception as e:
print(f"⚠️ {method_name} method failed: {e}")
continue
if vector_store is None:
print("❌ All initialization methods failed")
return None
print(f"Vector store: qdrant β€’ collection={collection_name}")
return vector_store
except Exception as e:
print(f"❌ Qdrant initialization failed: {e}")
return None
def vector_count(store: Qdrant) -> int:
"""
Get the number of vectors in the store.
Args:
store: Qdrant vector store instance
Returns:
Number of vectors in the collection
"""
try:
if store is None:
return 0
# Use client.count for robust counting
try:
result = store.client.count(store.collection_name, exact=True)
count = result.count
return count
except Exception:
# Fallback to collection info
collection_info = store.client.get_collection(store.collection_name)
if hasattr(collection_info, 'vectors_count'):
return collection_info.vectors_count
elif hasattr(collection_info, 'points_count'):
return collection_info.points_count
elif hasattr(collection_info, 'status') and hasattr(collection_info.status, 'vectors_count'):
return collection_info.status.vectors_count
else:
return 0
except Exception as e:
print(f"❌ Could not get vector count: {e}")
return 0
def add_texts(store: Qdrant, texts: List[str], metadatas: Optional[List[Dict[str, Any]]] = None) -> None:
"""
Add texts to the vector store.
Args:
store: Qdrant vector store instance
texts: List of text documents to add
metadatas: Optional list of metadata dictionaries
"""
try:
if store is None:
print("⚠️ Vector store not available - skipping add_texts")
return
if not texts:
print("⚠️ No texts to add")
return
# Ensure metadatas is properly formatted
if metadatas is None:
metadatas = [{}] * len(texts)
# Add documents in batches
batch_size = 100 # Reasonable batch size for Qdrant
total_added = 0
for i in range(0, len(texts), batch_size):
batch_texts = texts[i:i + batch_size]
batch_metadatas = metadatas[i:i + batch_size]
store.add_texts(
texts=batch_texts,
metadatas=batch_metadatas
)
total_added += len(batch_texts)
print(f"πŸ“ Added batch {i//batch_size + 1}: {len(batch_texts)} documents")
print(f"βœ… Added {total_added} documents to vector store")
except Exception as e:
print(f"❌ Failed to add texts to vector store: {e}")
def is_qdrant_available() -> bool:
"""
Check if Qdrant is available and properly configured.
Returns:
True if Qdrant is available and configured, False otherwise
"""
if not QDRANT_AVAILABLE:
return False
qdrant_url = os.getenv("QDRANT_URL")
return qdrant_url is not None