Commit c5db930603bdbcb38d832020524da3d4f3352bb9

Authored by YunaiV
1 parent 7dfa7a15

【优化】AI:依赖从文心一言,使用 spring ai 替代接入

Showing 16 changed files with 89 additions and 841 deletions
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
@@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; @@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
7 import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenOptions; 7 import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenOptions;
8 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel; 8 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel;
9 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoOptions; 9 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoOptions;
10 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatOptions;  
11 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 10 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
12 import cn.iocoder.yudao.framework.common.pojo.PageResult; 11 import cn.iocoder.yudao.framework.common.pojo.PageResult;
13 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 12 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@@ -33,6 +32,7 @@ import org.springframework.ai.chat.prompt.ChatOptions; @@ -33,6 +32,7 @@ import org.springframework.ai.chat.prompt.ChatOptions;
33 import org.springframework.ai.chat.prompt.Prompt; 32 import org.springframework.ai.chat.prompt.Prompt;
34 import org.springframework.ai.ollama.api.OllamaOptions; 33 import org.springframework.ai.ollama.api.OllamaOptions;
35 import org.springframework.ai.openai.OpenAiChatOptions; 34 import org.springframework.ai.openai.OpenAiChatOptions;
  35 +import org.springframework.ai.qianfan.QianFanChatOptions;
36 import org.springframework.stereotype.Service; 36 import org.springframework.stereotype.Service;
37 import org.springframework.transaction.annotation.Transactional; 37 import org.springframework.transaction.annotation.Transactional;
38 import reactor.core.publisher.Flux; 38 import reactor.core.publisher.Flux;
@@ -191,8 +191,9 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -191,8 +191,9 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
191 case OLLAMA: 191 case OLLAMA:
192 return OllamaOptions.create().withModel(model).withTemperature(temperatureF).withNumPredict(maxTokens); 192 return OllamaOptions.create().withModel(model).withTemperature(temperatureF).withNumPredict(maxTokens);
193 case YI_YAN: 193 case YI_YAN:
194 - // TODO @fan:增加一个 model  
195 - return new YiYanChatOptions().setTemperature(temperatureF).setMaxOutputTokens(maxTokens); 194 + // TODO 芋艿:貌似 model 只要一设置,就报错
  195 +// return QianFanChatOptions.builder().withModel(model).withTemperature(temperatureF).withMaxTokens(maxTokens).build();
  196 + return QianFanChatOptions.builder().withTemperature(temperatureF).withMaxTokens(maxTokens).build();
196 case XING_HUO: 197 case XING_HUO:
197 return new XingHuoOptions().setChatModel(XingHuoChatModel.valueOfModel(model)).setTemperature(temperatureF) 198 return new XingHuoOptions().setChatModel(XingHuoChatModel.valueOfModel(model)).setTemperature(temperatureF)
198 .setMaxTokens(maxTokens); 199 .setMaxTokens(maxTokens);
yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml
@@ -43,6 +43,13 @@ @@ -43,6 +43,13 @@
43 <artifactId>yudao-common</artifactId> 43 <artifactId>yudao-common</artifactId>
44 </dependency> 44 </dependency>
45 45
  46 + <!-- TODO 芋艿:等 spring-ai 官方发布后,需要把 groupId 改下 -->
  47 + <dependency>
  48 + <groupId>group.springframework.ai</groupId>
  49 + <artifactId>spring-ai-qianfan-spring-boot-starter</artifactId>
  50 + <version>1.1.0</version>
  51 + </dependency>
  52 +
46 <!-- 阿里云 通义千问 --> 53 <!-- 阿里云 通义千问 -->
47 <dependency> 54 <dependency>
48 <groupId>com.alibaba</groupId> 55 <groupId>com.alibaba</groupId>
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java
@@ -11,9 +11,6 @@ import cn.iocoder.yudao.framework.ai.core.model.tongyi.api.QianWenApi; @@ -11,9 +11,6 @@ import cn.iocoder.yudao.framework.ai.core.model.tongyi.api.QianWenApi;
11 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatClient; 11 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatClient;
12 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoOptions; 12 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoOptions;
13 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.api.XingHuoApi; 13 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.api.XingHuoApi;
14 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatClient;  
15 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatOptions;  
16 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanApi;  
17 import lombok.extern.slf4j.Slf4j; 14 import lombok.extern.slf4j.Slf4j;
18 import org.springframework.boot.autoconfigure.AutoConfiguration; 15 import org.springframework.boot.autoconfigure.AutoConfiguration;
19 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 16 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -79,27 +76,6 @@ public class YudaoAiAutoConfiguration { @@ -79,27 +76,6 @@ public class YudaoAiAutoConfiguration {
79 } 76 }
80 77
81 @Bean 78 @Bean
82 - @ConditionalOnProperty(value = "yudao.ai.yiyan.enable", havingValue = "true")  
83 - public YiYanChatClient yiYanChatClient(YudaoAiProperties yudaoAiProperties) {  
84 - YudaoAiProperties.YiYanProperties yiYanProperties = yudaoAiProperties.getYiyan();  
85 - // 转换配置  
86 - YiYanChatOptions yiYanOptions = new YiYanChatOptions();  
87 -// yiYanOptions.setTopK(yiYanProperties.getTopK()); TODO 芋艿:后续弄  
88 - yiYanOptions.setTopP(yiYanProperties.getTopP());  
89 - yiYanOptions.setTemperature(yiYanProperties.getTemperature());  
90 - yiYanOptions.setMaxOutputTokens(yiYanProperties.getMaxTokens());  
91 - return new YiYanChatClient(  
92 - new YiYanApi(  
93 - yiYanProperties.getAppKey(),  
94 - yiYanProperties.getSecretKey(),  
95 - yiYanProperties.getModel(),  
96 - yiYanProperties.getRefreshTokenSecondTime()  
97 - ),  
98 - yiYanOptions  
99 - );  
100 - }  
101 -  
102 - @Bean  
103 @ConditionalOnProperty(value = "yudao.ai.midjourney.enable", havingValue = "true") 79 @ConditionalOnProperty(value = "yudao.ai.midjourney.enable", havingValue = "true")
104 public MidjourneyApi midjourneyApi(YudaoAiProperties yudaoAiProperties) { 80 public MidjourneyApi midjourneyApi(YudaoAiProperties yudaoAiProperties) {
105 YudaoAiProperties.MidjourneyProperties config = yudaoAiProperties.getMidjourney(); 81 YudaoAiProperties.MidjourneyProperties config = yudaoAiProperties.getMidjourney();
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiProperties.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.framework.ai.config; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.framework.ai.config;
3 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; 3 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
4 import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenChatModal; 4 import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenChatModal;
5 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel; 5 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel;
6 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatModel;  
7 import lombok.Data; 6 import lombok.Data;
8 import lombok.experimental.Accessors; 7 import lombok.experimental.Accessors;
9 import org.springframework.ai.autoconfigure.openai.OpenAiImageProperties; 8 import org.springframework.ai.autoconfigure.openai.OpenAiImageProperties;
@@ -23,7 +22,6 @@ public class YudaoAiProperties { @@ -23,7 +22,6 @@ public class YudaoAiProperties {
23 22
24 private QianWenProperties qianwen; 23 private QianWenProperties qianwen;
25 private XingHuoProperties xinghuo; 24 private XingHuoProperties xinghuo;
26 - private YiYanProperties yiyan;  
27 private OpenAiImageProperties openAiImage; 25 private OpenAiImageProperties openAiImage;
28 private MidjourneyProperties midjourney; 26 private MidjourneyProperties midjourney;
29 private SunoProperties suno; 27 private SunoProperties suno;
@@ -63,7 +61,6 @@ public class YudaoAiProperties { @@ -63,7 +61,6 @@ public class YudaoAiProperties {
63 } 61 }
64 62
65 @Data 63 @Data
66 - @Accessors(chain = true)  
67 public static class XingHuoProperties extends ChatProperties { 64 public static class XingHuoProperties extends ChatProperties {
68 65
69 private String appId; 66 private String appId;
@@ -74,28 +71,6 @@ public class YudaoAiProperties { @@ -74,28 +71,6 @@ public class YudaoAiProperties {
74 } 71 }
75 72
76 @Data 73 @Data
77 - @Accessors(chain = true)  
78 - public static class YiYanProperties extends ChatProperties {  
79 -  
80 - /**  
81 - * appKey  
82 - */  
83 - private String appKey;  
84 - /**  
85 - * secretKey  
86 - */  
87 - private String secretKey;  
88 - /**  
89 - * 模型  
90 - */  
91 - private YiYanChatModel model = YiYanChatModel.ERNIE4_3_5_8K;  
92 - /**  
93 - * token 刷新时间(默认 86400 = 24小时)  
94 - */  
95 - private int refreshTokenSecondTime = 86400;  
96 - }  
97 -  
98 - @Data  
99 public static class MidjourneyProperties { 74 public static class MidjourneyProperties {
100 75
101 private String enable; 76 private String enable;
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactoryImpl.java
@@ -16,10 +16,11 @@ import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenChatModal; @@ -16,10 +16,11 @@ import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenChatModal;
16 import cn.iocoder.yudao.framework.ai.core.model.tongyi.api.QianWenApi; 16 import cn.iocoder.yudao.framework.ai.core.model.tongyi.api.QianWenApi;
17 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatClient; 17 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatClient;
18 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.api.XingHuoApi; 18 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.api.XingHuoApi;
19 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatClient;  
20 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanApi;  
21 import org.springframework.ai.autoconfigure.ollama.OllamaAutoConfiguration; 19 import org.springframework.ai.autoconfigure.ollama.OllamaAutoConfiguration;
22 import org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration; 20 import org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration;
  21 +import org.springframework.ai.autoconfigure.qianfan.QianFanAutoConfiguration;
  22 +import org.springframework.ai.autoconfigure.qianfan.QianFanChatProperties;
  23 +import org.springframework.ai.autoconfigure.qianfan.QianFanConnectionProperties;
23 import org.springframework.ai.chat.model.StreamingChatModel; 24 import org.springframework.ai.chat.model.StreamingChatModel;
24 import org.springframework.ai.image.ImageModel; 25 import org.springframework.ai.image.ImageModel;
25 import org.springframework.ai.ollama.OllamaChatModel; 26 import org.springframework.ai.ollama.OllamaChatModel;
@@ -29,8 +30,12 @@ import org.springframework.ai.openai.OpenAiImageModel; @@ -29,8 +30,12 @@ import org.springframework.ai.openai.OpenAiImageModel;
29 import org.springframework.ai.openai.api.ApiUtils; 30 import org.springframework.ai.openai.api.ApiUtils;
30 import org.springframework.ai.openai.api.OpenAiApi; 31 import org.springframework.ai.openai.api.OpenAiApi;
31 import org.springframework.ai.openai.api.OpenAiImageApi; 32 import org.springframework.ai.openai.api.OpenAiImageApi;
  33 +import org.springframework.ai.qianfan.QianFanChatModel;
  34 +import org.springframework.ai.qianfan.api.QianFanApi;
32 import org.springframework.ai.stabilityai.StabilityAiImageModel; 35 import org.springframework.ai.stabilityai.StabilityAiImageModel;
33 import org.springframework.ai.stabilityai.api.StabilityAiApi; 36 import org.springframework.ai.stabilityai.api.StabilityAiApi;
  37 +import org.springframework.retry.support.RetryTemplate;
  38 +import org.springframework.web.client.ResponseErrorHandler;
34 import org.springframework.web.client.RestClient; 39 import org.springframework.web.client.RestClient;
35 40
36 import java.util.List; 41 import java.util.List;
@@ -75,7 +80,7 @@ public class AiClientFactoryImpl implements AiClientFactory { @@ -75,7 +80,7 @@ public class AiClientFactoryImpl implements AiClientFactory {
75 case OLLAMA: 80 case OLLAMA:
76 return SpringUtil.getBean(OllamaChatModel.class); 81 return SpringUtil.getBean(OllamaChatModel.class);
77 case YI_YAN: 82 case YI_YAN:
78 - return SpringUtil.getBean(YiYanChatClient.class); 83 + return SpringUtil.getBean(QianFanChatModel.class);
79 case XING_HUO: 84 case XING_HUO:
80 return SpringUtil.getBean(XingHuoChatClient.class); 85 return SpringUtil.getBean(XingHuoChatClient.class);
81 case QIAN_WEN: 86 case QIAN_WEN:
@@ -153,15 +158,16 @@ public class AiClientFactoryImpl implements AiClientFactory { @@ -153,15 +158,16 @@ public class AiClientFactoryImpl implements AiClientFactory {
153 } 158 }
154 159
155 /** 160 /**
156 - * 可参考 {@link YudaoAiAutoConfiguration#yiYanChatClient(YudaoAiProperties)} 161 + * 可参考 {@link QianFanAutoConfiguration#qianFanChatModel(QianFanConnectionProperties, QianFanChatProperties, RestClient.Builder, RetryTemplate, ResponseErrorHandler)}
157 */ 162 */
158 - private static YiYanChatClient buildYiYanChatClient(String key) { 163 + private static QianFanChatModel buildYiYanChatClient(String key) {
  164 + // TODO 芋艿:貌似目前设置,request 势必会报错
159 List<String> keys = StrUtil.split(key, '|'); 165 List<String> keys = StrUtil.split(key, '|');
160 Assert.equals(keys.size(), 2, "YiYanChatClient 的密钥需要 (appKey|secretKey) 格式"); 166 Assert.equals(keys.size(), 2, "YiYanChatClient 的密钥需要 (appKey|secretKey) 格式");
161 String appKey = keys.get(0); 167 String appKey = keys.get(0);
162 String secretKey = keys.get(1); 168 String secretKey = keys.get(1);
163 - YiYanApi yiYanApi = new YiYanApi(appKey, secretKey, YiYanApi.DEFAULT_CHAT_MODEL, 0);  
164 - return new YiYanChatClient(yiYanApi); 169 + QianFanApi qianFanApi = new QianFanApi(appKey, secretKey);
  170 + return new QianFanChatModel(qianFanApi);
165 } 171 }
166 172
167 /** 173 /**
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/tongyi/QianWenChatClient.java
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.framework.ai.core.model.tongyi; @@ -2,7 +2,6 @@ package cn.iocoder.yudao.framework.ai.core.model.tongyi;
2 2
3 import cn.iocoder.yudao.framework.ai.core.exception.ChatException; 3 import cn.iocoder.yudao.framework.ai.core.exception.ChatException;
4 import cn.iocoder.yudao.framework.ai.core.model.tongyi.api.QianWenApi; 4 import cn.iocoder.yudao.framework.ai.core.model.tongyi.api.QianWenApi;
5 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.exception.YiYanApiException;  
6 import com.alibaba.dashscope.aigc.generation.GenerationResult; 5 import com.alibaba.dashscope.aigc.generation.GenerationResult;
7 import com.alibaba.dashscope.aigc.generation.models.QwenParam; 6 import com.alibaba.dashscope.aigc.generation.models.QwenParam;
8 import com.alibaba.dashscope.common.Message; 7 import com.alibaba.dashscope.common.Message;
@@ -59,7 +58,7 @@ public class QianWenChatClient implements ChatModel, StreamingChatModel { @@ -59,7 +58,7 @@ public class QianWenChatClient implements ChatModel, StreamingChatModel {
59 public final RetryTemplate retryTemplate = RetryTemplate.builder() 58 public final RetryTemplate retryTemplate = RetryTemplate.builder()
60 // 最大重试次数 10 59 // 最大重试次数 10
61 .maxAttempts(10) 60 .maxAttempts(10)
62 - .retryOn(YiYanApiException.class) 61 + .retryOn(Exception.class) // TODO 芋艿:临时这么写
63 // 最大重试5次,第一次间隔3000ms,第二次3000ms * 2,第三次3000ms * 3,以此类推,最大间隔3 * 60000ms 62 // 最大重试5次,第一次间隔3000ms,第二次3000ms * 2,第三次3000ms * 3,以此类推,最大间隔3 * 60000ms
64 .exponentialBackoff(Duration.ofMillis(3000), 2, Duration.ofMillis(3 * 60000)) 63 .exponentialBackoff(Duration.ofMillis(3000), 2, Duration.ofMillis(3 * 60000))
65 .withListener(new RetryListener() { 64 .withListener(new RetryListener() {
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/YiYanChatClient.java deleted
1 -package cn.iocoder.yudao.framework.ai.core.model.yiyan;  
2 -  
3 -import cn.hutool.core.bean.BeanUtil;  
4 -import cn.iocoder.yudao.framework.ai.core.exception.ChatException;  
5 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanApi;  
6 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatCompletionRequest;  
7 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatCompletionResponse;  
8 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.exception.YiYanApiException;  
9 -import lombok.extern.slf4j.Slf4j;  
10 -import org.springframework.ai.chat.client.ChatClient;  
11 -import org.springframework.ai.chat.messages.Message;  
12 -import org.springframework.ai.chat.messages.MessageType;  
13 -import org.springframework.ai.chat.model.ChatModel;  
14 -import org.springframework.ai.chat.model.ChatResponse;  
15 -import org.springframework.ai.chat.model.Generation;  
16 -import org.springframework.ai.chat.model.StreamingChatModel;  
17 -import org.springframework.ai.chat.prompt.ChatOptions;  
18 -import org.springframework.ai.chat.prompt.Prompt;  
19 -import org.springframework.http.ResponseEntity;  
20 -import org.springframework.retry.RetryCallback;  
21 -import org.springframework.retry.RetryContext;  
22 -import org.springframework.retry.RetryListener;  
23 -import org.springframework.retry.support.RetryTemplate;  
24 -import org.springframework.util.Assert;  
25 -import reactor.core.publisher.Flux;  
26 -  
27 -import java.time.Duration;  
28 -import java.util.List;  
29 -import java.util.stream.Collectors;  
30 -  
31 -/**  
32 - * 文心一言的 {@link ChatClient} 实现类  
33 - *  
34 - * @author fansili  
35 - */  
36 -@Slf4j  
37 -public class YiYanChatClient implements ChatModel, StreamingChatModel {  
38 -  
39 - private final YiYanApi yiYanApi;  
40 -  
41 - private YiYanChatOptions defaultOptions;  
42 -  
43 - // TODO @fan:参考 OpenAiChatClient 调整下 retryTemplate;使用 RetryUtils.DEFAULT_RETRY_TEMPLATE;加允许传入?  
44 -  
45 - public YiYanChatClient(YiYanApi yiYanApi) {  
46 - this.yiYanApi = yiYanApi;  
47 - // TODO @fan:这个情况,是不是搞个 defaultOptions;OpenAiChatOptions.builder().withModel(OpenAiApi.DEFAULT_CHAT_MODEL).withTemperature(0.7f).build()  
48 - }  
49 -  
50 - public YiYanChatClient(YiYanApi yiYanApi, YiYanChatOptions defaultOptions) {  
51 - Assert.notNull(yiYanApi, "OllamaApi must not be null");  
52 - Assert.notNull(defaultOptions, "DefaultOptions must not be null");  
53 - this.yiYanApi = yiYanApi;  
54 - this.defaultOptions = defaultOptions;  
55 - }  
56 -  
57 - public final RetryTemplate retryTemplate = RetryTemplate.builder()  
58 - .maxAttempts(10)  
59 - .retryOn(YiYanApiException.class)  
60 - .exponentialBackoff(Duration.ofMillis(3000), 2, Duration.ofMillis(3 * 60000))  
61 - .withListener(new RetryListener() {  
62 -  
63 - @Override  
64 - public <T, E extends Throwable> void onError(RetryContext context,  
65 - RetryCallback<T, E> callback, Throwable throwable) {  
66 - log.warn("重试异常:" + context.getRetryCount(), throwable);  
67 - }  
68 -  
69 - })  
70 - .build();  
71 -  
72 - @Override  
73 - public ChatResponse call(Prompt prompt) {  
74 - YiYanChatCompletionRequest request = createRequest(prompt, false);  
75 - return this.retryTemplate.execute(ctx -> {  
76 - // 发送请求  
77 - ResponseEntity<YiYanChatCompletionResponse> response = yiYanApi.chatCompletionEntity(request);  
78 - // 获取结果封装 ChatResponse  
79 - YiYanChatCompletionResponse chatCompletion = response.getBody();  
80 - if (chatCompletion == null) {  
81 - log.warn("No chat completion returned for prompt: {}", prompt);  
82 - return new ChatResponse(List.of());  
83 - } else {  
84 - // TODO @fan:chatResponseMetadata,参考 OpenAiChatResponseMetadata.from(completionEntity.getBody())  
85 - return new ChatResponse(List.of(new Generation(chatCompletion.getResult())));  
86 - }  
87 - });  
88 - }  
89 -  
90 - @Override  
91 - public ChatOptions getDefaultOptions() {  
92 - // TODO 芋艿:需要跟进下  
93 - throw new UnsupportedOperationException();  
94 - }  
95 -  
96 - @Override  
97 - public Flux<ChatResponse> stream(Prompt prompt) {  
98 - YiYanChatCompletionRequest request = this.createRequest(prompt, true);  
99 - return this.retryTemplate.execute(ctx -> {  
100 - // 调用 callWithFunctionSupport 发送请求  
101 - Flux<YiYanChatCompletionResponse> response = this.yiYanApi.chatCompletionStream(request);  
102 - return response.map(chunk -> {  
103 - // TODO @fan:ChatResponseMetadata chatResponseMetadata  
104 - return new ChatResponse(List.of(new Generation(chunk.getResult())));  
105 - });  
106 - });  
107 - }  
108 -  
109 - private YiYanChatCompletionRequest createRequest(Prompt prompt, boolean stream) {  
110 - // 参考 https://cloud.baidu.com/doc/WENXINWORKSHOP/s/clntwmv7t 文档,system 是独立字段  
111 - // 1.1 获取 user 和 assistant  
112 - List<YiYanChatCompletionRequest.Message> messageList = prompt.getInstructions().stream()  
113 - // 过滤 system  
114 - .filter(msg -> MessageType.SYSTEM != msg.getMessageType())  
115 - .map(message -> new YiYanChatCompletionRequest.Message()  
116 - .setRole(message.getMessageType().getValue()).setContent(message.getContent())  
117 - ).toList();  
118 - // 1.2 获取 system  
119 - String systemPrompt = prompt.getInstructions().stream()  
120 - .filter(message -> MessageType.SYSTEM == message.getMessageType())  
121 - .map(Message::getContent)  
122 - .collect(Collectors.joining());  
123 -  
124 - // 3. 创建 request  
125 - YiYanChatCompletionRequest request = new YiYanChatCompletionRequest(messageList);  
126 - // 复制 YiYanOptions 属性,到 request 中(这里 options 属性和 request 基本保持一致)  
127 - YiYanChatOptions useOptions = getYiYanOptions(prompt);  
128 - BeanUtil.copyProperties(useOptions, request);  
129 - request.setTopP(useOptions.getTopP())  
130 - .setMaxOutputTokens(useOptions.getMaxOutputTokens())  
131 - .setTemperature(useOptions.getTemperature())  
132 - .setSystem(systemPrompt)  
133 - .setStream(stream);  
134 - return request;  
135 - }  
136 -  
137 - // TODO @fan:Options 的处理,参考下 OpenAiChatClient 的 createRequest  
138 - private YiYanChatOptions getYiYanOptions(Prompt prompt) {  
139 - // 两个都为null 则没有配置文件  
140 - if (defaultOptions == null && prompt.getOptions() == null) {  
141 - // TODO @fan:IllegalArgumentException 参数更好哈  
142 - throw new ChatException("ChatOptions 未配置参数!");  
143 - }  
144 - // 优先使用 Prompt 里面的 ChatOptions  
145 - ChatOptions options = defaultOptions;  
146 - if (prompt.getOptions() != null) {  
147 - options = (ChatOptions) prompt.getOptions();  
148 - }  
149 - // Prompt 里面是一个 ChatOptions,用户可以随意传入,这里做一下判断  
150 - if (!(options instanceof YiYanChatOptions)) {  
151 - // TODO @fan:IllegalArgumentException 参数更好哈  
152 - // TODO @fan:需要兼容 ChatOptionsBuilder 创建出来的  
153 - throw new ChatException("Prompt 传入的不是 YiYanOptions!");  
154 - }  
155 - // 转换 YiYanOptions  
156 - return (YiYanChatOptions) options;  
157 - }  
158 -  
159 -}  
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/YiYanChatOptions.java deleted
1 -package cn.iocoder.yudao.framework.ai.core.model.yiyan;  
2 -  
3 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatCompletionRequest;  
4 -import lombok.Data;  
5 -import org.springframework.ai.chat.prompt.ChatOptions;  
6 -  
7 -import java.util.List;  
8 -  
9 -/**  
10 - * 文心一言的 {@link ChatOptions} 实现类  
11 - *  
12 - * 字段说明:参考 <a href="https://cloud.baidu.com/doc/WENXINWORKSHOP/s/clntwmv7t">ERNIE-4.0-8K</a>  
13 - *  
14 - * @author fansili  
15 - */  
16 -@Data  
17 -public class YiYanChatOptions implements ChatOptions {  
18 -  
19 - /**  
20 - * functions 函数  
21 - */  
22 - private List<YiYanChatCompletionRequest.Function> functions;  
23 - /**  
24 - * temperature  
25 - */  
26 - private Float temperature;  
27 - /**  
28 - * topP  
29 - */  
30 - private Float topP;  
31 - /**  
32 - * 通过对已生成的token增加惩罚,减少重复生成的现象  
33 - */  
34 - private Float penaltyScore;  
35 - /**  
36 - * stream 模式请求  
37 - */  
38 - private Boolean stream;  
39 - /**  
40 - * system 提示  
41 - */  
42 - private String system;  
43 - /**  
44 - * 生成停止标识,当模型生成结果以stop中某个元素结尾时,停止文本生成  
45 - */  
46 - private List<String> stop;  
47 - /**  
48 - * 是否强制关闭实时搜索功能  
49 - */  
50 - private Boolean disableSearch;  
51 - /**  
52 - * 是否开启上角标返回  
53 - */  
54 - private Boolean enableCitation;  
55 - /**  
56 - * 输出最大 token  
57 - */  
58 - private Integer maxOutputTokens;  
59 - /**  
60 - * 响应格式 text、json_object  
61 - */  
62 - private String responseFormat;  
63 - /**  
64 - * 用户id  
65 - */  
66 - private String userId;  
67 - /**  
68 - * 在函数调用场景下,提示大模型选择指定的函数(非强制),说明:指定的函数名必须在functions中存在  
69 - * tip: ERNIE-4.0-8K 模型没有这个字段  
70 - */  
71 - private String toolChoice;  
72 -  
73 - @Override  
74 - public Float getTemperature() {  
75 - return this.temperature;  
76 - }  
77 -  
78 - @Override  
79 - public Float getTopP() {  
80 - return topP;  
81 - }  
82 -  
83 - /**  
84 - * 百度么有 topK  
85 - */  
86 - @Override  
87 - public Integer getTopK() {  
88 - return null;  
89 - }  
90 -  
91 -}  
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanApi.java deleted
1 -package cn.iocoder.yudao.framework.ai.core.model.yiyan.api;  
2 -  
3 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.exception.YiYanApiException;  
4 -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;  
5 -import org.springframework.http.HttpStatusCode;  
6 -import org.springframework.http.ResponseEntity;  
7 -import org.springframework.web.reactive.function.client.WebClient;  
8 -import reactor.core.publisher.Flux;  
9 -import reactor.core.publisher.Mono;  
10 -  
11 -/**  
12 - * 文心一言 API  
13 - *  
14 - * @author fansili  
15 - */  
16 -public class YiYanApi {  
17 -  
18 - private static final String DEFAULT_BASE_URL = "https://aip.baidubce.com";  
19 -  
20 - private static final String AUTH_2_TOKEN_URI = "/oauth/2.0/token";  
21 -  
22 - public static final YiYanChatModel DEFAULT_CHAT_MODEL = YiYanChatModel.ERNIE4_0;  
23 -  
24 - private final String appKey;  
25 - private final String secretKey;  
26 - /**  
27 - * TODO fan:这个是不是要有个刷新机制哈;如果目前不需要,可以删除掉 refreshTokenSecondTime;整体更简洁;  
28 - */  
29 - private final String token;  
30 - /**  
31 - * token 刷新时间(秒)  
32 - */  
33 - private int refreshTokenSecondTime;  
34 - /**  
35 - * 发送请求 webClient  
36 - */  
37 - private final WebClient webClient;  
38 - /**  
39 - * 使用的模型  
40 - */  
41 - private final YiYanChatModel useChatModel;  
42 -  
43 - // TODO fan:看看是不是去掉 refreshTokenSecondTime 字段  
44 - public YiYanApi(String appKey, String secretKey, YiYanChatModel useChatModel, int refreshTokenSecondTime) {  
45 - this.appKey = appKey;  
46 - this.secretKey = secretKey;  
47 - this.useChatModel = useChatModel;  
48 - this.refreshTokenSecondTime = refreshTokenSecondTime;  
49 - this.webClient = WebClient.builder().baseUrl(DEFAULT_BASE_URL).build();  
50 - // 获取访问令牌  
51 - token = getToken();  
52 - }  
53 -  
54 - /**  
55 - * 获得访问令牌  
56 - *  
57 - * @see <a href="https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Ilkkrb0i5">文档地址</>  
58 - * @return 访问令牌  
59 - */  
60 - private String getToken() {  
61 - ResponseEntity<YiYanAuthResponse> response = this.webClient.post()  
62 - .uri(uriBuilder -> uriBuilder.path(AUTH_2_TOKEN_URI)  
63 - .queryParam("grant_type", "client_credentials")  
64 - .queryParam("client_id", appKey)  
65 - .queryParam("client_secret", secretKey)  
66 - .build()  
67 - )  
68 - .retrieve()  
69 - .toEntity(YiYanAuthResponse.class)  
70 - .block();  
71 - // 检查请求状态  
72 - // TODO @fan:可以使用 response.getStatusCode().is2xxSuccessful()  
73 - if (HttpStatusCode.valueOf(200) != response.getStatusCode()  
74 - || response.getBody() == null) {  
75 - // TODO @fan:可以使用 IllegalStateException 替代;另外,最好打印下返回;方便排错;  
76 - throw new YiYanApiException("一言认证失败! api:https://aip.baidubce.com/oauth/2.0/token 请检查 client_id、client_secret 是否正确!");  
77 - }  
78 - return response.getBody().getAccess_token();  
79 - }  
80 -  
81 - public ResponseEntity<YiYanChatCompletionResponse> chatCompletionEntity(YiYanChatCompletionRequest request) {  
82 - // TODO: 2024/3/10 小范 这里错误信息返回的结构不一样  
83 -// {"error_code":17,"error_msg":"Open api daily request limit reached"}  
84 - return this.webClient.post()  
85 - .uri(uriBuilder  
86 - -> uriBuilder.path(useChatModel.getUri())  
87 - .queryParam("access_token", token)  
88 - .build())  
89 - .body(Mono.just(JsonUtils.toJsonString(request)), String.class)  
90 - .retrieve()  
91 - .toEntity(YiYanChatCompletionResponse.class)  
92 - .block();  
93 - }  
94 -  
95 - public Flux<YiYanChatCompletionResponse> chatCompletionStream(YiYanChatCompletionRequest request) {  
96 - return this.webClient.post()  
97 - .uri(uriBuilder  
98 - -> uriBuilder.path(useChatModel.getUri())  
99 - .queryParam("access_token", token)  
100 - .build())  
101 - .body(Mono.just(request), YiYanChatCompletionRequest.class)  
102 - .retrieve()  
103 - .bodyToFlux(YiYanChatCompletionResponse.class);  
104 - }  
105 -  
106 -}  
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanAuthResponse.java deleted
1 -package cn.iocoder.yudao.framework.ai.core.model.yiyan.api;  
2 -  
3 -import lombok.Data;  
4 -  
5 -// TODO @fan:字段驼峰;字段注释都可以删除,贴个链接就好;  
6 -/**  
7 - * 获取文心一言的 access_token 的 Response  
8 - *  
9 - * @author fansili  
10 - */  
11 -@Data  
12 -public class YiYanAuthResponse {  
13 -  
14 - /**  
15 - * 访问凭证  
16 - */  
17 - private String access_token;  
18 - /**  
19 - * 有效期,Access Token的有效期。  
20 - * 说明:单位是秒,有效期30天  
21 - */  
22 - private int expires_in;  
23 - /**  
24 - * 错误码,说明:响应失败时返回该字段,成功时不返回  
25 - */  
26 - private String error;  
27 - /**  
28 - * 错误描述信息,帮助理解和解决发生的错误  
29 - * 说明:响应失败时返回该字段,成功时不返回  
30 - */  
31 - private String error_description;  
32 - /**  
33 - * 暂时未使用,可忽略  
34 - */  
35 - private String session_key;  
36 - /**  
37 - * 暂时未使用,可忽略  
38 - */  
39 - private String refresh_token;  
40 - /**  
41 - * 暂时未使用,可忽略  
42 - */  
43 - private String scope;  
44 - /**  
45 - * 暂时未使用,可忽略  
46 - */  
47 - private String session_secret;  
48 -}  
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanChatCompletionRequest.java deleted
1 -package cn.iocoder.yudao.framework.ai.core.model.yiyan.api;  
2 -  
3 -import com.fasterxml.jackson.annotation.JsonProperty;  
4 -import lombok.Data;  
5 -  
6 -import java.util.List;  
7 -  
8 -/**  
9 - * 文心一言 Completion Request  
10 - *  
11 - * 百度千帆文档:https://cloud.baidu.com/doc/WENXINWORKSHOP/s/jlil56u11  
12 - *  
13 - * @author fansili  
14 - */  
15 -@Data  
16 -public class YiYanChatCompletionRequest {  
17 -  
18 - public YiYanChatCompletionRequest(List<Message> messages) {  
19 - this.messages = messages;  
20 - }  
21 -  
22 - /**  
23 - * 聊天上下文信息  
24 - */  
25 - private List<Message> messages;  
26 - /**  
27 - * functions 函数  
28 - */  
29 - private List<Function> functions;  
30 - /**  
31 - * temperature  
32 - */  
33 - private Float temperature;  
34 - /**  
35 - * topP  
36 - */  
37 - @JsonProperty("top_p")  
38 - private Float topP;  
39 - /**  
40 - * 通过对已生成的token增加惩罚,减少重复生成的现象  
41 - */  
42 - @JsonProperty("penalty_score")  
43 - private Float penaltyScore;  
44 - /**  
45 - * stream 模式  
46 - */  
47 - private Boolean stream;  
48 - /**  
49 - * system 预设角色  
50 - */  
51 - private String system;  
52 - /**  
53 - * 生成停止标识,当模型生成结果以stop中某个元素结尾时,停止文本生成  
54 - */  
55 - private List<String> stop;  
56 - /**  
57 - * 是否强制关闭实时搜索功能  
58 - */  
59 - @JsonProperty("disable_search")  
60 - private Boolean disableSearch;  
61 - /**  
62 - * 是否开启上角标返回  
63 - */  
64 - @JsonProperty("enable_citation")  
65 - private Boolean enableCitation;  
66 - /**  
67 - * 最大输出 token 数  
68 - */  
69 - @JsonProperty("max_output_tokens")  
70 - private Integer maxOutputTokens;  
71 - /**  
72 - * 返回格式 text、json_object  
73 - */  
74 - @JsonProperty("response_format")  
75 - private String responseFormat;  
76 - /**  
77 - * 用户 id  
78 - */  
79 - @JsonProperty("user_id")  
80 - private String userId;  
81 - /**  
82 - * 在函数调用场景下,提示大模型选择指定的函数(非强制),说明:指定的函数名必须在functions中存在  
83 - * tip: ERNIE-4.0-8K 模型没有这个字段  
84 - */  
85 - @JsonProperty("tool_choice")  
86 - private String toolChoice;  
87 -  
88 -  
89 - @Data  
90 - public static class Message {  
91 -  
92 - private String role;  
93 -  
94 - private String content;  
95 -  
96 - }  
97 -  
98 - @Data  
99 - public static class ToolChoice {  
100 - /**  
101 - * 指定工具类型,function  
102 - * 必填: 是  
103 - */  
104 - private String type;  
105 - /**  
106 - * 指定要使用的函数  
107 - * 必填: 是  
108 - */  
109 - private Function function;  
110 - /**  
111 - * 指定要使用的函数名  
112 - * 必填: 是  
113 - */  
114 - private String name;  
115 - }  
116 -  
117 - @Data  
118 - public static class Function {  
119 - /**  
120 - * 函数名  
121 - * 必填: 是  
122 - */  
123 - private String name;  
124 - /**  
125 - * 函数描述  
126 - * 必填: 是  
127 - */  
128 - private String description;  
129 - /**  
130 - * 函数请求参数,说明:  
131 - * (1)JSON Schema 格式,参考JSON Schema描述  
132 - * (2)如果函数没有请求参数,parameters值格式如下:  
133 - * {"type": "object","properties": {}}  
134 - * 必填: 是  
135 - */  
136 - private String parameters;  
137 - /**  
138 - * 函数响应参数,JSON Schema 格式,参考JSON Schema描述  
139 - * 必填: 否  
140 - */  
141 - private String responses;  
142 - /**  
143 - * function调用的一些历史示例,说明:  
144 - * (1)可以提供正例(正常触发)和反例(无需触发)的example  
145 - * ·正例:从历史请求数据中获取  
146 - * ·反例:  
147 - * 当role = user,不会触发请求的query  
148 - * 当role = assistant,有固定的格式。function_call的name为空,arguments是空对象:"{}",thought可以填固定的:"我不需要调用任何工具"  
149 - * (2)兼容之前的 List(example) 格式  
150 - */  
151 - private String examples;  
152 - }  
153 -  
154 -}  
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanChatCompletionResponse.java deleted
1 -package cn.iocoder.yudao.framework.ai.core.model.yiyan.api;  
2 -  
3 -import lombok.Data;  
4 -  
5 -/**  
6 - * 文心一言 Completion Response  
7 - *  
8 - * 百度链接: https://cloud.baidu.com/doc/WENXINWORKSHOP/s/clntwmv7t  
9 - *  
10 - * @author fansili  
11 - */  
12 -@Data  
13 -public class YiYanChatCompletionResponse {  
14 -  
15 - /**  
16 - * 本轮对话的id  
17 - */  
18 - private String id;  
19 - /**  
20 - * 回包类型,chat.completion:多轮对话返回  
21 - */  
22 - private String object;  
23 - /**  
24 - * 时间戳  
25 - */  
26 - private int created;  
27 - /**  
28 - * 表示当前子句的序号。只有在流式接口模式下会返回该字段  
29 - */  
30 - private int sentence_id;  
31 - /**  
32 - * 表示当前子句是否是最后一句。只有在流式接口模式下会返回该字段  
33 - */  
34 - private boolean is_end;  
35 - /**  
36 - * 当前生成的结果是否被截断  
37 - */  
38 - private boolean is_truncated;  
39 - /**  
40 - * 输出内容标识,说明:  
41 - * · normal:输出内容完全由大模型生成,未触发截断、替换  
42 - * · stop:输出结果命中入参stop中指定的字段后被截断  
43 - * · length:达到了最大的token数,根据EB返回结果is_truncated来截断  
44 - * · content_filter:输出内容被截断、兜底、替换为**等  
45 - */  
46 - private String finish_reason;  
47 - /**  
48 - * 搜索数据,当请求参数enable_citation为true并且触发搜索时,会返回该字段  
49 - */  
50 - private String search_info;  
51 - /**  
52 - * 对话返回结果  
53 - */  
54 - private String result;  
55 - /**  
56 - * 表示用户输入是否存在安全,是否关闭当前会话,清理历史会话信息  
57 - * true:是,表示用户输入存在安全风险,建议关闭当前会话,清理历史会话信息  
58 - * false:否,表示用户输入无安全风险  
59 - */  
60 - private boolean need_clear_history;  
61 - /**  
62 - * 说明:  
63 - * · 0:正常返回  
64 - * · 其他:非正常  
65 - */  
66 - private int flag;  
67 - /**  
68 - * 当need_clear_history为true时,此字段会告知第几轮对话有敏感信息,如果是当前问题,ban_round=-1  
69 - */  
70 - private int ban_round;  
71 - /**  
72 - * token统计信息  
73 - */  
74 - private Usage usage;  
75 -  
76 - @Data  
77 - public static class Usage {  
78 - /**  
79 - * 问题tokens数  
80 - */  
81 - private int prompt_tokens;  
82 - /**  
83 - * 回答tokens数  
84 - */  
85 - private int completion_tokens;  
86 - /**  
87 - * tokens总数  
88 - */  
89 - private int total_tokens;  
90 - }  
91 -  
92 -}  
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanChatModel.java deleted
1 -package cn.iocoder.yudao.framework.ai.core.model.yiyan.api;  
2 -  
3 -import lombok.AllArgsConstructor;  
4 -import lombok.Getter;  
5 -  
6 -/**  
7 - * 文心一言的模型枚举  
8 - *  
9 - * 可参考 <a href="https://cloud.baidu.com/doc/WENXINWORKSHOP/s/clntwmv7t">百度文档</>  
10 - *  
11 - * @author fansili  
12 - */  
13 -@Getter  
14 -@AllArgsConstructor  
15 -public enum YiYanChatModel {  
16 -  
17 - ERNIE4_0("ERNIE 4.0", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro"),  
18 - ERNIE4_3_5_8K("ERNIE-3.5-8K", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions"),  
19 - ERNIE4_3_5_8K_0205("ERNIE-3.5-8K-0205", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-3.5-8k-0205"),  
20 - ERNIE4_3_5_8K_1222("ERNIE-3.5-8K-1222", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-3.5-8k-1222"),  
21 - ERNIE4_BOT_8K("ERNIE-Bot-8K", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie_bot_8k"),  
22 - ERNIE4_3_5_4K_0205("ERNIE-3.5-4K-0205", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-3.5-4k-0205"),  
23 - ;  
24 -  
25 - /**  
26 - * 模型名  
27 - */  
28 - private final String model;  
29 - /**  
30 - * API URL  
31 - */  
32 - private final String uri;  
33 -  
34 - public static YiYanChatModel valueOfModel(String model) {  
35 - for (YiYanChatModel modelEnum : YiYanChatModel.values()) {  
36 - if (modelEnum.getModel().equals(model)) {  
37 - return modelEnum;  
38 - }  
39 - }  
40 - throw new IllegalArgumentException("Invalid MessageType value: " + model);  
41 - }  
42 -}  
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/exception/YiYanApiException.java deleted
1 -package cn.iocoder.yudao.framework.ai.core.model.yiyan.exception;  
2 -  
3 -/**  
4 - * 一言 api 调用异常  
5 - */  
6 -public class YiYanApiException extends RuntimeException {  
7 -  
8 - public YiYanApiException(String message) {  
9 - super(message);  
10 - }  
11 -  
12 - public YiYanApiException(String message, Throwable cause) {  
13 - super(message, cause);  
14 - }  
15 -  
16 -}  
17 \ No newline at end of file 0 \ No newline at end of file
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/YiYanChatTests.java
1 package cn.iocoder.yudao.framework.ai.chat; 1 package cn.iocoder.yudao.framework.ai.chat;
2 2
3 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatClient;  
4 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatOptions;  
5 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanApi;  
6 -import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatModel;  
7 -import org.junit.Before;  
8 -import org.junit.Test;  
9 -import org.springframework.ai.chat.messages.Message;  
10 -import org.springframework.ai.chat.messages.SystemMessage;  
11 -import org.springframework.ai.chat.messages.UserMessage;  
12 -import org.springframework.ai.chat.model.ChatResponse;  
13 -import org.springframework.ai.chat.prompt.Prompt;  
14 -import reactor.core.publisher.Flux;  
15 -  
16 -import java.util.ArrayList;  
17 -import java.util.List;  
18 -import java.util.Scanner; 3 +//import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatClient;
  4 +//import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatOptions;
  5 +//import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanApi;
  6 +//import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatModel;
  7 +//import org.junit.Before;
  8 +//import org.junit.Test;
  9 +//import org.springframework.ai.chat.messages.Message;
  10 +//import org.springframework.ai.chat.messages.SystemMessage;
  11 +//import org.springframework.ai.chat.messages.UserMessage;
  12 +//import org.springframework.ai.chat.model.ChatResponse;
  13 +//import org.springframework.ai.chat.prompt.Prompt;
  14 +//import reactor.core.publisher.Flux;
  15 +//
  16 +//import java.util.ArrayList;
  17 +//import java.util.List;
  18 +//import java.util.Scanner;
19 19
20 // TODO 芋艿:整理单测 20 // TODO 芋艿:整理单测
21 /** 21 /**
@@ -26,49 +26,49 @@ import java.util.Scanner; @@ -26,49 +26,49 @@ import java.util.Scanner;
26 */ 26 */
27 public class YiYanChatTests { 27 public class YiYanChatTests {
28 28
29 - private YiYanChatClient yiYanChatClient;  
30 -  
31 - @Before  
32 - public void setup() {  
33 - YiYanApi yiYanApi = new YiYanApi(  
34 - "x0cuLZ7XsaTCU08vuJWO87Lg",  
35 - "R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK",  
36 - YiYanChatModel.ERNIE4_3_5_8K,  
37 - 86400  
38 - );  
39 - YiYanChatOptions yiYanOptions = new YiYanChatOptions();  
40 - yiYanOptions.setMaxOutputTokens(2048);  
41 - yiYanOptions.setTopP(0.6f);  
42 - yiYanOptions.setTemperature(0.85f);  
43 - yiYanChatClient = new YiYanChatClient(  
44 - yiYanApi,  
45 - yiYanOptions  
46 - );  
47 - }  
48 -  
49 - @Test  
50 - public void callTest() {  
51 -  
52 - // tip: 百度的message 有特殊规则(最后一个message为当前请求的信息,前面的message为历史对话信息)  
53 - // tip: 地址 https://cloud.baidu.com/doc/WENXINWORKSHOP/s/jlil56u11  
54 - List<Message> messages = new ArrayList<>();  
55 - messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景,所有问题都采用文言文回答。"));  
56 - messages.add(new UserMessage("长沙怎么样?"));  
57 -  
58 - ChatResponse call = yiYanChatClient.call(new Prompt(messages));  
59 - System.err.println(call.getResult());  
60 - }  
61 -  
62 - @Test  
63 - public void streamTest() {  
64 - List<Message> messages = new ArrayList<>();  
65 - messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景,所有问题都采用文言文回答。"));  
66 - messages.add(new UserMessage("长沙怎么样?"));  
67 -  
68 - Flux<ChatResponse> fluxResponse = yiYanChatClient.stream(new Prompt(messages));  
69 - fluxResponse.subscribe(chatResponse -> System.err.print(chatResponse.getResult().getOutput().getContent()));  
70 - // 阻止退出  
71 - Scanner scanner = new Scanner(System.in);  
72 - scanner.nextLine();  
73 - } 29 +// private YiYanChatClient yiYanChatClient;
  30 +//
  31 +// @Before
  32 +// public void setup() {
  33 +// YiYanApi yiYanApi = new YiYanApi(
  34 +// "x0cuLZ7XsaTCU08vuJWO87Lg",
  35 +// "R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK",
  36 +// YiYanChatModel.ERNIE4_3_5_8K,
  37 +// 86400
  38 +// );
  39 +// YiYanChatOptions yiYanOptions = new YiYanChatOptions();
  40 +// yiYanOptions.setMaxOutputTokens(2048);
  41 +// yiYanOptions.setTopP(0.6f);
  42 +// yiYanOptions.setTemperature(0.85f);
  43 +// yiYanChatClient = new YiYanChatClient(
  44 +// yiYanApi,
  45 +// yiYanOptions
  46 +// );
  47 +// }
  48 +//
  49 +// @Test
  50 +// public void callTest() {
  51 +//
  52 +// // tip: 百度的message 有特殊规则(最后一个message为当前请求的信息,前面的message为历史对话信息)
  53 +// // tip: 地址 https://cloud.baidu.com/doc/WENXINWORKSHOP/s/jlil56u11
  54 +// List<Message> messages = new ArrayList<>();
  55 +// messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景,所有问题都采用文言文回答。"));
  56 +// messages.add(new UserMessage("长沙怎么样?"));
  57 +//
  58 +// ChatResponse call = yiYanChatClient.call(new Prompt(messages));
  59 +// System.err.println(call.getResult());
  60 +// }
  61 +//
  62 +// @Test
  63 +// public void streamTest() {
  64 +// List<Message> messages = new ArrayList<>();
  65 +// messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景,所有问题都采用文言文回答。"));
  66 +// messages.add(new UserMessage("长沙怎么样?"));
  67 +//
  68 +// Flux<ChatResponse> fluxResponse = yiYanChatClient.stream(new Prompt(messages));
  69 +// fluxResponse.subscribe(chatResponse -> System.err.print(chatResponse.getResult().getOutput().getContent()));
  70 +// // 阻止退出
  71 +// Scanner scanner = new Scanner(System.in);
  72 +// scanner.nextLine();
  73 +// }
74 } 74 }
yudao-server/src/main/resources/application.yaml
@@ -160,19 +160,11 @@ spring: @@ -160,19 +160,11 @@ spring:
160 gemini: 160 gemini:
161 project-id: 1 # TODO 芋艿:缺配置 161 project-id: 1 # TODO 芋艿:缺配置
162 location: 2 162 location: 2
  163 + qianfan: # 文心一言
  164 + api-key: x0cuLZ7XsaTCU08vuJWO87Lg
  165 + secret-key: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK
163 166
164 yudao.ai: 167 yudao.ai:
165 - yiyan:  
166 - enable: true  
167 - aiPlatform: YI_YAN # TODO @fan:建议每个都独立配置属性类  
168 - max-tokens: 1500  
169 - temperature: 0.85  
170 - topP: 0.8  
171 - topK: 0  
172 - appKey: x0cuLZ7XsaTCU08vuJWO87Lg  
173 - secretKey: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK  
174 - refreshTokenSecondTime: 86400  
175 - model: ERNIE4_3_5_8K  
176 xinghuo: 168 xinghuo:
177 enable: true 169 enable: true
178 aiPlatform: XING_HUO # TODO @fan:建议每个都独立配置属性类 170 aiPlatform: XING_HUO # TODO @fan:建议每个都独立配置属性类