mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-08-18 20:38:02 +08:00
Compare commits
34 Commits
v7-dev
...
fa8f1f2091
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa8f1f2091 | ||
|
|
f5910f9db4 | ||
|
|
6f7d4f1402 | ||
|
|
b05f45a76f | ||
|
|
9fbf8d85d1 | ||
|
|
667915d05c | ||
|
|
6574dd010b | ||
|
|
90b83d16a5 | ||
|
|
8aff7bfb66 | ||
|
|
d2d5e3092f | ||
|
|
bf7777cdc9 | ||
|
|
c64e48e037 | ||
|
|
04a0b342e4 | ||
|
|
8be799e685 | ||
|
|
ea09b76332 | ||
|
|
8595c0a988 | ||
|
|
b0b44e2ec6 | ||
|
|
cdfdf6f5bd | ||
|
|
d98cded437 | ||
|
|
7c74c789e1 | ||
|
|
115b4b91c4 | ||
|
|
e019d98e3e | ||
|
|
fbd6821280 | ||
|
|
cf58e5e41e | ||
|
|
9f76238137 | ||
|
|
b9cedd8798 | ||
|
|
e91dc5b756 | ||
|
|
4f68e8f83e | ||
|
|
4aea2ef471 | ||
|
|
3658d9f7ca | ||
|
|
49e9ede07b | ||
|
|
58789b61f5 | ||
|
|
761c8c1757 | ||
|
|
ca4cdcb80a |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,4 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [Looly]
|
||||
custom: ['https://gitee.com/chinabugotech/hutool']
|
||||
custom: ['https://gitee.com/dromara/hutool', 'https://dromara.gitee.io/donate.html']
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 7.0.0-M1 (2025-05-07)
|
||||
# 6.0.0-M22 (2025-05-07)
|
||||
|
||||
### ❌不兼容特性
|
||||
|
||||
### 🐣新特性
|
||||
|
||||
### 🐞Bug修复
|
||||
* 【http】 修复`HttpClient5Response`无响应体导致的空指针问题(issue#3930@Github)
|
||||
38
README-EN.md
Normal file → Executable file
38
README-EN.md
Normal file → Executable file
@@ -33,11 +33,11 @@
|
||||
<a target="_blank" href='https://gitee.com/dromara/hutool/stargazers'>
|
||||
<img src='https://gitee.com/dromara/hutool/badge/star.svg?theme=gvp' alt='star'/>
|
||||
</a>
|
||||
<a target="_blank" href='https://github.com/chinabugotech/hutool'>
|
||||
<img src="https://img.shields.io/github/stars/chinabugotech/hutool.svg?style=social" alt="github star"/>
|
||||
<a target="_blank" href='https://github.com/dromara/hutool'>
|
||||
<img src="https://img.shields.io/github/stars/dromara/hutool.svg?style=social" alt="github star"/>
|
||||
</a>
|
||||
<a target="_blank" href='https://gitcode.com/chinabugotech/hutool'>
|
||||
<img src="https://gitcode.com/chinabugotech/hutool/star/badge.svg" alt="gitcode star"/>
|
||||
<a target="_blank" href='https://gitcode.com/dromara/hutool'>
|
||||
<img src="https://gitcode.com/dromara/hutool/star/badge.svg" alt="gitcode star"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -126,32 +126,32 @@ Each module can be introduced individually, or all modules can be introduced by
|
||||
### 🍊Maven
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>cn.hutool.v7</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>7.0.0-M2</version>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>6.0.0-M23</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### 🍐Gradle
|
||||
```
|
||||
implementation 'cn.hutool.v7:hutool-all:7.0.0-M2'
|
||||
implementation 'org.dromara.hutool:hutool-all:6.0.0-M23'
|
||||
```
|
||||
|
||||
## 📥Download
|
||||
|
||||
- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/v7/hutool-all/7.0.0-M2/)
|
||||
- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/6.0.0-M23/)
|
||||
|
||||
> 🔔️note:
|
||||
> Hutool 7.x supports JDK17 and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available.
|
||||
> Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available.
|
||||
> If your project uses JDK7, please use Hutool 4.x version.
|
||||
|
||||
### 🚽Compile and install
|
||||
|
||||
Download the entire project source code
|
||||
|
||||
gitee:[https://gitee.com/chinabugotech/hutool](https://gitee.com/chinabugotech/hutool)
|
||||
gitee:[https://gitee.com/dromara/hutool](https://gitee.com/dromara/hutool)
|
||||
|
||||
github:[https://github.com/chinabugotech/hutool](https://github.com/chinabugotech/hutool)
|
||||
github:[https://github.com/dromara/hutool](https://github.com/dromara/hutool)
|
||||
|
||||
```sh
|
||||
cd ${hutool}
|
||||
@@ -168,16 +168,16 @@ Hutool's source code is divided into two branches:
|
||||
|
||||
| branch | description |
|
||||
|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| v7-master | The master branch, the branch used by the release version, is the same as the jar committed to the central repository and does not receive any pr or modifications. |
|
||||
| v7-dev | Development branch, which defaults to the next SNAPSHOT version, accepts modifications or pr |
|
||||
| v6-master | The master branch, the branch used by the release version, is the same as the jar committed to the central repository and does not receive any pr or modifications. |
|
||||
| v6-dev | Development branch, which defaults to the next SNAPSHOT version, accepts modifications or pr |
|
||||
|
||||
### 🐞Provide feedback or suggestions on bugs
|
||||
|
||||
When submitting feedback, please indicate which JDK version, Hutool version, and related dependency library version you are using.
|
||||
|
||||
- [Gitee issue](https://gitee.com/chinabugotech/hutool/issues)
|
||||
- [Github issue](https://github.com/chinabugotech/hutool/issues)
|
||||
- [Gitcode issue](https://gitcode.com/chinabugotech/hutool/issues)
|
||||
- [Gitee issue](https://gitee.com/dromara/hutool/issues)
|
||||
- [Github issue](https://github.com/dromara/hutool/issues)
|
||||
- [Gitcode issue](https://gitcode.com/dromara/hutool/issues)
|
||||
|
||||
### 🧬Principles of PR(pull request)
|
||||
|
||||
@@ -186,13 +186,13 @@ Hutool welcomes anyone to contribute code to Hutool, but the author suffers from
|
||||
1. Improve the comments, especially each new method should follow the Java documentation specification to indicate the method description, parameter description, return value description and other information, if necessary, please add unit tests, if you want, you can also add your name.
|
||||
2. Code indentation according to Eclipse.
|
||||
3. Newly added methods do not use third-party library methods,Unless the method tool is add to the '**extra module**'.
|
||||
4. Please pull request to the `v7-dev` branch. Hutool uses a new branch after 7.x: `v7-master` is the master branch, which indicates the version of the central library that has been released, and this branch does not allow pr or modifications.
|
||||
4. Please pull request to the `v6-dev` branch. Hutool uses a new branch after 5.x: `v6-master` is the master branch, which indicates the version of the central library that has been released, and this branch does not allow pr or modifications.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
## ⭐Star Hutool
|
||||
|
||||
[](https://starchart.cc/chinabugotech/hutool)
|
||||
[](https://starchart.cc/dromara/hutool)
|
||||
|
||||
## 📌WeChat Official Account
|
||||
|
||||
|
||||
61
README.md
Normal file → Executable file
61
README.md
Normal file → Executable file
@@ -9,8 +9,8 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a target="_blank" href="https://search.maven.org/artifact/cn.hutool/hutool-all">
|
||||
<img alt="" src="https://img.shields.io/maven-central/v/cn.hutool/hutool-all.svg?label=Maven%20Central" />
|
||||
<a target="_blank" href="https://search.maven.org/artifact/org.dromara.hutool/hutool-all">
|
||||
<img alt="" src="https://img.shields.io/maven-central/v/org.dromara.hutool/hutool-all.svg?label=Maven%20Central" />
|
||||
</a>
|
||||
<a target="_blank" href="https://www.apache.org/licenses/LICENSE-2.0.html">
|
||||
<img alt="" src="https://img.shields.io/:license-apache2.0-blue.svg?logo=apache" />
|
||||
@@ -18,26 +18,26 @@
|
||||
<a target="_blank" href="https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html">
|
||||
<img alt="" src="https://img.shields.io/badge/JDK-8+-green.svg" />
|
||||
</a>
|
||||
<a target="_blank" href="https://travis-ci.com/chinabugotech/hutool">
|
||||
<img alt="" src="https://travis-ci.com/chinabugotech/hutool.svg?branch=v5-master" />
|
||||
<a target="_blank" href="https://travis-ci.com/dromara/hutool">
|
||||
<img alt="" src="https://travis-ci.com/dromara/hutool.svg?branch=v5-master" />
|
||||
</a>
|
||||
<a href="https://www.codacy.com/gh/chinabugotech/hutool/dashboard?utm_source=github.com&utm_medium=referral&utm_content=chinabugotech/hutool&utm_campaign=Badge_Grade">
|
||||
<a href="https://www.codacy.com/gh/dromara/hutool/dashboard?utm_source=github.com&utm_medium=referral&utm_content=dromara/hutool&utm_campaign=Badge_Grade">
|
||||
<img alt="" src="https://app.codacy.com/project/badge/Grade/8a6897d9de7440dd9de8804c28d2871d"/>
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/cn/hutool">
|
||||
<img alt="" src="https://codecov.io/gh/chinabugotech/hutool/branch/v7-master/graph/badge.svg" />
|
||||
<a href="https://codecov.io/gh/dromara/hutool">
|
||||
<img alt="" src="https://codecov.io/gh/dromara/hutool/branch/v6-master/graph/badge.svg" />
|
||||
</a>
|
||||
<a target="_blank" href="https://gitter.im/hutool/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge">
|
||||
<img alt="" src="https://badges.gitter.im/hutool/Lobby.svg" />
|
||||
</a>
|
||||
<a target="_blank" href='https://gitee.com/chinabugotech/hutool/stargazers'>
|
||||
<img alt="star" src='https://gitee.com/chinabugotech/hutool/badge/star.svg'/>
|
||||
<a target="_blank" href='https://gitee.com/dromara/hutool/stargazers'>
|
||||
<img alt="star" src='https://gitee.com/dromara/hutool/badge/star.svg?theme=gvp'/>
|
||||
</a>
|
||||
<a target="_blank" href='https://github.com/chinabugotech/hutool'>
|
||||
<img alt="github star" src="https://img.shields.io/github/stars/chinabugotech/hutool.svg?style=social"/>
|
||||
<a target="_blank" href='https://github.com/dromara/hutool'>
|
||||
<img alt="github star" src="https://img.shields.io/github/stars/dromara/hutool.svg?style=social"/>
|
||||
</a>
|
||||
<a target="_blank" href='https://gitcode.com/chinabugotech/hutool'>
|
||||
<img src="https://gitcode.com/chinabugotech/hutool/star/badge.svg" alt="gitcode star"/>
|
||||
<a target="_blank" href='https://gitcode.com/dromara/hutool'>
|
||||
<img src="https://gitcode.com/dromara/hutool/star/badge.svg" alt="gitcode star"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -77,14 +77,13 @@
|
||||
|
||||
### ✨版本选择
|
||||
|
||||
Hutool目前主要版本4.x、5.x、6.x、7.x,选择如下:
|
||||
Hutool目前主要版本4.x、5.x、6.x,选择如下:
|
||||
|
||||
| 版本 | jdk | Maven仓库 | 主要特点 |
|
||||
|-----|--------|--------------------------------------------------------------------------------------------------------|-------------------------------------|
|
||||
| 版本 | jdk| Maven仓库 | 主要特点 |
|
||||
|-----|----|--------------------------------------------------------------------------------------------------------|-------------------------------------|
|
||||
| 4.x | jdk1.7 | [cn.hutool/hutool-all/4.x](https://mvnrepository.com/artifact/cn.hutool/hutool-all/4.6.17) | jdk1.7编译 |
|
||||
| 5.x | jdk1.8 | [cn.hutool/hutool-all/5.x ](https://mvnrepository.com/artifact/cn.hutool/hutool-all) | jdk1.8编译,使用JavaEE,适配JDK11、17、21 |
|
||||
| 6.x | jdk1.8 | [org.dromara.hutool/hutool-all/6.x ](https://mvnrepository.com/artifact/org.dromara.hutool/hutool-all) | jdk1.8编译,使用Jakarta EE,适配JDK11、17、21 |
|
||||
| 7.x | jdk17 | [cn.hutool.v7/hutool-all/7.x ](https://mvnrepository.com/artifact/cn.hutool.v7/hutool-all) | jdk17编译,使用Jakarta EE,适配17+ |
|
||||
|
||||
## 🛠️包含组件
|
||||
|
||||
@@ -129,30 +128,30 @@ Hutool目前主要版本4.x、5.x、6.x、7.x,选择如下:
|
||||
```xml
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool.v7</groupId>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>7.0.0-M2</version>
|
||||
<version>6.0.0-M23</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### 🍐Gradle
|
||||
|
||||
```
|
||||
implementation 'cn.hutool.v7:hutool-all:7.0.0-M2'
|
||||
implementation 'org.dromara.hutool:hutool-all:6.0.0-M23'
|
||||
```
|
||||
|
||||
### 📥下载jar
|
||||
|
||||
点击以下链接,下载`hutool-all-X.X.X.jar`即可:
|
||||
|
||||
- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/v7/hutool-all/7.0.0-M2/)
|
||||
- [Maven中央库](https://repo1.maven.org/maven2/org/dromara/hutool/hutool-all/6.0.0-M23/)
|
||||
|
||||
> 🔔️注意
|
||||
> Hutool 7.x支持JDK17,对Android平台没有测试,不能保证所有工具类或工具方法可用。
|
||||
> Hutool 6.x支持JDK8+,对Android平台没有测试,不能保证所有工具类或工具方法可用。
|
||||
|
||||
### 🚽编译安装
|
||||
|
||||
访问Hutool的Gitee主页:[https://gitee.com/chinabugotech/hutool](https://gitee.com/chinabugotech/hutool)
|
||||
访问Hutool的Gitee主页:[https://gitee.com/dromara/hutool](https://gitee.com/dromara/hutool)
|
||||
下载整个项目源码(v6-master或v6-dev分支都可)然后进入Hutool项目目录执行:
|
||||
|
||||
```sh
|
||||
@@ -171,23 +170,23 @@ Hutool的源码分为两个分支,功能如下:
|
||||
|
||||
| 分支 | 作用 |
|
||||
|-----------|--------------------------------------------|
|
||||
| v7-master | 主分支,release版本使用的分支,与中央库提交的jar一致,不接收任何pr或修改 |
|
||||
| v7-dev | 开发分支,默认为下个版本的SNAPSHOT版本,接受修改或pr |
|
||||
| v6-master | 主分支,release版本使用的分支,与中央库提交的jar一致,不接收任何pr或修改 |
|
||||
| v6-dev | 开发分支,默认为下个版本的SNAPSHOT版本,接受修改或pr |
|
||||
|
||||
### 🐞提供bug反馈或建议
|
||||
|
||||
提交问题反馈请说明正在使用的JDK版本呢、Hutool版本和相关依赖库版本。
|
||||
|
||||
- [Gitee issue](https://gitee.com/chinabugotech/hutool/issues)
|
||||
- [Github issue](https://github.com/chinabugotech/hutool/issues)
|
||||
- [Gitcode issue Gitcode问题](https://gitcode.com/chinabugotech/hutool/issues)
|
||||
- [Gitee issue](https://gitee.com/dromara/hutool/issues)
|
||||
- [Github issue](https://github.com/dromara/hutool/issues)
|
||||
- [Gitcode issue Gitcode问题](https://gitcode.com/dromara/hutool/issues)
|
||||
|
||||
### 🧬贡献代码的步骤
|
||||
|
||||
1. 在Gitee、Github或Gitcode上fork项目到自己的repo
|
||||
2. 把fork过去的项目也就是你的项目clone到你的本地
|
||||
3. 修改代码(记得一定要修改v7-dev分支)
|
||||
4. commit后push到自己的库(v7-dev分支)
|
||||
3. 修改代码(记得一定要修改v6-dev分支)
|
||||
4. commit后push到自己的库(v6-dev分支)
|
||||
5. 登录Gitee、Github或Gitcode在你首页可以看到一个 pull request 按钮,点击它,填写一些说明信息,然后提交即可。
|
||||
6. 等待维护者合并
|
||||
|
||||
@@ -210,7 +209,7 @@ Hutool欢迎任何人为Hutool添砖加瓦,贡献代码,不过维护者是
|
||||
|
||||
## ⭐Star Hutool
|
||||
|
||||
[](https://starchart.cc/chinabugotech/hutool)
|
||||
[](https://starchart.cc/dromara/hutool)[](https://starchart.cc/dromara/hutool)
|
||||
|
||||
### GitHub Contributor Over Time
|
||||
[](https://git-contributor.com?chart=contributorOverTime&repo=dromara/hutool)
|
||||
|
||||
13
SECURITY.md
13
SECURITY.md
@@ -0,0 +1,13 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions(支持的版本)
|
||||
|
||||
| Version | Supported |
|
||||
|---------|--------------------|
|
||||
| 6.x.x | :white_check_mark: |
|
||||
|
||||
## Reporting a Vulnerability(报告漏洞)
|
||||
|
||||
如果你发现有安全问题或漏洞,请发送邮件到`loolly@aliyun.com`。
|
||||
|
||||
To report any found security issues or vulnerabilities, please send a mail to `loolly@aliyun.com`.
|
||||
@@ -16,12 +16,12 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
echo -e "\033[32mCheckout to v7-dev\033[0m"
|
||||
git checkout v7-dev
|
||||
echo -e "\033[32mCheckout to v6-dev\033[0m"
|
||||
git checkout v6-dev
|
||||
|
||||
echo -e "\033[32mPush to Github(origin) v7-dev\033[0m"
|
||||
git push origin v7-dev
|
||||
echo -e "\033[32mPush to Gitee v7-dev\033[0m"
|
||||
git push osc v7-dev
|
||||
echo -e "\033[32mPush to Gitcode v7-dev\033[0m"
|
||||
git push gitcode v7-dev
|
||||
echo -e "\033[32mPush to Github(origin) v6-dev\033[0m"
|
||||
git push origin v6-dev
|
||||
echo -e "\033[32mPush to Gitee v6-dev\033[0m"
|
||||
git push osc v6-dev
|
||||
echo -e "\033[32mPush to Gitcode v6-dev\033[0m"
|
||||
git push gitcode v6-dev
|
||||
|
||||
@@ -19,15 +19,15 @@
|
||||
# show Hutool logo
|
||||
"$(dirname ${BASH_SOURCE[0]})"/logo.sh
|
||||
|
||||
echo -e "\033[32mCheckout to v7-master\033[0m"
|
||||
git checkout v7-master
|
||||
echo -e "\033[32mCheckout to v6-master\033[0m"
|
||||
git checkout v6-master
|
||||
|
||||
echo -e "\033[32mMerge v7-dev branch\033[0m"
|
||||
git merge v7-dev -m 'Prepare release'
|
||||
echo -e "\033[32mMerge v6-dev branch\033[0m"
|
||||
git merge v6-dev -m 'Prepare release'
|
||||
|
||||
echo -e "\033[32mPush to Github(origin) v7-master\033[0m"
|
||||
git push origin v7-master
|
||||
echo -e "\033[32mPush to Gitee v7-master\033[0m"
|
||||
git push osc v7-master
|
||||
echo -e "\033[32mPush to Gitcode v7-master\033[0m"
|
||||
git push gitcode v7-master
|
||||
echo -e "\033[32mPush to Github(origin) v6-master\033[0m"
|
||||
git push origin v6-master
|
||||
echo -e "\033[32mPush to Gitee v6-master\033[0m"
|
||||
git push osc v6-master
|
||||
echo -e "\033[32mPush to Gitcode v6-master\033[0m"
|
||||
git push gitcode v6-master
|
||||
|
||||
10
bin/sync.sh
10
bin/sync.sh
@@ -19,10 +19,10 @@
|
||||
# show Hutool logo
|
||||
"$(dirname ${BASH_SOURCE[0]})"/logo.sh
|
||||
|
||||
# 保证当前在v7-dev分支
|
||||
git checkout v7-dev
|
||||
# 保证当前在v6-dev分支
|
||||
git checkout v6-dev
|
||||
|
||||
# 同时同步Gitee、Github和Gitcode的库
|
||||
git pull osc v7-dev
|
||||
git pull origin v7-dev
|
||||
git pull gitcode v7-dev
|
||||
git pull osc v6-dev
|
||||
git pull origin v6-dev
|
||||
git pull gitcode v6-dev
|
||||
|
||||
@@ -1 +1 @@
|
||||
7.0.0-M2
|
||||
6.0.0-M23
|
||||
|
||||
@@ -55,16 +55,6 @@
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<!-- 百度统计 -->
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function () {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?a76bc7a2d60207f04195af1c51cdb9ba";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -1 +1 @@
|
||||
var version = '7.0.0-M2'
|
||||
var version = '6.0.0-M23'
|
||||
@@ -7,9 +7,9 @@
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.hutool.v7</groupId>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>7.0.0-M2</version>
|
||||
<version>6.0.0-M23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-ai</artifactId>
|
||||
@@ -17,29 +17,34 @@
|
||||
<description>Hutool AI大模型封装</description>
|
||||
|
||||
<properties>
|
||||
<Automatic-Module-Name>cn.hutool.v7.ai</Automatic-Module-Name>
|
||||
<Automatic-Module-Name>org.dromara.hutool.ai</Automatic-Module-Name>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.hutool.v7</groupId>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool.v7</groupId>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-log</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool.v7</groupId>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-json</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool.v7</groupId>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-swing</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.doubao;
|
||||
|
||||
import cn.hutool.v7.ai.Models;
|
||||
import cn.hutool.v7.ai.core.BaseConfig;
|
||||
|
||||
/**
|
||||
* Doubao配置类,初始化API接口地址,设置默认的模型
|
||||
*
|
||||
* @author elichow
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class DoubaoConfig extends BaseConfig {
|
||||
|
||||
// 定义API的基础URL,用于和服务器通信
|
||||
private static final String API_URL = "https://ark.cn-beijing.volces.com/api/v3";
|
||||
|
||||
// 定义默认的模型配置,用于初始化配置对象时设定
|
||||
private static final String DEFAULT_MODEL = Models.Doubao.DOUBAO_1_5_LITE_32K.getModel();
|
||||
|
||||
/**
|
||||
* 无参构造函数,用于创建DoubaoConfig对象
|
||||
* 初始化时会设置API_URL和DEFAULT_MODEL
|
||||
*/
|
||||
public DoubaoConfig() {
|
||||
setApiUrl(API_URL);
|
||||
setModel(DEFAULT_MODEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 带有apiKey参数的构造函数,用于创建DoubaoConfig对象并设置API密钥
|
||||
* 初始化时会设置API_URL、DEFAULT_MODEL以及传入的apiKey
|
||||
*
|
||||
* @param apiKey 用户的API密钥,用于验证用户身份
|
||||
*/
|
||||
public DoubaoConfig(final String apiKey) {
|
||||
this(); // 先调用无参构造函数初始化API_URL和DEFAULT_MODEL
|
||||
setApiKey(apiKey); // 设置用户的API密钥
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getModelName() {
|
||||
return "doubao";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.ollama;
|
||||
|
||||
/**
|
||||
* Ollama公共类
|
||||
*
|
||||
* @author yangruoyu-yumeisoft
|
||||
* @since 5.8.40
|
||||
*/
|
||||
public class OllamaCommon {
|
||||
|
||||
/**
|
||||
* Ollama模型格式枚举
|
||||
*/
|
||||
public enum OllamaFormat {
|
||||
/**
|
||||
* JSON格式
|
||||
*/
|
||||
JSON("json"),
|
||||
/**
|
||||
* 无格式
|
||||
*/
|
||||
NONE("");
|
||||
|
||||
private final String format;
|
||||
|
||||
OllamaFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ollama选项常量
|
||||
*/
|
||||
public static class Options {
|
||||
/**
|
||||
* 温度参数
|
||||
*/
|
||||
public static final String TEMPERATURE = "temperature";
|
||||
/**
|
||||
* top_p参数
|
||||
*/
|
||||
public static final String TOP_P = "top_p";
|
||||
/**
|
||||
* top_k参数
|
||||
*/
|
||||
public static final String TOP_K = "top_k";
|
||||
/**
|
||||
* 最大token数
|
||||
*/
|
||||
public static final String NUM_PREDICT = "num_predict";
|
||||
/**
|
||||
* 随机种子
|
||||
*/
|
||||
public static final String SEED = "seed";
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.ollama;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.AIServiceProvider;
|
||||
|
||||
/**
|
||||
* 创建Ollama服务实现类
|
||||
*
|
||||
* @author yangruoyu-yumeisoft
|
||||
* @since 5.8.40
|
||||
*/
|
||||
public class OllamaProvider implements AIServiceProvider {
|
||||
|
||||
@Override
|
||||
public String getServiceName() {
|
||||
return "ollama";
|
||||
}
|
||||
|
||||
@Override
|
||||
public OllamaService create(final AIConfig config) {
|
||||
return new OllamaServiceImpl(config);
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.ollama;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIService;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Ollama特有的功能
|
||||
*
|
||||
* @author yangruoyu-yumeisoft
|
||||
* @since 5.8.40
|
||||
*/
|
||||
public interface OllamaService extends AIService {
|
||||
|
||||
/**
|
||||
* 生成文本补全
|
||||
*
|
||||
* @param prompt 输入提示
|
||||
* @return AI回答
|
||||
* @since 5.8.40
|
||||
*/
|
||||
String generate(String prompt);
|
||||
|
||||
/**
|
||||
* 生成文本补全-SSE流式输出
|
||||
*
|
||||
* @param prompt 输入提示
|
||||
* @param callback 流式数据回调函数
|
||||
* @since 5.8.40
|
||||
*/
|
||||
void generate(String prompt, Consumer<String> callback);
|
||||
|
||||
/**
|
||||
* 生成文本补全(带选项)
|
||||
*
|
||||
* @param prompt 输入提示
|
||||
* @param format 响应格式
|
||||
* @return AI回答
|
||||
* @since 5.8.40
|
||||
*/
|
||||
String generate(String prompt, String format);
|
||||
|
||||
/**
|
||||
* 生成文本补全(带选项)-SSE流式输出
|
||||
*
|
||||
* @param prompt 输入提示
|
||||
* @param format 响应格式
|
||||
* @param callback 流式数据回调函数
|
||||
* @since 5.8.40
|
||||
*/
|
||||
void generate(String prompt, String format, Consumer<String> callback);
|
||||
|
||||
/**
|
||||
* 生成文本嵌入向量
|
||||
*
|
||||
* @param prompt 输入文本
|
||||
* @return 嵌入向量结果
|
||||
* @since 5.8.40
|
||||
*/
|
||||
String embeddings(String prompt);
|
||||
|
||||
/**
|
||||
* 列出本地可用的模型
|
||||
*
|
||||
* @return 模型列表
|
||||
* @since 5.8.40
|
||||
*/
|
||||
String listModels();
|
||||
|
||||
/**
|
||||
* 显示模型信息
|
||||
*
|
||||
* @param modelName 模型名称
|
||||
* @return 模型信息
|
||||
* @since 5.8.40
|
||||
*/
|
||||
String showModel(String modelName);
|
||||
|
||||
/**
|
||||
* 拉取模型
|
||||
*
|
||||
* @param modelName 模型名称
|
||||
* @return 拉取结果
|
||||
* @since 5.8.40
|
||||
*/
|
||||
String pullModel(String modelName);
|
||||
|
||||
/**
|
||||
* 删除模型
|
||||
*
|
||||
* @param modelName 模型名称
|
||||
* @return 删除结果
|
||||
* @since 5.8.40
|
||||
*/
|
||||
String deleteModel(String modelName);
|
||||
|
||||
/**
|
||||
* 复制模型
|
||||
*
|
||||
* @param source 源模型名称
|
||||
* @param destination 目标模型名称
|
||||
* @return 复制结果
|
||||
* @since 5.8.40
|
||||
*/
|
||||
String copyModel(String source, String destination);
|
||||
|
||||
/**
|
||||
* 简化的对话方法
|
||||
*
|
||||
* @param prompt 对话题词
|
||||
* @return AI回答
|
||||
* @since 5.8.40
|
||||
*/
|
||||
default String chat(String prompt) {
|
||||
final List<Message> messages = new ArrayList<>();
|
||||
messages.add(new Message("user", prompt));
|
||||
return chat(messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* 简化的对话方法-SSE流式输出
|
||||
*
|
||||
* @param prompt 对话题词
|
||||
* @param callback 流式数据回调函数
|
||||
* @since 5.8.40
|
||||
*/
|
||||
default void chat(String prompt, Consumer<String> callback) {
|
||||
final List<Message> messages = new ArrayList<>();
|
||||
messages.add(new Message("user", prompt));
|
||||
chat(messages, callback);
|
||||
}
|
||||
}
|
||||
@@ -1,273 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.ollama;
|
||||
|
||||
import cn.hutool.v7.ai.AIException;
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.BaseAIService;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.core.bean.path.BeanPath;
|
||||
import cn.hutool.v7.core.text.StrUtil;
|
||||
import cn.hutool.v7.core.thread.ThreadUtil;
|
||||
import cn.hutool.v7.http.client.Request;
|
||||
import cn.hutool.v7.http.client.Response;
|
||||
import cn.hutool.v7.http.meta.HeaderName;
|
||||
import cn.hutool.v7.http.meta.Method;
|
||||
import cn.hutool.v7.json.JSONObject;
|
||||
import cn.hutool.v7.json.JSONUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Ollama服务,AI具体功能的实现
|
||||
*
|
||||
* @author yangruoyu-yumeisoft
|
||||
* @since 5.8.40
|
||||
*/
|
||||
public class OllamaServiceImpl extends BaseAIService implements OllamaService {
|
||||
|
||||
// 对话补全
|
||||
private static final String CHAT_ENDPOINT = "/api/chat";
|
||||
// 文本生成
|
||||
private static final String GENERATE_ENDPOINT = "/api/generate";
|
||||
// 文本嵌入
|
||||
private static final String EMBEDDINGS_ENDPOINT = "/api/embeddings";
|
||||
// 列出模型
|
||||
private static final String LIST_MODELS_ENDPOINT = "/api/tags";
|
||||
// 显示模型信息
|
||||
private static final String SHOW_MODEL_ENDPOINT = "/api/show";
|
||||
// 拉取模型
|
||||
private static final String PULL_MODEL_ENDPOINT = "/api/pull";
|
||||
// 删除模型
|
||||
private static final String DELETE_MODEL_ENDPOINT = "/api/delete";
|
||||
// 复制模型
|
||||
private static final String COPY_MODEL_ENDPOINT = "/api/copy";
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param config AI配置
|
||||
*/
|
||||
public OllamaServiceImpl(final AIConfig config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chat(final List<Message> messages) {
|
||||
final String paramJson = buildChatRequestBody(messages);
|
||||
final Response response = sendPost(CHAT_ENDPOINT, paramJson);
|
||||
final JSONObject responseJson = JSONUtil.parseObj(response.body());
|
||||
final Object errorMessage = BeanPath.of("error").getValue(responseJson);
|
||||
if(errorMessage!=null){
|
||||
throw new RuntimeException(errorMessage.toString());
|
||||
}
|
||||
return BeanPath.of("message.content").getValue(responseJson).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chat(final List<Message> messages, final Consumer<String> callback) {
|
||||
final Map<String, Object> paramMap = buildChatStreamRequestBody(messages);
|
||||
ThreadUtil.newThread(() -> sendPostStream(CHAT_ENDPOINT, paramMap, callback::accept), "ollama-chat-sse").start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generate(final String prompt) {
|
||||
final String paramJson = buildGenerateRequestBody(prompt, null);
|
||||
final Response response = sendPost(GENERATE_ENDPOINT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(final String prompt, final Consumer<String> callback) {
|
||||
final Map<String, Object> paramMap = buildGenerateStreamRequestBody(prompt, null);
|
||||
ThreadUtil.newThread(() -> sendPostStream(GENERATE_ENDPOINT, paramMap, callback::accept), "ollama-generate-sse").start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generate(final String prompt, final String format) {
|
||||
final String paramJson = buildGenerateRequestBody(prompt, format);
|
||||
final Response response = sendPost(GENERATE_ENDPOINT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(final String prompt, final String format, final Consumer<String> callback) {
|
||||
final Map<String, Object> paramMap = buildGenerateStreamRequestBody(prompt, format);
|
||||
ThreadUtil.newThread(() -> sendPostStream(GENERATE_ENDPOINT, paramMap, callback::accept), "ollama-generate-sse").start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String embeddings(final String prompt) {
|
||||
final String paramJson = buildEmbeddingsRequestBody(prompt);
|
||||
final Response response = sendPost(EMBEDDINGS_ENDPOINT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String listModels() {
|
||||
final Response response = sendGet(LIST_MODELS_ENDPOINT);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String showModel(final String modelName) {
|
||||
final String paramJson = buildShowModelRequestBody(modelName);
|
||||
final Response response = sendPost(SHOW_MODEL_ENDPOINT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String pullModel(final String modelName) {
|
||||
final String paramJson = buildPullModelRequestBody(modelName);
|
||||
final Response response = sendPost(PULL_MODEL_ENDPOINT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deleteModel(final String modelName) {
|
||||
final String paramJson = buildDeleteModelRequestBody(modelName);
|
||||
final Response response = sendDeleteRequest(DELETE_MODEL_ENDPOINT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String copyModel(final String source, final String destination) {
|
||||
final String paramJson = buildCopyModelRequestBody(source, destination);
|
||||
final Response response = sendPost(COPY_MODEL_ENDPOINT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
// 构建chat请求体
|
||||
private String buildChatRequestBody(final List<Message> messages) {
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("stream",false);
|
||||
paramMap.put("model", config.getModel());
|
||||
paramMap.put("messages", messages);
|
||||
// 合并其他参数
|
||||
paramMap.putAll(config.getAdditionalConfigMap());
|
||||
|
||||
return JSONUtil.toJsonStr(paramMap);
|
||||
}
|
||||
|
||||
// 构建chatStream请求体
|
||||
private Map<String, Object> buildChatStreamRequestBody(final List<Message> messages) {
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("stream", true);
|
||||
paramMap.put("model", config.getModel());
|
||||
paramMap.put("messages", messages);
|
||||
// 合并其他参数
|
||||
paramMap.putAll(config.getAdditionalConfigMap());
|
||||
|
||||
return paramMap;
|
||||
}
|
||||
|
||||
// 构建generate请求体
|
||||
private String buildGenerateRequestBody(final String prompt, final String format) {
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("model", config.getModel());
|
||||
paramMap.put("prompt", prompt);
|
||||
if (StrUtil.isNotBlank(format)) {
|
||||
paramMap.put("format", format);
|
||||
}
|
||||
// 合并其他参数
|
||||
paramMap.putAll(config.getAdditionalConfigMap());
|
||||
|
||||
return JSONUtil.toJsonStr(paramMap);
|
||||
}
|
||||
|
||||
// 构建generateStream请求体
|
||||
private Map<String, Object> buildGenerateStreamRequestBody(final String prompt, final String format) {
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("stream", true);
|
||||
paramMap.put("model", config.getModel());
|
||||
paramMap.put("prompt", prompt);
|
||||
if (StrUtil.isNotBlank(format)) {
|
||||
paramMap.put("format", format);
|
||||
}
|
||||
// 合并其他参数
|
||||
paramMap.putAll(config.getAdditionalConfigMap());
|
||||
|
||||
return paramMap;
|
||||
}
|
||||
|
||||
// 构建embeddings请求体
|
||||
private String buildEmbeddingsRequestBody(final String prompt) {
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("model", config.getModel());
|
||||
paramMap.put("prompt", prompt);
|
||||
// 合并其他参数
|
||||
paramMap.putAll(config.getAdditionalConfigMap());
|
||||
|
||||
return JSONUtil.toJsonStr(paramMap);
|
||||
}
|
||||
|
||||
// 构建showModel请求体
|
||||
private String buildShowModelRequestBody(final String modelName) {
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("name", modelName);
|
||||
|
||||
return JSONUtil.toJsonStr(paramMap);
|
||||
}
|
||||
|
||||
// 构建pullModel请求体
|
||||
private String buildPullModelRequestBody(final String modelName) {
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("name", modelName);
|
||||
|
||||
return JSONUtil.toJsonStr(paramMap);
|
||||
}
|
||||
|
||||
// 构建deleteModel请求体
|
||||
private String buildDeleteModelRequestBody(final String modelName) {
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("name", modelName);
|
||||
|
||||
return JSONUtil.toJsonStr(paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送DELETE请求
|
||||
*
|
||||
* @param endpoint 请求端点
|
||||
* @param paramJson 请求参数JSON
|
||||
* @return 响应结果
|
||||
*/
|
||||
private Response sendDeleteRequest(final String endpoint, final String paramJson) {
|
||||
try {
|
||||
return Request.of(config.getApiUrl() + endpoint)
|
||||
.method(Method.DELETE)
|
||||
.header(HeaderName.CONTENT_TYPE, "application/json")
|
||||
.header(HeaderName.ACCEPT, "application/json")
|
||||
.body(paramJson)
|
||||
.send();
|
||||
} catch (final Exception e) {
|
||||
throw new AIException("Failed to send DELETE request: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// 构建copyModel请求体
|
||||
private String buildCopyModelRequestBody(final String source, final String destination) {
|
||||
final Map<String, Object> requestBody = new HashMap<>();
|
||||
requestBody.put("source", source);
|
||||
requestBody.put("destination", destination);
|
||||
return JSONUtil.toJsonStr(requestBody);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 对Ollama的封装实现.
|
||||
* <p>
|
||||
* 使用方法:
|
||||
* // 创建AI服务
|
||||
* <pre>{@code
|
||||
* OllamaService aiService = AIServiceFactory.getAIService(
|
||||
* new AIConfigBuilder(ModelName.OLLAMA.getValue())
|
||||
* .setApiUrl("http://localhost:11434")
|
||||
* .setModel("qwen2.5-coder:32b")
|
||||
* .build(),
|
||||
* OllamaService.class
|
||||
* );
|
||||
*
|
||||
* // 构造上下文
|
||||
* List<Message> messageList=new ArrayList<>();
|
||||
* messageList.add(new Message("system","你是一个疯疯癫癫的机器人"));
|
||||
* messageList.add(new Message("user","你能帮我做什么"));
|
||||
*
|
||||
* // 输出对话结果
|
||||
* System.out.println(aiService.chat(messageList));
|
||||
* }</pre>
|
||||
*
|
||||
* @author yangruoyu-yumeisoft
|
||||
* @since 5.8.40
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.ollama;
|
||||
@@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai;
|
||||
package org.dromara.hutool.ai;
|
||||
|
||||
import cn.hutool.v7.core.exception.HutoolException;
|
||||
import org.dromara.hutool.core.exception.HutoolException;
|
||||
|
||||
/**
|
||||
* 异常处理类
|
||||
@@ -14,16 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai;
|
||||
package org.dromara.hutool.ai;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.AIService;
|
||||
import cn.hutool.v7.ai.core.AIServiceProvider;
|
||||
import cn.hutool.v7.core.spi.ServiceLoader;
|
||||
import cn.hutool.v7.core.spi.SpiUtil;
|
||||
import org.dromara.hutool.ai.core.AIConfig;
|
||||
import org.dromara.hutool.ai.core.AIService;
|
||||
import org.dromara.hutool.ai.core.AIServiceProvider;
|
||||
import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* 创建AIModelService的工厂类
|
||||
@@ -33,11 +32,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*/
|
||||
public class AIServiceFactory {
|
||||
|
||||
private static final Map<String, AIServiceProvider> providers = new ConcurrentHashMap<>();
|
||||
private static final Map<String, AIServiceProvider> providers = new SafeConcurrentHashMap<>();
|
||||
|
||||
// 加载所有 AIModelProvider 实现类
|
||||
static {
|
||||
final ServiceLoader<AIServiceProvider> loader = SpiUtil.loadList(AIServiceProvider.class);
|
||||
final ServiceLoader<AIServiceProvider> loader = ServiceLoader.load(AIServiceProvider.class);
|
||||
for (final AIServiceProvider provider : loader) {
|
||||
providers.put(provider.getServiceName().toLowerCase(), provider);
|
||||
}
|
||||
@@ -14,16 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai;
|
||||
package org.dromara.hutool.ai;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.AIService;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.ai.model.deepseek.DeepSeekService;
|
||||
import cn.hutool.v7.ai.model.doubao.DoubaoService;
|
||||
import cn.hutool.v7.ai.model.grok.GrokService;
|
||||
import cn.hutool.v7.ai.model.hutool.HutoolService;
|
||||
import cn.hutool.v7.ai.model.openai.OpenaiService;
|
||||
import org.dromara.hutool.ai.core.AIConfig;
|
||||
import org.dromara.hutool.ai.core.AIService;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
import org.dromara.hutool.ai.model.deepseek.DeepSeekService;
|
||||
import org.dromara.hutool.ai.model.doubao.DoubaoService;
|
||||
import org.dromara.hutool.ai.model.grok.GrokService;
|
||||
import org.dromara.hutool.ai.model.hutool.HutoolService;
|
||||
import org.dromara.hutool.ai.model.openai.OpenaiService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai;
|
||||
package org.dromara.hutool.ai;
|
||||
|
||||
/**
|
||||
* 模型厂商的名称(不指具体的模型)
|
||||
@@ -42,11 +42,7 @@ public enum ModelName {
|
||||
/**
|
||||
* grok
|
||||
*/
|
||||
GROK("grok"),
|
||||
/**
|
||||
* ollama
|
||||
*/
|
||||
OLLAMA("ollama");
|
||||
GROK("grok");
|
||||
|
||||
private final String value;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai;
|
||||
package org.dromara.hutool.ai;
|
||||
|
||||
/**
|
||||
* 各模型厂商包含的model(指具体的模型)
|
||||
@@ -30,7 +30,7 @@ public class Models {
|
||||
|
||||
private final String model;
|
||||
|
||||
Hutool(final String model) {
|
||||
Hutool(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class Models {
|
||||
|
||||
private final String model;
|
||||
|
||||
DeepSeek(final String model) {
|
||||
DeepSeek(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public class Models {
|
||||
|
||||
private final String model;
|
||||
|
||||
Openai(final String model) {
|
||||
Openai(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ public class Models {
|
||||
|
||||
private final String model;
|
||||
|
||||
Doubao(final String model) {
|
||||
Doubao(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ public class Models {
|
||||
|
||||
private final String model;
|
||||
|
||||
Grok(final String model) {
|
||||
Grok(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@@ -191,18 +191,4 @@ public class Models {
|
||||
}
|
||||
}
|
||||
|
||||
// Ollama的模型
|
||||
public enum Ollama {
|
||||
QWEN3_32B("qwen3:32b");
|
||||
|
||||
private final String model;
|
||||
|
||||
Ollama(final String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.core;
|
||||
package org.dromara.hutool.ai.core;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.core;
|
||||
package org.dromara.hutool.ai.core;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
@@ -14,13 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.core;
|
||||
package org.dromara.hutool.ai.core;
|
||||
|
||||
import cn.hutool.v7.core.spi.ServiceLoader;
|
||||
import cn.hutool.v7.core.spi.SpiUtil;
|
||||
import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* AIConfig实现类的加载器
|
||||
@@ -30,11 +29,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*/
|
||||
public class AIConfigRegistry {
|
||||
|
||||
private static final Map<String, Class<? extends AIConfig>> configClasses = new ConcurrentHashMap<>();
|
||||
private static final Map<String, Class<? extends AIConfig>> configClasses = new SafeConcurrentHashMap<>();
|
||||
|
||||
// 加载所有 AIConfig 实现类
|
||||
static {
|
||||
final ServiceLoader<AIConfig> loader = SpiUtil.loadList(AIConfig.class);
|
||||
final ServiceLoader<AIConfig> loader = ServiceLoader.load(AIConfig.class);
|
||||
for (final AIConfig config : loader) {
|
||||
configClasses.put(config.getModelName().toLowerCase(), config.getClass());
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.core;
|
||||
package org.dromara.hutool.ai.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.core;
|
||||
package org.dromara.hutool.ai.core;
|
||||
|
||||
/**
|
||||
* 用于加载AI服务,每一个通过SPI创建的AI服务都要实现此接口
|
||||
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.core;
|
||||
package org.dromara.hutool.ai.core;
|
||||
|
||||
import cn.hutool.v7.ai.AIException;
|
||||
import cn.hutool.v7.http.HttpGlobalConfig;
|
||||
import cn.hutool.v7.http.HttpUtil;
|
||||
import cn.hutool.v7.http.client.Response;
|
||||
import cn.hutool.v7.http.meta.HeaderName;
|
||||
import cn.hutool.v7.http.meta.Method;
|
||||
import cn.hutool.v7.json.JSONUtil;
|
||||
import org.dromara.hutool.ai.AIException;
|
||||
import org.dromara.hutool.http.HttpGlobalConfig;
|
||||
import org.dromara.hutool.http.HttpUtil;
|
||||
import org.dromara.hutool.http.client.Response;
|
||||
import org.dromara.hutool.http.meta.HeaderName;
|
||||
import org.dromara.hutool.http.meta.Method;
|
||||
import org.dromara.hutool.json.JSONUtil;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
@@ -40,9 +40,6 @@ import java.util.function.Consumer;
|
||||
*/
|
||||
public class BaseAIService {
|
||||
|
||||
/**
|
||||
* AI配置
|
||||
*/
|
||||
protected final AIConfig config;
|
||||
|
||||
/**
|
||||
@@ -125,11 +122,11 @@ public class BaseAIService {
|
||||
* @param paramMap 请求参数
|
||||
* @param callback 流式数据回调函数
|
||||
*/
|
||||
protected void sendPostStream(final String endpoint, final Map<String, Object> paramMap, final Consumer<String> callback) {
|
||||
protected void sendPostStream(final String endpoint, final Map<String, Object> paramMap, Consumer<String> callback) {
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
// 创建连接
|
||||
final URL apiUrl = new URL(config.getApiUrl() + endpoint);
|
||||
URL apiUrl = new URL(config.getApiUrl() + endpoint);
|
||||
connection = (HttpURLConnection) apiUrl.openConnection();
|
||||
connection.setRequestMethod(Method.POST.name());
|
||||
connection.setRequestProperty(HeaderName.CONTENT_TYPE.getValue(), "application/json");
|
||||
@@ -140,21 +137,21 @@ public class BaseAIService {
|
||||
//设置连接超时
|
||||
connection.setConnectTimeout(config.getTimeout());
|
||||
// 发送请求体
|
||||
try (final OutputStream os = connection.getOutputStream()) {
|
||||
final String jsonInputString = JSONUtil.toJsonStr(paramMap);
|
||||
try (OutputStream os = connection.getOutputStream()) {
|
||||
String jsonInputString = JSONUtil.toJsonStr(paramMap);
|
||||
os.write(jsonInputString.getBytes());
|
||||
os.flush();
|
||||
}
|
||||
|
||||
// 读取流式响应
|
||||
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
// 调用回调函数处理每一行数据
|
||||
callback.accept(line);
|
||||
}
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
} catch (Exception e) {
|
||||
callback.accept("{\"error\": \"" + e.getMessage() + "\"}");
|
||||
} finally {
|
||||
// 关闭连接
|
||||
@@ -14,10 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.core;
|
||||
package org.dromara.hutool.ai.core;
|
||||
|
||||
import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Config基础类,定义模型配置的基本属性
|
||||
@@ -27,29 +28,17 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*/
|
||||
public class BaseConfig implements AIConfig {
|
||||
|
||||
/**
|
||||
* API Key
|
||||
*/
|
||||
//apiKey
|
||||
protected volatile String apiKey;
|
||||
/**
|
||||
* API请求地址
|
||||
*/
|
||||
//API请求地址
|
||||
protected volatile String apiUrl;
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
//具体模型
|
||||
protected volatile String model;
|
||||
/**
|
||||
* 额外的配置
|
||||
*/
|
||||
protected final Map<String, Object> additionalConfig = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* 请求超时
|
||||
*/
|
||||
//动态扩展字段
|
||||
protected Map<String, Object> additionalConfig = new SafeConcurrentHashMap<>();
|
||||
//连接超时时间
|
||||
protected volatile int timeout = 180000;
|
||||
/**
|
||||
* 读取超时
|
||||
*/
|
||||
//读取超时时间
|
||||
protected volatile int readTimeout = 300000;
|
||||
|
||||
@Override
|
||||
@@ -94,7 +83,7 @@ public class BaseConfig implements AIConfig {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAdditionalConfigMap() {
|
||||
return new ConcurrentHashMap<>(additionalConfig);
|
||||
return new SafeConcurrentHashMap<>(additionalConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.core;
|
||||
package org.dromara.hutool.ai.core;
|
||||
|
||||
/**
|
||||
* 公共Message类
|
||||
@@ -21,4 +21,4 @@
|
||||
* @since 6.0.0
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.core;
|
||||
package org.dromara.hutool.ai.core;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.deepseek;
|
||||
package org.dromara.hutool.ai.model.deepseek;
|
||||
|
||||
/**
|
||||
* deepSeek公共类
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.deepseek;
|
||||
package org.dromara.hutool.ai.model.deepseek;
|
||||
|
||||
import cn.hutool.v7.ai.Models;
|
||||
import cn.hutool.v7.ai.core.BaseConfig;
|
||||
import org.dromara.hutool.ai.Models;
|
||||
import org.dromara.hutool.ai.core.BaseConfig;
|
||||
|
||||
/**
|
||||
* DeepSeek配置类,初始化API接口地址,设置默认的模型
|
||||
@@ -27,37 +27,20 @@ import cn.hutool.v7.ai.core.BaseConfig;
|
||||
*/
|
||||
public class DeepSeekConfig extends BaseConfig {
|
||||
|
||||
/**
|
||||
* 定义API的基础URL,用于后续的所有API请求
|
||||
*/
|
||||
public final String API_URL = "https://api.deepseek.com";
|
||||
private final String API_URL = "https://api.deepseek.com";
|
||||
|
||||
/**
|
||||
* 定义默认的模型名称,用于在没有指定模型时使用
|
||||
*/
|
||||
public final String DEFAULT_MODEL = Models.DeepSeek.DEEPSEEK_CHAT.getModel();
|
||||
private final String DEFAULT_MODEL = Models.DeepSeek.DEEPSEEK_CHAT.getModel();
|
||||
|
||||
/**
|
||||
* 默认构造函数,用于初始化DeepSeek配置对象
|
||||
* 设置API的基础URL和默认的模型名称
|
||||
*/
|
||||
public DeepSeekConfig() {
|
||||
setApiUrl(API_URL);
|
||||
setModel(DEFAULT_MODEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 带API密钥参数的构造函数
|
||||
* 用于初始化DeepSeek配置对象,并设置API密钥
|
||||
*
|
||||
* @param apiKey 用户的API密钥,用于认证和授权
|
||||
*/
|
||||
public DeepSeekConfig(final String apiKey) {
|
||||
this(); // 调用默认构造函数初始化API_URL和DEFAULT_MODEL
|
||||
public DeepSeekConfig(String apiKey) {
|
||||
this();
|
||||
setApiKey(apiKey);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getModelName() {
|
||||
return "deepSeek";
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.deepseek;
|
||||
package org.dromara.hutool.ai.model.deepseek;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.AIServiceProvider;
|
||||
import org.dromara.hutool.ai.core.AIConfig;
|
||||
import org.dromara.hutool.ai.core.AIServiceProvider;
|
||||
|
||||
/**
|
||||
* 创建DeepSeek服务实现类
|
||||
@@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.deepseek;
|
||||
package org.dromara.hutool.ai.model.deepseek;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIService;
|
||||
import org.dromara.hutool.ai.core.AIService;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.deepseek;
|
||||
package org.dromara.hutool.ai.model.deepseek;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.BaseAIService;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.core.thread.ThreadUtil;
|
||||
import cn.hutool.v7.http.client.Response;
|
||||
import cn.hutool.v7.json.JSONUtil;
|
||||
import org.dromara.hutool.ai.core.AIConfig;
|
||||
import org.dromara.hutool.ai.core.BaseAIService;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||
import org.dromara.hutool.http.client.Response;
|
||||
import org.dromara.hutool.json.JSONUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -21,4 +21,4 @@
|
||||
* @since 6.0.0
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.deepseek;
|
||||
package org.dromara.hutool.ai.model.deepseek;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.doubao;
|
||||
package org.dromara.hutool.ai.model.doubao;
|
||||
|
||||
/**
|
||||
* doubao公共类
|
||||
@@ -24,139 +24,70 @@ package cn.hutool.v7.ai.model.doubao;
|
||||
*/
|
||||
public class DoubaoCommon {
|
||||
|
||||
/**
|
||||
* doubao上下文缓存参数
|
||||
*/
|
||||
//doubao上下文缓存参数
|
||||
public enum DoubaoContext {
|
||||
|
||||
/**
|
||||
* session
|
||||
*/
|
||||
SESSION("session"),
|
||||
/**
|
||||
* common_prefix
|
||||
*/
|
||||
COMMON_PREFIX("common_prefix");
|
||||
|
||||
private final String mode;
|
||||
|
||||
DoubaoContext(final String mode) {
|
||||
DoubaoContext(String mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参数
|
||||
*
|
||||
* @return 参数
|
||||
*/
|
||||
public String getMode() {
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* doubao视觉参数
|
||||
*/
|
||||
//doubao视觉参数
|
||||
public enum DoubaoVision {
|
||||
|
||||
/**
|
||||
* 自动
|
||||
*/
|
||||
AUTO("auto"),
|
||||
/**
|
||||
* 低
|
||||
*/
|
||||
LOW("low"),
|
||||
/**
|
||||
* 高
|
||||
*/
|
||||
HIGH("high");
|
||||
|
||||
private final String detail;
|
||||
|
||||
DoubaoVision(final String detail) {
|
||||
DoubaoVision(String detail) {
|
||||
this.detail = detail;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参数
|
||||
*
|
||||
* @return 参数
|
||||
*/
|
||||
public String getDetail() {
|
||||
return detail;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* doubao视频生成参数
|
||||
*/
|
||||
//doubao视频生成参数
|
||||
public enum DoubaoVideo {
|
||||
|
||||
//宽高比例
|
||||
/**
|
||||
* 视频比例16:9,适用于横向宽屏显示,常用作标准视频比例
|
||||
*/
|
||||
RATIO_16_9("--rt", "16:9"),//[1280, 720]
|
||||
|
||||
/**
|
||||
* 视频比例4:3,传统电视屏幕比例,适用于标准清晰度的视频内容
|
||||
*/
|
||||
RATIO_4_3("--rt", "4:3"),//[960, 720]
|
||||
|
||||
/**
|
||||
* 视频比例1:1,正方形画面,适用于社交媒体平台上的短视频内容
|
||||
*/
|
||||
RATIO_1_1("--rt", "1:1"),//[720, 720]
|
||||
|
||||
/**
|
||||
* 视频比例3:4,竖向视频比例,适用于手机端的视频播放场景
|
||||
*/
|
||||
RATIO_3_4("--rt", "3:4"),//[720, 960]
|
||||
|
||||
/**
|
||||
* 视频比例9:16,常见的竖屏视频比例,广泛用于短视频应用
|
||||
*/
|
||||
RATIO_9_16("--rt", "9:16"),//[720, 1280]
|
||||
|
||||
/**
|
||||
* 视频比例21:9,超宽屏幕比例,提供更广阔的视野,适合电影和游戏体验
|
||||
*/
|
||||
RATIO_21_9("--rt", "21:9"),//[1280, 544]
|
||||
|
||||
//生成视频时长
|
||||
/**
|
||||
* 文生视频,图生视频
|
||||
*/
|
||||
DURATION_5("--dur", 5),
|
||||
/**
|
||||
* 文生视频
|
||||
*/
|
||||
DURATION_10("--dur", 10),
|
||||
DURATION_5("--dur", 5),//文生视频,图生视频
|
||||
DURATION_10("--dur", 10),//文生视频
|
||||
|
||||
/**
|
||||
* 帧率,即一秒时间内视频画面数量
|
||||
*/
|
||||
//帧率,即一秒时间内视频画面数量
|
||||
FPS_5("--fps", 24),
|
||||
|
||||
/**
|
||||
* 视频分辨率
|
||||
*/
|
||||
//视频分辨率
|
||||
RESOLUTION_5("--rs", "720p"),
|
||||
|
||||
/**
|
||||
* 生成视频包含水印
|
||||
*/
|
||||
//生成视频是否包含水印
|
||||
WATERMARK_TRUE("--wm", true),
|
||||
/**
|
||||
* 生成视频不包含水印
|
||||
*/
|
||||
WATERMARK_FALSE("--wm", false);
|
||||
|
||||
private final String type;
|
||||
private final Object value;
|
||||
|
||||
DoubaoVideo(final String type, final Object value) {
|
||||
DoubaoVideo(String type, Object value) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
@@ -14,42 +14,36 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.ollama;
|
||||
package org.dromara.hutool.ai.model.doubao;
|
||||
|
||||
import cn.hutool.v7.ai.Models;
|
||||
import cn.hutool.v7.ai.core.BaseConfig;
|
||||
import org.dromara.hutool.ai.Models;
|
||||
import org.dromara.hutool.ai.core.BaseConfig;
|
||||
|
||||
/**
|
||||
* Ollama配置类,初始化API接口地址,设置默认的模型
|
||||
* Doubao配置类,初始化API接口地址,设置默认的模型
|
||||
*
|
||||
* @author yangruoyu-yumeisoft
|
||||
* @since 5.8.40
|
||||
* @author elichow
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class OllamaConfig extends BaseConfig {
|
||||
public class DoubaoConfig extends BaseConfig {
|
||||
|
||||
private final String API_URL = "http://localhost:11434";
|
||||
private final String API_URL = "https://ark.cn-beijing.volces.com/api/v3";
|
||||
|
||||
private final String DEFAULT_MODEL = Models.Ollama.QWEN3_32B.getModel();
|
||||
private final String DEFAULT_MODEL = Models.Doubao.DOUBAO_1_5_LITE_32K.getModel();
|
||||
|
||||
public OllamaConfig() {
|
||||
public DoubaoConfig() {
|
||||
setApiUrl(API_URL);
|
||||
setModel(DEFAULT_MODEL);
|
||||
}
|
||||
|
||||
public OllamaConfig(String apiUrl) {
|
||||
public DoubaoConfig(String apiKey) {
|
||||
this();
|
||||
setApiUrl(apiUrl);
|
||||
}
|
||||
|
||||
public OllamaConfig(String apiUrl, String model) {
|
||||
this();
|
||||
setApiUrl(apiUrl);
|
||||
setModel(model);
|
||||
setApiKey(apiKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModelName() {
|
||||
return "ollama";
|
||||
return "doubao";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.doubao;
|
||||
package org.dromara.hutool.ai.model.doubao;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.AIServiceProvider;
|
||||
import org.dromara.hutool.ai.core.AIConfig;
|
||||
import org.dromara.hutool.ai.core.AIServiceProvider;
|
||||
|
||||
/**
|
||||
* 创建Doubap服务实现类
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.doubao;
|
||||
package org.dromara.hutool.ai.model.doubao;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIService;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import org.dromara.hutool.ai.core.AIService;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.doubao;
|
||||
package org.dromara.hutool.ai.model.doubao;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.BaseAIService;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.core.text.StrUtil;
|
||||
import cn.hutool.v7.core.thread.ThreadUtil;
|
||||
import cn.hutool.v7.http.client.Response;
|
||||
import cn.hutool.v7.json.JSONUtil;
|
||||
import org.dromara.hutool.ai.core.AIConfig;
|
||||
import org.dromara.hutool.ai.core.BaseAIService;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||
import org.dromara.hutool.http.client.Response;
|
||||
import org.dromara.hutool.json.JSONUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -39,25 +39,25 @@ import java.util.function.Consumer;
|
||||
public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
|
||||
//对话
|
||||
private static final String CHAT_ENDPOINT = "/chat/completions";
|
||||
private final String CHAT_ENDPOINT = "/chat/completions";
|
||||
//文本向量化
|
||||
private static final String EMBEDDING_TEXT = "/embeddings";
|
||||
private final String EMBEDDING_TEXT = "/embeddings";
|
||||
//图文向量化
|
||||
private static final String EMBEDDING_VISION = "/embeddings/multimodal";
|
||||
private final String EMBEDDING_VISION = "/embeddings/multimodal";
|
||||
//应用bots
|
||||
private static final String BOTS_CHAT = "/bots/chat/completions";
|
||||
private final String BOTS_CHAT = "/bots/chat/completions";
|
||||
//分词
|
||||
private static final String TOKENIZATION = "/tokenization";
|
||||
private final String TOKENIZATION = "/tokenization";
|
||||
//批量推理chat
|
||||
private static final String BATCH_CHAT = "/batch/chat/completions";
|
||||
private final String BATCH_CHAT = "/batch/chat/completions";
|
||||
//创建上下文缓存
|
||||
private static final String CREATE_CONTEXT = "/context/create";
|
||||
private final String CREATE_CONTEXT = "/context/create";
|
||||
//上下文缓存对话
|
||||
private static final String CHAT_CONTEXT = "/context/chat/completions";
|
||||
private final String CHAT_CONTEXT = "/context/chat/completions";
|
||||
//创建视频生成任务
|
||||
private static final String CREATE_VIDEO = "/contents/generations/tasks";
|
||||
private final String CREATE_VIDEO = "/contents/generations/tasks";
|
||||
//文生图
|
||||
private static final String IMAGES_GENERATIONS = "/images/generations";
|
||||
private final String IMAGES_GENERATIONS = "/images/generations";
|
||||
|
||||
public DoubaoServiceImpl(final AIConfig config) {
|
||||
//初始化doubao客户端
|
||||
@@ -66,109 +66,109 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
|
||||
@Override
|
||||
public String chat(final List<Message> messages) {
|
||||
final String paramJson = buildChatRequestBody(messages);
|
||||
final Response response = sendPost(CHAT_ENDPOINT, paramJson);
|
||||
String paramJson = buildChatRequestBody(messages);
|
||||
Response response = sendPost(CHAT_ENDPOINT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chat(final List<Message> messages, final Consumer<String> callback) {
|
||||
final Map<String, Object> paramMap = buildChatStreamRequestBody(messages);
|
||||
public void chat(List<Message> messages, Consumer<String> callback) {
|
||||
Map<String, Object> paramMap = buildChatStreamRequestBody(messages);
|
||||
ThreadUtil.newThread(() -> sendPostStream(CHAT_ENDPOINT, paramMap, callback::accept), "doubao-chat-sse").start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chatVision(final String prompt, final List<String> images, final String detail) {
|
||||
final String paramJson = buildChatVisionRequestBody(prompt, images, detail);
|
||||
final Response response = sendPost(CHAT_ENDPOINT, paramJson);
|
||||
public String chatVision(String prompt, final List<String> images, String detail) {
|
||||
String paramJson = buildChatVisionRequestBody(prompt, images, detail);
|
||||
Response response = sendPost(CHAT_ENDPOINT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chatVision(final String prompt, final List<String> images, final String detail, final Consumer<String> callback) {
|
||||
final Map<String, Object> paramMap = buildChatVisionStreamRequestBody(prompt, images, detail);
|
||||
public void chatVision(String prompt, List<String> images, String detail, Consumer<String> callback) {
|
||||
Map<String, Object> paramMap = buildChatVisionStreamRequestBody(prompt, images, detail);
|
||||
ThreadUtil.newThread(() -> sendPostStream(CHAT_ENDPOINT, paramMap, callback::accept), "doubao-chatVision-sse").start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String videoTasks(final String text, final String image, final List<DoubaoCommon.DoubaoVideo> videoParams) {
|
||||
final String paramJson = buildGenerationsTasksRequestBody(text, image, videoParams);
|
||||
final Response response = sendPost(CREATE_VIDEO, paramJson);
|
||||
public String videoTasks(String text, String image, final List<DoubaoCommon.DoubaoVideo> videoParams) {
|
||||
String paramJson = buildGenerationsTasksRequestBody(text, image, videoParams);
|
||||
Response response = sendPost(CREATE_VIDEO, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVideoTasksInfo(final String taskId) {
|
||||
final Response response = sendGet(CREATE_VIDEO + "/" + taskId);
|
||||
public String getVideoTasksInfo(String taskId) {
|
||||
Response response = sendGet(CREATE_VIDEO + "/" + taskId);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String embeddingText(final String[] input) {
|
||||
final String paramJson = buildEmbeddingTextRequestBody(input);
|
||||
final Response response = sendPost(EMBEDDING_TEXT, paramJson);
|
||||
public String embeddingText(String[] input) {
|
||||
String paramJson = buildEmbeddingTextRequestBody(input);
|
||||
Response response = sendPost(EMBEDDING_TEXT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String embeddingVision(final String text, final String image) {
|
||||
final String paramJson = buildEmbeddingVisionRequestBody(text, image);
|
||||
final Response response = sendPost(EMBEDDING_VISION, paramJson);
|
||||
public String embeddingVision(String text, String image) {
|
||||
String paramJson = buildEmbeddingVisionRequestBody(text, image);
|
||||
Response response = sendPost(EMBEDDING_VISION, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String botsChat(final List<Message> messages) {
|
||||
final String paramJson = buildBotsChatRequestBody(messages);
|
||||
final Response response = sendPost(BOTS_CHAT, paramJson);
|
||||
String paramJson = buildBotsChatRequestBody(messages);
|
||||
Response response = sendPost(BOTS_CHAT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void botsChat(final List<Message> messages, final Consumer<String> callback) {
|
||||
final Map<String, Object> paramMap = buildBotsChatStreamRequestBody(messages);
|
||||
public void botsChat(List<Message> messages, Consumer<String> callback) {
|
||||
Map<String, Object> paramMap = buildBotsChatStreamRequestBody(messages);
|
||||
ThreadUtil.newThread(() -> sendPostStream(BOTS_CHAT, paramMap, callback::accept), "doubao-botsChat-sse").start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tokenization(final String[] text) {
|
||||
final String paramJson = buildTokenizationRequestBody(text);
|
||||
final Response response = sendPost(TOKENIZATION, paramJson);
|
||||
public String tokenization(String[] text) {
|
||||
String paramJson = buildTokenizationRequestBody(text);
|
||||
Response response = sendPost(TOKENIZATION, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String batchChat(final List<Message> messages) {
|
||||
final String paramJson = buildBatchChatRequestBody(messages);
|
||||
final Response response = sendPost(BATCH_CHAT, paramJson);
|
||||
String paramJson = buildBatchChatRequestBody(messages);
|
||||
Response response = sendPost(BATCH_CHAT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createContext(final List<Message> messages, final String mode) {
|
||||
final String paramJson = buildCreateContextRequest(messages, mode);
|
||||
final Response response = sendPost(CREATE_CONTEXT, paramJson);
|
||||
public String createContext(final List<Message> messages, String mode) {
|
||||
String paramJson = buildCreateContextRequest(messages, mode);
|
||||
Response response = sendPost(CREATE_CONTEXT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chatContext(final List<Message> messages, final String contextId) {
|
||||
final String paramJson = buildChatContentRequestBody(messages, contextId);
|
||||
final Response response = sendPost(CHAT_CONTEXT, paramJson);
|
||||
public String chatContext(final List<Message> messages, String contextId) {
|
||||
String paramJson = buildChatContentRequestBody(messages, contextId);
|
||||
Response response = sendPost(CHAT_CONTEXT, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chatContext(final List<Message> messages, final String contextId, final Consumer<String> callback) {
|
||||
final Map<String, Object> paramMap = buildChatContentStreamRequestBody(messages, contextId);
|
||||
public void chatContext(List<Message> messages, String contextId, Consumer<String> callback) {
|
||||
Map<String, Object> paramMap = buildChatContentStreamRequestBody(messages, contextId);
|
||||
ThreadUtil.newThread(() -> sendPostStream(CHAT_CONTEXT, paramMap, callback::accept), "doubao-chatContext-sse").start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String imagesGenerations(final String prompt) {
|
||||
final String paramJson = buildImagesGenerationsRequestBody(prompt);
|
||||
final Response response = sendPost(IMAGES_GENERATIONS, paramJson);
|
||||
public String imagesGenerations(String prompt) {
|
||||
String paramJson = buildImagesGenerationsRequestBody(prompt);
|
||||
Response response = sendPost(IMAGES_GENERATIONS, paramJson);
|
||||
return response.bodyStr();
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
}
|
||||
|
||||
//构建chatVision请求体
|
||||
private String buildChatVisionRequestBody(final String prompt, final List<String> images, final String detail) {
|
||||
private String buildChatVisionRequestBody(String prompt, final List<String> images, String detail) {
|
||||
// 定义消息结构
|
||||
final List<Message> messages = new ArrayList<>();
|
||||
final List<Object> content = new ArrayList<>();
|
||||
@@ -207,10 +207,10 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
contentMap.put("type", "text");
|
||||
contentMap.put("text", prompt);
|
||||
content.add(contentMap);
|
||||
for (final String img : images) {
|
||||
final HashMap<String, Object> imgUrlMap = new HashMap<>();
|
||||
for (String img : images) {
|
||||
HashMap<String, Object> imgUrlMap = new HashMap<>();
|
||||
imgUrlMap.put("type", "image_url");
|
||||
final HashMap<String, String> urlMap = new HashMap<>();
|
||||
HashMap<String, String> urlMap = new HashMap<>();
|
||||
urlMap.put("url", img);
|
||||
urlMap.put("detail", detail);
|
||||
imgUrlMap.put("image_url", urlMap);
|
||||
@@ -228,7 +228,7 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
return JSONUtil.toJsonStr(paramMap);
|
||||
}
|
||||
|
||||
private Map<String, Object> buildChatVisionStreamRequestBody(final String prompt, final List<String> images, final String detail) {
|
||||
private Map<String, Object> buildChatVisionStreamRequestBody(String prompt, final List<String> images, String detail) {
|
||||
// 定义消息结构
|
||||
final List<Message> messages = new ArrayList<>();
|
||||
final List<Object> content = new ArrayList<>();
|
||||
@@ -237,10 +237,10 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
contentMap.put("type", "text");
|
||||
contentMap.put("text", prompt);
|
||||
content.add(contentMap);
|
||||
for (final String img : images) {
|
||||
final HashMap<String, Object> imgUrlMap = new HashMap<>();
|
||||
for (String img : images) {
|
||||
HashMap<String, Object> imgUrlMap = new HashMap<>();
|
||||
imgUrlMap.put("type", "image_url");
|
||||
final HashMap<String, String> urlMap = new HashMap<>();
|
||||
HashMap<String, String> urlMap = new HashMap<>();
|
||||
urlMap.put("url", img);
|
||||
urlMap.put("detail", detail);
|
||||
imgUrlMap.put("image_url", urlMap);
|
||||
@@ -260,7 +260,7 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
}
|
||||
|
||||
//构建文本向量化请求体
|
||||
private String buildEmbeddingTextRequestBody(final String[] input) {
|
||||
private String buildEmbeddingTextRequestBody(String[] input) {
|
||||
//使用JSON工具
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("model", config.getModel());
|
||||
@@ -271,7 +271,7 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
}
|
||||
|
||||
//构建图文向量化请求体
|
||||
private String buildEmbeddingVisionRequestBody(final String text, final String image) {
|
||||
private String buildEmbeddingVisionRequestBody(String text, String image) {
|
||||
//使用JSON工具
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("model", config.getModel());
|
||||
@@ -311,7 +311,7 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
}
|
||||
|
||||
//构建分词请求体
|
||||
private String buildTokenizationRequestBody(final String[] text) {
|
||||
private String buildTokenizationRequestBody(String[] text) {
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("model", config.getModel());
|
||||
paramMap.put("text", text);
|
||||
@@ -328,7 +328,7 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
}
|
||||
|
||||
//构建创建上下文缓存请求体
|
||||
private String buildCreateContextRequest(final List<Message> messages, final String mode) {
|
||||
private String buildCreateContextRequest(final List<Message> messages, String mode) {
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("messages", messages);
|
||||
paramMap.put("model", config.getModel());
|
||||
@@ -340,7 +340,7 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
}
|
||||
|
||||
//构建上下文缓存对话请求体
|
||||
private String buildChatContentRequestBody(final List<Message> messages, final String contextId) {
|
||||
private String buildChatContentRequestBody(final List<Message> messages, String contextId) {
|
||||
//使用JSON工具
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("model", config.getModel());
|
||||
@@ -352,7 +352,7 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
return JSONUtil.toJsonStr(paramMap);
|
||||
}
|
||||
|
||||
private Map<String, Object> buildChatContentStreamRequestBody(final List<Message> messages, final String contextId) {
|
||||
private Map<String, Object> buildChatContentStreamRequestBody(final List<Message> messages, String contextId) {
|
||||
//使用JSON工具
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("stream", true);
|
||||
@@ -366,7 +366,7 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
}
|
||||
|
||||
//构建创建视频任务请求体
|
||||
private String buildGenerationsTasksRequestBody(final String text, final String image, final List<DoubaoCommon.DoubaoVideo> videoParams) {
|
||||
private String buildGenerationsTasksRequestBody(String text, String image, final List<DoubaoCommon.DoubaoVideo> videoParams) {
|
||||
//使用JSON工具
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("model", config.getModel());
|
||||
@@ -392,10 +392,10 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
//添加视频参数
|
||||
if (videoParams != null && !videoParams.isEmpty()) {
|
||||
//如果有文本参数就加在后面
|
||||
if (!textMap.isEmpty()) {
|
||||
final int textIndex = content.indexOf(textMap);
|
||||
final StringBuilder textBuilder = new StringBuilder(text);
|
||||
for (final DoubaoCommon.DoubaoVideo videoParam : videoParams) {
|
||||
if (textMap != null && !textMap.isEmpty()) {
|
||||
int textIndex = content.indexOf(textMap);
|
||||
StringBuilder textBuilder = new StringBuilder(text);
|
||||
for (DoubaoCommon.DoubaoVideo videoParam : videoParams) {
|
||||
textBuilder.append(" ").append(videoParam.getType()).append(" ").append(videoParam.getValue());
|
||||
}
|
||||
textMap.put("type", "text");
|
||||
@@ -408,8 +408,8 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
}
|
||||
} else {
|
||||
//如果没有文本参数就重新增加
|
||||
final StringBuilder textBuilder = new StringBuilder();
|
||||
for (final DoubaoCommon.DoubaoVideo videoParam : videoParams) {
|
||||
StringBuilder textBuilder = new StringBuilder();
|
||||
for (DoubaoCommon.DoubaoVideo videoParam : videoParams) {
|
||||
textBuilder.append(videoParam.getType()).append(videoParam.getValue()).append(" ");
|
||||
}
|
||||
textMap.put("type", "text");
|
||||
@@ -426,7 +426,7 @@ public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||
}
|
||||
|
||||
//构建文生图请求体
|
||||
private String buildImagesGenerationsRequestBody(final String prompt) {
|
||||
private String buildImagesGenerationsRequestBody(String prompt) {
|
||||
final Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("model", config.getModel());
|
||||
paramMap.put("prompt", prompt);
|
||||
@@ -21,4 +21,4 @@
|
||||
* @since 6.0.0
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.doubao;
|
||||
package org.dromara.hutool.ai.model.doubao;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.grok;
|
||||
package org.dromara.hutool.ai.model.grok;
|
||||
|
||||
/**
|
||||
* grok公共类
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.grok;
|
||||
package org.dromara.hutool.ai.model.grok;
|
||||
|
||||
import cn.hutool.v7.ai.Models;
|
||||
import cn.hutool.v7.ai.core.BaseConfig;
|
||||
import org.dromara.hutool.ai.Models;
|
||||
import org.dromara.hutool.ai.core.BaseConfig;
|
||||
|
||||
/**
|
||||
* Grok配置类,初始化API接口地址,设置默认的模型
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.grok;
|
||||
package org.dromara.hutool.ai.model.grok;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.AIServiceProvider;
|
||||
import org.dromara.hutool.ai.core.AIConfig;
|
||||
import org.dromara.hutool.ai.core.AIServiceProvider;
|
||||
|
||||
/**
|
||||
* 创建Grok服务实现类
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.grok;
|
||||
package org.dromara.hutool.ai.model.grok;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIService;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import org.dromara.hutool.ai.core.AIService;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -14,14 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.grok;
|
||||
package org.dromara.hutool.ai.model.grok;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.BaseAIService;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.core.thread.ThreadUtil;
|
||||
import cn.hutool.v7.http.client.Response;
|
||||
import cn.hutool.v7.json.JSONUtil;
|
||||
import org.dromara.hutool.ai.core.AIConfig;
|
||||
import org.dromara.hutool.ai.core.BaseAIService;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||
import org.dromara.hutool.http.client.Response;
|
||||
import org.dromara.hutool.json.JSONUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -21,4 +21,4 @@
|
||||
* @since 6.0.0
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.grok;
|
||||
package org.dromara.hutool.ai.model.grok;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.hutool;
|
||||
package org.dromara.hutool.ai.model.hutool;
|
||||
|
||||
/**
|
||||
* hutool公共类
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.hutool;
|
||||
package org.dromara.hutool.ai.model.hutool;
|
||||
|
||||
import cn.hutool.v7.ai.Models;
|
||||
import cn.hutool.v7.ai.core.BaseConfig;
|
||||
import org.dromara.hutool.ai.Models;
|
||||
import org.dromara.hutool.ai.core.BaseConfig;
|
||||
|
||||
/**
|
||||
* Hutool配置类,初始化API接口地址,设置默认的模型
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.hutool;
|
||||
package org.dromara.hutool.ai.model.hutool;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.AIServiceProvider;
|
||||
import org.dromara.hutool.ai.core.AIConfig;
|
||||
import org.dromara.hutool.ai.core.AIServiceProvider;
|
||||
|
||||
/**r
|
||||
* 创建Hutool服务实现类
|
||||
@@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.hutool;
|
||||
package org.dromara.hutool.ai.model.hutool;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIService;
|
||||
import org.dromara.hutool.ai.core.AIService;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
@@ -14,16 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.hutool;
|
||||
package org.dromara.hutool.ai.model.hutool;
|
||||
|
||||
import cn.hutool.v7.ai.AIException;
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.BaseAIService;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.core.text.StrUtil;
|
||||
import cn.hutool.v7.core.thread.ThreadUtil;
|
||||
import cn.hutool.v7.http.client.Response;
|
||||
import cn.hutool.v7.json.JSONUtil;
|
||||
import org.dromara.hutool.ai.AIException;
|
||||
import org.dromara.hutool.ai.core.AIConfig;
|
||||
import org.dromara.hutool.ai.core.BaseAIService;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||
import org.dromara.hutool.http.client.Response;
|
||||
import org.dromara.hutool.json.JSONUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
@@ -21,4 +21,4 @@
|
||||
* @since 6.0.0
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.hutool;
|
||||
package org.dromara.hutool.ai.model.hutool;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.openai;
|
||||
package org.dromara.hutool.ai.model.openai;
|
||||
|
||||
/**
|
||||
* openai公共类
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.openai;
|
||||
package org.dromara.hutool.ai.model.openai;
|
||||
|
||||
import cn.hutool.v7.ai.Models;
|
||||
import cn.hutool.v7.ai.core.BaseConfig;
|
||||
import org.dromara.hutool.ai.Models;
|
||||
import org.dromara.hutool.ai.core.BaseConfig;
|
||||
|
||||
/**
|
||||
* openai配置类,初始化API接口地址,设置默认的模型
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.openai;
|
||||
package org.dromara.hutool.ai.model.openai;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.AIServiceProvider;
|
||||
import org.dromara.hutool.ai.core.AIConfig;
|
||||
import org.dromara.hutool.ai.core.AIServiceProvider;
|
||||
|
||||
/**
|
||||
* 创建Openai服务实现类
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.openai;
|
||||
package org.dromara.hutool.ai.model.openai;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIService;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import org.dromara.hutool.ai.core.AIService;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.openai;
|
||||
package org.dromara.hutool.ai.model.openai;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfig;
|
||||
import cn.hutool.v7.ai.core.BaseAIService;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.core.text.StrUtil;
|
||||
import cn.hutool.v7.core.thread.ThreadUtil;
|
||||
import cn.hutool.v7.http.client.Response;
|
||||
import cn.hutool.v7.json.JSONUtil;
|
||||
import org.dromara.hutool.ai.core.AIConfig;
|
||||
import org.dromara.hutool.ai.core.BaseAIService;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||
import org.dromara.hutool.http.client.Response;
|
||||
import org.dromara.hutool.json.JSONUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
@@ -21,4 +21,4 @@
|
||||
* @since 6.0.0
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.openai;
|
||||
package org.dromara.hutool.ai.model.openai;
|
||||
@@ -21,4 +21,4 @@
|
||||
* @since 6.0.0
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model;
|
||||
package org.dromara.hutool.ai.model;
|
||||
@@ -21,4 +21,4 @@
|
||||
* @since 6.0.0
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai;
|
||||
package org.dromara.hutool.ai;
|
||||
@@ -1,6 +0,0 @@
|
||||
cn.hutool.v7.ai.model.hutool.HutoolConfig
|
||||
cn.hutool.v7.ai.model.deepseek.DeepSeekConfig
|
||||
cn.hutool.v7.ai.model.openai.OpenaiConfig
|
||||
cn.hutool.v7.ai.model.doubao.DoubaoConfig
|
||||
cn.hutool.v7.ai.model.grok.GrokConfig
|
||||
cn.hutool.v7.ai.model.ollama.OllamaConfig
|
||||
@@ -1,6 +0,0 @@
|
||||
cn.hutool.v7.ai.model.hutool.HutoolProvider
|
||||
cn.hutool.v7.ai.model.deepseek.DeepSeekProvider
|
||||
cn.hutool.v7.ai.model.openai.OpenaiProvider
|
||||
cn.hutool.v7.ai.model.doubao.DoubaoProvider
|
||||
cn.hutool.v7.ai.model.grok.GrokProvider
|
||||
cn.hutool.v7.ai.model.ollama.OllamaProvider
|
||||
@@ -0,0 +1,5 @@
|
||||
org.dromara.hutool.ai.model.hutool.HutoolConfig
|
||||
org.dromara.hutool.ai.model.deepseek.DeepSeekConfig
|
||||
org.dromara.hutool.ai.model.openai.OpenaiConfig
|
||||
org.dromara.hutool.ai.model.doubao.DoubaoConfig
|
||||
org.dromara.hutool.ai.model.grok.GrokConfig
|
||||
@@ -0,0 +1,5 @@
|
||||
org.dromara.hutool.ai.model.hutool.HutoolProvider
|
||||
org.dromara.hutool.ai.model.deepseek.DeepSeekProvider
|
||||
org.dromara.hutool.ai.model.openai.OpenaiProvider
|
||||
org.dromara.hutool.ai.model.doubao.DoubaoProvider
|
||||
org.dromara.hutool.ai.model.grok.GrokProvider
|
||||
@@ -1,256 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.hutool.v7.ai.model.ollama;
|
||||
|
||||
import cn.hutool.v7.ai.AIServiceFactory;
|
||||
import cn.hutool.v7.ai.ModelName;
|
||||
import cn.hutool.v7.ai.core.AIConfigBuilder;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.core.text.split.SplitUtil;
|
||||
import cn.hutool.v7.core.thread.ThreadUtil;
|
||||
import cn.hutool.v7.json.JSON;
|
||||
import cn.hutool.v7.json.JSONArray;
|
||||
import cn.hutool.v7.json.JSONUtil;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
/**
|
||||
* OllamaService
|
||||
*
|
||||
* @author yangruoyu-yumeisoft
|
||||
* @since 5.8.40
|
||||
*/
|
||||
class OllamaServiceTest {
|
||||
// 创建service
|
||||
OllamaService ollamaService = AIServiceFactory.getAIService(
|
||||
new AIConfigBuilder(ModelName.OLLAMA.getValue())
|
||||
// 这里填写Ollama服务的地址
|
||||
.setApiUrl("http://127.0.0.1:11434")
|
||||
// 这里填写使用的模型
|
||||
.setModel("qwen2.5-coder:32b")
|
||||
.build(),
|
||||
OllamaService.class
|
||||
);
|
||||
|
||||
// 假设有一个Java工程师的Agent提示词
|
||||
String javaEngineerPrompt= """
|
||||
# 角色
|
||||
你是一位精通Spring Boot 3.0的资深Java全栈工程师,具备以下核心能力:
|
||||
- 精通Spring Boot 3.0新特性与最佳实践
|
||||
- 熟练整合Hutool工具包、Redis数据访问、Feign远程调用、FreeMarker模板引擎
|
||||
- 能输出符合工程规范的代码结构和配置文件
|
||||
- 注重代码可读性与注释规范
|
||||
|
||||
# 任务
|
||||
请完成以下编程任务(按优先级排序):
|
||||
1. **核心要求**
|
||||
- 使用Spring Boot 3.0构建项目
|
||||
- 必须包含以下依赖:
|
||||
- `cn.hutool:hutool-all`(最新版)
|
||||
- `org.springframework.boot:spring-boot-starter-data-redis`
|
||||
- `org.springframework.cloud:spring-cloud-starter-openfeign`
|
||||
- `org.springframework.boot:spring-boot-starter-freemarker`
|
||||
2. **约束条件**
|
||||
- 代码需符合Java 17语法规范
|
||||
- 每个类必须包含Javadoc风格的类注释
|
||||
- 关键方法需添加`@Api`/`@ApiOperation`注解(若涉及接口)
|
||||
- Redis操作需使用`RedisTemplate`实现
|
||||
3. **实现流程**
|
||||
```
|
||||
1. 生成pom.xml依赖配置
|
||||
2. 创建基础配置类(如RedisConfig)
|
||||
3. 编写Feign客户端接口
|
||||
4. 实现FreeMarker模板渲染服务
|
||||
5. 提供完整Controller示例
|
||||
```
|
||||
|
||||
# 输出要求
|
||||
请以严格Markdown格式输出,每个模块独立代码块:
|
||||
```markdown
|
||||
## 1. 项目依赖配置(pom.xml片段)
|
||||
```xml
|
||||
<dependency>...</dependency>
|
||||
```
|
||||
|
||||
## 2. Redis配置类
|
||||
```java
|
||||
@Configuration
|
||||
public class RedisConfig { ... }
|
||||
```
|
||||
|
||||
## 3. Feign客户端示例
|
||||
```java
|
||||
@FeignClient(name = "...")
|
||||
public interface ... { ... }
|
||||
```
|
||||
|
||||
## 4. FreeMarker模板服务
|
||||
```java
|
||||
@Service
|
||||
public class TemplateService { ... }
|
||||
```
|
||||
|
||||
## 5. 控制器示例
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/example")
|
||||
public class ExampleController { ... }
|
||||
```
|
||||
```
|
||||
|
||||
# 示例片段(供格式参考)
|
||||
```java
|
||||
/**
|
||||
* 示例Feign客户端
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@FeignClient(name = "demo-service", url = "${demo.service.url}")
|
||||
public interface DemoClient {
|
||||
|
||||
@GetMapping("/data/{id}")
|
||||
@ApiOperation("获取示例数据")
|
||||
ResponseEntity<String> getData(@PathVariable("id") Long id);
|
||||
}
|
||||
```
|
||||
|
||||
请按此规范输出完整代码结构,确保自动化程序可直接解析生成项目文件。""";
|
||||
|
||||
/**
|
||||
* 同步方式调用
|
||||
*/
|
||||
@Test
|
||||
@Disabled
|
||||
void testSimple() {
|
||||
final String answer = ollamaService.chat("写一个疯狂星期四广告词");
|
||||
assertNotNull(answer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按流方式输出
|
||||
*/
|
||||
@Test
|
||||
@Disabled
|
||||
void testStream() {
|
||||
final AtomicBoolean isDone = new AtomicBoolean(false);
|
||||
final AtomicReference<String> errorMessage = new AtomicReference<>();
|
||||
ollamaService.chat("写一个疯狂星期四广告词", data -> {
|
||||
// 输出到控制台
|
||||
final JSON streamData = JSONUtil.parse(data);
|
||||
if (streamData.getByPath("error") != null) {
|
||||
isDone.set(true);
|
||||
errorMessage.set(streamData.getByPath("error").toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if ("true".equals(streamData.getByPath("done").toString())) {
|
||||
isDone.set(true);
|
||||
}
|
||||
});
|
||||
// 轮询检查结束标志
|
||||
while (!isDone.get()) {
|
||||
ThreadUtil.sleep(100);
|
||||
}
|
||||
if (errorMessage.get() != null) {
|
||||
throw new RuntimeException(errorMessage.get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 带历史上下文的同步方式调用
|
||||
*/
|
||||
@Test
|
||||
@Disabled
|
||||
void testSimpleWithHistory(){
|
||||
final List<Message> messageList=new ArrayList<>();
|
||||
messageList.add(new Message("system",javaEngineerPrompt));
|
||||
messageList.add(new Message("user","帮我写一个Java通过Post方式发送JSON给HTTP接口,请求头带有token"));
|
||||
final String result = ollamaService.chat(messageList);
|
||||
assertNotNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
void testStreamWithHistory(){
|
||||
final List<Message> messageList=new ArrayList<>();
|
||||
messageList.add(new Message("system",javaEngineerPrompt));
|
||||
messageList.add(new Message("user","帮我写一个Java通过Post方式发送JSON给HTTP接口,请求头带有token"));
|
||||
final AtomicBoolean isDone = new AtomicBoolean(false);
|
||||
final AtomicReference<String> errorMessage = new AtomicReference<>();
|
||||
ollamaService.chat(messageList, data -> {
|
||||
// 输出到控制台
|
||||
final JSON streamData = JSONUtil.parse(data);
|
||||
if (streamData.getByPath("error") != null) {
|
||||
isDone.set(true);
|
||||
errorMessage.set(streamData.getByPath("error").toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if ("true".equals(streamData.getByPath("done").toString())) {
|
||||
isDone.set(true);
|
||||
}
|
||||
});
|
||||
// 轮询检查结束标志
|
||||
while (!isDone.get()) {
|
||||
ThreadUtil.sleep(100);
|
||||
}
|
||||
if (errorMessage.get() != null) {
|
||||
throw new RuntimeException(errorMessage.get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出所有已经拉取到服务器上的模型
|
||||
*/
|
||||
@Test
|
||||
@Disabled
|
||||
void testListModels(){
|
||||
final String models = ollamaService.listModels();
|
||||
final JSONArray modelList = JSONUtil.parse(models).getByPath("models", JSONArray.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 让Ollama拉取模型
|
||||
*/
|
||||
@Test
|
||||
@Disabled
|
||||
void testPullModel(){
|
||||
final String result = ollamaService.pullModel("qwen2.5:0.5b");
|
||||
final List<String> lines = SplitUtil.splitTrim(result, "\n");
|
||||
for (final String line : lines) {
|
||||
if(line.contains("error")){
|
||||
throw new RuntimeException(JSONUtil.parse(line).getByPath("error").toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 让Ollama删除已经存在的模型
|
||||
*/
|
||||
@Test
|
||||
@Disabled
|
||||
void testDeleteModel(){
|
||||
// 不会返回任何信息
|
||||
ollamaService.deleteModel("qwen2.5:0.5b");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai;
|
||||
package org.dromara.hutool.ai;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfigBuilder;
|
||||
import cn.hutool.v7.ai.core.AIService;
|
||||
import cn.hutool.v7.ai.model.deepseek.DeepSeekService;
|
||||
import org.dromara.hutool.ai.core.AIConfigBuilder;
|
||||
import org.dromara.hutool.ai.core.AIService;
|
||||
import org.dromara.hutool.ai.model.deepseek.DeepSeekService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
@@ -14,16 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai;
|
||||
package org.dromara.hutool.ai;
|
||||
|
||||
import cn.hutool.v7.ai.core.AIConfigBuilder;
|
||||
import cn.hutool.v7.ai.core.AIService;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.ai.model.deepseek.DeepSeekService;
|
||||
import cn.hutool.v7.ai.model.doubao.DoubaoService;
|
||||
import cn.hutool.v7.ai.model.grok.GrokService;
|
||||
import cn.hutool.v7.ai.model.hutool.HutoolService;
|
||||
import cn.hutool.v7.ai.model.openai.OpenaiService;
|
||||
import org.dromara.hutool.ai.core.AIConfigBuilder;
|
||||
import org.dromara.hutool.ai.core.AIService;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
import org.dromara.hutool.ai.model.deepseek.DeepSeekService;
|
||||
import org.dromara.hutool.ai.model.doubao.DoubaoService;
|
||||
import org.dromara.hutool.ai.model.grok.GrokService;
|
||||
import org.dromara.hutool.ai.model.hutool.HutoolService;
|
||||
import org.dromara.hutool.ai.model.openai.OpenaiService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.deepseek;
|
||||
package org.dromara.hutool.ai.model.deepseek;
|
||||
|
||||
import cn.hutool.v7.ai.AIServiceFactory;
|
||||
import cn.hutool.v7.ai.ModelName;
|
||||
import cn.hutool.v7.ai.core.AIConfigBuilder;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.core.thread.ThreadUtil;
|
||||
import org.dromara.hutool.ai.AIServiceFactory;
|
||||
import org.dromara.hutool.ai.ModelName;
|
||||
import org.dromara.hutool.ai.core.AIConfigBuilder;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.doubao;
|
||||
package org.dromara.hutool.ai.model.doubao;
|
||||
|
||||
import cn.hutool.v7.ai.AIServiceFactory;
|
||||
import cn.hutool.v7.ai.ModelName;
|
||||
import cn.hutool.v7.ai.Models;
|
||||
import cn.hutool.v7.ai.core.AIConfigBuilder;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.core.thread.ThreadUtil;
|
||||
import cn.hutool.v7.swing.img.ImgUtil;
|
||||
import org.dromara.hutool.ai.AIServiceFactory;
|
||||
import org.dromara.hutool.ai.ModelName;
|
||||
import org.dromara.hutool.ai.Models;
|
||||
import org.dromara.hutool.ai.core.AIConfigBuilder;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||
import org.dromara.hutool.swing.img.ImgUtil;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.grok;
|
||||
package org.dromara.hutool.ai.model.grok;
|
||||
|
||||
import cn.hutool.v7.ai.AIServiceFactory;
|
||||
import cn.hutool.v7.ai.ModelName;
|
||||
import cn.hutool.v7.ai.Models;
|
||||
import cn.hutool.v7.ai.core.AIConfigBuilder;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.core.thread.ThreadUtil;
|
||||
import cn.hutool.v7.swing.img.ImgUtil;
|
||||
import org.dromara.hutool.ai.AIServiceFactory;
|
||||
import org.dromara.hutool.ai.ModelName;
|
||||
import org.dromara.hutool.ai.Models;
|
||||
import org.dromara.hutool.ai.core.AIConfigBuilder;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||
import org.dromara.hutool.swing.img.ImgUtil;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -14,16 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.hutool;
|
||||
package org.dromara.hutool.ai.model.hutool;
|
||||
|
||||
import cn.hutool.v7.ai.AIException;
|
||||
import cn.hutool.v7.ai.AIServiceFactory;
|
||||
import cn.hutool.v7.ai.ModelName;
|
||||
import cn.hutool.v7.ai.core.AIConfigBuilder;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.core.io.file.FileUtil;
|
||||
import cn.hutool.v7.core.thread.ThreadUtil;
|
||||
import cn.hutool.v7.swing.img.ImgUtil;
|
||||
import org.dromara.hutool.ai.AIException;
|
||||
import org.dromara.hutool.ai.AIServiceFactory;
|
||||
import org.dromara.hutool.ai.ModelName;
|
||||
import org.dromara.hutool.ai.core.AIConfigBuilder;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
import org.dromara.hutool.core.io.file.FileUtil;
|
||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||
import org.dromara.hutool.swing.img.ImgUtil;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.ai.model.openai;
|
||||
package org.dromara.hutool.ai.model.openai;
|
||||
|
||||
import cn.hutool.v7.ai.AIServiceFactory;
|
||||
import cn.hutool.v7.ai.ModelName;
|
||||
import cn.hutool.v7.ai.Models;
|
||||
import cn.hutool.v7.ai.core.AIConfigBuilder;
|
||||
import cn.hutool.v7.ai.core.Message;
|
||||
import cn.hutool.v7.core.io.file.FileUtil;
|
||||
import cn.hutool.v7.core.thread.ThreadUtil;
|
||||
import org.dromara.hutool.ai.AIServiceFactory;
|
||||
import org.dromara.hutool.ai.ModelName;
|
||||
import org.dromara.hutool.ai.Models;
|
||||
import org.dromara.hutool.ai.core.AIConfigBuilder;
|
||||
import org.dromara.hutool.ai.core.Message;
|
||||
import org.dromara.hutool.core.io.file.FileUtil;
|
||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.hutool.v7</groupId>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>7.0.0-M2</version>
|
||||
<version>6.0.0-M23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-all</artifactId>
|
||||
@@ -33,7 +33,7 @@
|
||||
<description>
|
||||
Hutool是一个功能丰富且易用的Java工具库,通过诸多实用工具类的使用,旨在帮助开发者快速、便捷地完成各类开发任务。这些封装的工具涵盖了字符串、数字、集合、编码、日期、文件、IO、加密、数据库JDBC、JSON、HTTP客户端等一系列操作,可以满足各种不同的开发需求。
|
||||
</description>
|
||||
<url>https://github.com/chinabugotech/hutool</url>
|
||||
<url>https://github.com/dromara/hutool</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7;
|
||||
package org.dromara.hutool;
|
||||
|
||||
import cn.hutool.v7.core.lang.ConsoleTable;
|
||||
import cn.hutool.v7.core.reflect.ClassUtil;
|
||||
import cn.hutool.v7.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.lang.ConsoleTable;
|
||||
import org.dromara.hutool.core.reflect.ClassUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@@ -60,7 +60,7 @@ public class Hutool {
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static Set<Class<?>> getAllUtils() {
|
||||
return ClassUtil.scanPackage("cn.hutool.v7",
|
||||
return ClassUtil.scanPackage("org.dromara.hutool",
|
||||
(clazz) -> (!clazz.isInterface()) && StrUtil.endWith(clazz.getSimpleName(), "Util"));
|
||||
}
|
||||
|
||||
@@ -23,4 +23,4 @@
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
package cn.hutool.v7;
|
||||
package org.dromara.hutool;
|
||||
@@ -23,15 +23,15 @@
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.hutool.v7</groupId>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>7.0.0-M2</version>
|
||||
<version>6.0.0-M23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-bom</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>提供丰富的Java工具方法,此模块为Hutool所有模块汇总,最终形式为拆分开的多个jar包,可以通过exclude方式排除不需要的模块</description>
|
||||
<url>https://github.com/chinabugotech/hutool</url>
|
||||
<url>https://github.com/dromara/hutool</url>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.hutool.v7</groupId>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>7.0.0-M2</version>
|
||||
<version>6.0.0-M23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-core</artifactId>
|
||||
@@ -33,7 +33,7 @@
|
||||
<description>Hutool核心,包括集合、字符串、Bean等工具</description>
|
||||
|
||||
<properties>
|
||||
<Automatic-Module-Name>cn.hutool.v7.core</Automatic-Module-Name>
|
||||
<Automatic-Module-Name>org.dromara.hutool.core</Automatic-Module-Name>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2025 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.bean;
|
||||
|
||||
import cn.hutool.v7.core.bean.copier.ValueProvider;
|
||||
import cn.hutool.v7.core.reflect.ConstructorUtil;
|
||||
|
||||
import java.lang.reflect.RecordComponent;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* java.lang.Record 相关工具类封装
|
||||
*
|
||||
* @author Looly
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public class RecordUtil {
|
||||
|
||||
/**
|
||||
* 判断给定类是否为Record类
|
||||
*
|
||||
* @param clazz 类
|
||||
* @return 是否为Record类
|
||||
*/
|
||||
public static boolean isRecord(final Class<?> clazz) {
|
||||
return null != clazz && clazz.isRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Record类中所有字段名称,getter方法名与字段同名
|
||||
*
|
||||
* @param recordClass Record类
|
||||
* @return 字段数组
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map.Entry<String, Type>[] getRecordComponents(final Class<?> recordClass) {
|
||||
final RecordComponent[] components = recordClass.getRecordComponents();
|
||||
final Map.Entry<String, Type>[] entries = new Map.Entry[components.length];
|
||||
for (int i = 0; i < components.length; i++) {
|
||||
entries[i] = new AbstractMap.SimpleEntry<>(components[i].getName(), components[i].getGenericType());
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化Record类
|
||||
*
|
||||
* @param recordClass 类
|
||||
* @param valueProvider 参数值提供器
|
||||
* @return Record类
|
||||
*/
|
||||
public static Object newInstance(final Class<?> recordClass, final ValueProvider<String> valueProvider) {
|
||||
final Map.Entry<String, Type>[] recordComponents = getRecordComponents(recordClass);
|
||||
final Object[] args = new Object[recordComponents.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
args[i] = valueProvider.value(recordComponents[i].getKey(), recordComponents[i].getValue());
|
||||
}
|
||||
|
||||
return ConstructorUtil.newInstance(recordClass, args);
|
||||
}
|
||||
}
|
||||
@@ -1,307 +0,0 @@
|
||||
package cn.hutool.v7.core.thread;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 可召回批处理线程池执行器
|
||||
* <pre>
|
||||
* 1.数据分批并行处理
|
||||
* 2.主线程、线程池混合执行批处理任务,主线程空闲时会尝试召回线程池队列中的任务执行
|
||||
* 3.线程安全,可用同时执行多个任务,线程池满载时,效率与单线程模式相当,无阻塞风险,无脑提交任务即可
|
||||
* </pre>
|
||||
*
|
||||
* 适用场景:
|
||||
* <pre>
|
||||
* 1.批量处理数据且需要同步结束的场景,能一定程度上提高吞吐量、防止任务堆积 {@link #process(List, int, Function)}
|
||||
* 2.普通查询接口加速 {@link #processByWarp(Warp[])}
|
||||
* </pre>
|
||||
*
|
||||
* @author likuan
|
||||
*/
|
||||
public class RecyclableBatchThreadPoolExecutor {
|
||||
|
||||
private final ExecutorService executor;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param poolSize 线程池大小
|
||||
*/
|
||||
public RecyclableBatchThreadPoolExecutor(final int poolSize){
|
||||
this(poolSize,"recyclable-batch-pool-");
|
||||
}
|
||||
|
||||
/**
|
||||
* 建议的构造方法
|
||||
* <pre>
|
||||
* 1.使用无界队列,主线程会召回队列中的任务执行,不会有任务堆积,无需考虑拒绝策略
|
||||
* 2.假如在web场景中请求量过大导致oom,不使用此工具也会有同样的结果,甚至更严重,应该对请求做限制或做其他优化
|
||||
* </pre>
|
||||
*
|
||||
* @param poolSize 线程池大小
|
||||
* @param threadPoolPrefix 线程名前缀
|
||||
*/
|
||||
public RecyclableBatchThreadPoolExecutor(final int poolSize, final String threadPoolPrefix){
|
||||
final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
final ThreadFactory threadFactory = r -> {
|
||||
final Thread t = new Thread(r, threadPoolPrefix + threadNumber.getAndIncrement());
|
||||
if (t.isDaemon()) {
|
||||
t.setDaemon(false);
|
||||
}
|
||||
if (t.getPriority() != Thread.NORM_PRIORITY) {
|
||||
t.setPriority(Thread.NORM_PRIORITY);
|
||||
}
|
||||
return t;
|
||||
};
|
||||
this.executor = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(),threadFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义线程池,一般不需要使用
|
||||
* @param executor 线程池
|
||||
*/
|
||||
public RecyclableBatchThreadPoolExecutor(final ExecutorService executor){
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭线程池
|
||||
*/
|
||||
public void shutdown(){
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取线程池
|
||||
* @return ExecutorService
|
||||
*/
|
||||
public ExecutorService getExecutor(){
|
||||
return executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分批次处理数据
|
||||
* <pre>
|
||||
* 1.所有批次执行完成后会过滤null并返回合并结果,保持输入数据顺序,不需要结果{@link Function}返回null即可
|
||||
* 2.{@link Function}需自行处理异常、保证线程安全
|
||||
* 3.原始数据在分片后可能被外部修改,导致批次数据不一致,如有必要,传参之前进行数据拷贝
|
||||
* 4.主线程会参与处理批次数据,如果要异步执行任务请使用普通线程池
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> 输入数据类型
|
||||
* @param <R> 输出数据类型
|
||||
* @param data 待处理数据集合
|
||||
* @param batchSize 每批次数据量
|
||||
* @param processor 单条数据处理函数
|
||||
* @return 处理结果集合
|
||||
*/
|
||||
public <T,R> List<R> process(final List<T> data, final int batchSize, final Function<T,R> processor) {
|
||||
if (batchSize < 1) {
|
||||
throw new IllegalArgumentException("batchSize >= 1");
|
||||
}
|
||||
final List<List<T>> batches = splitData(data, batchSize);
|
||||
final int batchCount = batches.size();
|
||||
final int minusOne = batchCount - 1;
|
||||
final ArrayDeque<IdempotentTask<R>> taskQueue = new ArrayDeque<>(minusOne);
|
||||
final Map<Integer,Future<TaskResult<R>>> futuresMap = new HashMap<>();
|
||||
// 提交前 batchCount-1 批任务
|
||||
for (int i = 0 ; i < minusOne ; i++) {
|
||||
final int index = i;
|
||||
final IdempotentTask<R> task = new IdempotentTask<>(i,() -> processBatch(batches.get(index), processor));
|
||||
taskQueue.add(task);
|
||||
futuresMap.put(i,executor.submit(task));
|
||||
}
|
||||
@SuppressWarnings("unchecked") final List<R>[] resultArr = new ArrayList[batchCount];
|
||||
// 处理最后一批
|
||||
resultArr[minusOne] = processBatch(batches.get(minusOne), processor);
|
||||
// 处理剩余任务
|
||||
processRemainingTasks(taskQueue, futuresMap,resultArr);
|
||||
//排序、过滤null
|
||||
return Stream.of(resultArr)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(List::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理剩余任务并收集结果
|
||||
* @param taskQueue 任务队列
|
||||
* @param futuresMap 异步任务映射
|
||||
* @param resultArr 结果存储数组
|
||||
*/
|
||||
private <R> void processRemainingTasks(final Queue<IdempotentTask<R>> taskQueue, final Map<Integer,Future<TaskResult<R>>> futuresMap, final List<R>[] resultArr) {
|
||||
// 主消费未执行任务
|
||||
IdempotentTask<R> task;
|
||||
while ((task = taskQueue.poll()) != null) {
|
||||
try {
|
||||
final TaskResult<R> call = task.call();
|
||||
if (call.effective) {
|
||||
// 取消被主线程执行任务
|
||||
final Future<TaskResult<R>> future = futuresMap.remove(task.index);
|
||||
future.cancel(false);
|
||||
//加入结果集
|
||||
resultArr[task.index] = call.result;
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
// 不处理异常
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
futuresMap.forEach((index,future)->{
|
||||
try {
|
||||
final TaskResult<R> taskResult = future.get();
|
||||
if(taskResult.effective){
|
||||
resultArr[index] = taskResult.result;
|
||||
}
|
||||
} catch (final InterruptedException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 幂等任务包装类,确保任务只执行一次
|
||||
*/
|
||||
private static class IdempotentTask<R> implements Callable<TaskResult<R>> {
|
||||
|
||||
private final int index;
|
||||
private final Callable<List<R>> delegate;
|
||||
private final AtomicBoolean executed = new AtomicBoolean(false);
|
||||
|
||||
IdempotentTask(final int index, final Callable<List<R>> delegate) {
|
||||
this.index = index;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskResult<R> call() throws Exception {
|
||||
if (executed.compareAndSet(false, true)) {
|
||||
return new TaskResult<>(delegate.call(), true);
|
||||
}
|
||||
return new TaskResult<>(null, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 结果包装类,标记结果有效性
|
||||
*/
|
||||
private static class TaskResult<R>{
|
||||
private final List<R> result;
|
||||
private final boolean effective;
|
||||
TaskResult(final List<R> result, final boolean effective){
|
||||
this.result = result;
|
||||
this.effective = effective;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据分片方法
|
||||
* @param data 原始数据
|
||||
* @param batchSize 每批次数据量
|
||||
* @return 分片后的二维集合
|
||||
*/
|
||||
private static <T> List<List<T>> splitData(final List<T> data, final int batchSize) {
|
||||
final int batchCount = (data.size() + batchSize - 1) / batchSize;
|
||||
return new AbstractList<List<T>>() {
|
||||
@Override
|
||||
public List<T> get(final int index) {
|
||||
final int from = index * batchSize;
|
||||
final int to = Math.min((index + 1) * batchSize, data.size());
|
||||
return data.subList(from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return batchCount;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 单批次数据处理
|
||||
* @param batch 单批次数据
|
||||
* @param processor 处理函数
|
||||
* @return 处理结果
|
||||
*/
|
||||
private static <T,R> List<R> processBatch(final List<T> batch, final Function<T,R> processor) {
|
||||
return batch.stream().map(processor).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理Warp数组
|
||||
*
|
||||
* <pre>{@code
|
||||
* Warp<String> warp1 = Warp.of(this::select1);
|
||||
* Warp<List<String>> warp2 = Warp.of(this::select2);
|
||||
* executor.processByWarp(warp1, warp2);
|
||||
* String r1 = warp1.get();
|
||||
* List<String> r2 = warp2.get();
|
||||
* }</pre>
|
||||
*
|
||||
* @param warps Warp数组
|
||||
* @return Warp集合,此方法返回结果为空的不会被过滤
|
||||
*/
|
||||
public List<Warp<?>> processByWarp(final Warp<?>... warps) {
|
||||
return processByWarp(Arrays.asList(warps));
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理Warp集合
|
||||
* @param warps Warp集合
|
||||
* @return Warp集合,此方法返回结果为空的不会被过滤
|
||||
*/
|
||||
public List<Warp<?>> processByWarp(final List<Warp<?>> warps) {
|
||||
return process(warps, 1, Warp::execute);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理逻辑包装类
|
||||
* @param <R> 结果类型
|
||||
*/
|
||||
public static class Warp<R>{
|
||||
|
||||
private Warp(final Supplier<R> supplier){
|
||||
Objects.requireNonNull(supplier);
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Warp
|
||||
* @param supplier 执行逻辑
|
||||
* @return Warp
|
||||
* @param <R> 结果类型
|
||||
*/
|
||||
public static <R> Warp<R> of(final Supplier<R> supplier){
|
||||
return new Warp<>(supplier);
|
||||
}
|
||||
|
||||
private final Supplier<R> supplier;
|
||||
private R result;
|
||||
|
||||
/**
|
||||
* 获取结果
|
||||
* @return 结果
|
||||
*/
|
||||
public R get() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行
|
||||
* @return this
|
||||
*/
|
||||
public Warp<R> execute() {
|
||||
result = supplier.get();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2025 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.thread.lock;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.StampedLock;
|
||||
|
||||
/**
|
||||
* 锁相关工具
|
||||
*
|
||||
* @author Looly
|
||||
* @since 5.2.5
|
||||
*/
|
||||
public class LockUtil {
|
||||
|
||||
private static final NoLock NO_LOCK = new NoLock();
|
||||
|
||||
/**
|
||||
* 创建{@link StampedLock}锁
|
||||
*
|
||||
* @return {@link StampedLock}锁
|
||||
*/
|
||||
public static StampedLock createStampLock() {
|
||||
return new StampedLock();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建{@link ReentrantReadWriteLock}锁
|
||||
*
|
||||
* @param fair 是否公平锁
|
||||
* @return {@link ReentrantReadWriteLock}锁
|
||||
*/
|
||||
public static ReentrantReadWriteLock createReadWriteLock(final boolean fair) {
|
||||
return new ReentrantReadWriteLock(fair);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单例的无锁对象
|
||||
*
|
||||
* @return {@link NoLock}
|
||||
*/
|
||||
public static NoLock getNoLock(){
|
||||
return NO_LOCK;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2025 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 锁的实现
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
package cn.hutool.v7.core.thread.lock;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation;
|
||||
package org.dromara.hutool.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation;
|
||||
package org.dromara.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.v7.core.annotation.elements.HierarchicalAnnotatedElements;
|
||||
import cn.hutool.v7.core.annotation.elements.MetaAnnotatedElement;
|
||||
import cn.hutool.v7.core.annotation.elements.RepeatableMetaAnnotatedElement;
|
||||
import cn.hutool.v7.core.array.ArrayUtil;
|
||||
import cn.hutool.v7.core.map.reference.WeakConcurrentMap;
|
||||
import cn.hutool.v7.core.util.ObjUtil;
|
||||
import org.dromara.hutool.core.annotation.elements.HierarchicalAnnotatedElements;
|
||||
import org.dromara.hutool.core.annotation.elements.MetaAnnotatedElement;
|
||||
import org.dromara.hutool.core.annotation.elements.RepeatableMetaAnnotatedElement;
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Inherited;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation;
|
||||
package org.dromara.hutool.core.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -14,10 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation;
|
||||
package org.dromara.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.v7.core.reflect.method.MethodUtil;
|
||||
import cn.hutool.v7.core.text.CharSequenceUtil;
|
||||
import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap;
|
||||
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
||||
import org.dromara.hutool.core.text.CharSequenceUtil;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
@@ -27,7 +28,6 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -96,7 +96,7 @@ public final class AnnotationMappingProxy<T extends Annotation> implements Invoc
|
||||
private AnnotationMappingProxy(final AnnotationMapping<T> annotation) {
|
||||
final int methodCount = annotation.getAttributes().length;
|
||||
this.methods = new HashMap<>(methodCount + 5);
|
||||
this.valueCache = new ConcurrentHashMap<>(methodCount);
|
||||
this.valueCache = new SafeConcurrentHashMap<>(methodCount);
|
||||
this.mapping = annotation;
|
||||
loadMethods();
|
||||
}
|
||||
@@ -14,12 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation;
|
||||
package org.dromara.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.v7.core.reflect.method.MethodUtil;
|
||||
import cn.hutool.v7.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
@@ -35,7 +34,6 @@ import java.util.Map;
|
||||
* @since 5.7.23
|
||||
*/
|
||||
public class AnnotationProxy<T extends Annotation> implements Annotation, InvocationHandler, Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
@@ -14,21 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation;
|
||||
package org.dromara.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.v7.core.annotation.elements.CombinationAnnotatedElement;
|
||||
import cn.hutool.v7.core.array.ArrayUtil;
|
||||
import cn.hutool.v7.core.classloader.ClassLoaderUtil;
|
||||
import cn.hutool.v7.core.exception.HutoolException;
|
||||
import cn.hutool.v7.core.func.LambdaInfo;
|
||||
import cn.hutool.v7.core.func.LambdaUtil;
|
||||
import cn.hutool.v7.core.func.SerFunction;
|
||||
import cn.hutool.v7.core.map.reference.WeakConcurrentMap;
|
||||
import cn.hutool.v7.core.reflect.FieldUtil;
|
||||
import cn.hutool.v7.core.reflect.method.MethodUtil;
|
||||
import cn.hutool.v7.core.text.CharSequenceUtil;
|
||||
import cn.hutool.v7.core.text.StrUtil;
|
||||
import cn.hutool.v7.core.util.ObjUtil;
|
||||
import org.dromara.hutool.core.annotation.elements.CombinationAnnotatedElement;
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.classloader.ClassLoaderUtil;
|
||||
import org.dromara.hutool.core.exception.HutoolException;
|
||||
import org.dromara.hutool.core.func.LambdaInfo;
|
||||
import org.dromara.hutool.core.func.LambdaUtil;
|
||||
import org.dromara.hutool.core.func.SerFunction;
|
||||
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
|
||||
import org.dromara.hutool.core.reflect.FieldUtil;
|
||||
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
||||
import org.dromara.hutool.core.text.CharSequenceUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation;
|
||||
package org.dromara.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.v7.core.reflect.ClassUtil;
|
||||
import cn.hutool.v7.core.reflect.method.MethodUtil;
|
||||
import cn.hutool.v7.core.text.CharSequenceUtil;
|
||||
import org.dromara.hutool.core.reflect.ClassUtil;
|
||||
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
||||
import org.dromara.hutool.core.text.CharSequenceUtil;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation;
|
||||
package org.dromara.hutool.core.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation;
|
||||
package org.dromara.hutool.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation;
|
||||
package org.dromara.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.v7.core.array.ArrayUtil;
|
||||
import cn.hutool.v7.core.collection.CollUtil;
|
||||
import cn.hutool.v7.core.map.reference.WeakConcurrentMap;
|
||||
import cn.hutool.v7.core.reflect.method.MethodUtil;
|
||||
import cn.hutool.v7.core.text.CharSequenceUtil;
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.collection.CollUtil;
|
||||
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
|
||||
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
||||
import org.dromara.hutool.core.text.CharSequenceUtil;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Repeatable;
|
||||
@@ -14,16 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation;
|
||||
package org.dromara.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.v7.core.annotation.elements.MetaAnnotatedElement;
|
||||
import cn.hutool.v7.core.collection.CollUtil;
|
||||
import cn.hutool.v7.core.lang.Assert;
|
||||
import cn.hutool.v7.core.map.multi.Graph;
|
||||
import cn.hutool.v7.core.reflect.ClassUtil;
|
||||
import cn.hutool.v7.core.reflect.method.MethodUtil;
|
||||
import cn.hutool.v7.core.text.CharSequenceUtil;
|
||||
import cn.hutool.v7.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.annotation.elements.MetaAnnotatedElement;
|
||||
import org.dromara.hutool.core.collection.CollUtil;
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.map.multi.Graph;
|
||||
import org.dromara.hutool.core.reflect.ClassUtil;
|
||||
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
||||
import org.dromara.hutool.core.text.CharSequenceUtil;
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation;
|
||||
package org.dromara.hutool.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation.elements;
|
||||
package org.dromara.hutool.core.annotation.elements;
|
||||
|
||||
import cn.hutool.v7.core.annotation.AnnotationUtil;
|
||||
import cn.hutool.v7.core.array.ArrayUtil;
|
||||
import cn.hutool.v7.core.collection.set.SetUtil;
|
||||
import cn.hutool.v7.core.map.TableMap;
|
||||
import org.dromara.hutool.core.annotation.AnnotationUtil;
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.collection.set.SetUtil;
|
||||
import org.dromara.hutool.core.map.TableMap;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.*;
|
||||
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation.elements;
|
||||
package org.dromara.hutool.core.annotation.elements;
|
||||
|
||||
import cn.hutool.v7.core.annotation.AnnotationUtil;
|
||||
import cn.hutool.v7.core.collection.CollUtil;
|
||||
import cn.hutool.v7.core.collection.set.SetUtil;
|
||||
import cn.hutool.v7.core.reflect.ClassUtil;
|
||||
import cn.hutool.v7.core.reflect.method.MethodUtil;
|
||||
import cn.hutool.v7.core.text.CharSequenceUtil;
|
||||
import cn.hutool.v7.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.annotation.AnnotationUtil;
|
||||
import org.dromara.hutool.core.collection.CollUtil;
|
||||
import org.dromara.hutool.core.collection.set.SetUtil;
|
||||
import org.dromara.hutool.core.reflect.ClassUtil;
|
||||
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
||||
import org.dromara.hutool.core.text.CharSequenceUtil;
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.annotation.elements;
|
||||
package org.dromara.hutool.core.annotation.elements;
|
||||
|
||||
import cn.hutool.v7.core.annotation.AnnotationMapping;
|
||||
import cn.hutool.v7.core.annotation.AnnotationUtil;
|
||||
import cn.hutool.v7.core.annotation.ResolvedAnnotationMapping;
|
||||
import cn.hutool.v7.core.stream.EasyStream;
|
||||
import cn.hutool.v7.core.text.CharSequenceUtil;
|
||||
import cn.hutool.v7.core.array.ArrayUtil;
|
||||
import cn.hutool.v7.core.util.ObjUtil;
|
||||
import org.dromara.hutool.core.annotation.AnnotationMapping;
|
||||
import org.dromara.hutool.core.annotation.AnnotationUtil;
|
||||
import org.dromara.hutool.core.annotation.ResolvedAnnotationMapping;
|
||||
import org.dromara.hutool.core.stream.EasyStream;
|
||||
import org.dromara.hutool.core.text.CharSequenceUtil;
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Inherited;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user