From ac005c585a1d9cb981952d244ae812e1e330ff80 Mon Sep 17 00:00:00 2001 From: wxg0103 <727495428@qq.com> Date: Thu, 3 Sep 2026 15:34:29 +0800 Subject: [PATCH] feat: enhance multimodal embedding support and refactor embedding logic --- .../model/embedding.py | 55 +++++++++++++------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/apps/models_provider/impl/aliyun_bai_lian_model_provider/model/embedding.py b/apps/models_provider/impl/aliyun_bai_lian_model_provider/model/embedding.py index 3f335bb466a..c38bb790756 100644 --- a/apps/models_provider/impl/aliyun_bai_lian_model_provider/model/embedding.py +++ b/apps/models_provider/impl/aliyun_bai_lian_model_provider/model/embedding.py @@ -17,9 +17,6 @@ class AliyunBaiLianEmbedding(MaxKBBaseEmbeddingModel): - def supports_image_embedding(self) -> bool: - return False - model_name: str optional_params: dict api_base: str @@ -35,6 +32,14 @@ def __init__(self, api_key, model_name: str, api_base: str, optional_params: dic def is_cache_model(self): return False + @staticmethod + def _is_multimodal(model_name: str) -> bool: + """判断模型是否为多模态向量模型(支持图片/视频独立向量)。""" + return any(k in model_name for k in ("vl-embedding", "embedding-vision", "multimodal")) + + def supports_image_embedding(self) -> bool: + return self._is_multimodal(self.model_name) + @staticmethod def new_instance(model_type, model_name, model_credential: Dict[str, object], **model_kwargs): optional_params = MaxKBBaseEmbeddingModel.filter_optional_params(model_kwargs) @@ -51,21 +56,8 @@ def embed_query(self, text: str): def embed_documents(self, texts: List[str], chunk_size: int | None = None) -> List[List[float]]: # 处理多模态的向量化 - if any(k in self.model_name for k in ("vl-embedding", "embedding-vision", "multimodal")): - dashscope.api_key = self.api_key - dashscope.base_http_api_url = self.api_base - multimodal_input = [{"text": text} for text in texts] - resp = dashscope.MultiModalEmbedding.call( - model=self.model_name, - input=multimodal_input, # type: ignore - **self.optional_params, - ) - - if resp.status_code == HTTPStatus.OK: - embeddings_data = resp.output.get("embeddings", []) - return [item.get("embedding", []) for item in embeddings_data] - else: - raise Exception(f"MultiModalEmbedding call failed: status={resp.status_code}, message={resp.message}") + if self._is_multimodal(self.model_name): + return self._call_multimodal([{"text": text} for text in texts]) if len(self.optional_params) > 0: res = self.client.create( @@ -74,3 +66,30 @@ def embed_documents(self, texts: List[str], chunk_size: int | None = None) -> Li else: res = self.client.create(input=texts, model=self.model_name, encoding_format="float") return [e.embedding for e in res.data] + + def embed_images(self, images: List[str]) -> List[List[float]]: + """对图片 URL / data URL 做独立向量化(每张图生成一个向量)。""" + if not self.supports_image_embedding(): + return [] + return self._call_multimodal([{"image": image} for image in images]) + + def _multimodal_base_url(self) -> str: + """DashScope 原生多模态接口走 /api/v1,与 OpenAI 兼容地址区分开。""" + base = self.api_base or "https://dashscope.aliyuncs.com/api/v1" + if "/compatible-mode/" in base: + return base.split("/compatible-mode/")[0] + "/api/v1" + return base + + def _call_multimodal(self, items: List[dict]) -> List[List[float]]: + dashscope.api_key = self.api_key + dashscope.base_http_api_url = self._multimodal_base_url() + resp = dashscope.MultiModalEmbedding.call( + model=self.model_name, + input=items, # type: ignore + **self.optional_params, + ) + + if resp.status_code == HTTPStatus.OK: + embeddings_data = resp.output.get("embeddings", []) + return [item.get("embedding", []) for item in embeddings_data] + raise Exception(f"MultiModalEmbedding call failed: status={resp.status_code}, message={resp.message}")