Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions docs/EMBEDDINGS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# EmbeddingBlock Documentation

## Overview

The `EmbeddingBlock` class provides a flexible interface for generating text embeddings using LiteLLM. It supports multiple embedding providers through a single, consistent API.

## Quick Start

```python
from quantmind.config import EmbeddingConfig
from quantmind.llm import create_embedding_block

# Simple configuration
config = EmbeddingConfig(
model="text-embedding-ada-002"
)

embedding_block = create_embedding_block(config)
embedding = embedding_block.generate_embedding("Sample text")
```

## Configuration

### Required Parameters
- `model`: Embedding model name (e.g., "text-embedding-ada-002")

### Optional Parameters
- `user`: Unique identifier for end-user
- `dimensions`: Number of dimensions (OpenAI text-embedding-3+)
- `encoding_format`: "float" or "base64" (default: "float")
- `timeout`: Request timeout in seconds (default: 600)
- `api_base`: Custom API endpoint
- `api_version`: Azure-specific API version
- `api_key`: API key for authentication
- `api_type`: Type of API to use

## Examples

### Basic Usage
```python
config = EmbeddingConfig(model="text-embedding-ada-002")
embedding_block = create_embedding_block(config)
embedding = embedding_block.generate_embedding("Text to embed")
```

### With Custom Dimensions
```python
config = EmbeddingConfig(
model="text-embedding-3-small",
dimensions=512
)
```

### Azure OpenAI
```python
config = EmbeddingConfig(
model="text-embedding-ada-002",
api_key="azure-key",
api_base="https://your-resource.openai.azure.com/",
api_version="2023-05-15",
api_type="azure"
)
```

## Methods

- `generate_embedding(text)`: Generate single embedding
- `generate_embeddings(texts)`: Generate multiple embeddings
- `batch_embed(texts, batch_size)`: Process large datasets
- `test_connection()`: Test API connection
- `get_info()`: Get configuration information
- `get_embedding_dimension()`: Get embedding dimension

## See Also

- `examples/llm/embedding_block_example.py` for complete examples
205 changes: 205 additions & 0 deletions examples/llm/embedding_block_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
"""Example usage of EmbeddingBlock for different embedding providers."""

import os
from typing import List

from quantmind.config import EmbeddingConfig
from quantmind.llm import EmbeddingBlock, create_embedding_block
from quantmind.utils.logger import get_logger

logger = get_logger(__name__)


def example_openai_embeddings():
"""Example using OpenAI embeddings."""
print("\n=== OpenAI Embeddings Example ===")

# Configuration for OpenAI embeddings
config = EmbeddingConfig(
model="text-embedding-ada-002",
api_key=os.getenv("OPENAI_API_KEY"),
timeout=30,
encoding_format="float",
)

# Create embedding block
embedding_block = create_embedding_block(config)

# Test connection
if embedding_block.test_connection():
print("✅ OpenAI connection successful")
else:
print("❌ OpenAI connection failed")
return

# Generate single embedding
text = "This is a sample text for embedding generation."
embedding = embedding_block.generate_embedding(text)

if embedding:
print(f"✅ Generated embedding with {len(embedding)} dimensions")
print(f" First 5 values: {embedding[:5]}")

# Generate multiple embeddings
texts = [
"First sample text for embedding.",
"Second sample text with different content.",
"Third sample text for batch processing.",
]

embeddings = embedding_block.generate_embeddings(texts)

if embeddings:
print(f"✅ Generated {len(embeddings)} embeddings")
for i, emb in enumerate(embeddings):
print(f" Text {i + 1}: {len(emb)} dimensions")

# Get embedding information
info = embedding_block.get_info()
print(f"📊 Model info: {info['model']}")
print(f"📊 Provider: {info['provider']}")


def example_azure_embeddings():
"""Example using Azure OpenAI embeddings."""
print("\n=== Azure OpenAI Embeddings Example ===")

# Configuration for Azure OpenAI embeddings
config = EmbeddingConfig(
model="text-embedding-ada-002",
api_key=os.getenv("AZURE_API_KEY"),
api_base=os.getenv("AZURE_API_BASE"),
api_version=os.getenv("AZURE_API_VERSION", "2023-05-15"),
api_type="azure",
timeout=30,
encoding_format="float",
)

# Create embedding block
embedding_block = create_embedding_block(config)

# Test connection
if embedding_block.test_connection():
print("✅ Azure OpenAI connection successful")
else:
print("❌ Azure OpenAI connection failed")
return

# Generate single embedding
text = "This is a sample text for Azure OpenAI embedding generation."
embedding = embedding_block.generate_embedding(text)

if embedding:
print(f"✅ Generated embedding with {len(embedding)} dimensions")
print(f" First 5 values: {embedding[:5]}")

# Generate multiple embeddings
texts = [
"First sample text for Azure embedding.",
"Second sample text with different content.",
"Third sample text for batch processing.",
]

embeddings = embedding_block.generate_embeddings(texts)

if embeddings:
print(f"✅ Generated {len(embeddings)} embeddings")
for i, emb in enumerate(embeddings):
print(f" Text {i + 1}: {len(emb)} dimensions")

# Get embedding information
info = embedding_block.get_info()
print(f"📊 Model info: {info['model']}")
print(f"📊 Provider: {info['provider']}")


def example_configuration_variants():
"""Example showing different configuration variants."""
print("\n=== Configuration Variants Example ===")

# Base configuration
base_config = EmbeddingConfig(
model="text-embedding-ada-002",
api_key=os.getenv("OPENAI_API_KEY"),
encoding_format="float",
)

# Create variants with different parameters
fast_config = base_config.create_variant(timeout=10, retry_attempts=1)

conservative_config = base_config.create_variant(
timeout=120, retry_attempts=5, retry_delay=2.0
)

print(f"Base config timeout: {base_config.timeout}s")
print(f"Fast config timeout: {fast_config.timeout}s")
print(f"Conservative config timeout: {conservative_config.timeout}s")

# Test with temporary configuration
embedding_block = create_embedding_block(base_config)

with embedding_block.temporary_config(timeout=5):
print("Using temporary configuration with 5s timeout")
# Any embedding operations here will use the temporary config
embedding = embedding_block.generate_embedding("Test with temp config")
if embedding:
print("✅ Temporary configuration worked")


def example_error_handling():
"""Example showing error handling and fallbacks."""
print("\n=== Error Handling Example ===")

# Try with invalid API key
config = EmbeddingConfig(
model="text-embedding-ada-002",
api_key="invalid_key",
timeout=5,
)

embedding_block = create_embedding_block(config)

# This should fail gracefully
embedding = embedding_block.generate_embedding("Test text")
if embedding is None:
print("✅ Gracefully handled invalid API key")

# Try with non-existent model
config = EmbeddingConfig(
model="non-existent-model",
timeout=5,
)

try:
embedding_block = create_embedding_block(config)
print("❌ Should have failed with non-existent model")
except Exception as e:
print(f"✅ Gracefully handled non-existent model: {e}")


def main():
"""Run all embedding examples."""
print("🚀 EmbeddingBlock Examples")
print("=" * 50)

# Run examples based on available API keys
if os.getenv("OPENAI_API_KEY"):
example_openai_embeddings()
else:
print("\n⚠️ Skipping OpenAI examples - OPENAI_API_KEY not set")

if os.getenv("AZURE_API_KEY") and os.getenv("AZURE_API_BASE"):
example_azure_embeddings()
else:
print(
"\n⚠️ Skipping Azure example - AZURE_API_KEY or AZURE_API_BASE not set"
)

example_configuration_variants()
example_error_handling()

print("\n✅ All examples completed!")


if __name__ == "__main__":
main()
8 changes: 4 additions & 4 deletions examples/storage/storage_performance_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def simulate_old_behavior(storage: LocalStorage, num_lookups: int = 50):
old_time = end_time - start_time

print(f" Time for {num_lookups} lookups: {old_time:.4f} seconds")
print(f" Average per lookup: {(old_time/num_lookups)*1000:.2f} ms")
print(f" Average per lookup: {(old_time / num_lookups) * 1000:.2f} ms")

return old_time

Expand All @@ -86,7 +86,7 @@ def test_new_indexing_performance(storage: LocalStorage, num_lookups: int = 50):
new_time = end_time - start_time

print(f" Time for {num_lookups} lookups: {new_time:.4f} seconds")
print(f" Average per lookup: {(new_time/num_lookups)*1000:.2f} ms")
print(f" Average per lookup: {(new_time / num_lookups) * 1000:.2f} ms")

return new_time

Expand All @@ -110,7 +110,7 @@ def test_knowledge_lookup_performance(
print(
f" Time for {num_lookups} knowledge lookups: {lookup_time:.4f} seconds"
)
print(f" Average per lookup: {(lookup_time/num_lookups)*1000:.2f} ms")
print(f" Average per lookup: {(lookup_time / num_lookups) * 1000:.2f} ms")

return lookup_time

Expand All @@ -128,7 +128,7 @@ def test_batch_operations(storage: LocalStorage):
count = len(all_knowledges)

print(f" Retrieved {count} knowledge items in {batch_time:.4f} seconds")
print(f" Average per item: {(batch_time/count)*1000:.2f} ms")
print(f" Average per item: {(batch_time / count) * 1000:.2f} ms")

return batch_time

Expand Down
2 changes: 2 additions & 0 deletions quantmind/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
SummaryFlowConfig,
)
from .llm import LLMConfig
from .embedding import EmbeddingConfig
from .parsers import LlamaParserConfig, PDFParserConfig
from .settings import (
Setting,
Expand All @@ -27,6 +28,7 @@
"Setting",
# LLM Configuration
"LLMConfig",
"EmbeddingConfig",
# Tagger Configurations
"LLMTaggerConfig",
# Parser Configurations
Expand Down
Loading