diff --git a/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfig.java b/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfig.java index dffcad977..8efbbca59 100644 --- a/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfig.java +++ b/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfig.java @@ -110,4 +110,36 @@ public interface AIConfig { */ Map getAdditionalConfigMap(); + /** + * 设置连接超时时间 + * + * @param timeout 连接超时时间 + * @since 5.8.39 + */ + void setTimeout(int timeout); + + /** + * 获取连接超时时间 + * + * @return timeout + * @since 5.8.39 + */ + int getTimeout(); + + /** + * 设置读取超时时间 + * + * @param readTimeout 连接超时时间 + * @since 5.8.39 + */ + void setReadTimeout(int readTimeout); + + /** + * 获取读取超时时间 + * + * @return readTimeout + * @since 5.8.39 + */ + int getReadTimeout(); + } diff --git a/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigBuilder.java b/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigBuilder.java index 9eb1698ab..4065056ac 100644 --- a/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigBuilder.java +++ b/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigBuilder.java @@ -106,6 +106,34 @@ public class AIConfigBuilder { return this; } + /** + * 设置连接超时时间,不设置为默认值 + * + * @param timeout 超时时间 + * @return config + * @since 5.8.39 + */ + public synchronized AIConfigBuilder setTimout(final int timeout) { + if (timeout > 0) { + config.setTimeout(timeout); + } + return this; + } + + /** + * 设置读取超时时间,不设置为默认值 + * + * @param readTimout 取超时时间 + * @return config + * @since 5.8.39 + */ + public synchronized AIConfigBuilder setReadTimout(final int readTimout) { + if (readTimout > 0) { + config.setReadTimeout(readTimout); + } + return this; + } + /** * 返回config实例 * diff --git a/hutool-ai/src/main/java/cn/hutool/ai/core/BaseAIService.java b/hutool-ai/src/main/java/cn/hutool/ai/core/BaseAIService.java index 898a1c943..1106e8bf7 100644 --- a/hutool-ai/src/main/java/cn/hutool/ai/core/BaseAIService.java +++ b/hutool-ai/src/main/java/cn/hutool/ai/core/BaseAIService.java @@ -59,7 +59,7 @@ public class BaseAIService { return HttpRequest.get(config.getApiUrl() + endpoint) .header(Header.ACCEPT, "application/json") .header(Header.AUTHORIZATION, "Bearer " + config.getApiKey()) - .timeout(180000) + .timeout(config.getTimeout()) .execute(); } catch (final AIException e) { throw new AIException("Failed to send GET request: " + e.getMessage(), e); @@ -80,7 +80,7 @@ public class BaseAIService { .header(Header.ACCEPT, "application/json") .header(Header.AUTHORIZATION, "Bearer " + config.getApiKey()) .body(paramJson) - .timeout(180000) + .timeout(config.getTimeout()) .execute(); } catch (final AIException e) { throw new AIException("Failed to send POST request:" + e.getMessage(), e); @@ -103,7 +103,7 @@ public class BaseAIService { .header(Header.ACCEPT, "application/json") .header(Header.AUTHORIZATION, "Bearer " + config.getApiKey()) .form(paramMap) - .timeout(180000) + .timeout(config.getTimeout()) .execute(); } catch (final AIException e) { throw new AIException("Failed to send POST request:" + e.getMessage(), e); @@ -128,9 +128,9 @@ public class BaseAIService { connection.setRequestProperty(Header.AUTHORIZATION.getValue(), "Bearer " + config.getApiKey()); connection.setDoOutput(true); //5分钟 - connection.setReadTimeout(300000); + connection.setReadTimeout(config.getReadTimeout()); //3分钟 - connection.setConnectTimeout(180000); + connection.setConnectTimeout(config.getTimeout()); // 发送请求体 try (OutputStream os = connection.getOutputStream()) { String jsonInputString = JSONUtil.toJsonStr(paramMap); diff --git a/hutool-ai/src/main/java/cn/hutool/ai/core/BaseConfig.java b/hutool-ai/src/main/java/cn/hutool/ai/core/BaseConfig.java index 0d5cd0747..3b99e9059 100644 --- a/hutool-ai/src/main/java/cn/hutool/ai/core/BaseConfig.java +++ b/hutool-ai/src/main/java/cn/hutool/ai/core/BaseConfig.java @@ -35,6 +35,10 @@ public class BaseConfig implements AIConfig { protected volatile String model; //动态扩展字段 protected Map additionalConfig = new ConcurrentHashMap<>(); + //连接超时时间 + protected volatile int timeout = 180000; + //读取超时时间 + protected volatile int readTimeout = 300000; @Override public void setApiKey(final String apiKey) { @@ -81,4 +85,23 @@ public class BaseConfig implements AIConfig { return new ConcurrentHashMap<>(additionalConfig); } + @Override + public int getTimeout() { + return timeout; + } + + @Override + public void setTimeout(final int timeout) { + this.timeout = timeout; + } + + @Override + public int getReadTimeout() { + return readTimeout; + } + + @Override + public void setReadTimeout(final int readTimeout) { + this.readTimeout = readTimeout; + } } diff --git a/hutool-ai/src/test/java/cn/hutool/ai/model/deepseek/DeepSeekServiceTest.java b/hutool-ai/src/test/java/cn/hutool/ai/model/deepseek/DeepSeekServiceTest.java index d658265d3..629a3d004 100644 --- a/hutool-ai/src/test/java/cn/hutool/ai/model/deepseek/DeepSeekServiceTest.java +++ b/hutool-ai/src/test/java/cn/hutool/ai/model/deepseek/DeepSeekServiceTest.java @@ -51,7 +51,7 @@ class DeepSeekServiceTest { deepSeekService.chat(prompt, data -> { assertNotNull(data); - if (data.equals("data: [DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) { @@ -92,7 +92,7 @@ class DeepSeekServiceTest { deepSeekService.beta(beta, data -> { assertNotNull(data); - if (data.equals("data: [DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) { diff --git a/hutool-ai/src/test/java/cn/hutool/ai/model/doubao/DoubaoServiceTest.java b/hutool-ai/src/test/java/cn/hutool/ai/model/doubao/DoubaoServiceTest.java index 90195ee02..c7b05756a 100644 --- a/hutool-ai/src/test/java/cn/hutool/ai/model/doubao/DoubaoServiceTest.java +++ b/hutool-ai/src/test/java/cn/hutool/ai/model/doubao/DoubaoServiceTest.java @@ -55,7 +55,7 @@ class DoubaoServiceTest { doubaoService.chat(prompt, data -> { assertNotNull(data); - if (data.equals("data: [DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) { @@ -111,7 +111,7 @@ class DoubaoServiceTest { AtomicBoolean isDone = new AtomicBoolean(false); doubaoService.chatVision(prompt,images, data -> { assertNotNull(data); - if (data.equals("data: [DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) { @@ -188,7 +188,7 @@ class DoubaoServiceTest { AtomicBoolean isDone = new AtomicBoolean(false); doubaoService.botsChat(messages, data -> { assertNotNull(data); - if (data.equals("data: [DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) { @@ -286,7 +286,7 @@ class DoubaoServiceTest { AtomicBoolean isDone = new AtomicBoolean(false); doubaoService.chatContext(messages,contextId, data -> { assertNotNull(data); - if (data.equals("data: [DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) { diff --git a/hutool-ai/src/test/java/cn/hutool/ai/model/grok/GrokServiceTest.java b/hutool-ai/src/test/java/cn/hutool/ai/model/grok/GrokServiceTest.java index c6df69a25..52506006b 100644 --- a/hutool-ai/src/test/java/cn/hutool/ai/model/grok/GrokServiceTest.java +++ b/hutool-ai/src/test/java/cn/hutool/ai/model/grok/GrokServiceTest.java @@ -56,7 +56,7 @@ class GrokServiceTest { grokService.chat(prompt, data -> { assertNotNull(data); - if (data.equals("data: [DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) { @@ -96,7 +96,7 @@ class GrokServiceTest { AtomicBoolean isDone = new AtomicBoolean(false); grokService.message(prompt, 4096, data -> { assertNotNull(data); - if (data.equals("data: [DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) { @@ -130,7 +130,7 @@ class GrokServiceTest { AtomicBoolean isDone = new AtomicBoolean(false); grokService.chatVision(prompt,images, data -> { assertNotNull(data); - if (data.equals("data: [DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) { diff --git a/hutool-ai/src/test/java/cn/hutool/ai/model/hutool/HutoolServiceTest.java b/hutool-ai/src/test/java/cn/hutool/ai/model/hutool/HutoolServiceTest.java index 7ef56d820..c0ffd4638 100644 --- a/hutool-ai/src/test/java/cn/hutool/ai/model/hutool/HutoolServiceTest.java +++ b/hutool-ai/src/test/java/cn/hutool/ai/model/hutool/HutoolServiceTest.java @@ -59,7 +59,7 @@ class HutoolServiceTest { hutoolService.chat(prompt, data -> { assertNotNull(data); - if (data.equals("data: [DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) { @@ -102,7 +102,7 @@ class HutoolServiceTest { AtomicBoolean isDone = new AtomicBoolean(false); hutoolService.chatVision(prompt,images, data -> { assertNotNull(data); - if (data.equals("data:[DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) { diff --git a/hutool-ai/src/test/java/cn/hutool/ai/model/openai/OpenaiServiceTest.java b/hutool-ai/src/test/java/cn/hutool/ai/model/openai/OpenaiServiceTest.java index 7948ab495..d773517d5 100644 --- a/hutool-ai/src/test/java/cn/hutool/ai/model/openai/OpenaiServiceTest.java +++ b/hutool-ai/src/test/java/cn/hutool/ai/model/openai/OpenaiServiceTest.java @@ -62,7 +62,7 @@ class OpenaiServiceTest { openaiService.chat(prompt, data -> { assertNotNull(data); - if (data.equals("data: [DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) { @@ -107,7 +107,7 @@ class OpenaiServiceTest { AtomicBoolean isDone = new AtomicBoolean(false); openaiService.chatVision(prompt,images, data -> { assertNotNull(data); - if (data.equals("data: [DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) { @@ -229,7 +229,7 @@ class OpenaiServiceTest { AtomicBoolean isDone = new AtomicBoolean(false); openaiService.chatReasoning(messages,OpenaiCommon.OpenaiReasoning.HIGH.getEffort(), data -> { assertNotNull(data); - if (data.equals("data: [DONE]")) { + if (data.contains("[DONE]")) { // 设置结束标志 isDone.set(true); } else if (data.contains("\"error\"")) {