Skip to content

Commit a70a9ee

Browse files
committed
🚀release5.8.43
2 parents ecf4a70 + 86ebc4c commit a70a9ee

File tree

90 files changed

+2709
-159
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+2709
-159
lines changed

CHANGELOG.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,42 @@
11

22
# 🚀Changelog
3+
-------------------------------------------------------------------------------------------------------------
4+
# 5.8.43(2026-01-04)
5+
6+
### 🐣新特性
7+
* 【core 】 `ColorUtil`颜色名称DARKGOLD、LIGHTGOLD新增蛇形命名匹配(pr#1400@Github)
8+
* 【core 】 添加`BeanPath`方法中对“*”的处理逻辑(pr#1412@Gitee)
9+
* 【core 】 `StrUtil`添加`reverseByCodePoint`方法(pr#4187@Github)
10+
* 【core 】 `JdkUtil`添加`IS_AT_LEAST_JDK25`
11+
* 【core 】 `HexUtil.toHex`添加对float和double的支持,并提供反向方法(pr#4193@Github)
12+
* 【core 】 增强`BitSetBloomFilter`构造器的参数有效性校验逻辑(pr#4194@Github)
13+
* 【core 】 `HexUtil.isHexNumber`增加空检查(pr#1420@Gitee)
14+
* 【core 】 `BooleanUtil`增加中文、英文及符号布尔值的识别能力(pr#1429@Gitee)
15+
* 【core 】 `DataBetween`类的构造函数中做 defensive copy(pr#1426@Gitee)
16+
* 【core 】 `RadixUtil.decode`添加校验(pr#1422@Gitee)
17+
* 【core 】 `CharUtil.toCloseByNumber`增加下边界检查(pr#1421@Gitee)
18+
* 【ai 】 增加`gemini`支持(pr#4205@Github)
19+
20+
### 🐞Bug修复
21+
* 【core 】 修复`Calculator.conversion`方法计算包含科学计数法表达式的值时逻辑有误,结果不符合预期(pr#4172@Github)
22+
* 【core 】 修复`NumberUtil.getBinaryStr`方法计算Double等丢失小数问题(pr#1411@Gitee)
23+
* 【core 】 修复`MathUtil.multiple`方法在大整数乘法运算中整数溢出风险(pr#4174@Github)
24+
* 【core 】 修复`CharSequenceUtil.move`方法在局部循环位移中输出不符合预期问题(issue#IDD181@Gitee)
25+
* 【bloomFilter】 修复`AbstractFilter``init`方法在`maxValue`小于`machineNum`时导致数组越界异常(pr#4189@Github)
26+
* 【ai 】 修复`Models`枚举命名大小写混用问题(pr#4185@Github)
27+
* 【core 】 修复`ThreadUtil.getMainThread`在JDK25中返回null的问题(pr#1416@Gitee)
28+
* 【core 】 修复`NumberUtil.parseNumber`使用中文逗号导致识别问题(issue#4197@Github)
29+
* 【crypto 】 修复`SecureUtil.hmacSha1``hmacSha256`生成随机密钥时存在逻辑问题(pr#4199@Github)
30+
* 【core 】 修复`StopWatch.stop`时间回拨时计算结果为负的问题(pr#1417@Gitee)
31+
* 【core 】 修复`SplitIter.reset`后无法重新迭代的问题(pr#1418@Gitee)
32+
* 【core 】 修复`StrMatcher`连续变量解析导致的歧义问题(pr#1419@Gitee)
33+
* 【ai 】 修复`BaseAIService`发送请求方法中try/catch块捕获的应该是Exception而不是自定义的AIException(pr#1430@Gitee)
34+
* 【core 】 修复`StrUtil.truncateByByteLength`在限制长度小于...时报错问题(issue#IDFTJS@Gitee)
35+
* 【core 】 修复`Calculator.conversion`方法计算包含%连接一元运算符的计算表达式的结果时逻辑缺陷(pr#4191@Github)
36+
* 【db 】 修复`SqlUtil.PATTERN_IN_CLAUSE`逻辑缺陷导致in语句参数不正确的问题(pr#4203@Github)
37+
* 【json 】 修复`ObjectMapper`过滤器对Bean复制无效的问题(pr#1431@Gitee)
38+
* 【core 】 修复`DateUnit`毫秒转换问题(issue#4209@Github)
39+
340
-------------------------------------------------------------------------------------------------------------
441
# 5.8.42(2025-11-28)
542

hutool-ai/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
<parent>
77
<groupId>cn.hutool</groupId>
88
<artifactId>hutool-parent</artifactId>
9+
<<<<<<< HEAD
910
<version>5.8.43-SNAPSHOT</version>
11+
=======
12+
<version>5.8.43</version>
13+
>>>>>>> v5-dev
1014
</parent>
1115

1216
<artifactId>hutool-ai</artifactId>

hutool-ai/src/main/java/cn/hutool/ai/AIUtil.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import cn.hutool.ai.core.Message;
2222
import cn.hutool.ai.model.deepseek.DeepSeekService;
2323
import cn.hutool.ai.model.doubao.DoubaoService;
24+
import cn.hutool.ai.model.gemini.GeminiService;
2425
import cn.hutool.ai.model.grok.GrokService;
2526
import cn.hutool.ai.model.hutool.HutoolService;
2627
import cn.hutool.ai.model.openai.OpenaiService;
@@ -114,6 +115,17 @@ public static OpenaiService getOpenAIService(final AIConfig config) {
114115
return getAIService(config, OpenaiService.class);
115116
}
116117

118+
/**
119+
* 获取Gemini模型服务
120+
*
121+
* @param config 创建的AI服务模型的配置
122+
* @return GeminiService
123+
* @since 5.8.43
124+
*/
125+
public static GeminiService getGeminiService(final AIConfig config) {
126+
return getAIService(config, GeminiService.class);
127+
}
128+
117129
/**
118130
* AI大模型对话功能
119131
*

hutool-ai/src/main/java/cn/hutool/ai/ModelName.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ public enum ModelName {
4747
/**
4848
* ollama
4949
*/
50-
OLLAMA("ollama");
50+
OLLAMA("ollama"),
51+
/**
52+
* gemini
53+
*/
54+
GEMINI("gemini");
5155

5256
private final String value;
5357

hutool-ai/src/main/java/cn/hutool/ai/Models.java

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,6 @@ public enum Doubao {
109109
DOUBAO_1_5_PRO_32K("doubao-1.5-pro-32k-250115"),
110110
DOUBAO_1_5_PRO_256K("doubao-1.5-pro-256k-250115"),
111111
DOUBAO_1_5_LITE_32K("doubao-1.5-lite-32k-250115"),
112-
DEEPSEEK_R1("deepseek-r1-250120"),
113-
DEEPSEEK_R1_DISTILL_QWEN_32B("deepseek-r1-distill-qwen-32b-250120"),
114-
DEEPSEEK_R1_DISTILL_QWEN_7B("deepseek-r1-distill-qwen-7b-250120"),
115-
DEEPSEEK_V3("deepseek-v3-241226"),
116112
DOUBAO_PRO_4K_240515("doubao-pro-4k-240515"),
117113
DOUBAO_PRO_4K_CHARACTER_240728("doubao-pro-4k-character-240728"),
118114
DOUBAO_PRO_4K_FUNCTIONCALL_240615("doubao-pro-4k-functioncall-240615"),
@@ -127,7 +123,11 @@ public enum Doubao {
127123
DOUBAO_LITE_4K_PRETRAIN_CHARACTER_240516("doubao-lite-4k-pretrain-character-240516"),
128124
DOUBAO_LITE_32K_240828("doubao-lite-32k-240828"),
129125
DOUBAO_LITE_32K_CHARACTER_241015("doubao-lite-32k-character-241015"),
130-
DOUBAO_LITE_128K_240828("240828"),
126+
DOUBAO_LITE_128K_240828("doubao-lite-128k-240828"),
127+
DEEPSEEK_R1("deepseek-r1-250120"),
128+
DEEPSEEK_R1_DISTILL_QWEN_32B("deepseek-r1-distill-qwen-32b-250120"),
129+
DEEPSEEK_R1_DISTILL_QWEN_7B("deepseek-r1-distill-qwen-7b-250120"),
130+
DEEPSEEK_V3("deepseek-v3-241226"),
131131
MOONSHOT_V1_8K("moonshot-v1-8k"),
132132
MOONSHOT_V1_32K("moonshot-v1-32k"),
133133
MOONSHOT_V1_128K("moonshot-v1-128k"),
@@ -141,10 +141,10 @@ public enum Doubao {
141141
DOUBAO_EMBEDDING_TEXT_240715("doubao-embedding-text-240715"),
142142
DOUBAO_EMBEDDING_VISION("doubao-embedding-vision-241215"),
143143
DOUBAO_SEEDREAM_3_0_T2I("doubao-seedream-3-0-t2i-250415"),
144-
Doubao_Seedance_1_0_lite_t2v("doubao-seedance-1-0-lite-t2v-250428"),
145-
Doubao_Seedance_1_0_lite_i2v("doubao-seedance-1-0-lite-i2v-250428"),
146-
Wan2_1_14B_t2v("wan2-1-14b-t2v-250225"),
147-
Wan2_1_14B_i2v("wan2-1-14b-i2v-250225");
144+
DOUBAO_SEEDDANCE_1_0_LITE_T2V("doubao-seedance-1-0-lite-t2v-250428"),
145+
DOUBAO_SEEDDANCE_1_0_lite_I2V("doubao-seedance-1-0-lite-i2v-250428"),
146+
WAN2_1_14B_T2V("wan2-1-14b-t2v-250225"),
147+
WAN2_1_14B_I2V("wan2-1-14b-i2v-250225");
148148

149149
private final String model;
150150

@@ -174,7 +174,7 @@ public enum Grok {
174174
GROK_2_IMAGE_LATEST("grok-2-image-1212"),
175175
GROK_2_IMAGE("grok-2-image-1212"),
176176
GROK_2_IMAGE_1212("grok-2-image-1212"),
177-
grok_2_latest("grok-2-1212"),
177+
GROK_2_LATEST("grok-2-1212"),
178178
GROK_2("grok-2-1212"),
179179
GROK_2_1212("grok-2-1212"),
180180
GROK_2_VISION_1212("grok-2-vision-1212"),
@@ -207,4 +207,42 @@ public String getModel() {
207207
}
208208
}
209209

210+
// Gemini的模型
211+
public enum Gemini {
212+
GEMINI_2_5_PRO_PREVIEW_TTS("gemini-2.5-pro-preview-tts"),
213+
GEMINI_2_5_FLASH_PREVIEW_TTS("gemini-2.5-flash-preview-tts"),
214+
VEO_2_0_GENERATE_001("veo-2.0-generate-001"),
215+
VEO_3_0_FAST_GENERATE_001("veo-3.0-fast-generate-001"),
216+
VEO_3_0_GENERATE_001("veo-3.0-generate-001"),
217+
VEO_3_1_FAST_GENERATE_PREVIEW("veo-3.1-fast-generate-preview"),
218+
VEO_3_1_GENERATE_PREVIEW("veo-3.1-generate-preview"),
219+
IMAGEN_4_0_GENERATE_001("imagen-4.0-generate-001"),
220+
IMAGEN_4_0_ULTRA_GENERATE_001("imagen-4.0-ultra-generate-001"),
221+
IMAGEN_4_0_FAST_GENERATE_001("imagen-4.0-fast-generate-001"),
222+
IMAGEN_3_0_GENERATE_002("imagen-3.0-generate-002"),
223+
GEMINI_3_PRO_PREVIEW("gemini-3-pro-preview"),
224+
GEMINI_3_FLASH("gemini-3-flash"),
225+
GEMINI_2_5_PRO("gemini-2.5-pro"),
226+
GEMINI_2_5_FLASH("gemini-2.5-flash"),
227+
GEMINI_2_5_FLASH_LITE("gemini-2.5-flash-lite"),
228+
GEMINI_2_5_FLASH_IMAGE("gemini-2.5-flash-image"),
229+
GEMINI_2_0_FLASH("gemini-2.0-flash"),
230+
GEMINI_2_0_FLASH_LITE("gemini-2.0-flash-lite"),
231+
GEMINI_2_0_PRO_EXP("gemini-2.0-pro-exp"),
232+
GEMINI_1_5_FLASH("gemini-1.5-flash"),
233+
GEMINI_1_5_PRO("gemini-1.5-pro"),
234+
GEMINI_1_5_FLASH_8B("gemini-1.5-flash-8b"),
235+
GEMINI_1_0_PRO("gemini-1.0-pro");
236+
237+
private final String model;
238+
239+
Gemini(String model) {
240+
this.model = model;
241+
}
242+
243+
public String getModel() {
244+
return model;
245+
}
246+
}
247+
210248
}

hutool-ai/src/main/java/cn/hutool/ai/core/BaseAIService.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ protected HttpResponse sendGet(final String endpoint) {
6666
httpRequest.setProxy(config.getProxy());
6767
}
6868
return httpRequest.execute();
69-
} catch (final AIException e) {
69+
} catch (final Exception e) {
7070
throw new AIException("Failed to send GET request: " + e.getMessage(), e);
7171
}
7272
}
@@ -90,7 +90,7 @@ protected HttpResponse sendPost(final String endpoint, final String paramJson) {
9090
httpRequest.setProxy(config.getProxy());
9191
}
9292
return httpRequest.execute();
93-
} catch (final AIException e) {
93+
} catch (final Exception e) {
9494
throw new AIException("Failed to send POST request:" + e.getMessage(), e);
9595
}
9696

@@ -116,7 +116,7 @@ protected HttpResponse sendFormData(final String endpoint, final Map<String, Obj
116116
httpRequest.setProxy(config.getProxy());
117117
}
118118
return httpRequest.execute();
119-
} catch (final AIException e) {
119+
} catch (final Exception e) {
120120
throw new AIException("Failed to send POST request:" + e.getMessage(), e);
121121
}
122122
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright (c) 2025 Hutool Team and hutool.cn
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package cn.hutool.ai.model.gemini;
18+
19+
/**
20+
* gemini公共类
21+
*
22+
* @author elichow
23+
* @since 5.8.43
24+
*/
25+
public class GeminiCommon {
26+
27+
//要生成的图片数量
28+
public enum GeminiImageCount {
29+
30+
ONE(1),
31+
TWO(2),
32+
THREE(3),
33+
FOUR(4);
34+
35+
private final int count;
36+
37+
GeminiImageCount(int count) {
38+
this.count = count;
39+
}
40+
41+
public int getCount() {
42+
return count;
43+
}
44+
}
45+
46+
//生成的图片大小 (imageSize) - 仅限 Standard 和 Ultra
47+
public enum GeminiImageSize {
48+
49+
SIZE_1K("1K"),
50+
SIZE_2K("2K");
51+
52+
private final String value;
53+
54+
GeminiImageSize(String value) {
55+
this.value = value;
56+
}
57+
58+
public String getValue() {
59+
return value;
60+
}
61+
}
62+
63+
//宽高比
64+
public enum GeminiAspectRatio {
65+
66+
SQUARE("1:1"),
67+
PORTRAIT_3_4("3:4"),
68+
LANDSCAPE_4_3("4:3"),
69+
PORTRAIT_9_16("9:16"),
70+
LANDSCAPE_16_9("16:9");
71+
72+
private final String ratio;
73+
74+
GeminiAspectRatio(String ratio) {
75+
this.ratio = ratio;
76+
}
77+
78+
public String getRatio() {
79+
return ratio;
80+
}
81+
82+
}
83+
84+
//人物生成权限
85+
public enum GeminiPersonGeneration {
86+
87+
DONT_ALLOW("dont_allow"),
88+
ALLOW_ADULT("allow_adult"),
89+
ALLOW_ALL("allow_all");
90+
91+
private final String value;
92+
93+
GeminiPersonGeneration(String value) {
94+
this.value = value;
95+
}
96+
97+
public String getValue() {
98+
return value;
99+
}
100+
}
101+
102+
//生成的视频的时长
103+
public enum GeminiDurationSeconds {
104+
105+
FOUR(4),
106+
SIX(6),
107+
EIGHT(8);
108+
109+
private final Integer value;
110+
111+
GeminiDurationSeconds(Integer value) {
112+
this.value = value;
113+
}
114+
115+
public Integer getValue() {
116+
return value;
117+
}
118+
}
119+
120+
//语音音色
121+
public enum GeminiVoice {
122+
123+
AOEDE("Aoede"),
124+
CHARON("Charon"),
125+
KORE("Kore"),
126+
FENRIR("Fenrir"),
127+
PUCK("Puck");
128+
129+
private final String value;
130+
131+
GeminiVoice(String value) {
132+
this.value = value;
133+
}
134+
135+
public String getValue() {
136+
return value;
137+
}
138+
}
139+
140+
}

0 commit comments

Comments
 (0)