A Python library for embedding, indexing, and applying semantic search for text and image data.
-
Multi-modal Semantic Search
- Embed and index images using SigLIP SO400M (1152-dim, 384×384)
- Embed and index text using BGE-M3 (1024-dim dense + sparse vectors)
- Search images by image or text queries
- Search text by semantic similarity with hybrid dense+sparse fusion
- Cross-modal unified search across images and text in a shared embedding space
-
Clustering & Captioning
- Cluster image embeddings using KMeans (specify k) or HDBSCAN (auto-detect)
- Caption images using Florence-2 (detailed captions, object detection, OCR)
- Customizable LLM-powered topic labeling via callback
-
Retrieval-Augmented Generation (RAG)
- Answer questions based on text data using LiteLLM + Ollama
- Semantic chunking with BGE-M3 embeddings
- Cross-encoder reranking with BGE-reranker-v2-m3
- Pluggable LLM via callback pattern
-
Duplicate Detection
- Find near-duplicate images or text above a similarity threshold
pip install deep-semantic-searchInstall with optional extras:
pip install deep-semantic-search[llm] # RAG / question answering (LiteLLM)
pip install deep-semantic-search[clustering] # Image clustering (scikit-learn)
pip install deep-semantic-search[viz] # Plotting / visualization
pip install deep-semantic-search[all] # EverythingFor development:
pip install deep-semantic-search[dev]from deep_semantic_search import LoadImageData, ImageIndexer, ImageSearcher
# Load and index images
loader = LoadImageData()
image_paths = loader.from_folder(["path/to/images"])
indexer = ImageIndexer(image_paths)
indexer.run_index()
# Search by text
searcher = ImageSearcher(indexer)
results = searcher.search_by_text("cat on a sofa", n=5)
for r in results:
print(f"{r['score']:.3f} {r['path']}")
# Search by image
results = searcher.search_by_image("query.jpg", n=5)
# Find duplicate images
duplicates = searcher.find_duplicates(threshold=0.95)from deep_semantic_search import LoadTextData, TextEmbedder, TextSearch
# Load and embed text data
loader = LoadTextData()
corpus = loader.from_folder("path/to/text/files")
embedder = TextEmbedder()
embedder.embed(corpus)
# Search with hybrid dense+sparse fusion
search = TextSearch(embedder)
results = search.find_similar("your search query", top_n=5, hybrid=True)
# With cross-encoder reranking
results = search.find_similar("query", top_n=5, rerank=True)from deep_semantic_search import UnifiedIndexer, UnifiedSearcher
# Index images and texts in a shared embedding space
indexer = UnifiedIndexer()
indexer.add_images(image_paths)
indexer.add_texts(["description 1", "description 2"], labels=["doc1", "doc2"])
indexer.build_index()
# Search across modalities
searcher = UnifiedSearcher(indexer)
results = searcher.search("sunset over mountains", n=10)
# Filter by modality
results = searcher.search("sunset", modality_filter="image")from deep_semantic_search import ImageIndexer, ImageClusterer, ImageCaptioner
indexer = ImageIndexer(image_paths)
indexer.run_index()
# Auto-detect clusters with HDBSCAN
clusterer = ImageClusterer(indexer)
result = clusterer.cluster() # n_clusters=None → HDBSCAN
# Or specify exact number with KMeans
result = clusterer.cluster(n_clusters=5)
# With Florence-2 captioning for topic labels
captioner = ImageCaptioner()
result = clusterer.cluster(n_clusters=5, captioner=captioner)
# Save organized clusters to disk
clusterer.save_clusters("./output/clusters")Requires pip install deep-semantic-search[llm] for LiteLLM.
from deep_semantic_search import RAG
texts = ["Document 1 content...", "Document 2 content..."]
# With semantic chunking and reranking
rag = RAG(rerank=True)
answer = rag.ask(texts, "What is the main topic?", semantic_chunking=True)
# With a custom LLM
answer = rag.ask(texts, "Summarize this.", llm_fn=my_custom_llm)
# Backward-compatible wrapper
from deep_semantic_search import ask_question
answer = ask_question(texts, "What is the main topic?", llm_fn=my_fn)By default, metadata is stored in ~/.deep-semantic-search/. Override per instance:
indexer = ImageIndexer(image_paths, metadata_dir="./my_project/index")
embedder = TextEmbedder(metadata_dir="./my_project/text_index")LoadImageData— Load image paths from folders or CSVImageIndexer— SigLIP embedding + USearch indexingImageSearcher— Image/text similarity search + duplicate detectionImageClusterer— KMeans/HDBSCAN clustering with topic labelingImageCaptioner— Florence-2 image captioning
LoadTextData— Load text from folders (.txt/.html) or CSVTextEmbedder— BGE-M3 dense + sparse embeddingsTextSearch— Hybrid search with optional reranking + duplicate detection
UnifiedIndexer— Cross-modal SigLIP indexing for images + textUnifiedSearcher— Search across modalities
RAG— Object-oriented RAG with semantic chunking and rerankingask_question()— Backward-compatible wrapper
DeepSemanticSearchError— Base exceptionIndexNotFoundError,ModelLoadError,SearchError,EmbeddingError,ClusteringError,MigrationError,CaptioningError
The package includes dss, a command-line interface for all major features.
dss --help # Show all commands
dss --version # Show version
dss <command> --help # Help for a specific commandGlobal flags: -v/--verbose for debug output, -q/--quiet to suppress progress.
# Search by text
dss image-search --folder ./photos --query "sunset over the ocean" --top 5
# Search by image
dss image-search --folder ./photos --query ./photos/reference.jpg --top 10
# Multiple folders, JSON output
dss image-search -f ./photos -f ./vacation --query "mountains" --format json# Basic search (hybrid enabled by default)
dss text-search --folder ./documents "machine learning algorithms" --top 5
# With reranking
dss text-search -f ./docs "neural networks" --rerank
# Dense-only (no sparse fusion)
dss text-search -f ./docs "query" --no-hybrid# KMeans with explicit k
dss image-cluster --folder ./photos --clusters 5
# HDBSCAN auto-detection (omit -k)
dss image-cluster -f ./photos --min-cluster-size 3
# With Florence-2 captioning for topic labels
dss image-cluster -f ./photos -k 5 --caption
# Save clustered images
dss image-cluster -f ./photos -k 8 --save-dir ./output/clusters# Search across images and text
dss unified-search --image-folder ./photos --text-folder ./docs --query "sunset"
# Filter by modality
dss unified-search --image-folder ./photos --query "sunset" --filter imagedss find-duplicates --folder ./photos --threshold 0.95dss ask --folder ./documents "What is the main conclusion?"
# With reranking and semantic chunking (default)
dss ask -f ./docs "Summarize the findings" --rerank
# Fixed chunking
dss ask -f ./docs "question" --no-semantic-chunkingThe CLI respects environment variables:
OLLAMA_LLM_MODEL— LLM model for RAG (default:gemma4:e4b)
- Python >= 3.10
- PyTorch, Sentence Transformers, Transformers, USearch, FlagEmbedding, and more (auto-installed)
MIT