Configurable embedding backend with caching and safe fallbacks.
| 232 | |
| 233 | |
| 234 | class EmbeddingService: |
| 235 | """Configurable embedding backend with caching and safe fallbacks.""" |
| 236 | |
| 237 | def __init__( |
| 238 | self, |
| 239 | provider: Optional[str] = None, |
| 240 | model: Optional[str] = None, |
| 241 | dimensions: Optional[int] = None, |
| 242 | cache_dir: Optional[Path] = None, |
| 243 | ): |
| 244 | requested_provider = ( |
| 245 | provider |
| 246 | or _get_first_env_value("PAPERFLOW_EMBED_PROVIDER", "EMBEDDING_PROVIDER") |
| 247 | or "hash" |
| 248 | ).strip().lower() |
| 249 | self.dimensions = int( |
| 250 | dimensions |
| 251 | or _get_first_env_value("PAPERFLOW_EMBED_DIMENSIONS", "EMBEDDING_DIMENSIONS") |
| 252 | or "768" |
| 253 | ) |
| 254 | self.cache_dir = Path(cache_dir or DEFAULT_CACHE_DIR) |
| 255 | self.cache_dir.mkdir(parents=True, exist_ok=True) |
| 256 | |
| 257 | self.client = None |
| 258 | self.local_model = None |
| 259 | self.model_source = None |
| 260 | |
| 261 | if requested_provider in {"openai", "dashscope", "aliyun", "bailian"}: |
| 262 | self.provider = "openai" |
| 263 | provider_hint = requested_provider |
| 264 | self.model = model or _get_openai_embedding_model(provider_hint) |
| 265 | api_key = _get_openai_api_key(provider_hint) |
| 266 | if OPENAI_AVAILABLE and not _is_placeholder_openai_key(api_key): |
| 267 | self.client = OpenAI( |
| 268 | api_key=api_key, |
| 269 | base_url=_get_openai_base_url(provider_hint), |
| 270 | timeout=_get_openai_timeout(provider_hint), |
| 271 | ) |
| 272 | else: |
| 273 | self.provider = "hash" |
| 274 | self.model = "hash" |
| 275 | elif requested_provider in {"nscale_api", "nscale"}: |
| 276 | self.provider = "nscale_api" |
| 277 | self.model = model or os.environ.get("NSCALE_EMBEDDING_MODEL") or os.environ.get("HF_EMBEDDING_MODEL") or "Qwen3-Embedding-8B" |
| 278 | api_key = ( |
| 279 | os.environ.get("NSCALE_API_KEY") |
| 280 | or os.environ.get("NSCALE_SERVICE_TOKEN") |
| 281 | or "" |
| 282 | ) |
| 283 | if _is_placeholder_nscale_key(api_key): |
| 284 | api_key = "" |
| 285 | base_url = ( |
| 286 | os.environ.get("NSCALE_BASE_URL") |
| 287 | or "https://aiproxy.infaas-amd-dev.glo1.nscale.com" |
| 288 | ).strip().rstrip("/") |
| 289 | timeout = float(os.environ.get("NSCALE_API_TIMEOUT", os.environ.get("HF_API_TIMEOUT", "60"))) |
| 290 | if api_key: |
| 291 | self.client = { |
no outgoing calls
no test coverage detected