Commit 83bd96d6725b0769808ea5c83b43d54e04859c6e

Authored by YunaiV
1 parent b4538568

【功能新增】AI:集成 Azure 的 OpenAI 模型

yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/DocServiceImpl.java
@@ -7,7 +7,6 @@ import org.springframework.ai.reader.tika.TikaDocumentReader; @@ -7,7 +7,6 @@ import org.springframework.ai.reader.tika.TikaDocumentReader;
7 import org.springframework.ai.transformer.splitter.TokenTextSplitter; 7 import org.springframework.ai.transformer.splitter.TokenTextSplitter;
8 import org.springframework.ai.vectorstore.RedisVectorStore; 8 import org.springframework.ai.vectorstore.RedisVectorStore;
9 import org.springframework.beans.factory.annotation.Value; 9 import org.springframework.beans.factory.annotation.Value;
10 -import org.springframework.stereotype.Service;  
11 10
12 import java.util.List; 11 import java.util.List;
13 12
@@ -16,7 +15,7 @@ import java.util.List; @@ -16,7 +15,7 @@ import java.util.List;
16 * 15 *
17 * @author xiaoxin 16 * @author xiaoxin
18 */ 17 */
19 -@Service 18 +//@Service // TODO 芋艿:临时注释,避免无法启动
20 @Slf4j 19 @Slf4j
21 public class DocServiceImpl implements DocService { 20 public class DocServiceImpl implements DocService {
22 21
yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml
@@ -23,7 +23,6 @@ @@ -23,7 +23,6 @@
23 <artifactId>spring-ai-zhipuai-spring-boot-starter</artifactId> 23 <artifactId>spring-ai-zhipuai-spring-boot-starter</artifactId>
24 <version>${spring-ai.version}</version> 24 <version>${spring-ai.version}</version>
25 </dependency> 25 </dependency>
26 -  
27 <dependency> 26 <dependency>
28 <groupId>org.springframework.ai</groupId> 27 <groupId>org.springframework.ai</groupId>
29 <artifactId>spring-ai-openai-spring-boot-starter</artifactId> 28 <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
@@ -31,6 +30,11 @@ @@ -31,6 +30,11 @@
31 </dependency> 30 </dependency>
32 <dependency> 31 <dependency>
33 <groupId>org.springframework.ai</groupId> 32 <groupId>org.springframework.ai</groupId>
  33 + <artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
  34 + <version>${spring-ai.version}</version>
  35 + </dependency>
  36 + <dependency>
  37 + <groupId>org.springframework.ai</groupId>
34 <artifactId>spring-ai-ollama-spring-boot-starter</artifactId> 38 <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
35 <version>${spring-ai.version}</version> 39 <version>${spring-ai.version}</version>
36 </dependency> 40 </dependency>
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java
@@ -12,6 +12,7 @@ import com.alibaba.cloud.ai.tongyi.TongYiAutoConfiguration; @@ -12,6 +12,7 @@ import com.alibaba.cloud.ai.tongyi.TongYiAutoConfiguration;
12 import lombok.extern.slf4j.Slf4j; 12 import lombok.extern.slf4j.Slf4j;
13 import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreProperties; 13 import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreProperties;
14 import org.springframework.ai.document.MetadataMode; 14 import org.springframework.ai.document.MetadataMode;
  15 +import org.springframework.ai.embedding.EmbeddingModel;
15 import org.springframework.ai.transformer.splitter.TokenTextSplitter; 16 import org.springframework.ai.transformer.splitter.TokenTextSplitter;
16 import org.springframework.ai.transformers.TransformersEmbeddingModel; 17 import org.springframework.ai.transformers.TransformersEmbeddingModel;
17 import org.springframework.ai.vectorstore.RedisVectorStore; 18 import org.springframework.ai.vectorstore.RedisVectorStore;
@@ -21,6 +22,7 @@ import org.springframework.boot.autoconfigure.data.redis.RedisProperties; @@ -21,6 +22,7 @@ import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
21 import org.springframework.boot.context.properties.EnableConfigurationProperties; 22 import org.springframework.boot.context.properties.EnableConfigurationProperties;
22 import org.springframework.context.annotation.Bean; 23 import org.springframework.context.annotation.Bean;
23 import org.springframework.context.annotation.Import; 24 import org.springframework.context.annotation.Import;
  25 +import org.springframework.context.annotation.Lazy;
24 import redis.clients.jedis.JedisPooled; 26 import redis.clients.jedis.JedisPooled;
25 27
26 /** 28 /**
@@ -82,7 +84,8 @@ public class YudaoAiAutoConfiguration { @@ -82,7 +84,8 @@ public class YudaoAiAutoConfiguration {
82 84
83 // ========== rag 相关 ========== 85 // ========== rag 相关 ==========
84 @Bean 86 @Bean
85 - public TransformersEmbeddingModel transformersEmbeddingClient() { 87 + @Lazy // TODO 芋艿:临时注释,避免无法启动
  88 + public EmbeddingModel transformersEmbeddingClient() {
86 return new TransformersEmbeddingModel(MetadataMode.EMBED); 89 return new TransformersEmbeddingModel(MetadataMode.EMBED);
87 } 90 }
88 91
@@ -90,6 +93,7 @@ public class YudaoAiAutoConfiguration { @@ -90,6 +93,7 @@ public class YudaoAiAutoConfiguration {
90 * 我们启动有加载很多 Embedding 模型,不晓得取哪个好,先 new 个 TransformersEmbeddingModel 跑 93 * 我们启动有加载很多 Embedding 模型,不晓得取哪个好,先 new 个 TransformersEmbeddingModel 跑
91 */ 94 */
92 @Bean 95 @Bean
  96 + @Lazy // TODO 芋艿:临时注释,避免无法启动
93 public RedisVectorStore vectorStore(TransformersEmbeddingModel transformersEmbeddingModel, RedisVectorStoreProperties properties, 97 public RedisVectorStore vectorStore(TransformersEmbeddingModel transformersEmbeddingModel, RedisVectorStoreProperties properties,
94 RedisProperties redisProperties) { 98 RedisProperties redisProperties) {
95 var config = RedisVectorStore.RedisVectorStoreConfig.builder() 99 var config = RedisVectorStore.RedisVectorStoreConfig.builder()
@@ -105,6 +109,7 @@ public class YudaoAiAutoConfiguration { @@ -105,6 +109,7 @@ public class YudaoAiAutoConfiguration {
105 } 109 }
106 110
107 @Bean 111 @Bean
  112 + @Lazy // TODO 芋艿:临时注释,避免无法启动
108 public TokenTextSplitter tokenTextSplitter() { 113 public TokenTextSplitter tokenTextSplitter() {
109 return new TokenTextSplitter(500, 100, 5, 10000, true); 114 return new TokenTextSplitter(500, 100, 5, 10000, true);
110 } 115 }
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/enums/AiPlatformEnum.java
@@ -22,7 +22,8 @@ public enum AiPlatformEnum { @@ -22,7 +22,8 @@ public enum AiPlatformEnum {
22 22
23 // ========== 国外平台 ========== 23 // ========== 国外平台 ==========
24 24
25 - OPENAI("OpenAI", "OpenAI"), 25 + OPENAI("OpenAI", "OpenAI"), // OpenAI 官方
  26 + AZURE_OPENAI("AzureOpenAI", "AzureOpenAI"), // OpenAI 微软
26 OLLAMA("Ollama", "Ollama"), 27 OLLAMA("Ollama", "Ollama"),
27 28
28 STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI 29 STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java
@@ -21,6 +21,10 @@ import com.alibaba.cloud.ai.tongyi.image.TongYiImagesModel; @@ -21,6 +21,10 @@ import com.alibaba.cloud.ai.tongyi.image.TongYiImagesModel;
21 import com.alibaba.cloud.ai.tongyi.image.TongYiImagesProperties; 21 import com.alibaba.cloud.ai.tongyi.image.TongYiImagesProperties;
22 import com.alibaba.dashscope.aigc.generation.Generation; 22 import com.alibaba.dashscope.aigc.generation.Generation;
23 import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis; 23 import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis;
  24 +import com.azure.ai.openai.OpenAIClient;
  25 +import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiAutoConfiguration;
  26 +import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiChatProperties;
  27 +import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiConnectionProperties;
24 import org.springframework.ai.autoconfigure.ollama.OllamaAutoConfiguration; 28 import org.springframework.ai.autoconfigure.ollama.OllamaAutoConfiguration;
25 import org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration; 29 import org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration;
26 import org.springframework.ai.autoconfigure.qianfan.QianFanAutoConfiguration; 30 import org.springframework.ai.autoconfigure.qianfan.QianFanAutoConfiguration;
@@ -31,6 +35,7 @@ import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiAutoConfiguration; @@ -31,6 +35,7 @@ import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiAutoConfiguration;
31 import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiChatProperties; 35 import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiChatProperties;
32 import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiConnectionProperties; 36 import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiConnectionProperties;
33 import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiImageProperties; 37 import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiImageProperties;
  38 +import org.springframework.ai.azure.openai.AzureOpenAiChatModel;
34 import org.springframework.ai.chat.model.ChatModel; 39 import org.springframework.ai.chat.model.ChatModel;
35 import org.springframework.ai.image.ImageModel; 40 import org.springframework.ai.image.ImageModel;
36 import org.springframework.ai.model.function.FunctionCallbackContext; 41 import org.springframework.ai.model.function.FunctionCallbackContext;
@@ -82,6 +87,8 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -82,6 +87,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
82 return buildXingHuoChatModel(apiKey); 87 return buildXingHuoChatModel(apiKey);
83 case OPENAI: 88 case OPENAI:
84 return buildOpenAiChatModel(apiKey, url); 89 return buildOpenAiChatModel(apiKey, url);
  90 + case AZURE_OPENAI:
  91 + return buildAzureOpenAiChatModel(apiKey, url);
85 case OLLAMA: 92 case OLLAMA:
86 return buildOllamaChatModel(url); 93 return buildOllamaChatModel(url);
87 default: 94 default:
@@ -106,6 +113,8 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -106,6 +113,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
106 return SpringUtil.getBean(XingHuoChatModel.class); 113 return SpringUtil.getBean(XingHuoChatModel.class);
107 case OPENAI: 114 case OPENAI:
108 return SpringUtil.getBean(OpenAiChatModel.class); 115 return SpringUtil.getBean(OpenAiChatModel.class);
  116 + case AZURE_OPENAI:
  117 + return SpringUtil.getBean(AzureOpenAiChatModel.class);
109 case OLLAMA: 118 case OLLAMA:
110 return SpringUtil.getBean(OllamaChatModel.class); 119 return SpringUtil.getBean(OllamaChatModel.class);
111 default: 120 default:
@@ -269,6 +278,21 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -269,6 +278,21 @@ public class AiModelFactoryImpl implements AiModelFactory {
269 } 278 }
270 279
271 /** 280 /**
  281 + * 可参考 {@link AzureOpenAiAutoConfiguration}
  282 + */
  283 + private static AzureOpenAiChatModel buildAzureOpenAiChatModel(String apiKey, String url) {
  284 + AzureOpenAiAutoConfiguration azureOpenAiAutoConfiguration = new AzureOpenAiAutoConfiguration();
  285 + // 创建 OpenAIClient 对象
  286 + AzureOpenAiConnectionProperties connectionProperties = new AzureOpenAiConnectionProperties();
  287 + connectionProperties.setApiKey(apiKey);
  288 + connectionProperties.setEndpoint(url);
  289 + OpenAIClient openAIClient = azureOpenAiAutoConfiguration.openAIClient(connectionProperties);
  290 + // 获取 AzureOpenAiChatProperties 对象
  291 + AzureOpenAiChatProperties chatProperties = SpringUtil.getBean(AzureOpenAiChatProperties.class);
  292 + return azureOpenAiAutoConfiguration.azureOpenAiChatModel(openAIClient, chatProperties, null, null);
  293 + }
  294 +
  295 + /**
272 * 可参考 {@link OpenAiAutoConfiguration} 296 * 可参考 {@link OpenAiAutoConfiguration}
273 */ 297 */
274 private OpenAiImageModel buildOpenAiImageModel(String openAiToken, String url) { 298 private OpenAiImageModel buildOpenAiImageModel(String openAiToken, String url) {
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/util/AiUtils.java
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
5 import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatOptions; 5 import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatOptions;
6 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatOptions; 6 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatOptions;
7 import com.alibaba.cloud.ai.tongyi.chat.TongYiChatOptions; 7 import com.alibaba.cloud.ai.tongyi.chat.TongYiChatOptions;
  8 +import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
8 import org.springframework.ai.chat.messages.*; 9 import org.springframework.ai.chat.messages.*;
9 import org.springframework.ai.chat.prompt.ChatOptions; 10 import org.springframework.ai.chat.prompt.ChatOptions;
10 import org.springframework.ai.ollama.api.OllamaOptions; 11 import org.springframework.ai.ollama.api.OllamaOptions;
@@ -35,6 +36,9 @@ public class AiUtils { @@ -35,6 +36,9 @@ public class AiUtils {
35 return XingHuoChatOptions.builder().model(model).temperature(temperatureF).maxTokens(maxTokens).build(); 36 return XingHuoChatOptions.builder().model(model).temperature(temperatureF).maxTokens(maxTokens).build();
36 case OPENAI: 37 case OPENAI:
37 return OpenAiChatOptions.builder().withModel(model).withTemperature(temperatureF).withMaxTokens(maxTokens).build(); 38 return OpenAiChatOptions.builder().withModel(model).withTemperature(temperatureF).withMaxTokens(maxTokens).build();
  39 + case AZURE_OPENAI:
  40 + // TODO 芋艿:貌似没 model 字段???!
  41 + return AzureOpenAiChatOptions.builder().withDeploymentName(model).withTemperature(temperatureF).withMaxTokens(maxTokens).build();
38 case OLLAMA: 42 case OLLAMA:
39 return OllamaOptions.create().withModel(model).withTemperature(temperatureF).withNumPredict(maxTokens); 43 return OllamaOptions.create().withModel(model).withTemperature(temperatureF).withNumPredict(maxTokens);
40 default: 44 default:
yudao-server/src/main/resources/application.yaml
@@ -162,9 +162,13 @@ spring: @@ -162,9 +162,13 @@ spring:
162 secret-key: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK 162 secret-key: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK
163 zhipuai: # 智谱 AI 163 zhipuai: # 智谱 AI
164 api-key: 32f84543e54eee31f8d56b2bd6020573.3vh9idLJZ2ZhxDEs 164 api-key: 32f84543e54eee31f8d56b2bd6020573.3vh9idLJZ2ZhxDEs
165 - openai: 165 + openai: # OpenAI 官方
166 api-key: sk-yzKea6d8e8212c3bdd99f9f44ced1cae37c097e5aa3BTS7z 166 api-key: sk-yzKea6d8e8212c3bdd99f9f44ced1cae37c097e5aa3BTS7z
167 base-url: https://api.gptsapi.net 167 base-url: https://api.gptsapi.net
  168 + azure: # OpenAI 微软
  169 + openai:
  170 + endpoint: https://eastusprejade.openai.azure.com
  171 + api-key: xxx
168 ollama: 172 ollama:
169 base-url: http://127.0.0.1:11434 173 base-url: http://127.0.0.1:11434
170 chat: 174 chat: