mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-21 06:25:30 -04:00
Co-authored-by: John Tramm <jtramm@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
120 lines
5.2 KiB
Python
120 lines
5.2 KiB
Python
"""Thin wrapper around sentence-transformers for embedding text into vectors.
|
|
|
|
Uses the all-MiniLM-L6-v2 model — a small (22M param, 384-dim) model that
|
|
runs on CPU with no GPU or API key required.
|
|
|
|
Network behavior and privacy
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
No user code, queries, or file contents are EVER sent to HuggingFace or any
|
|
external service. All embedding computation happens locally. The only network
|
|
activity is the one-time model download on first use:
|
|
|
|
First run (model not yet cached, ~80MB download):
|
|
- Downloads model weight files from huggingface.co. This is a standard
|
|
HTTP file download, similar to pip installing a package.
|
|
- The only metadata sent in these requests is an HTTP user-agent header
|
|
containing library version numbers (e.g. "hf_hub/1.6.0;
|
|
python/3.12.3; torch/2.10.0"). No filenames, file contents, queries,
|
|
or any user-identifiable information is sent.
|
|
- The huggingface_hub library has an optional feature where it can report
|
|
anonymous library usage statistics (just version numbers, not user
|
|
data) back to HuggingFace. We disable this by setting
|
|
HF_HUB_DISABLE_TELEMETRY=1.
|
|
|
|
Subsequent runs (model already cached):
|
|
- We set HF_HUB_OFFLINE=1 automatically (see _set_offline_if_cached()
|
|
below), which prevents ALL network calls. The model loads entirely
|
|
from the local cache at ~/.cache/huggingface/hub/. Zero bytes leave
|
|
the machine.
|
|
|
|
How the model is downloaded
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
The SentenceTransformer() constructor (called in __init__ below) handles
|
|
the download automatically on first use. It calls into the huggingface_hub
|
|
library, which downloads the model files from:
|
|
|
|
https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2
|
|
|
|
The files are saved to ~/.cache/huggingface/hub/ and reused on subsequent
|
|
runs. We pass token=False to ensure no authentication token is sent.
|
|
|
|
This module is imported by both the MCP server (for search queries) and the
|
|
indexer (for bulk embedding of code chunks). The bulk embed() call shows a
|
|
progress bar; the single-query embed_query() does not.
|
|
|
|
The env vars below must be set before importing transformers or
|
|
sentence_transformers. They suppress warnings and progress bars that these
|
|
libraries emit by default. Stray stderr output would interfere with the MCP
|
|
server's JSON-RPC transport.
|
|
"""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
MODEL_NAME = "all-MiniLM-L6-v2"
|
|
|
|
# These env vars control logging behavior in the HuggingFace libraries.
|
|
# They must be set before the libraries are imported.
|
|
os.environ.setdefault("TRANSFORMERS_VERBOSITY", "error") # suppress warnings
|
|
os.environ.setdefault("HF_HUB_VERBOSITY", "error") # suppress warnings
|
|
os.environ.setdefault("HF_HUB_DISABLE_PROGRESS_BARS", "1")
|
|
os.environ.setdefault("TOKENIZERS_PARALLELISM", "false") # suppress threading warning
|
|
# Disable anonymous library usage statistics (version numbers only, not user
|
|
# data — but we disable it anyway as a matter of policy).
|
|
os.environ.setdefault("HF_HUB_DISABLE_TELEMETRY", "1")
|
|
|
|
|
|
def _set_offline_if_cached():
|
|
"""If the model has already been downloaded, tell huggingface_hub to
|
|
skip all network calls by setting HF_HUB_OFFLINE=1.
|
|
|
|
Without this, huggingface_hub makes an HTTP request to huggingface.co
|
|
on every load to check if the cached model is still up to date — even
|
|
though the model never changes. Setting HF_HUB_OFFLINE=1 prevents this.
|
|
|
|
This must run before sentence_transformers is imported, because the
|
|
library reads the env var at import time.
|
|
"""
|
|
# HuggingFace caches downloaded models under ~/.cache/huggingface/hub/
|
|
# in directories named like "models--sentence-transformers--all-MiniLM-L6-v2".
|
|
# The HF_HOME env var can override the base cache location.
|
|
hf_home = os.environ.get("HF_HOME")
|
|
if hf_home:
|
|
cache_dir = Path(hf_home) / "hub"
|
|
else:
|
|
cache_dir = Path.home() / ".cache" / "huggingface" / "hub"
|
|
|
|
model_dir = cache_dir / f"models--sentence-transformers--{MODEL_NAME}"
|
|
if model_dir.exists():
|
|
os.environ.setdefault("HF_HUB_OFFLINE", "1")
|
|
|
|
|
|
_set_offline_if_cached()
|
|
|
|
# This import must come after the env vars above are set, because the
|
|
# transformers library reads them at import time.
|
|
import transformers
|
|
transformers.logging.disable_progress_bar()
|
|
|
|
|
|
class EmbeddingProvider:
|
|
"""Sentence-transformers embedder using all-MiniLM-L6-v2."""
|
|
|
|
def __init__(self, model_name: str = MODEL_NAME):
|
|
from sentence_transformers import SentenceTransformer
|
|
|
|
# This constructor loads the model from the local cache. If the model
|
|
# has not been downloaded yet, it downloads it from huggingface.co
|
|
# (~80MB, one-time). token=False ensures no auth token is sent.
|
|
self.model = SentenceTransformer(model_name, token=False)
|
|
self.dim = self.model.get_sentence_embedding_dimension()
|
|
|
|
def embed(self, texts: list[str]) -> list[list[float]]:
|
|
"""Embed a list of texts into vectors."""
|
|
embeddings = self.model.encode(texts, show_progress_bar=True,
|
|
batch_size=64)
|
|
return embeddings.tolist()
|
|
|
|
def embed_query(self, text: str) -> list[float]:
|
|
"""Embed a single query text."""
|
|
return self.model.encode([text])[0].tolist()
|