"""嵌入服务 — Embedding 适配器外观。 用法:: from app.ai_provider.embedding import EmbeddingService service = EmbeddingService(manager) result = await service.embed("要嵌入的文本") results = await service.embed(["文本1", "文本2"]) """ from __future__ import annotations from app.ai_provider.embedding.base import ( EmbeddingProtocol, EmbeddingRequest, EmbeddingResponse, EmbeddingResult, EmbeddingServiceError, ) from app.ai_provider.types.errors import AIProviderError class EmbeddingService: """外观类,负责解析 Embedding 模型并委托给 ProviderManager。 接受 ProviderManager 或实现了以下接口的适配器: - ``.model_registry`` → 具有 ``list_by_capability(capability)`` 方法 - ``.create_embedding(name)`` → 返回 EmbeddingProtocol 实例 """ def __init__(self, manager) -> None: self._manager = manager self._adapter: EmbeddingProtocol | None = None # ── Registry 兼容适配 ───────────────────────────────────────── @property def _registry(self): mgr = self._manager if hasattr(mgr, "model_registry"): return mgr.model_registry return mgr @property def _factory(self): mgr = self._manager if hasattr(mgr, "create_embedding"): return mgr return None # ── Embedding ────────────────────────────────────────────────── @property def adapter(self) -> EmbeddingProtocol: """解析并缓存 Embedding 适配器。""" if self._adapter is None: self._adapter = self._resolve() return self._adapter async def embed( self, input: str | list[str], model_hint: str | None = None, dimensions: int | None = None, ) -> EmbeddingResponse: """快捷方法:构造请求并调用 Embedding 适配器。""" model_name = self._resolve_model_name(model_hint) # 优先从模型配置读 dimensions effective_dimensions = dimensions if effective_dimensions is None: effective_dimensions = self._resolve_model_dimensions(model_hint) request = EmbeddingRequest( input=input if isinstance(input, list) else [input], model=model_name, dimensions=effective_dimensions, ) return await self.adapter.embed(request) # ── 解析 ─────────────────────────────────────────────────────── def _resolve(self) -> EmbeddingProtocol: """查找第一个活跃的 Embedding 模型并通过工厂创建。""" models = self._list_capability_models("embedding") if not models: raise AIProviderError( status_code=503, code="embedding_no_model", message="No embedding model configured in the model registry.", ) factory = self._factory if factory is None: raise AIProviderError( status_code=501, code="embedding_no_factory", message="Embedding adapter factory not available (provider manager missing create_embedding).", ) return factory.create_embedding(models[0].name) def _resolve_model_name(self, model_hint: str | None) -> str: models = self._list_capability_models("embedding") if model_hint: return model_hint if models: return models[0].name return "" def _resolve_model_dimensions(self, model_hint: str | None) -> int | None: """从模型配置读取向量维度。""" models = self._list_capability_models("embedding") if model_hint: for m in models: if m.name == model_hint: return m.dimensions if models: return models[0].dimensions return None def _list_capability_models(self, tag: str): reg = self._registry if hasattr(reg, "list_capability_models"): return reg.list_capability_models(tag) if hasattr(reg, "list_by_capability"): return reg.list_by_capability(tag) return [] # ── 生命周期 ──────────────────────────────────────────────────── async def close(self) -> None: if self._adapter is not None: close = getattr(self._adapter, "close", None) if close is not None: await close() async def __aenter__(self) -> EmbeddingService: return self async def __aexit__(self, *exc_info: object) -> None: await self.close() __all__ = [ "EmbeddingProtocol", "EmbeddingRequest", "EmbeddingResponse", "EmbeddingResult", "EmbeddingService", "EmbeddingServiceError", ]