"""Offline, lazy CPU runtime; one encoder call per process, with a fast busy response.""" from functools import lru_cache from threading import Lock from fastapi import HTTPException from app.core.config import settings from app.services.embedding import LOCAL_MODELS, EmbeddingSpec, LocalEmbeddingProvider class EmbeddingRuntime: def __init__(self, spec: EmbeddingSpec, cache_dir, batch_size: int, threads: int): self.spec = spec self.cache_dir, self.batch_size, self.threads = cache_dir, batch_size, threads self._provider = None self._lock = Lock() def encode(self, texts: list[str], *, query: bool = False) -> list[list[float]]: if not self._lock.acquire(blocking=False): raise HTTPException(503, "本地编码器忙,请稍后重试") try: if self._provider is None: self._provider = LocalEmbeddingProvider( self.spec, cache_dir=self.cache_dir, batch_size=self.batch_size, threads=self.threads, offline=True, ) return self._provider.encode(texts, query=query) finally: self._lock.release() @lru_cache(maxsize=1) def runtime(spec, cache_dir, batch_size, threads): return EmbeddingRuntime(spec, cache_dir, batch_size, threads) def get_embedding_provider(): if not settings.embedding_enabled: raise HTTPException(503, "本地 Embedding 未启用,请先完成模型缓存和运行环境配置") return runtime( LOCAL_MODELS[settings.embedding_model], settings.embedding_cache_dir, settings.embedding_batch_size, settings.embedding_threads, )