Explorar o código

适配讯飞星火 chatOptions

cherishsince hai 1 ano
pai
achega
94e9ee9590

+ 0 - 2
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;
 
 /**

+ 6 - 8
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<XingHuoChatCompletion> chatCompletionEntity(XingHuoChatCompletionRequest request) {
+    public ResponseEntity<XingHuoChatCompletion> 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<XingHuoChatCompletion> chatCompletionStream(XingHuoChatCompletionRequest request) {
+    public Flux<XingHuoChatCompletion> 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);
         }

+ 55 - 25
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 <T extends Object, E extends Throwable> void onError(RetryContext context,
                                                                             RetryCallback<T, E> 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<XingHuoChatCompletion> response = xingHuoApi.chatCompletionEntity(request);
+            ResponseEntity<XingHuoChatCompletion> 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<ChatResponse> stream(Prompt prompt) {
+        // 获取 chatOptions 属性
+        XingHuoOptions chatOptions = this.getChatOptions(prompt);
+        // 创建 request 请求,stream模式需要供应商支持
+        XingHuoChatCompletionRequest request = this.createRequest(prompt, chatOptions);
+        // 发送请求
+        Flux<XingHuoChatCompletion> 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<ChatResponse> stream(Prompt prompt) {
-        // 创建 request 请求,stream模式需要供应商支持
-        XingHuoChatCompletionRequest request = this.createRequest(prompt, false);
-        // 发送请求
-        Flux<XingHuoChatCompletion> 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)));
-        });
-    }
 }

+ 76 - 0
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) {
+
+    }
+}

+ 18 - 3
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;
         }
     }
 

+ 0 - 14
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/exception/XingHuoApiException.java

@@ -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);
-    }
-}

+ 3 - 3
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(

+ 4 - 3
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)
         );
     }