Spaces:
Running
Running
| """Protocol definition for embedding services. | |
| This module defines the common interface that all embedding services must implement. | |
| Using Protocol (PEP 544) for structural subtyping - no inheritance required. | |
| Design Pattern: Strategy Pattern (Gang of Four) | |
| - Each implementation (EmbeddingService, LlamaIndexRAGService) is a concrete strategy | |
| - Protocol defines the strategy interface | |
| - service_loader selects the appropriate strategy at runtime | |
| SOLID Principles: | |
| - Interface Segregation: Protocol includes only methods needed by consumers | |
| - Dependency Inversion: Consumers depend on Protocol (abstraction), not concrete classes | |
| - Liskov Substitution: All implementations are interchangeable | |
| """ | |
| from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable | |
| if TYPE_CHECKING: | |
| from src.utils.models import Evidence | |
| class EmbeddingServiceProtocol(Protocol): | |
| """Common interface for embedding services. | |
| Both EmbeddingService (local/free) and LlamaIndexRAGService (OpenAI/premium) | |
| implement this interface, allowing seamless swapping via get_embedding_service(). | |
| All methods are async to avoid blocking the event loop during: | |
| - Embedding computation (CPU-bound with local models) | |
| - Vector store operations (I/O-bound with persistent storage) | |
| - API calls (network I/O with OpenAI embeddings) | |
| Example: | |
| ```python | |
| from src.utils.service_loader import get_embedding_service | |
| # Get best available service (LlamaIndex if OpenAI key, else local) | |
| service = get_embedding_service() | |
| # Use via protocol interface | |
| await service.add_evidence("id", "content", {"source": "pubmed"}) | |
| results = await service.search_similar("query", n_results=5) | |
| unique = await service.deduplicate(evidence_list) | |
| # Direct embedding (for MMR/diversity selection) | |
| embedding = await service.embed("text") | |
| embeddings = await service.embed_batch(["text1", "text2"]) | |
| ``` | |
| """ | |
| async def embed(self, text: str) -> list[float]: | |
| """Embed a single text into a vector. | |
| Args: | |
| text: Text to embed | |
| Returns: | |
| Embedding vector as list of floats | |
| """ | |
| ... | |
| async def embed_batch(self, texts: list[str]) -> list[list[float]]: | |
| """Embed multiple texts efficiently. | |
| More efficient than calling embed() multiple times due to batching. | |
| Args: | |
| texts: List of texts to embed | |
| Returns: | |
| List of embedding vectors | |
| """ | |
| ... | |
| async def add_evidence(self, evidence_id: str, content: str, metadata: dict[str, Any]) -> None: | |
| """Store evidence with embeddings. | |
| Args: | |
| evidence_id: Unique identifier (typically URL) | |
| content: Text content to embed and store | |
| metadata: Additional metadata for retrieval filtering | |
| Expected keys: source, title, date, authors, url | |
| """ | |
| ... | |
| async def search_similar(self, query: str, n_results: int = 5) -> list[dict[str, Any]]: | |
| """Search for semantically similar content. | |
| Args: | |
| query: Search query text | |
| n_results: Maximum number of results to return | |
| Returns: | |
| List of dicts with keys: | |
| - id: Evidence identifier | |
| - content: Original text content | |
| - metadata: Stored metadata | |
| - distance: Semantic distance (0 = identical, higher = less similar) | |
| """ | |
| ... | |
| async def deduplicate( | |
| self, evidence: list["Evidence"], threshold: float = 0.9 | |
| ) -> list["Evidence"]: | |
| """Remove duplicate evidence based on semantic similarity. | |
| Uses the embedding service to check if new evidence is similar to | |
| existing stored evidence. Unique evidence is stored automatically. | |
| Args: | |
| evidence: List of evidence items to deduplicate | |
| threshold: Similarity threshold (0.9 = 90% similar is duplicate) | |
| ChromaDB cosine distance interpretation: | |
| - 0 = identical vectors | |
| - 2 = opposite vectors | |
| Duplicate if: distance < (1 - threshold) | |
| Returns: | |
| List of unique evidence items (duplicates removed) | |
| """ | |
| ... | |