From b47da3f4383f48d53c9ab3d0cc30f1de69e7939c Mon Sep 17 00:00:00 2001
From: Robust_H <1511209518@qq.com>
Date: Sat, 4 Oct 2025 04:50:12 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=9D=E5=A7=8B=E5=8C=96=E5=A4=9A?=
=?UTF-8?q?=E4=BE=9B=E5=BA=94=E5=95=86=E5=A4=9A=E5=B5=8C=E5=85=A5=E6=A8=A1?=
=?UTF-8?q?=E5=9E=8B=E9=9B=86=E6=88=90=EF=BC=8C=E9=87=87=E7=94=A8=E7=AD=96?=
=?UTF-8?q?=E7=95=A5=E6=A8=A1=E5=BC=8F=E5=92=8C=E5=B7=A5=E5=8E=82=E6=A8=A1?=
=?UTF-8?q?=E5=BC=8F=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../main/java/org/ruoyi/domain/ChatModel.java | 6 +
.../java/org/ruoyi/domain/bo/ChatModelBo.java | 5 +
.../java/org/ruoyi/domain/vo/ChatModelVo.java | 6 +
ruoyi-modules-api/ruoyi-knowledge-api/pom.xml | 4 +
.../embedding/BaseEmbedModelService.java | 26 ++
.../embedding/EmbeddingModelFactory.java | 70 +++++
.../MultiModalEmbedModelService.java | 35 +++
.../impl/AliBaiLianBaseEmbedProvider.java | 14 +
.../AliBaiLianMultiEmbeddingProvider.java | 281 ++++++++++++++++++
.../impl/OllamaEmbeddingProvider.java | 41 +++
.../impl/OpenAiEmbeddingProvider.java | 43 +++
.../impl/SiliconFlowEmbeddingProvider.java | 18 ++
.../impl/ZhiPuAiEmbeddingProvider.java | 43 +++
.../model/AliyunMultiModalEmbedRequest.java | 44 +++
.../model/AliyunMultiModalEmbedResponse.java | 44 +++
.../ruoyi/embedding/model/ModalityType.java | 8 +
.../embedding/model/MultiModalInput.java | 71 +++++
17 files changed, 759 insertions(+)
create mode 100644 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/BaseEmbedModelService.java
create mode 100644 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/EmbeddingModelFactory.java
create mode 100644 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/MultiModalEmbedModelService.java
create mode 100644 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianBaseEmbedProvider.java
create mode 100644 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianMultiEmbeddingProvider.java
create mode 100644 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/OllamaEmbeddingProvider.java
create mode 100644 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/OpenAiEmbeddingProvider.java
create mode 100644 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/SiliconFlowEmbeddingProvider.java
create mode 100644 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/ZhiPuAiEmbeddingProvider.java
create mode 100644 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/model/AliyunMultiModalEmbedRequest.java
create mode 100644 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/model/AliyunMultiModalEmbedResponse.java
create mode 100644 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/model/ModalityType.java
create mode 100644 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/model/MultiModalInput.java
diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatModel.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatModel.java
index e8f0e308..34465613 100644
--- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatModel.java
+++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatModel.java
@@ -1,6 +1,7 @@
package org.ruoyi.domain;
+import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -81,6 +82,11 @@ public class ChatModel extends BaseEntity {
*/
private Integer priority;
+ /**
+ * 模型供应商
+ */
+ private String ProviderName;
+
/**
* 备注
*/
diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatModelBo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatModelBo.java
index b828515b..34ee975e 100644
--- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatModelBo.java
+++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatModelBo.java
@@ -1,5 +1,6 @@
package org.ruoyi.domain.bo;
+import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
@@ -85,6 +86,10 @@ public class ChatModelBo extends BaseEntity {
@NotBlank(message = "密钥不能为空", groups = { AddGroup.class, EditGroup.class })
private String apiKey;
+ /**
+ * 模型供应商
+ */
+ private String ProviderName;
/**
* 备注
diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java
index 0638c13a..6a2de3cf 100644
--- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java
+++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java
@@ -95,6 +95,12 @@ public class ChatModelVo implements Serializable {
@ExcelProperty(value = "优先级")
private Integer priority;
+ /**
+ * 模型供应商
+ */
+ @ExcelProperty(value = "模型供应商")
+ private String ProviderName;
+
/**
* 备注
*/
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/pom.xml b/ruoyi-modules-api/ruoyi-knowledge-api/pom.xml
index f8082a67..0394b6d1 100644
--- a/ruoyi-modules-api/ruoyi-knowledge-api/pom.xml
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/pom.xml
@@ -106,6 +106,10 @@
dashscope-sdk-java
2.19.0
+
+ org.ruoyi
+ ruoyi-chat-api
+
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/BaseEmbedModelService.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/BaseEmbedModelService.java
new file mode 100644
index 00000000..9b3d0021
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/BaseEmbedModelService.java
@@ -0,0 +1,26 @@
+package org.ruoyi.embedding;
+
+import dev.langchain4j.model.embedding.EmbeddingModel;
+import org.ruoyi.domain.vo.ChatModelVo;
+import org.ruoyi.embedding.model.ModalityType;
+
+import java.util.Set;
+
+/**
+ * BaseEmbedModelService 接口,扩展了 EmbeddingModel 接口
+ * 该接口定义了嵌入模型服务的基本配置和功能方法
+ */
+public interface BaseEmbedModelService extends EmbeddingModel {
+ /**
+ * 根据配置信息配置嵌入模型
+ * @param config 包含模型配置信息的 ChatModelVo 对象
+ */
+ void configure(ChatModelVo config);
+
+ /**
+ * 获取当前嵌入模型支持的所有模态类型
+ * @return 返回支持的模态类型集合
+ */
+ Set getSupportedModalities();
+
+}
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/EmbeddingModelFactory.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/EmbeddingModelFactory.java
new file mode 100644
index 00000000..0d2155cc
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/EmbeddingModelFactory.java
@@ -0,0 +1,70 @@
+package org.ruoyi.embedding;
+
+import lombok.RequiredArgsConstructor;
+import org.ruoyi.domain.vo.ChatModelVo;
+import org.ruoyi.service.IChatModelService;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 嵌入模型工厂服务类
+ * 负责创建和管理各种嵌入模型实例
+ */
+@Service
+@RequiredArgsConstructor
+public class EmbeddingModelFactory {
+ private final ApplicationContext applicationContext;
+
+ private final IChatModelService iChatModelService;
+
+ private final Map modelCache = new ConcurrentHashMap<>();
+
+ public BaseEmbedModelService createModel(Long embeddingModelId) {
+ ChatModelVo chatModelVo = iChatModelService.queryById(embeddingModelId);
+
+ return createModelInstance(chatModelVo.getProviderName(), chatModelVo);
+ }
+
+ private BaseEmbedModelService createModelInstance(String factory, ChatModelVo config) {
+ try {
+ BaseEmbedModelService model = applicationContext.getBean(factory, BaseEmbedModelService.class);
+ // TODO 缓存设置
+ model.configure(config);
+
+ return model;
+ } catch (NoSuchBeanDefinitionException e) {
+ throw new IllegalArgumentException("获取不到嵌入模型: " + factory, e);
+ }
+ }
+
+ // 检查模型是否支持多模态
+ public boolean isMultimodalModel(Long tenantId) {
+ BaseEmbedModelService model = createModel(tenantId);
+ return model instanceof MultiModalEmbedModelService;
+ }
+
+ // 获取多模态模型(如果支持)
+ public MultiModalEmbedModelService createMultimodalModel(Long tenantId) {
+ BaseEmbedModelService model = createModel(tenantId);
+ if (model instanceof MultiModalEmbedModelService) {
+ return (MultiModalEmbedModelService) model;
+ }
+ throw new IllegalArgumentException("该模型不支持多模态");
+ }
+
+ public void refreshModel(String tenantId, String factory) {
+ String cacheKey = tenantId + ":" + factory;
+ modelCache.remove(cacheKey);
+ }
+
+ public List getSupportedFactories() {
+ return new ArrayList<>(applicationContext.getBeansOfType(BaseEmbedModelService.class)
+ .keySet());
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/MultiModalEmbedModelService.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/MultiModalEmbedModelService.java
new file mode 100644
index 00000000..062ff00f
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/MultiModalEmbedModelService.java
@@ -0,0 +1,35 @@
+package org.ruoyi.embedding;
+
+import dev.langchain4j.data.embedding.Embedding;
+import dev.langchain4j.model.output.Response;
+import org.ruoyi.embedding.model.MultiModalInput;
+
+
+/**
+ * 多模态嵌入模型服务接口,继承自基础嵌入模型服务
+ * 该接口提供了处理图像、视频以及多模态数据并转换为嵌入向量的功能
+ */
+public interface MultiModalEmbedModelService extends BaseEmbedModelService {
+ /**
+ * 将图像数据转换为嵌入向量
+ * @param imageDataUrl 图像的地址,必须是公开可访问的URL
+ * @return 包含嵌入向量的响应对象,可能包含状态信息和嵌入结果
+ */
+ Response embedImage(String imageDataUrl);
+
+ /**
+ * 将视频数据转换为嵌入向量
+ * @param videoDataUrl 视频的地址,必须是公开可访问的URL
+ * @return 包含嵌入向量的响应对象,可能包含状态信息和嵌入结果
+ */
+ Response embedVideo(String videoDataUrl);
+
+
+ /**
+ * 处理多模态输入并返回嵌入向量的方法
+ *
+ * @param input 包含多种模态信息(如图像、文本等)的输入对象
+ * @return Response 包含嵌入向量的响应对象,Embedding通常表示输入数据的向量表示
+ */
+ Response embedMultiModal(MultiModalInput input);
+}
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianBaseEmbedProvider.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianBaseEmbedProvider.java
new file mode 100644
index 00000000..1511a0fe
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianBaseEmbedProvider.java
@@ -0,0 +1,14 @@
+package org.ruoyi.embedding.impl;
+
+
+import org.springframework.stereotype.Component;
+
+/**
+ * @Author: Robust_H
+ * @Date: 2025-09-30-下午3:00
+ * @Description: 阿里百炼基础嵌入模型(兼容openai)
+ */
+@Component("alibailian")
+public class AliBaiLianBaseEmbedProvider extends OpenAiEmbeddingProvider{
+
+}
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianMultiEmbeddingProvider.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianMultiEmbeddingProvider.java
new file mode 100644
index 00000000..ad3e8374
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianMultiEmbeddingProvider.java
@@ -0,0 +1,281 @@
+package org.ruoyi.embedding.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import dev.langchain4j.data.embedding.Embedding;
+import dev.langchain4j.data.segment.TextSegment;
+import dev.langchain4j.model.output.Response;
+import dev.langchain4j.model.output.TokenUsage;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import org.ruoyi.domain.vo.ChatModelVo;
+import org.ruoyi.embedding.MultiModalEmbedModelService;
+import org.ruoyi.embedding.model.AliyunMultiModalEmbedRequest;
+import org.ruoyi.embedding.model.AliyunMultiModalEmbedResponse;
+import org.ruoyi.embedding.model.ModalityType;
+import org.ruoyi.embedding.model.MultiModalInput;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 阿里云百炼多模态嵌入模型服务实现类
+ * 实现了MultiModalEmbedModelService接口,提供文本、图像和视频的嵌入向量生成服务
+ */
+@Component("bailianMultiModel")
+@Slf4j
+public class AliBaiLianMultiEmbeddingProvider implements MultiModalEmbedModelService {
+ private ChatModelVo chatModelVo;
+
+ private final OkHttpClient okHttpClient;
+
+ /**
+ * 构造函数,初始化HTTP客户端
+ * 设置连接超时、读取超时和写入超时时间
+ */
+ public AliBaiLianMultiEmbeddingProvider() {
+ this.okHttpClient = new OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)
+ .readTimeout(60, TimeUnit.SECONDS)
+ .writeTimeout(30, TimeUnit.SECONDS)
+ .build();
+ }
+
+ /**
+ * 图像嵌入向量生成
+ * @param imageDataUrl 图像数据的URL
+ * @return 包含图像嵌入向量的Response对象
+ */
+ @Override
+ public Response embedImage(String imageDataUrl) {
+ return embedSingleModality("image", imageDataUrl);
+ }
+
+ /**
+ * 视频嵌入向量生成
+ * @param videoDataUrl 视频数据的URL
+ * @return 包含视频嵌入向量的Response对象
+ */
+ @Override
+ public Response embedVideo(String videoDataUrl) {
+ return embedSingleModality("video", videoDataUrl);
+ }
+
+ /**
+ * 多模态嵌入向量生成
+ * 支持同时处理文本、图像和视频等多种模态的数据
+ * @param input 包含多种模态输入的对象
+ * @return 包含多模态嵌入向量的Response对象
+ */
+ @Override
+ public Response embedMultiModal(MultiModalInput input) {
+ try {
+ // 构建请求内容
+ List