"""Deterministic mock embedding client for testing and local development. No network calls are made. Vectors are generated from a seeded hash of the input text so identical inputs always produce identical vectors. """ import hashlib import math from app.embeddings.base import EmbeddingClient _MOCK_DIM = 1536 class MockEmbeddingClient(EmbeddingClient): """Return deterministic pseudo-random vectors without calling any API. The vector for each text is derived from ``sha256(text)``. This ensures tests that check vector similarity behave consistently across runs. Example:: client = MockEmbeddingClient() v = client.get_embedding("hello") assert len(v) == 1536 """ @property def dimension(self) -> int: return _MOCK_DIM def get_embedding(self, text: str) -> list[float]: """Return a deterministic unit vector derived from ``sha256(text)``. Args: text: Input text. Returns: Normalised float vector of length :attr:`dimension`. """ seed = int(hashlib.sha256(text.encode()).hexdigest(), 16) vector: list[float] = [] for _i in range(_MOCK_DIM): seed = (seed * 6364136223846793005 + 1442695040888963407) & 0xFFFFFFFFFFFFFFFF val = (seed >> 33) / (2**31) - 1.0 vector.append(val) # Normalise to unit length norm = math.sqrt(sum(v * v for v in vector)) or 1.0 return [v / norm for v in vector] def get_embeddings(self, texts: list[str]) -> list[list[float]]: """Embed a batch of texts using the deterministic mock. Args: texts: List of input strings. Returns: List of unit vectors in the same order as ``texts``. """ return [self.get_embedding(t) for t in texts]