diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/QianWenChatClient.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/QianWenChatClient.java index f704dee1c..60b533559 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/QianWenChatClient.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/QianWenChatClient.java @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.ai.chat.*; import cn.iocoder.yudao.framework.ai.chat.messages.MessageType; import cn.iocoder.yudao.framework.ai.chat.prompt.ChatOptions; import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; -import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanOptions; import cn.iocoder.yudao.framework.ai.chatyiyan.exception.YiYanApiException; import com.aliyun.broadscope.bailian.sdk.models.*; import lombok.extern.slf4j.Slf4j; @@ -19,7 +18,6 @@ import reactor.core.publisher.Flux; import java.time.Duration; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; /** diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoApi.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoApi.java index a053884a2..323b8a7b7 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoApi.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoApi.java @@ -39,22 +39,20 @@ public class XingHuoApi { private String appKey; private String secretKey; private WebClient webClient; - private XingHuoChatModel useChatModel; // 创建 WebSocketClient 实例 private ReactorNettyWebSocketClient socketClient = new ReactorNettyWebSocketClient(); - public XingHuoApi(String appId, String appKey, String secretKey, XingHuoChatModel useChatModel) { + public XingHuoApi(String appId, String appKey, String secretKey) { this.appId = appId; this.appKey = appKey; this.secretKey = secretKey; - this.useChatModel = useChatModel; - } - public ResponseEntity chatCompletionEntity(XingHuoChatCompletionRequest request) { + public ResponseEntity chatCompletionEntity(XingHuoChatCompletionRequest request, XingHuoChatModel xingHuoChatModel) { String authUrl; try { - authUrl = getAuthorizationUrl("spark-api.xf-yun.com", useChatModel.getUri()); +// XingHuoChatModel useChatModel; + authUrl = getAuthorizationUrl("spark-api.xf-yun.com", xingHuoChatModel.getUri()); } catch (NoSuchAlgorithmException | InvalidKeyException e) { throw new RuntimeException(e); } @@ -125,10 +123,10 @@ public class XingHuoApi { return "wss://" + host + path + "?" + toParams; } - public Flux chatCompletionStream(XingHuoChatCompletionRequest request) { + public Flux chatCompletionStream(XingHuoChatCompletionRequest request, XingHuoChatModel xingHuoChatModel) { String authUrl; try { - authUrl = getAuthorizationUrl("spark-api.xf-yun.com", useChatModel.getUri()); + authUrl = getAuthorizationUrl("spark-api.xf-yun.com", xingHuoChatModel.getUri()); } catch (NoSuchAlgorithmException | InvalidKeyException e) { throw new RuntimeException(e); } diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoChatClient.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoChatClient.java index 23e85be6d..eef59cac0 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoChatClient.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoChatClient.java @@ -1,13 +1,12 @@ package cn.iocoder.yudao.framework.ai.chatxinghuo; -import cn.iocoder.yudao.framework.ai.chat.ChatClient; -import cn.iocoder.yudao.framework.ai.chat.ChatResponse; -import cn.iocoder.yudao.framework.ai.chat.Generation; -import cn.iocoder.yudao.framework.ai.chat.StreamingChatClient; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.iocoder.yudao.framework.ai.chat.*; +import cn.iocoder.yudao.framework.ai.chat.prompt.ChatOptions; import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; import cn.iocoder.yudao.framework.ai.chatxinghuo.api.XingHuoChatCompletion; import cn.iocoder.yudao.framework.ai.chatxinghuo.api.XingHuoChatCompletionRequest; -import cn.iocoder.yudao.framework.ai.chatxinghuo.exception.XingHuoApiException; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.retry.RetryCallback; @@ -31,16 +30,19 @@ public class XingHuoChatClient implements ChatClient, StreamingChatClient { private XingHuoApi xingHuoApi; + private XingHuoOptions xingHuoOptions; + public final RetryTemplate retryTemplate = RetryTemplate.builder() // 最大重试次数 10 - .maxAttempts(10) - .retryOn(XingHuoApiException.class) + .maxAttempts(3) + .retryOn(ChatException.class) // 最大重试5次,第一次间隔3000ms,第二次3000ms * 2,第三次3000ms * 3,以此类推,最大间隔3 * 60000ms .exponentialBackoff(Duration.ofMillis(3000), 2, Duration.ofMillis(3 * 60000)) .withListener(new RetryListener() { @Override public void onError(RetryContext context, RetryCallback callback, Throwable throwable) { + System.err.println("正在重试... " + ExceptionUtil.getMessage(throwable)); log.warn("重试异常:" + context.getRetryCount(), throwable); } @@ -52,26 +54,67 @@ public class XingHuoChatClient implements ChatClient, StreamingChatClient { this.xingHuoApi = xingHuoApi; } + public XingHuoChatClient(XingHuoApi xingHuoApi, XingHuoOptions xingHuoOptions) { + this.xingHuoApi = xingHuoApi; + this.xingHuoOptions = xingHuoOptions; + } + @Override public ChatResponse call(Prompt prompt) { return this.retryTemplate.execute(ctx -> { // ctx 会有重试的信息 + // 获取 chatOptions 属性 + XingHuoOptions chatOptions = this.getChatOptions(prompt); // 创建 request 请求,stream模式需要供应商支持 - XingHuoChatCompletionRequest request = this.createRequest(prompt, false); + XingHuoChatCompletionRequest request = this.createRequest(prompt, chatOptions); // 调用 callWithFunctionSupport 发送请求 - ResponseEntity response = xingHuoApi.chatCompletionEntity(request); + ResponseEntity response = xingHuoApi.chatCompletionEntity(request, chatOptions.getDomain()); // 获取结果封装 ChatResponse return new ChatResponse(List.of(new Generation(response.getBody().getPayload().getChoices().getText().get(0).getContent()))); }); } - private XingHuoChatCompletionRequest createRequest(Prompt prompt, boolean b) { + @Override + public Flux stream(Prompt prompt) { + // 获取 chatOptions 属性 + XingHuoOptions chatOptions = this.getChatOptions(prompt); + // 创建 request 请求,stream模式需要供应商支持 + XingHuoChatCompletionRequest request = this.createRequest(prompt, chatOptions); + // 发送请求 + Flux response = this.xingHuoApi.chatCompletionStream(request, chatOptions.getDomain()); + return response.map(res -> { + String content = res.getPayload().getChoices().getText().stream() + .map(item -> item.getContent()).collect(Collectors.joining()); + return new ChatResponse(List.of(new Generation(content))); + }); + } + + private XingHuoOptions getChatOptions(Prompt prompt) { + // 两个都为null 则没有配置文件 + if (xingHuoOptions == null && prompt.getOptions() == null) { + throw new ChatException("ChatOptions 未配置参数!"); + } + // 优先使用 Prompt 里面的 ChatOptions + ChatOptions options = xingHuoOptions; + if (prompt.getOptions() != null) { + options = (ChatOptions) prompt.getOptions(); + } + // Prompt 里面是一个 ChatOptions,用户可以随意传入,这里做一下判断 + if (!(options instanceof XingHuoOptions)) { + throw new ChatException("Prompt 传入的不是 XingHuoOptions!"); + } + return (XingHuoOptions) options; + } + + private XingHuoChatCompletionRequest createRequest(Prompt prompt, XingHuoOptions xingHuoOptions) { // 创建 header XingHuoChatCompletionRequest.Header header = new XingHuoChatCompletionRequest.Header().setApp_id(xingHuoApi.getAppId()); // 创建 params - XingHuoChatCompletionRequest.Parameter parameter = new XingHuoChatCompletionRequest.Parameter() - .setChat(new XingHuoChatCompletionRequest.Parameter.Chat().setDomain(xingHuoApi.getUseChatModel().getValue())); + XingHuoChatCompletionRequest.Parameter.Chat chatParameter = new XingHuoChatCompletionRequest.Parameter.Chat(); + BeanUtil.copyProperties(xingHuoOptions, chatParameter); + chatParameter.setDomain(xingHuoOptions.getDomain().getValue()); + XingHuoChatCompletionRequest.Parameter parameter = new XingHuoChatCompletionRequest.Parameter().setChat(chatParameter); // 创建 payload text 信息 XingHuoChatCompletionRequest.Payload.Message.Text text = new XingHuoChatCompletionRequest.Payload.Message.Text(); text.setRole(XingHuoChatCompletionRequest.Payload.Message.Text.Role.USER.getName()); @@ -85,17 +128,4 @@ public class XingHuoChatClient implements ChatClient, StreamingChatClient { .setParameter(parameter) .setPayload(payload); } - - @Override - public Flux stream(Prompt prompt) { - // 创建 request 请求,stream模式需要供应商支持 - XingHuoChatCompletionRequest request = this.createRequest(prompt, false); - // 发送请求 - Flux response = this.xingHuoApi.chatCompletionStream(request); - return response.map(res -> { - String content = res.getPayload().getChoices().getText().stream() - .map(item -> item.getContent()).collect(Collectors.joining()); - return new ChatResponse(List.of(new Generation(content))); - }); - } } diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoOptions.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoOptions.java new file mode 100644 index 000000000..5c539d491 --- /dev/null +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoOptions.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.framework.ai.chatxinghuo; + +import cn.iocoder.yudao.framework.ai.chat.prompt.ChatOptions; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 讯飞星火 + * + * author: fansili + * time: 2024/3/16 20:29 + */ +@Data +@Accessors(chain = true) +public class XingHuoOptions implements ChatOptions { + + /** + * https://www.xfyun.cn/doc/spark/Web.html#_1-%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E + * + * 指定访问的领域: + * general指向V1.5版本; + * generalv2指向V2版本; + * generalv3指向V3版本; + * generalv3.5指向V3.5版本; + * 注意:不同的取值对应的url也不一样! + */ + private XingHuoChatModel domain = XingHuoChatModel.XING_HUO_3_5; + /** + * 取值范围 (0,1] ,默认值0.5 + */ + private Float temperature; + /** + * V1.5取值为[1,4096] + * V2.0、V3.0和V3.5取值为[1,8192],默认为2048。 + */ + private Integer max_tokens; + /** + * 取值为[1,6],默认为4 + */ + private Integer top_k; + /** + * 需要保障用户下的唯一性,用于关联用户会话 + */ + private String chat_id; + + + @Override + public Float getTemperature() { + return null; + } + + @Override + public void setTemperature(Float temperature) { + + } + + @Override + public Float getTopP() { + return null; + } + + @Override + public void setTopP(Float topP) { + + } + + @Override + public Integer getTopK() { + return null; + } + + @Override + public void setTopK(Integer topK) { + + } +} diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/api/XingHuoChatCompletionRequest.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/api/XingHuoChatCompletionRequest.java index 009789cb3..a90697bfc 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/api/XingHuoChatCompletionRequest.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/api/XingHuoChatCompletionRequest.java @@ -45,9 +45,24 @@ public class XingHuoChatCompletionRequest { * generalv3.5指向V3.5版本; * 注意:不同的取值对应的url也不一样! */ - private String domain = "general"; - private Double temperature = 0.5; - private Integer max_tokens = 2048; + private String domain = "generalv3.5"; + /** + * 取值范围 (0,1] ,默认值0.5 + */ + private Float temperature; + /** + * V1.5取值为[1,4096] + * V2.0、V3.0和V3.5取值为[1,8192],默认为2048。 + */ + private Integer max_tokens; + /** + * 取值为[1,6],默认为4 + */ + private Integer top_k; + /** + * 需要保障用户下的唯一性,用于关联用户会话 + */ + private String chat_id; } } diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/exception/XingHuoApiException.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/exception/XingHuoApiException.java deleted file mode 100644 index cde6147c7..000000000 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/exception/XingHuoApiException.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.iocoder.yudao.framework.ai.chatxinghuo.exception; - -/** - * 讯飞星火 exception - * - * author: fansili - * time: 2024/3/11 10:22 - */ -public class XingHuoApiException extends RuntimeException { - - public XingHuoApiException(String message) { - super(message); - } -} diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/QianWenChatClientTests.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/QianWenChatClientTests.java index 14b839747..2c2b44685 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/QianWenChatClientTests.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/QianWenChatClientTests.java @@ -23,9 +23,9 @@ public class QianWenChatClientTests { @Before public void setup() { QianWenApi qianWenApi = new QianWenApi( - "LTAI5tNTVhXW4fLKUjMrr98z", - "ZJ0JQeyjzxxm5CfeTV6k1wNE9UsvZP", - "f0c1088824594f589c8f10567ccd929f_p_efm", + "", + "", + "", null ); qianWenChatClient = new QianWenChatClient( diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/XingHuoChatClientTests.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/XingHuoChatClientTests.java index da8bc9d5d..4a4b06b81 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/XingHuoChatClientTests.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/XingHuoChatClientTests.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoApi; import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatClient; import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatModel; +import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoOptions; import org.junit.Before; import org.junit.Test; import reactor.core.publisher.Flux; @@ -28,9 +29,9 @@ public class XingHuoChatClientTests { new XingHuoApi( "13c8cca6", "cb6415c19d6162cda07b47316fcb0416", - "Y2JiYTIxZjA3MDMxMjNjZjQzYzVmNzdh", - XingHuoChatModel.XING_HUO_3_5 - ) + "Y2JiYTIxZjA3MDMxMjNjZjQzYzVmNzdh" + ), + new XingHuoOptions().setDomain(XingHuoChatModel.XING_HUO_3_5) ); }