Coverage for node / src / stigmem_node / embedding / local_adapter.py: 94%
33 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-25 01:49 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-25 01:49 +0000
1"""Local embedding adapter via Ollama HTTP API (design memo §2).
3Default model: ``nomic-embed-text-v1.5`` (768-dim, Apache-2.0, Matryoshka).
4Requires a running Ollama instance; install the model with::
6 ollama pull nomic-embed-text
8Install the optional dependency::
10 pip install 'stigmem-node[embed-local]' # includes httpx
11"""
13from __future__ import annotations
15import logging
17from .base import EmbeddingError, EmbeddingModel, Vector, l2_normalize
19logger = logging.getLogger("stigmem.embed.local")
21_DEFAULT_MODEL = "nomic-embed-text-v1.5"
22_DEFAULT_OLLAMA_URL = "http://localhost:11434"
25class OllamaEmbeddingModel(EmbeddingModel):
26 """Embed via Ollama's ``/api/embeddings`` endpoint."""
28 def __init__(
29 self,
30 model_id: str = _DEFAULT_MODEL,
31 ollama_url: str = _DEFAULT_OLLAMA_URL,
32 dimension: int = 768,
33 ) -> None:
34 self._model_id = model_id
35 self._ollama_url = ollama_url.rstrip("/")
36 self._dimension = dimension
38 @property
39 def model_id(self) -> str:
40 return self._model_id
42 @property
43 def dimension(self) -> int:
44 return self._dimension
46 def embed(self, texts: list[str]) -> list[Vector]:
47 try:
48 import httpx
49 except ImportError as exc:
50 raise EmbeddingError(
51 "httpx is required for the Ollama embedding adapter. "
52 "It is already a core stigmem-node dependency."
53 ) from exc
55 results: list[Vector] = []
56 url = f"{self._ollama_url}/api/embeddings"
57 for text in texts:
58 try:
59 resp = httpx.post(
60 url,
61 json={"model": self._model_id, "prompt": text},
62 timeout=30.0,
63 )
64 resp.raise_for_status()
65 vec = resp.json()["embedding"]
66 except Exception as exc:
67 raise EmbeddingError(f"Ollama embedding failed: {exc}") from exc
68 results.append(l2_normalize(vec))
69 return results