【代码优化】AI:完善 DeepSeekChatTests、XingHuoChatModelTests 单测,方便大家快速体验

This commit is contained in:
YunaiV 2024-07-06 17:37:17 +08:00
parent 4daff93313
commit 59c853b54d
10 changed files with 74 additions and 67 deletions

View File

@ -2,11 +2,11 @@ package cn.iocoder.yudao.framework.ai.config;
import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactory; import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactory;
import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactoryImpl; import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactoryImpl;
import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatClient; import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel;
import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatOptions; import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatOptions;
import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi;
import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi; import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatClient; import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatOptions; import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatOptions;
import com.alibaba.cloud.ai.tongyi.TongYiAutoConfiguration; import com.alibaba.cloud.ai.tongyi.TongYiAutoConfiguration;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -34,22 +34,9 @@ public class YudaoAiAutoConfiguration {
// ========== 各种 AI Client 创建 ========== // ========== 各种 AI Client 创建 ==========
@Bean
@ConditionalOnProperty(value = "yudao.ai.xinghuo.enable", havingValue = "true")
public XingHuoChatClient xingHuoChatClient(YudaoAiProperties yudaoAiProperties) {
YudaoAiProperties.XingHuoProperties properties = yudaoAiProperties.getXinghuo();
XingHuoChatOptions options = XingHuoChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topK(properties.getTopK())
.build();
return new XingHuoChatClient(properties.getAppKey(), properties.getSecretKey(), options);
}
@Bean @Bean
@ConditionalOnProperty(value = "yudao.ai.deepseek.enable", havingValue = "true") @ConditionalOnProperty(value = "yudao.ai.deepseek.enable", havingValue = "true")
public DeepSeekChatClient deepSeekChatClient(YudaoAiProperties yudaoAiProperties) { public DeepSeekChatModel deepSeekChatModel(YudaoAiProperties yudaoAiProperties) {
YudaoAiProperties.DeepSeekProperties properties = yudaoAiProperties.getDeepSeek(); YudaoAiProperties.DeepSeekProperties properties = yudaoAiProperties.getDeepSeek();
DeepSeekChatOptions options = DeepSeekChatOptions.builder() DeepSeekChatOptions options = DeepSeekChatOptions.builder()
.model(properties.getModel()) .model(properties.getModel())
@ -57,7 +44,20 @@ public class YudaoAiAutoConfiguration {
.maxTokens(properties.getMaxTokens()) .maxTokens(properties.getMaxTokens())
.topP(properties.getTopP()) .topP(properties.getTopP())
.build(); .build();
return new DeepSeekChatClient(properties.getApiKey(), options); return new DeepSeekChatModel(properties.getApiKey(), options);
}
@Bean
@ConditionalOnProperty(value = "yudao.ai.xinghuo.enable", havingValue = "true")
public XingHuoChatModel xingHuoChatClient(YudaoAiProperties yudaoAiProperties) {
YudaoAiProperties.XingHuoProperties properties = yudaoAiProperties.getXinghuo();
XingHuoChatOptions options = XingHuoChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topK(properties.getTopK())
.build();
return new XingHuoChatModel(properties.getAppKey(), properties.getSecretKey(), options);
} }
@Bean @Bean

View File

@ -13,16 +13,16 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@Data @Data
public class YudaoAiProperties { public class YudaoAiProperties {
/**
* 讯飞星火
*/
private XingHuoProperties xinghuo;
/** /**
* DeepSeek * DeepSeek
*/ */
private DeepSeekProperties deepSeek; private DeepSeekProperties deepSeek;
/**
* 讯飞星火
*/
private XingHuoProperties xinghuo;
/** /**
* Midjourney 绘图 * Midjourney 绘图
*/ */

View File

@ -9,10 +9,10 @@ import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.ai.config.YudaoAiAutoConfiguration; import cn.iocoder.yudao.framework.ai.config.YudaoAiAutoConfiguration;
import cn.iocoder.yudao.framework.ai.config.YudaoAiProperties; import cn.iocoder.yudao.framework.ai.config.YudaoAiProperties;
import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatClient; import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel;
import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi;
import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi; import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatClient; import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel;
import com.alibaba.cloud.ai.tongyi.TongYiAutoConfiguration; import com.alibaba.cloud.ai.tongyi.TongYiAutoConfiguration;
import com.alibaba.cloud.ai.tongyi.TongYiConnectionProperties; import com.alibaba.cloud.ai.tongyi.TongYiConnectionProperties;
import com.alibaba.cloud.ai.tongyi.chat.TongYiChatModel; import com.alibaba.cloud.ai.tongyi.chat.TongYiChatModel;
@ -59,10 +59,10 @@ public class AiModelFactoryImpl implements AiModelFactory {
return buildTongYiChatModel(apiKey); return buildTongYiChatModel(apiKey);
case YI_YAN: case YI_YAN:
return buildYiYanChatModel(apiKey); return buildYiYanChatModel(apiKey);
case XING_HUO:
return buildXingHuoChatClient(apiKey);
case DEEP_SEEK: case DEEP_SEEK:
return buildDeepSeekChatClient(apiKey); return buildDeepSeekChatModel(apiKey);
case XING_HUO:
return buildXingHuoChatModel(apiKey);
case OPENAI: case OPENAI:
return buildOpenAiChatModel(apiKey, url); return buildOpenAiChatModel(apiKey, url);
case OLLAMA: case OLLAMA:
@ -82,7 +82,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
case YI_YAN: case YI_YAN:
return SpringUtil.getBean(QianFanChatModel.class); return SpringUtil.getBean(QianFanChatModel.class);
case XING_HUO: case XING_HUO:
return SpringUtil.getBean(XingHuoChatClient.class); return SpringUtil.getBean(XingHuoChatModel.class);
case OPENAI: case OPENAI:
return SpringUtil.getBean(OpenAiChatModel.class); return SpringUtil.getBean(OpenAiChatModel.class);
case OLLAMA: case OLLAMA:
@ -112,7 +112,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
case OPENAI: case OPENAI:
return buildOpenAiImageModel(apiKey, url); return buildOpenAiImageModel(apiKey, url);
case STABLE_DIFFUSION: case STABLE_DIFFUSION:
return buildStabilityAiImageClient(apiKey, url); return buildStabilityAiImageModel(apiKey, url);
default: default:
throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform)); throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
} }
@ -168,6 +168,24 @@ public class AiModelFactoryImpl implements AiModelFactory {
return new QianFanChatModel(qianFanApi); return new QianFanChatModel(qianFanApi);
} }
/**
* 可参考 {@link YudaoAiAutoConfiguration#deepSeekChatModel(YudaoAiProperties)}
*/
private static DeepSeekChatModel buildDeepSeekChatModel(String apiKey) {
return new DeepSeekChatModel(apiKey);
}
/**
* 可参考 {@link YudaoAiAutoConfiguration#xingHuoChatClient(YudaoAiProperties)}
*/
private static XingHuoChatModel buildXingHuoChatModel(String key) {
List<String> keys = StrUtil.split(key, '|');
Assert.equals(keys.size(), 3, "XingHuoChatClient 的密钥需要 (appid|appKey|secretKey) 格式");
String appKey = keys.get(1);
String secretKey = keys.get(2);
return new XingHuoChatModel(appKey, secretKey);
}
/** /**
* 可参考 {@link OpenAiAutoConfiguration} * 可参考 {@link OpenAiAutoConfiguration}
*/ */
@ -194,22 +212,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
return new OllamaChatModel(ollamaApi); return new OllamaChatModel(ollamaApi);
} }
/** private StabilityAiImageModel buildStabilityAiImageModel(String apiKey, String url) {
* 可参考 {@link YudaoAiAutoConfiguration#xingHuoChatClient(YudaoAiProperties)}
*/
private static XingHuoChatClient buildXingHuoChatClient(String key) {
List<String> keys = StrUtil.split(key, '|');
Assert.equals(keys.size(), 3, "XingHuoChatClient 的密钥需要 (appid|appKey|secretKey) 格式");
String appKey = keys.get(1);
String secretKey = keys.get(2);
return new XingHuoChatClient(appKey, secretKey);
}
private static DeepSeekChatClient buildDeepSeekChatClient(String apiKey) {
return new DeepSeekChatClient(apiKey);
}
private StabilityAiImageModel buildStabilityAiImageClient(String apiKey, String url) {
url = StrUtil.blankToDefault(url, StabilityAiApi.DEFAULT_BASE_URL); url = StrUtil.blankToDefault(url, StabilityAiApi.DEFAULT_BASE_URL);
StabilityAiApi stabilityAiApi = new StabilityAiApi(apiKey, StabilityAiApi.DEFAULT_IMAGE_MODEL, url); StabilityAiApi stabilityAiApi = new StabilityAiApi(apiKey, StabilityAiApi.DEFAULT_IMAGE_MODEL, url);
return new StabilityAiImageModel(stabilityAiApi); return new StabilityAiImageModel(stabilityAiApi);

View File

@ -29,7 +29,7 @@ import static cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatOpti
* @author fansili * @author fansili
*/ */
@Slf4j @Slf4j
public class DeepSeekChatClient implements ChatModel { public class DeepSeekChatModel implements ChatModel {
private static final String BASE_URL = "https://api.deepseek.com"; private static final String BASE_URL = "https://api.deepseek.com";
@ -43,15 +43,15 @@ public class DeepSeekChatClient implements ChatModel {
*/ */
private final OpenAiApi openAiApi; private final OpenAiApi openAiApi;
public DeepSeekChatClient(String apiKey) { public DeepSeekChatModel(String apiKey) {
this(apiKey, DeepSeekChatOptions.builder().model(MODEL_DEFAULT).temperature(0.7F).build()); this(apiKey, DeepSeekChatOptions.builder().model(MODEL_DEFAULT).temperature(0.7F).build());
} }
public DeepSeekChatClient(String apiKey, DeepSeekChatOptions options) { public DeepSeekChatModel(String apiKey, DeepSeekChatOptions options) {
this(apiKey, options, RetryUtils.DEFAULT_RETRY_TEMPLATE); this(apiKey, options, RetryUtils.DEFAULT_RETRY_TEMPLATE);
} }
public DeepSeekChatClient(String apiKey, DeepSeekChatOptions options, RetryTemplate retryTemplate) { public DeepSeekChatModel(String apiKey, DeepSeekChatOptions options, RetryTemplate retryTemplate) {
Assert.notEmpty(apiKey, "apiKey 不能为空"); Assert.notEmpty(apiKey, "apiKey 不能为空");
Assert.notNull(options, "options 不能为空"); Assert.notNull(options, "options 不能为空");
Assert.notNull(retryTemplate, "retryTemplate 不能为空"); Assert.notNull(retryTemplate, "retryTemplate 不能为空");

View File

@ -29,7 +29,7 @@ import static cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatOption
* @author fansili * @author fansili
*/ */
@Slf4j @Slf4j
public class XingHuoChatClient implements ChatModel { public class XingHuoChatModel implements ChatModel {
private static final String BASE_URL = "https://spark-api-open.xf-yun.com"; private static final String BASE_URL = "https://spark-api-open.xf-yun.com";
@ -43,16 +43,16 @@ public class XingHuoChatClient implements ChatModel {
*/ */
private final OpenAiApi openAiApi; private final OpenAiApi openAiApi;
public XingHuoChatClient(String apiKey, String secretKey) { public XingHuoChatModel(String apiKey, String secretKey) {
this(apiKey, secretKey, this(apiKey, secretKey,
XingHuoChatOptions.builder().model(MODEL_DEFAULT).temperature(0.7F).build()); XingHuoChatOptions.builder().model(MODEL_DEFAULT).temperature(0.7F).build());
} }
public XingHuoChatClient(String apiKey, String secretKey, XingHuoChatOptions options) { public XingHuoChatModel(String apiKey, String secretKey, XingHuoChatOptions options) {
this(apiKey, secretKey, options, RetryUtils.DEFAULT_RETRY_TEMPLATE); this(apiKey, secretKey, options, RetryUtils.DEFAULT_RETRY_TEMPLATE);
} }
public XingHuoChatClient(String apiKey, String secretKey, XingHuoChatOptions options, RetryTemplate retryTemplate) { public XingHuoChatModel(String apiKey, String secretKey, XingHuoChatOptions options, RetryTemplate retryTemplate) {
Assert.notEmpty(apiKey, "apiKey 不能为空"); Assert.notEmpty(apiKey, "apiKey 不能为空");
Assert.notEmpty(secretKey, "secretKey 不能为空"); Assert.notEmpty(secretKey, "secretKey 不能为空");
Assert.notNull(options, "options 不能为空"); Assert.notNull(options, "options 不能为空");

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.framework.ai.chat; package cn.iocoder.yudao.framework.ai.chat;
import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatClient; import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.SystemMessage;
@ -13,13 +13,13 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* {@link DeepSeekChatClient} 集成测试 * {@link DeepSeekChatModel} 集成测试
* *
* @author 芋道源码 * @author 芋道源码
*/ */
public class DeepSeekChatTests { public class DeepSeekChatModelTests {
private final DeepSeekChatClient chatModel = new DeepSeekChatClient("sk-e94db327cc7d457d99a8de8810fc6b12"); private final DeepSeekChatModel chatModel = new DeepSeekChatModel("sk-e94db327cc7d457d99a8de8810fc6b12");
@Test @Test
public void testCall() { public void testCall() {

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.framework.ai.chat; package cn.iocoder.yudao.framework.ai.chat;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatClient; import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.Message;
@ -17,7 +17,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* {@link XingHuoChatClient} 集成测试 * {@link XingHuoChatModel} 集成测试
* *
* @author 芋道源码 * @author 芋道源码
*/ */

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.framework.ai.chat; package cn.iocoder.yudao.framework.ai.chat;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatClient; import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.SystemMessage;
@ -13,13 +13,13 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* {@link XingHuoChatClient} 集成测试 * {@link XingHuoChatModel} 集成测试
* *
* @author fansili * @author fansili
*/ */
public class XingHuoChatClientTests { public class XingHuoChatModelTests {
private final XingHuoChatClient chatModel = new XingHuoChatClient( private final XingHuoChatModel chatModel = new XingHuoChatModel(
"cb6415c19d6162cda07b47316fcb0416", "cb6415c19d6162cda07b47316fcb0416",
"Y2JiYTIxZjA3MDMxMjNjZjQzYzVmNzdh"); "Y2JiYTIxZjA3MDMxMjNjZjQzYzVmNzdh");

View File

@ -19,7 +19,7 @@ import java.util.List;
* *
* @author fansili * @author fansili
*/ */
public class YiYanChatTests { public class YiYanChatModelTests {
private final QianFanApi qianFanApi = new QianFanApi( private final QianFanApi qianFanApi = new QianFanApi(
"qS8k8dYr2nXunagK4SSU8Xjj", "qS8k8dYr2nXunagK4SSU8Xjj",

View File

@ -153,6 +153,9 @@ spring:
spring: spring:
ai: ai:
qianfan: # 文心一言
api-key: x0cuLZ7XsaTCU08vuJWO87Lg
secret-key: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK
ollama: ollama:
base-url: http://127.0.0.1:11434 base-url: http://127.0.0.1:11434
chat: chat:
@ -162,9 +165,6 @@ spring:
base-url: https://api.gptsapi.net base-url: https://api.gptsapi.net
stabilityai: stabilityai:
api-key: sk-e53UqbboF8QJCscYvzJscJxJXoFcFg4iJjl1oqgE7baJETmx api-key: sk-e53UqbboF8QJCscYvzJscJxJXoFcFg4iJjl1oqgE7baJETmx
qianfan: # 文心一言
api-key: x0cuLZ7XsaTCU08vuJWO87Lg
secret-key: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK
cloud: cloud:
ai: ai:
tongyi: # 通义千问 tongyi: # 通义千问
@ -173,6 +173,10 @@ spring:
yudao: yudao:
ai: ai:
deep-seek:
enable: true
api-key: sk-e94db327cc7d457d99a8de8810fc6b12
model: deepseek-chat
xinghuo: xinghuo:
enable: true enable: true
appId: 13c8cca6 appId: 13c8cca6