mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
commit
5b1476c8c9
@ -101,6 +101,7 @@ A Java-based tool class for files, streams, encryption and decryption, transcodi
|
|||||||
| hutool-poi | Tools for working with Excel and Word in POI |
|
| hutool-poi | Tools for working with Excel and Word in POI |
|
||||||
| hutool-socket | Java-based tool classes for NIO and AIO sockets |
|
| hutool-socket | Java-based tool classes for NIO and AIO sockets |
|
||||||
| hutool-swing | Swing and AWT tools |
|
| hutool-swing | Swing and AWT tools |
|
||||||
|
| hutool-ai | AI tools |
|
||||||
|
|
||||||
Each module can be introduced individually, or all modules can be introduced by introducing `hutool-all` as required.
|
Each module can be introduced individually, or all modules can be introduced by introducing `hutool-all` as required.
|
||||||
|
|
||||||
|
27
README.md
27
README.md
@ -87,20 +87,21 @@ Hutool目前主要版本4.x、5.x、6.x,选择如下:
|
|||||||
|
|
||||||
## 🛠️包含组件
|
## 🛠️包含组件
|
||||||
|
|
||||||
| 模块 | 介绍 |
|
| 模块 | 介绍 |
|
||||||
|----------------|-------------------------------------------------|
|
|----------------|-----------------------------------------------|
|
||||||
| hutool-core | 核心,包括Bean操作、日期、各种Util等 |
|
| hutool-core | 核心,包括Bean操作、日期、各种Util等 |
|
||||||
| hutool-cron | 定时任务模块,提供类Crontab表达式的定时任务 |
|
| hutool-cron | 定时任务模块,提供类Crontab表达式的定时任务 |
|
||||||
| hutool-crypto | 加密解密模块,提供对称、非对称和摘要算法封装 |
|
| hutool-crypto | 加密解密模块,提供对称、非对称和摘要算法封装 |
|
||||||
| hutool-db | JDBC封装后的数据操作,基于ActiveRecord思想 |
|
| hutool-db | JDBC封装后的数据操作,基于ActiveRecord思想 |
|
||||||
| hutool-extra | 扩展模块,对第三方封装(模板引擎、邮件、Servlet、二维码、Emoji、FTP、分词等) |
|
| hutool-extra | 扩展模块,对第三方封装(模板引擎、邮件、Servlet、二维码、Emoji、FTP、分词等) |
|
||||||
| hutool-http | 基于HttpUrlConnection、HttpClient、OkHttp的Http客户端封装 |
|
| hutool-http | 基于HttpUrlConnection、HttpClient、OkHttp的Http客户端封装 |
|
||||||
| hutool-log | 功能强大的日志门面 |
|
| hutool-log | 功能强大的日志门面 |
|
||||||
| hutool-setting | 功能更强大的配置文件封装和工具 |
|
| hutool-setting | 功能更强大的配置文件封装和工具 |
|
||||||
| hutool-json | JSON实现 |
|
| hutool-json | JSON实现 |
|
||||||
| hutool-poi | POI中Excel和Word的封装以及OFD封装 |
|
| hutool-poi | POI中Excel和Word的封装以及OFD封装 |
|
||||||
| hutool-socket | 基于Java的NIO和AIO的Socket封装 |
|
| hutool-socket | 基于Java的NIO和AIO的Socket封装 |
|
||||||
| hutool-swing | Swing和JWT相关封装 |
|
| hutool-swing | Swing和JWT相关封装 |
|
||||||
|
| hutool-ai | AI大模型封装 |
|
||||||
|
|
||||||
可以根据需求对每个模块单独引入,也可以通过引入`hutool-all`方式引入所有模块。
|
可以根据需求对每个模块单独引入,也可以通过引入`hutool-all`方式引入所有模块。
|
||||||
|
|
||||||
|
17
hutool-ai/README.md
Normal file
17
hutool-ai/README.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<p align="center">
|
||||||
|
<a href="https://hutool.cn/"><img src="https://plus.hutool.cn/images/hutool.svg" width="45%"></a>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<strong>🍬Make Java Sweet Again.</strong>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
👉 <a href="https://hutool.cn">https://hutool.cn/</a> 👈
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## 📚Hutool-ai 模块介绍
|
||||||
|
|
||||||
|
`Hutool-ai`提供了AI大模型的封装。
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## 🛠️包含内容
|
54
hutool-ai/pom.xml
Normal file
54
hutool-ai/pom.xml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.dromara.hutool</groupId>
|
||||||
|
<artifactId>hutool-parent</artifactId>
|
||||||
|
<version>6.0.0-M21</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>hutool-ai</artifactId>
|
||||||
|
<name>${project.artifactId}</name>
|
||||||
|
<description>Hutool AI大模型封装</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<Automatic-Module-Name>org.dromara.hutool.ai</Automatic-Module-Name>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<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>org.dromara.hutool</groupId>
|
||||||
|
<artifactId>hutool-log</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara.hutool</groupId>
|
||||||
|
<artifactId>hutool-json</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara.hutool</groupId>
|
||||||
|
<artifactId>hutool-swing</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,35 @@
|
|||||||
|
package org.dromara.hutool.ai;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.exception.ExceptionUtil;
|
||||||
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常处理类
|
||||||
|
*/
|
||||||
|
public class AIException extends RuntimeException {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public AIException(Throwable e) {
|
||||||
|
super(ExceptionUtil.getMessage(e), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AIException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AIException(String messageTemplate, Object... params) {
|
||||||
|
super(StrUtil.format(messageTemplate, params));
|
||||||
|
}
|
||||||
|
|
||||||
|
public AIException(String message, Throwable throwable) {
|
||||||
|
super(message, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AIException(String message, Throwable throwable, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, throwable, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AIException(Throwable throwable, String messageTemplate, Object... params) {
|
||||||
|
super(StrUtil.format(messageTemplate, params), throwable);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package org.dromara.hutool.ai;
|
||||||
|
|
||||||
|
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 org.dromara.hutool.http.HttpUtil;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建AIModelService的工厂类
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class AIServiceFactory {
|
||||||
|
|
||||||
|
private static final Map<String, AIServiceProvider> providers = new SafeConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 加载所有 AIModelProvider 实现类
|
||||||
|
static {
|
||||||
|
ServiceLoader<AIServiceProvider> loader = ServiceLoader.load(AIServiceProvider.class);
|
||||||
|
for (AIServiceProvider provider : loader) {
|
||||||
|
providers.put(provider.getServiceName().toLowerCase(), provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取AI服务
|
||||||
|
*
|
||||||
|
* @param config AIConfig配置
|
||||||
|
* @return AI服务实例
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static AIService getAIService(AIConfig config) {
|
||||||
|
return getAIService(config, AIService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取AI服务
|
||||||
|
*
|
||||||
|
* @param config AIConfig配置
|
||||||
|
* @param clazz AI服务类
|
||||||
|
* @return clazz对应的AI服务类实例
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static <T extends AIService> T getAIService(AIConfig config, Class<T> clazz) {
|
||||||
|
//异步执行
|
||||||
|
CompletableFuture.runAsync(() -> {
|
||||||
|
try {
|
||||||
|
HttpUtil.get("https://static.hutool.cn");
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AIServiceProvider provider = providers.get(config.getModelName().toLowerCase());
|
||||||
|
if (provider == null) {
|
||||||
|
throw new IllegalArgumentException("Unsupported model: " + config.getModelName());
|
||||||
|
}
|
||||||
|
|
||||||
|
AIService service = provider.create(config);
|
||||||
|
if (!clazz.isInstance(service)) {
|
||||||
|
throw new AIException("Model service is not of type: " + clazz.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T) service;
|
||||||
|
}
|
||||||
|
}
|
112
hutool-ai/src/main/java/org/dromara/hutool/ai/AIUtil.java
Normal file
112
hutool-ai/src/main/java/org/dromara/hutool/ai/AIUtil.java
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package org.dromara.hutool.ai;
|
||||||
|
|
||||||
|
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.openai.OpenaiService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI工具类
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class AIUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取AI模型服务,每个大模型提供的功能会不一样,可以调用此方法指定不同AI服务类,调用不同的功能
|
||||||
|
*
|
||||||
|
* @param config 创建的AI服务模型的配置
|
||||||
|
* @param clazz AI模型服务类
|
||||||
|
* @return AIModelService的实现类实例
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static <T extends AIService> T getAIService(AIConfig config, Class<T> clazz) {
|
||||||
|
return AIServiceFactory.getAIService(config, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取AI模型服务
|
||||||
|
*
|
||||||
|
* @param config 创建的AI服务模型的配置
|
||||||
|
* @return AIModelService 其中只有公共方法
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static AIService getAIService(AIConfig config) {
|
||||||
|
return getAIService(config, AIService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取DeepSeek模型服务
|
||||||
|
*
|
||||||
|
* @param config 创建的AI服务模型的配置
|
||||||
|
* @return DeepSeekService
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static DeepSeekService getDeepSeekService(AIConfig config) {
|
||||||
|
return getAIService(config, DeepSeekService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Doubao模型服务
|
||||||
|
*
|
||||||
|
* @param config 创建的AI服务模型的配置
|
||||||
|
* @return DoubaoService
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static DoubaoService getDoubaoService(AIConfig config) {
|
||||||
|
return getAIService(config, DoubaoService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Grok模型服务
|
||||||
|
*
|
||||||
|
* @param config 创建的AI服务模型的配置
|
||||||
|
* @return GrokService
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static GrokService getGrokService(AIConfig config) {
|
||||||
|
return getAIService(config, GrokService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Openai模型服务
|
||||||
|
*
|
||||||
|
* @param config 创建的AI服务模型的配置
|
||||||
|
* @return OpenAIService
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static OpenaiService getOpenAIService(AIConfig config) {
|
||||||
|
return getAIService(config, OpenaiService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI大模型对话功能
|
||||||
|
*
|
||||||
|
* @param config 创建的AI服务模型的配置
|
||||||
|
* @param prompt 需要对话的内容
|
||||||
|
* @return AI模型返回的Response响应字符串
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static String chat(AIConfig config, String prompt) {
|
||||||
|
return getAIService(config).chat(prompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI大模型对话功能
|
||||||
|
*
|
||||||
|
* @param config 创建的AI服务模型的配置
|
||||||
|
* @param messages 由目前为止的对话组成的消息列表,可以设置role,content。详细参考官方文档
|
||||||
|
* @return AI模型返回的Response响应字符串
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static String chat(AIConfig config, List<Message> messages) {
|
||||||
|
return getAIService(config).chat(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
hutool-ai/src/main/java/org/dromara/hutool/ai/ModelName.java
Normal file
24
hutool-ai/src/main/java/org/dromara/hutool/ai/ModelName.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package org.dromara.hutool.ai;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型厂商的名称(不指具体的模型)
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public enum ModelName {
|
||||||
|
DEEPSEEK("deepSeek"),
|
||||||
|
OPENAI("openai"),
|
||||||
|
DOUBAO("doubao"),
|
||||||
|
GROK("grok");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
ModelName(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
141
hutool-ai/src/main/java/org/dromara/hutool/ai/Models.java
Normal file
141
hutool-ai/src/main/java/org/dromara/hutool/ai/Models.java
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package org.dromara.hutool.ai;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 各模型厂商包含的model(指具体的模型)
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class Models {
|
||||||
|
|
||||||
|
// DeepSeek的模型
|
||||||
|
public enum DeepSeek {
|
||||||
|
DEEPSEEK_CHAT("deepseek-chat"),
|
||||||
|
DEEPSEEK_REASONER("deepseek-reasoner");
|
||||||
|
|
||||||
|
private final String model;
|
||||||
|
|
||||||
|
DeepSeek(String model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Openai的模型
|
||||||
|
public enum Openai {
|
||||||
|
GPT_4_5_PREVIEW("gpt-4.5-preview"),
|
||||||
|
GPT_4O("gpt-4o"),
|
||||||
|
CHATGPT_4O_LATEST("chatgpt-4o-latest"),
|
||||||
|
GPT_4O_MINI("gpt-4o-mini"),
|
||||||
|
O1("o1"),
|
||||||
|
O1_MINI("o1-mini"),
|
||||||
|
O1_PREVIEW("o1-preview"),
|
||||||
|
O3_MINI("o3-mini"),
|
||||||
|
GPT_4O_REALTIME_PREVIEW("gpt-4o-realtime-preview"),
|
||||||
|
GPT_4O_MINI_REALTIME_PREVIEW("gpt-4o-mini-realtime-preview"),
|
||||||
|
GPT_4O_AUDIO_PREVIEW("gpt-4o-audio-preview"),
|
||||||
|
GPT_4O_MINI_AUDIO_PREVIEW("gpt-4o-mini-audio-preview"),
|
||||||
|
GPT_4_TURBO("gpt-4-turbo"),
|
||||||
|
GPT_4_TURBO_PREVIEW("gpt-4-turbo-preview"),
|
||||||
|
GPT_4("gpt-4"),
|
||||||
|
GPT_3_5_TURBO_0125("gpt-3.5-turbo-0125"),
|
||||||
|
GPT_3_5_TURBO("gpt-3.5-turbo"),
|
||||||
|
GPT_3_5_TURBO_1106("gpt-3.5-turbo-1106"),
|
||||||
|
GPT_3_5_TURBO_INSTRUCT("gpt-3.5-turbo-instruct"),
|
||||||
|
DALL_E_3("dall-e-3"),
|
||||||
|
DALL_E_2("dall-e-2"),
|
||||||
|
TTS_1("tts-1"),
|
||||||
|
TTS_1_HD("tts-1-hd"),
|
||||||
|
WHISPER_1("whisper-1"),
|
||||||
|
TEXT_EMBEDDING_3_LARGE("text-embedding-3-large"),
|
||||||
|
TEXT_EMBEDDING_3_SMALL("text-embedding-3-small"),
|
||||||
|
TEXT_EMBEDDING_ADA_002("text-embedding-ada-002"),
|
||||||
|
OMNI_MODERATION_LATEST("omni-moderation-latest"),
|
||||||
|
OMNI_MODERATION_2024_09_26("omni-moderation-2024-09-26"),
|
||||||
|
TEXT_MODERATION_LATEST("text-moderation-latest"),
|
||||||
|
TEXT_MODERATION_STABLE("text-moderation-stable"),
|
||||||
|
TEXT_MODERATION_007("text-moderation-007"),
|
||||||
|
BABBAGE_002("babbage-002"),
|
||||||
|
DAVINCI_002("davinci-002");
|
||||||
|
|
||||||
|
private final String model;
|
||||||
|
|
||||||
|
Openai(String model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Doubao的模型
|
||||||
|
public enum Doubao {
|
||||||
|
DOUBAO_1_5_PRO_32K("doubao-1.5-pro-32k-250115"),
|
||||||
|
DOUBAO_1_5_PRO_256K("doubao-1.5-pro-256k-250115"),
|
||||||
|
DOUBAO_1_5_LITE_32K("doubao-1.5-lite-32k-250115"),
|
||||||
|
DEEPSEEK_R1("deepseek-r1-250120"),
|
||||||
|
DEEPSEEK_R1_DISTILL_QWEN_32B("deepseek-r1-distill-qwen-32b-250120"),
|
||||||
|
DEEPSEEK_R1_DISTILL_QWEN_7B("deepseek-r1-distill-qwen-7b-250120"),
|
||||||
|
DEEPSEEK_V3("deepseek-v3-241226"),
|
||||||
|
DOUBAO_PRO_4K_240515("doubao-pro-4k-240515"),
|
||||||
|
DOUBAO_PRO_4K_CHARACTER_240728("doubao-pro-4k-character-240728"),
|
||||||
|
DOUBAO_PRO_4K_FUNCTIONCALL_240615("doubao-pro-4k-functioncall-240615"),
|
||||||
|
DOUBAO_PRO_4K_BROWSING_240524("doubao-pro-4k-browsing-240524"),
|
||||||
|
DOUBAO_PRO_32K_241215("doubao-pro-32k-241215"),
|
||||||
|
DOUBAO_PRO_32K_FUNCTIONCALL_241028("doubao-pro-32k-functioncall-241028"),
|
||||||
|
DOUBAO_PRO_32K_BROWSING_241115("doubao-pro-32k-browsing-241115"),
|
||||||
|
DOUBAO_PRO_32K_CHARACTER_241215("doubao-pro-32k-character-241215"),
|
||||||
|
DOUBAO_PRO_128K_240628("doubao-pro-128k-240628"),
|
||||||
|
DOUBAO_PRO_256K_240828("doubao-pro-256k-240828"),
|
||||||
|
DOUBAO_LITE_4K_240328("doubao-lite-4k-240328"),
|
||||||
|
DOUBAO_LITE_4K_PRETRAIN_CHARACTER_240516("doubao-lite-4k-pretrain-character-240516"),
|
||||||
|
DOUBAO_LITE_32K_240828("doubao-lite-32k-240828"),
|
||||||
|
DOUBAO_LITE_32K_CHARACTER_241015("doubao-lite-32k-character-241015"),
|
||||||
|
DOUBAO_LITE_128K_240828("240828"),
|
||||||
|
MOONSHOT_V1_8K("moonshot-v1-8k"),
|
||||||
|
MOONSHOT_V1_32K("moonshot-v1-32k"),
|
||||||
|
MOONSHOT_V1_128K("moonshot-v1-128k"),
|
||||||
|
CHATGLM3_130B_FC("chatglm3-130b-fc-v1.0"),
|
||||||
|
CHATGLM3_130_FIN("chatglm3-130-fin-v1.0-update"),
|
||||||
|
MISTRAL_7B("mistral-7b-instruct-v0.2"),
|
||||||
|
DOUBAO_1_5_VISION_PRO_32K("doubao-1.5-vision-pro-32k-250115"),
|
||||||
|
DOUBAO_VISION_PRO_32K("doubao-vision-pro-32k-241008"),
|
||||||
|
DOUBAO_VISION_LITE_32K("doubao-vision-lite-32k-241015"),
|
||||||
|
DOUBAO_EMBEDDING_LARGE("doubao-embedding-large-text-240915"),
|
||||||
|
DOUBAO_EMBEDDING_TEXT_240715("doubao-embedding-text-240715"),
|
||||||
|
DOUBAO_EMBEDDING_VISION("doubao-embedding-vision-241215");
|
||||||
|
|
||||||
|
private final String model;
|
||||||
|
|
||||||
|
Doubao(String model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grok的模型
|
||||||
|
public enum Grok {
|
||||||
|
GROK_2_1212("grok-2-1212"),
|
||||||
|
GROK_2_VISION_1212("grok-2-vision-1212"),
|
||||||
|
GROK_BETA("grok-beta"),
|
||||||
|
GROK_VISION_BETA("grok-vision-beta");
|
||||||
|
|
||||||
|
private final String model;
|
||||||
|
|
||||||
|
Grok(String model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
package org.dromara.hutool.ai.core;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI配置类
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public interface AIConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模型(厂商)名称
|
||||||
|
*
|
||||||
|
* @return 模型(厂商)名称
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
default String getModelName() {
|
||||||
|
return this.getClass().getSimpleName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置apiKey
|
||||||
|
*
|
||||||
|
* @param apiKey apiKey
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
void setApiKey(String apiKey);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取apiKey
|
||||||
|
*
|
||||||
|
* @return apiKey
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String getApiKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置apiUrl
|
||||||
|
*
|
||||||
|
* @param apiUrl api请求地址
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
void setApiUrl(String apiUrl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取apiUrl
|
||||||
|
*
|
||||||
|
* @return apiUrl
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String getApiUrl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置model
|
||||||
|
*
|
||||||
|
* @param model model
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
void setModel(String model);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回model
|
||||||
|
*
|
||||||
|
* @return model
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String getModel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置动态参数
|
||||||
|
*
|
||||||
|
* @param key 参数字段
|
||||||
|
* @param value 参数值
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
void putAdditionalConfigByKey(String key, Object value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取动态参数
|
||||||
|
*
|
||||||
|
* @param key 参数字段
|
||||||
|
* @return 参数值
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
Object getAdditionalConfigByKey(String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取动态参数列表
|
||||||
|
*
|
||||||
|
* @return 参数列表Map
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
Map<String, Object> getAdditionalConfigMap();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
package org.dromara.hutool.ai.core;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于AIConfig的创建,创建同时支持链式设置参数
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class AIConfigBuilder {
|
||||||
|
|
||||||
|
private final AIConfig config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param modelName 模型厂商的名称(注意不是指具体的模型)
|
||||||
|
*/
|
||||||
|
public AIConfigBuilder(String modelName) {
|
||||||
|
try {
|
||||||
|
// 获取配置类
|
||||||
|
Class<? extends AIConfig> configClass = AIConfigRegistry.getConfigClass(modelName);
|
||||||
|
if (configClass == null) {
|
||||||
|
throw new IllegalArgumentException("Unsupported model: " + modelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用反射创建实例
|
||||||
|
Constructor<? extends AIConfig> constructor = configClass.getDeclaredConstructor();
|
||||||
|
config = constructor.newInstance();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to create AIConfig instance", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置apiKey
|
||||||
|
*
|
||||||
|
* @param apiKey apiKey
|
||||||
|
* @return config
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public synchronized AIConfigBuilder setApiKey(String apiKey) {
|
||||||
|
if (apiKey != null) {
|
||||||
|
config.setApiKey(apiKey);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置AI模型请求API接口的地址,不设置为默认值
|
||||||
|
*
|
||||||
|
* @param apiUrl API接口地址
|
||||||
|
* @return config
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public synchronized AIConfigBuilder setApiUrl(String apiUrl) {
|
||||||
|
if (apiUrl != null) {
|
||||||
|
config.setApiUrl(apiUrl);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置具体的model,不设置为默认值
|
||||||
|
*
|
||||||
|
* @param model 具体model的名称
|
||||||
|
* @return config
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public synchronized AIConfigBuilder setModel(String model) {
|
||||||
|
if (model != null) {
|
||||||
|
config.setModel(model);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态设置Request请求体中的属性字段,每个模型功能支持的字段请参照对应的官方文档
|
||||||
|
*
|
||||||
|
* @param key Request中的支持的属性名
|
||||||
|
* @param value 设置的属性值
|
||||||
|
* @return config
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public AIConfigBuilder putAdditionalConfig(String key, Object value) {
|
||||||
|
if (value != null) {
|
||||||
|
config.putAdditionalConfigByKey(key, value);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回config实例
|
||||||
|
*
|
||||||
|
* @return config
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public AIConfig build() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package org.dromara.hutool.ai.core;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AIConfig实现类的加载器
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class AIConfigRegistry {
|
||||||
|
|
||||||
|
private static final Map<String, Class<? extends AIConfig>> configClasses = new SafeConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 加载所有 AIConfig 实现类
|
||||||
|
static {
|
||||||
|
ServiceLoader<AIConfig> loader = ServiceLoader.load(AIConfig.class);
|
||||||
|
for (AIConfig config : loader) {
|
||||||
|
configClasses.put(config.getModelName().toLowerCase(), config.getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class<? extends AIConfig> getConfigClass(String modelName) {
|
||||||
|
return configClasses.get(modelName.toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package org.dromara.hutool.ai.core;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型公共的API功能,特有的功能在model.xx.XXService下定义
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public interface AIService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话
|
||||||
|
*
|
||||||
|
* @param prompt user题词
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String chat(String prompt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话
|
||||||
|
*
|
||||||
|
* @param messages 由目前为止的对话组成的消息列表,可以设置role,content。详细参考官方文档
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String chat(List<Message> messages);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package org.dromara.hutool.ai.core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于加载AI服务,每一个通过SPI创建的AI服务都要实现此接口
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public interface AIServiceProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取AI服务名称
|
||||||
|
*
|
||||||
|
* @return AI服务名称
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String getServiceName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建AI服务实例
|
||||||
|
*
|
||||||
|
* @param config AIConfig配置
|
||||||
|
* @param <T> AIService类型
|
||||||
|
* @return AI服务实例
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
<T extends AIService> T create(AIConfig config);
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
package org.dromara.hutool.ai.core;
|
||||||
|
|
||||||
|
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 java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础AIService,包含基公共参数和公共方法
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class BaseAIService {
|
||||||
|
|
||||||
|
protected final AIConfig config;
|
||||||
|
|
||||||
|
public BaseAIService(AIConfig config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Response sendGet(String endpoint) {
|
||||||
|
//链式构建请求
|
||||||
|
try {
|
||||||
|
//设置超时3分钟
|
||||||
|
HttpGlobalConfig.setTimeout(180000);
|
||||||
|
return HttpUtil.createRequest(config.getApiUrl() + endpoint, Method.GET)
|
||||||
|
.header(HeaderName.ACCEPT, "application/json")
|
||||||
|
.header(HeaderName.AUTHORIZATION, "Bearer " + config.getApiKey())
|
||||||
|
.send();
|
||||||
|
} catch (AIException e) {
|
||||||
|
throw new AIException("Failed to send GET request: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Response sendPost(String endpoint, String paramJson) {
|
||||||
|
//链式构建请求
|
||||||
|
try {
|
||||||
|
//设置超时3分钟
|
||||||
|
HttpGlobalConfig.setTimeout(180000);
|
||||||
|
return HttpUtil.createRequest(config.getApiUrl() + endpoint, Method.POST)
|
||||||
|
.header(HeaderName.CONTENT_TYPE, "application/json")
|
||||||
|
.header(HeaderName.ACCEPT, "application/json")
|
||||||
|
.header(HeaderName.AUTHORIZATION, "Bearer " + config.getApiKey())
|
||||||
|
.body(paramJson)
|
||||||
|
.send();
|
||||||
|
} catch (AIException e) {
|
||||||
|
throw new AIException("Failed to send POST request:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Response sendFormData(String endpoint, Map<String, Object> paramMap) {
|
||||||
|
//链式构建请求
|
||||||
|
try {
|
||||||
|
//设置超时3分钟
|
||||||
|
HttpGlobalConfig.setTimeout(180000);
|
||||||
|
return HttpUtil.createPost(config.getApiUrl() + endpoint)
|
||||||
|
//form表单中有file对象会自动将文件编码为 multipart/form-data 格式。不需要设置
|
||||||
|
// .header(HeaderName.CONTENT_TYPE, "multipart/form-data")
|
||||||
|
.header(HeaderName.AUTHORIZATION, "Bearer " + config.getApiKey())
|
||||||
|
.form(paramMap)
|
||||||
|
.send();
|
||||||
|
} catch (AIException e) {
|
||||||
|
throw new AIException("Failed to send POST request:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package org.dromara.hutool.ai.core;
|
||||||
|
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Config基础类,定义模型配置的基本属性
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class BaseConfig implements AIConfig {
|
||||||
|
|
||||||
|
//apiKey
|
||||||
|
protected volatile String apiKey;
|
||||||
|
//API请求地址
|
||||||
|
protected volatile String apiUrl;
|
||||||
|
//具体模型
|
||||||
|
protected volatile String model;
|
||||||
|
//动态扩展字段
|
||||||
|
protected Map<String, Object> additionalConfig = new SafeConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApiKey(String apiKey) {
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getApiKey() {
|
||||||
|
return apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApiUrl(String apiUrl) {
|
||||||
|
this.apiUrl = apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getApiUrl() {
|
||||||
|
return apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setModel(String model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putAdditionalConfigByKey(String key, Object value) {
|
||||||
|
this.additionalConfig.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getAdditionalConfigByKey(String key) {
|
||||||
|
return additionalConfig.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getAdditionalConfigMap() {
|
||||||
|
return new SafeConcurrentHashMap<>(additionalConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package org.dromara.hutool.ai.core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公共Message类
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class Message {
|
||||||
|
//角色 注意:如果设置系统消息,请放在messages列表的第一位
|
||||||
|
private final String role;
|
||||||
|
//内容
|
||||||
|
private final Object content;
|
||||||
|
|
||||||
|
public Message(String role, Object content) {
|
||||||
|
this.role = role;
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRole() {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package org.dromara.hutool.ai.model.deepseek;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* deepSeek公共类
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class DeepSeekCommon {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package org.dromara.hutool.ai.model.deepseek;
|
||||||
|
|
||||||
|
import org.dromara.hutool.ai.Models;
|
||||||
|
import org.dromara.hutool.ai.core.BaseConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeepSeek配置类,初始化API接口地址,设置默认的模型
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class DeepSeekConfig extends BaseConfig {
|
||||||
|
|
||||||
|
private final String API_URL = "https://api.deepseek.com";
|
||||||
|
|
||||||
|
private final String DEFAULT_MODEL = Models.DeepSeek.DEEPSEEK_CHAT.getModel();
|
||||||
|
|
||||||
|
public DeepSeekConfig() {
|
||||||
|
setApiUrl(API_URL);
|
||||||
|
setModel(DEFAULT_MODEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeepSeekConfig(String apiKey) {
|
||||||
|
this();
|
||||||
|
setApiKey(apiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModelName() {
|
||||||
|
return "deepSeek";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package org.dromara.hutool.ai.model.deepseek;
|
||||||
|
|
||||||
|
|
||||||
|
import org.dromara.hutool.ai.core.AIConfig;
|
||||||
|
import org.dromara.hutool.ai.core.AIServiceProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建DeepSeek服务实现类
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class DeepSeekProvider implements AIServiceProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServiceName() {
|
||||||
|
return "deepSeek";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeepSeekService create(AIConfig config) {
|
||||||
|
return new DeepSeekServiceImpl(config);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package org.dromara.hutool.ai.model.deepseek;
|
||||||
|
|
||||||
|
import org.dromara.hutool.ai.core.AIService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* deepSeek支持的扩展接口
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public interface DeepSeekService extends AIService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型beta功能
|
||||||
|
*
|
||||||
|
* @param prompt 题词
|
||||||
|
* @return AI的回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String beta(String prompt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列出所有模型列表
|
||||||
|
*
|
||||||
|
* @return model列表
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String models();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询余额
|
||||||
|
*
|
||||||
|
* @return 余额
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String balance();
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
package org.dromara.hutool.ai.model.deepseek;
|
||||||
|
|
||||||
|
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.http.client.Response;
|
||||||
|
import org.dromara.hutool.json.JSONUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeepSeek服务,AI具体功能的实现
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class DeepSeekServiceImpl extends BaseAIService implements DeepSeekService {
|
||||||
|
|
||||||
|
//对话补全
|
||||||
|
private final String CHAT_ENDPOINT = "/chat/completions";
|
||||||
|
//FIM补全(beta)
|
||||||
|
private final String BETA_ENDPOINT = "/beta/completions";
|
||||||
|
//列出模型
|
||||||
|
private final String MODELS_ENDPOINT = "/models";
|
||||||
|
//余额查询
|
||||||
|
private final String BALANCE_ENDPOINT = "/user/balance";
|
||||||
|
|
||||||
|
public DeepSeekServiceImpl(AIConfig config) {
|
||||||
|
//初始化DeepSeek客户端
|
||||||
|
super(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chat(String prompt) {
|
||||||
|
// 定义消息结构
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system", "You are a helpful assistant"));
|
||||||
|
messages.add(new Message("user", prompt));
|
||||||
|
return chat(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chat(List<Message> messages) {
|
||||||
|
String paramJson = buildChatRequestBody(messages);
|
||||||
|
Response response = sendPost(CHAT_ENDPOINT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String beta(String prompt) {
|
||||||
|
String paramJson = buildBetaRequestBody(prompt);
|
||||||
|
Response response = sendPost(BETA_ENDPOINT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String models() {
|
||||||
|
Response response = sendGet(MODELS_ENDPOINT);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String balance() {
|
||||||
|
Response response = sendGet(BALANCE_ENDPOINT);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建chat请求体
|
||||||
|
private String buildChatRequestBody(List<Message> messages) {
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("messages", messages);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建beta请求体
|
||||||
|
private String buildBetaRequestBody(String prompt) {
|
||||||
|
// 定义消息结构
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("prompt", prompt);
|
||||||
|
// //合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
package org.dromara.hutool.ai.model.doubao;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* doubao公共类
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class DoubaoCommon {
|
||||||
|
|
||||||
|
//doubao上下文缓存参数
|
||||||
|
public enum DoubaoContext {
|
||||||
|
|
||||||
|
SESSION("session"),
|
||||||
|
COMMON_PREFIX("common_prefix");
|
||||||
|
|
||||||
|
private final String mode;
|
||||||
|
|
||||||
|
DoubaoContext(String mode) {
|
||||||
|
this.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMode() {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//豆包视觉参数
|
||||||
|
public enum DoubaoVision {
|
||||||
|
|
||||||
|
AUTO("auto"),
|
||||||
|
LOW("low"),
|
||||||
|
HIGH("high");
|
||||||
|
|
||||||
|
private final String detail;
|
||||||
|
|
||||||
|
DoubaoVision(String detail) {
|
||||||
|
this.detail = detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDetail() {
|
||||||
|
return detail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//doubao视频生成参数
|
||||||
|
public enum DoubaoVideo {
|
||||||
|
|
||||||
|
//宽高比例
|
||||||
|
RATIO_16_9("--rt", "16:9"),//[1280, 720]
|
||||||
|
RATIO_4_3("--rt", "4:3"),//[960, 720]
|
||||||
|
RATIO_1_1("--rt", "1:1"),//[720, 720]
|
||||||
|
RATIO_3_4("--rt", "3:4"),//[720, 960]
|
||||||
|
RATIO_9_16("--rt", "9:16"),//[720, 1280]
|
||||||
|
RATIO_21_9("--rt", "21:9"),//[1280, 544]
|
||||||
|
|
||||||
|
//生成视频时长
|
||||||
|
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(String type, Object value) {
|
||||||
|
this.type = type;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
if (value instanceof String) {
|
||||||
|
return (String) value;
|
||||||
|
} else if (value instanceof Integer) {
|
||||||
|
return (Integer) value;
|
||||||
|
} else if (value instanceof Boolean) {
|
||||||
|
return (Boolean) value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package org.dromara.hutool.ai.model.doubao;
|
||||||
|
|
||||||
|
import org.dromara.hutool.ai.Models;
|
||||||
|
import org.dromara.hutool.ai.core.BaseConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Doubao配置类,初始化API接口地址,设置默认的模型
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class DoubaoConfig extends BaseConfig {
|
||||||
|
|
||||||
|
private final String API_URL = "https://ark.cn-beijing.volces.com/api/v3";
|
||||||
|
|
||||||
|
private final String DEFAULT_MODEL = Models.Doubao.DOUBAO_1_5_LITE_32K.getModel();
|
||||||
|
|
||||||
|
public DoubaoConfig() {
|
||||||
|
setApiUrl(API_URL);
|
||||||
|
setModel(DEFAULT_MODEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubaoConfig(String apiKey) {
|
||||||
|
this();
|
||||||
|
setApiKey(apiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModelName() {
|
||||||
|
return "doubao";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package org.dromara.hutool.ai.model.doubao;
|
||||||
|
|
||||||
|
import org.dromara.hutool.ai.core.AIConfig;
|
||||||
|
import org.dromara.hutool.ai.core.AIServiceProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建Doubap服务实现类
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class DoubaoProvider implements AIServiceProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServiceName() {
|
||||||
|
return "doubao";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoubaoService create(AIConfig config) {
|
||||||
|
return new DoubaoServiceImpl(config);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,179 @@
|
|||||||
|
package org.dromara.hutool.ai.model.doubao;
|
||||||
|
|
||||||
|
import org.dromara.hutool.ai.core.AIService;
|
||||||
|
import org.dromara.hutool.ai.core.Message;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* doubao支持的扩展接口
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public interface DoubaoService extends AIService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图像理解:模型会依据传入的图片信息以及问题,给出回复。
|
||||||
|
*
|
||||||
|
* @param prompt 提问
|
||||||
|
* @param images 图片列表/或者图片Base64编码图片列表(URI形式)
|
||||||
|
* @param detail 手动设置图片的质量,取值范围high、low、auto,默认为auto
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String chatVision(String prompt, List<String> images, String detail);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图像理解:模型会依据传入的图片信息以及问题,给出回复。
|
||||||
|
*
|
||||||
|
* @param prompt 提问
|
||||||
|
* @param images 传入的图片列表地址/或者图片Base64编码图片列表(URI形式)
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
default String chatVision(String prompt, List<String> images) {
|
||||||
|
return chatVision(prompt, images, DoubaoCommon.DoubaoVision.AUTO.getDetail());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建视频生成任务
|
||||||
|
* 注意:调用该方法时,配置config中的model为您创建的推理接入点(Endpoint)ID。详细参考官方文档
|
||||||
|
*
|
||||||
|
* @param text 文本提示词
|
||||||
|
* @param image 图片/或者图片Base64编码图片(URI形式)
|
||||||
|
* @param videoParams 视频参数列表
|
||||||
|
* @return 生成任务id
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String videoTasks(String text, String image, List<DoubaoCommon.DoubaoVideo> videoParams);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建视频生成任务
|
||||||
|
* 注意:调用该方法时,配置config中的model为您创建的推理接入点(Endpoint)ID。详细参考官方文档
|
||||||
|
*
|
||||||
|
* @param text 文本提示词
|
||||||
|
* @param image 图片/或者图片Base64编码图片(URI形式)
|
||||||
|
* @return 生成任务id
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
default String videoTasks(String text, String image) {
|
||||||
|
return videoTasks(text, image, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询视频生成任务信息
|
||||||
|
*
|
||||||
|
* @param taskId 通过创建生成视频任务返回的生成任务id
|
||||||
|
* @return 生成任务信息
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String getVideoTasksInfo(String taskId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本向量化
|
||||||
|
*
|
||||||
|
* @param input 需要向量化的内容列表,支持中文、英文
|
||||||
|
* @return 处理后的向量信息
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String embeddingText(String[] input);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图文向量化:仅支持单一文本、单张图片或文本与图片的组合输入(即一段文本 + 一张图片),暂不支持批量文本 / 图片的同时处理
|
||||||
|
*
|
||||||
|
* @param text 需要向量化的内容
|
||||||
|
* @param image 需要向量化的图片地址/或者图片Base64编码图片(URI形式)
|
||||||
|
* @return 处理后的向量信息
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String embeddingVision(String text, String image);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用(Bot) config中model设置为您创建的应用ID
|
||||||
|
*
|
||||||
|
* @param messages 由对话组成的消息列表。如系统人设,背景信息等,用户自定义的信息
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String botsChat(List<Message> messages);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分词:可以将文本转换为模型可理解的 token id,并返回文本的 tokens 数量、token id、 token 在原始文本中的偏移量等信息
|
||||||
|
*
|
||||||
|
* @param text 需要分词的内容列表
|
||||||
|
* @return 分词结果
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String tokenization(String[] text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量推理 Chat
|
||||||
|
* 注意:调用该方法时,配置config中的model为您创建的批量推理接入点(Endpoint)ID。详细参考官方文档
|
||||||
|
* 该方法不支持流式
|
||||||
|
*
|
||||||
|
* @param prompt chat内容
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String batchChat(String prompt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量推理 Chat
|
||||||
|
* 注意:调用该方法时,配置config中的model为您创建的批量推理接入点(Endpoint)ID。详细参考官方文档
|
||||||
|
* 该方法不支持流式
|
||||||
|
*
|
||||||
|
* @param messages 由对话组成的消息列表。如系统人设,背景信息等,用户自定义的信息
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String batchChat(List<Message> messages);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建上下文缓存: 创建上下文缓存,获得缓存 id字段后,在上下文缓存对话 API中使用。
|
||||||
|
* 注意:调用该方法时,配置config中的model为您创建的推理接入点(Endpoint)ID,
|
||||||
|
* 推理接入点中使用的模型需要在模型管理中开启缓存功能。详细参考官方文档
|
||||||
|
*
|
||||||
|
* @param messages 由对话组成的消息列表。如系统人设,背景信息等,用户自定义的信息
|
||||||
|
* @param mode 上下文缓存的类型,详细参考官方文档 默认为session
|
||||||
|
* @return 返回的缓存id
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String createContext(List<Message> messages, String mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建上下文缓存: 创建上下文缓存,获得缓存 id字段后,在上下文缓存对话 API中使用。
|
||||||
|
* 注意:调用该方法时,配置config中的model为您创建的推理接入点(Endpoint)ID,
|
||||||
|
* 推理接入点中使用的模型需要在模型管理中开启缓存功能。详细参考官方文档
|
||||||
|
*
|
||||||
|
* @param messages 由对话组成的消息列表。如系统人设,背景信息等,用户自定义的信息
|
||||||
|
* @return 返回的缓存id
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
default String createContext(List<Message> messages) {
|
||||||
|
return createContext(messages, DoubaoCommon.DoubaoContext.SESSION.getMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上下文缓存对话: 向大模型发起带上下文缓存的请求
|
||||||
|
* 注意:配置config中的model可以为您创建的推理接入点(Endpoint)ID,也可以是支持chat的model
|
||||||
|
*
|
||||||
|
* @param prompt 对话的内容题词
|
||||||
|
* @param contextId 创建上下文缓存后获取的缓存id
|
||||||
|
* @return AI的回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String chatContext(String prompt, String contextId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上下文缓存对话: 向大模型发起带上下文缓存的请求
|
||||||
|
* 注意:配置config中的model可以为您创建的推理接入点(Endpoint)ID,也可以是支持chat的model
|
||||||
|
*
|
||||||
|
* @param messages 对话的信息 不支持最后一个元素的role设置为assistant。如使用session 缓存(mode设置为session)传入最新一轮对话的信息,无需传入历史信息
|
||||||
|
* @param contextId 创建上下文缓存后获取的缓存id
|
||||||
|
* @return AI的回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String chatContext(List<Message> messages, String contextId);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,341 @@
|
|||||||
|
package org.dromara.hutool.ai.model.doubao;
|
||||||
|
|
||||||
|
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.http.client.Response;
|
||||||
|
import org.dromara.hutool.json.JSONUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Doubao服务,AI具体功能的实现
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class DoubaoServiceImpl extends BaseAIService implements DoubaoService {
|
||||||
|
|
||||||
|
//对话
|
||||||
|
private final String CHAT_ENDPOINT = "/chat/completions";
|
||||||
|
//文本向量化
|
||||||
|
private final String EMBEDDING_TEXT = "/embeddings";
|
||||||
|
//图文向量化
|
||||||
|
private final String EMBEDDING_VISION = "/embeddings/multimodal";
|
||||||
|
//应用bots
|
||||||
|
private final String BOTS_CHAT = "/bots/chat/completions";
|
||||||
|
//分词
|
||||||
|
private final String TOKENIZATION = "/tokenization";
|
||||||
|
//批量推理chat
|
||||||
|
private final String BATCH_CHAT = "/batch/chat/completions";
|
||||||
|
//创建上下文缓存
|
||||||
|
private final String CREATE_CONTEXT = "/context/create";
|
||||||
|
//上下文缓存对话
|
||||||
|
private final String CHAT_CONTEXT = "/context/chat/completions";
|
||||||
|
//创建视频生成任务
|
||||||
|
private final String CREATE_VIDEO = "/contents/generations/tasks";
|
||||||
|
|
||||||
|
public DoubaoServiceImpl(AIConfig config) {
|
||||||
|
//初始化doubao客户端
|
||||||
|
super(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chat(String prompt) {
|
||||||
|
// 定义消息结构
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system", "You are a helpful assistant"));
|
||||||
|
messages.add(new Message("user", prompt));
|
||||||
|
return chat(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chat(List<Message> messages) {
|
||||||
|
String paramJson = buildChatRequestBody(messages);
|
||||||
|
Response response = sendPost(CHAT_ENDPOINT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chatVision(String prompt, List<String> images, String detail) {
|
||||||
|
String paramJson = buildChatVisionRequestBody(prompt, images, detail);
|
||||||
|
Response response = sendPost(CHAT_ENDPOINT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String videoTasks(String text, String image, List<DoubaoCommon.DoubaoVideo> videoParams) {
|
||||||
|
String paramJson = buildGenerationsTasksRequestBody(text, image, videoParams);
|
||||||
|
Response response = sendPost(CREATE_VIDEO, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVideoTasksInfo(String taskId) {
|
||||||
|
Response response = sendGet(CREATE_VIDEO + "/" + taskId);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String embeddingText(String[] input) {
|
||||||
|
String paramJson = buildEmbeddingTextRequestBody(input);
|
||||||
|
Response response = sendPost(EMBEDDING_TEXT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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(List<Message> messages) {
|
||||||
|
String paramJson = buildBotsChatRequestBody(messages);
|
||||||
|
System.out.println(paramJson);
|
||||||
|
Response response = sendPost(BOTS_CHAT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String tokenization(String[] text) {
|
||||||
|
String paramJson = buildTokenizationRequestBody(text);
|
||||||
|
Response response = sendPost(TOKENIZATION, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String batchChat(String prompt) {
|
||||||
|
// 定义消息结构
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system", "You are a helpful assistant"));
|
||||||
|
messages.add(new Message("user", prompt));
|
||||||
|
return batchChat(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String batchChat(List<Message> messages) {
|
||||||
|
String paramJson = buildBatchChatRequestBody(messages);
|
||||||
|
System.out.println(paramJson);
|
||||||
|
Response response = sendPost(BATCH_CHAT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createContext(List<Message> messages, String mode) {
|
||||||
|
String paramJson = buildCreateContextRequest(messages, mode);
|
||||||
|
System.out.println(paramJson);
|
||||||
|
Response response = sendPost(CREATE_CONTEXT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chatContext(String prompt, String contextId) {
|
||||||
|
// 定义消息结构
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("user", prompt));
|
||||||
|
return chatContext(messages, contextId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chatContext(List<Message> messages, String contextId) {
|
||||||
|
String paramJson = buildChatContentRequestBody(messages, contextId);
|
||||||
|
Response response = sendPost(CHAT_CONTEXT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建chat请求体
|
||||||
|
private String buildChatRequestBody(List<Message> messages) {
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("messages", messages);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建chatVision请求体
|
||||||
|
private String buildChatVisionRequestBody(String prompt, List<String> images, String detail) {
|
||||||
|
// 定义消息结构
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
List<Object> content = new ArrayList<>();
|
||||||
|
|
||||||
|
Map<String, String> contentMap = new HashMap<>();
|
||||||
|
contentMap.put("type", "text");
|
||||||
|
contentMap.put("text", prompt);
|
||||||
|
content.add(contentMap);
|
||||||
|
for (String img : images) {
|
||||||
|
HashMap<String, Object> imgUrlMap = new HashMap<>();
|
||||||
|
imgUrlMap.put("type", "image_url");
|
||||||
|
HashMap<String, String> urlMap = new HashMap<>();
|
||||||
|
urlMap.put("url", img);
|
||||||
|
urlMap.put("detail", detail);
|
||||||
|
imgUrlMap.put("image_url", urlMap);
|
||||||
|
content.add(imgUrlMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.add(new Message("user", content));
|
||||||
|
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("messages", messages);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建文本向量化请求体
|
||||||
|
private String buildEmbeddingTextRequestBody(String[] input) {
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("input", input);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建图文向量化请求体
|
||||||
|
private String buildEmbeddingVisionRequestBody(String text, String image) {
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
|
||||||
|
List<Object> input = new ArrayList<>();
|
||||||
|
//添加文本参数
|
||||||
|
if (!StrUtil.isBlank(text)) {
|
||||||
|
Map<String, String> textMap = new HashMap<>();
|
||||||
|
textMap.put("type", "text");
|
||||||
|
textMap.put("text", text);
|
||||||
|
input.add(textMap);
|
||||||
|
}
|
||||||
|
//添加图片参数
|
||||||
|
if (!StrUtil.isBlank(image)) {
|
||||||
|
HashMap<String, Object> imgUrlMap = new HashMap<>();
|
||||||
|
imgUrlMap.put("type", "image_url");
|
||||||
|
HashMap<String, String> urlMap = new HashMap<>();
|
||||||
|
urlMap.put("url", image);
|
||||||
|
imgUrlMap.put("image_url", urlMap);
|
||||||
|
input.add(imgUrlMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
paramMap.put("input", input);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建应用chat请求体
|
||||||
|
private String buildBotsChatRequestBody(List<Message> messages) {
|
||||||
|
return buildChatRequestBody(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建分词请求体
|
||||||
|
private String buildTokenizationRequestBody(String[] text) {
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("text", text);
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建批量推理chat请求体
|
||||||
|
private String buildBatchChatRequestBody(List<Message> messages) {
|
||||||
|
return buildChatRequestBody(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建创建上下文缓存请求体
|
||||||
|
private String buildCreateContextRequest(List<Message> messages, String mode) {
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("messages", messages);
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("mode", mode);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建上下文缓存对话请求体
|
||||||
|
private String buildChatContentRequestBody(List<Message> messages, String contextId) {
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("messages", messages);
|
||||||
|
paramMap.put("context_id", contextId);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建创建视频任务请求体
|
||||||
|
private String buildGenerationsTasksRequestBody(String text, String image, List<DoubaoCommon.DoubaoVideo> videoParams) {
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
|
||||||
|
List<Object> content = new ArrayList<>();
|
||||||
|
//添加文本参数
|
||||||
|
Map<String, String> textMap = new HashMap<>();
|
||||||
|
if (!StrUtil.isBlank(text)) {
|
||||||
|
textMap.put("type", "text");
|
||||||
|
textMap.put("text", text);
|
||||||
|
content.add(textMap);
|
||||||
|
}
|
||||||
|
//添加图片参数
|
||||||
|
if (!StrUtil.isNotBlank(image)) {
|
||||||
|
Map<String, Object> imgUrlMap = new HashMap<>();
|
||||||
|
imgUrlMap.put("type", "image_url");
|
||||||
|
HashMap<String, String> urlMap = new HashMap<>();
|
||||||
|
urlMap.put("url", image);
|
||||||
|
imgUrlMap.put("image_url", urlMap);
|
||||||
|
content.add(imgUrlMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//添加视频参数
|
||||||
|
if (videoParams != null && !videoParams.isEmpty()) {
|
||||||
|
//如果有文本参数就加在后面
|
||||||
|
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");
|
||||||
|
textMap.put("text", textBuilder.toString());
|
||||||
|
|
||||||
|
if (textIndex != -1) {
|
||||||
|
content.set(textIndex, textMap);
|
||||||
|
} else {
|
||||||
|
content.add(textMap);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//如果没有文本参数就重新增加
|
||||||
|
StringBuilder textBuilder = new StringBuilder();
|
||||||
|
for (DoubaoCommon.DoubaoVideo videoParam : videoParams) {
|
||||||
|
textBuilder.append(videoParam.getType()).append(videoParam.getValue()).append(" ");
|
||||||
|
}
|
||||||
|
textMap.put("type", "text");
|
||||||
|
textMap.put("text", textBuilder.toString());
|
||||||
|
content.add(textMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
paramMap.put("content", content);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package org.dromara.hutool.ai.model.grok;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* grok公共类
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class GrokCommon {
|
||||||
|
|
||||||
|
//grok视觉参数
|
||||||
|
public enum GrokVision {
|
||||||
|
|
||||||
|
AUTO("auto"),
|
||||||
|
LOW("low"),
|
||||||
|
HIGH("high");
|
||||||
|
|
||||||
|
private final String detail;
|
||||||
|
|
||||||
|
GrokVision(String detail) {
|
||||||
|
this.detail = detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDetail() {
|
||||||
|
return detail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package org.dromara.hutool.ai.model.grok;
|
||||||
|
|
||||||
|
import org.dromara.hutool.ai.Models;
|
||||||
|
import org.dromara.hutool.ai.core.BaseConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grok配置类,初始化API接口地址,设置默认的模型
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class GrokConfig extends BaseConfig {
|
||||||
|
|
||||||
|
private final String API_URL = "https://api.x.ai/v1";
|
||||||
|
|
||||||
|
private final String DEFAULT_MODEL = Models.Grok.GROK_2_1212.getModel();
|
||||||
|
|
||||||
|
|
||||||
|
public GrokConfig() {
|
||||||
|
setApiUrl(API_URL);
|
||||||
|
setModel(DEFAULT_MODEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GrokConfig(String apiKey) {
|
||||||
|
this();
|
||||||
|
setApiKey(apiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModelName() {
|
||||||
|
return "grok";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package org.dromara.hutool.ai.model.grok;
|
||||||
|
|
||||||
|
import org.dromara.hutool.ai.core.AIConfig;
|
||||||
|
import org.dromara.hutool.ai.core.AIServiceProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建Grok服务实现类
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class GrokProvider implements AIServiceProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServiceName() {
|
||||||
|
return "grok";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GrokService create(AIConfig config) {
|
||||||
|
return new GrokServiceImpl(config);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
package org.dromara.hutool.ai.model.grok;
|
||||||
|
|
||||||
|
import org.dromara.hutool.ai.core.AIService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* grok支持的扩展接口
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public interface GrokService extends AIService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建消息回复
|
||||||
|
*
|
||||||
|
* @param prompt 题词
|
||||||
|
* @param maxToken 最大token
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String message(String prompt, int maxToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图像理解:模型会依据传入的图片信息以及问题,给出回复。
|
||||||
|
*
|
||||||
|
* @param prompt 题词
|
||||||
|
* @param images 图片列表/或者图片Base64编码图片列表(URI形式)
|
||||||
|
* @param detail 手动设置图片的质量,取值范围high、low、auto,默认为auto
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String chatVision(String prompt, List<String> images, String detail);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图像理解:模型会依据传入的图片信息以及问题,给出回复。
|
||||||
|
*
|
||||||
|
* @param prompt 题词
|
||||||
|
* @param images 传入的图片列表地址/或者图片Base64编码图片列表(URI形式)
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
default String chatVision(String prompt, List<String> images) {
|
||||||
|
return chatVision(prompt, images, GrokCommon.GrokVision.AUTO.getDetail());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列出所有model列表
|
||||||
|
*
|
||||||
|
* @return model列表
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String models();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模型信息
|
||||||
|
*
|
||||||
|
* @param modelId model ID
|
||||||
|
* @return model信息
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String getModel(String modelId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列出所有语言model
|
||||||
|
*
|
||||||
|
* @return languageModel列表
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String languageModels();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取语言模型信息
|
||||||
|
*
|
||||||
|
* @param modelId model ID
|
||||||
|
* @return model信息
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String getLanguageModel(String modelId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分词:可以将文本转换为模型可理解的 token 信息
|
||||||
|
*
|
||||||
|
* @param text 需要分词的内容
|
||||||
|
* @return 分词结果
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String tokenizeText(String text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从延迟对话中获取结果
|
||||||
|
*
|
||||||
|
* @param requestId 延迟对话中的延迟请求ID
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String deferredCompletion(String requestId);
|
||||||
|
}
|
@ -0,0 +1,177 @@
|
|||||||
|
package org.dromara.hutool.ai.model.grok;
|
||||||
|
|
||||||
|
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.http.client.Response;
|
||||||
|
import org.dromara.hutool.json.JSONUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grok服务,AI具体功能的实现
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class GrokServiceImpl extends BaseAIService implements GrokService {
|
||||||
|
|
||||||
|
//对话补全
|
||||||
|
private final String CHAT_ENDPOINT = "/chat/completions";
|
||||||
|
//创建消息回复
|
||||||
|
private final String MESSAGES = "/messages";
|
||||||
|
//列出模型
|
||||||
|
private final String MODELS_ENDPOINT = "/models";
|
||||||
|
//列出语言模型
|
||||||
|
private final String LANGUAGE_MODELS = "/language-models";
|
||||||
|
//分词
|
||||||
|
private final String TOKENIZE_TEXT = "/tokenize-text";
|
||||||
|
//获取延迟对话
|
||||||
|
private final String DEFERRED_COMPLETION = "/chat/deferred-completion";
|
||||||
|
|
||||||
|
public GrokServiceImpl(AIConfig config) {
|
||||||
|
//初始化grok客户端
|
||||||
|
super(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chat(String prompt) {
|
||||||
|
// 定义消息结构
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system", "You are a helpful assistant"));
|
||||||
|
messages.add(new Message("user", prompt));
|
||||||
|
return chat(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chat(List<Message> messages) {
|
||||||
|
String paramJson = buildChatRequestBody(messages);
|
||||||
|
Response response = sendPost(CHAT_ENDPOINT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String message(String prompt, int maxToken) {
|
||||||
|
// 定义消息结构
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system", "You are a helpful assistant"));
|
||||||
|
messages.add(new Message("user", prompt));
|
||||||
|
String paramJson = buildMessageRequestBody(messages, maxToken);
|
||||||
|
Response response = sendPost(MESSAGES, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chatVision(String prompt, List<String> images, String detail) {
|
||||||
|
String paramJson = buildChatVisionRequestBody(prompt, images, detail);
|
||||||
|
Response response = sendPost(CHAT_ENDPOINT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String models() {
|
||||||
|
Response response = sendGet(MODELS_ENDPOINT);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModel(String modelId) {
|
||||||
|
Response response = sendGet(MODELS_ENDPOINT + "/" + modelId);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String languageModels() {
|
||||||
|
Response response = sendGet(LANGUAGE_MODELS);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLanguageModel(String modelId) {
|
||||||
|
Response response = sendGet(LANGUAGE_MODELS + "/" + modelId);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String tokenizeText(String text) {
|
||||||
|
String paramJson = buildTokenizeRequestBody(text);
|
||||||
|
Response response = sendPost(TOKENIZE_TEXT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String deferredCompletion(String requestId) {
|
||||||
|
Response response = sendGet(DEFERRED_COMPLETION + "/" + requestId);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建chat请求体
|
||||||
|
private String buildChatRequestBody(List<Message> messages) {
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("messages", messages);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建chatVision请求体
|
||||||
|
private String buildChatVisionRequestBody(String prompt, List<String> images, String detail) {
|
||||||
|
// 定义消息结构
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
List<Object> content = new ArrayList<>();
|
||||||
|
|
||||||
|
Map<String, String> contentMap = new HashMap<>();
|
||||||
|
contentMap.put("type", "text");
|
||||||
|
contentMap.put("text", prompt);
|
||||||
|
content.add(contentMap);
|
||||||
|
for (String img : images) {
|
||||||
|
HashMap<String, Object> imgUrlMap = new HashMap<>();
|
||||||
|
imgUrlMap.put("type", "image_url");
|
||||||
|
HashMap<String, String> urlMap = new HashMap<>();
|
||||||
|
urlMap.put("url", img);
|
||||||
|
urlMap.put("detail", detail);
|
||||||
|
imgUrlMap.put("image_url", urlMap);
|
||||||
|
content.add(imgUrlMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.add(new Message("user", content));
|
||||||
|
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("messages", messages);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建消息回复请求体
|
||||||
|
private String buildMessageRequestBody(List<Message> messages, int maxToken) {
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("messages", messages);
|
||||||
|
paramMap.put("max_tokens", maxToken);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建分词请求体
|
||||||
|
private String buildTokenizeRequestBody(String text) {
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("text", text);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package org.dromara.hutool.ai.model.openai;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* openai公共类
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class OpenaiCommon {
|
||||||
|
|
||||||
|
//openai推理参数
|
||||||
|
public enum OpenaiReasoning {
|
||||||
|
|
||||||
|
LOW("low"),
|
||||||
|
MEDIUM("medium"),
|
||||||
|
HIGH("high");
|
||||||
|
|
||||||
|
private final String effort;
|
||||||
|
|
||||||
|
OpenaiReasoning(String effort) {
|
||||||
|
this.effort = effort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEffort() {
|
||||||
|
return effort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//openai视觉参数
|
||||||
|
public enum OpenaiVision {
|
||||||
|
|
||||||
|
AUTO("auto"),
|
||||||
|
LOW("low"),
|
||||||
|
HIGH("high");
|
||||||
|
|
||||||
|
private final String detail;
|
||||||
|
|
||||||
|
OpenaiVision(String detail) {
|
||||||
|
this.detail = detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDetail() {
|
||||||
|
return detail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//openai音频参数
|
||||||
|
public enum OpenaiSpeech {
|
||||||
|
|
||||||
|
ALLOY("alloy"),
|
||||||
|
ASH("ash"),
|
||||||
|
CORAL("coral"),
|
||||||
|
ECHO("echo"),
|
||||||
|
FABLE("fable"),
|
||||||
|
ONYX("onyx"),
|
||||||
|
NOVA("nova"),
|
||||||
|
SAGE("sage"),
|
||||||
|
SHIMMER("shimmer");
|
||||||
|
|
||||||
|
private final String voice;
|
||||||
|
|
||||||
|
OpenaiSpeech(String voice) {
|
||||||
|
this.voice = voice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVoice() {
|
||||||
|
return voice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package org.dromara.hutool.ai.model.openai;
|
||||||
|
|
||||||
|
|
||||||
|
import org.dromara.hutool.ai.Models;
|
||||||
|
import org.dromara.hutool.ai.core.BaseConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* openai配置类,初始化API接口地址,设置默认的模型
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class OpenaiConfig extends BaseConfig {
|
||||||
|
|
||||||
|
private final String API_URL = "https://api.openai.com/v1";
|
||||||
|
|
||||||
|
private final String DEFAULT_MODEL = Models.Openai.GPT_4O.getModel();
|
||||||
|
|
||||||
|
public OpenaiConfig() {
|
||||||
|
setApiUrl(API_URL);
|
||||||
|
setModel(DEFAULT_MODEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenaiConfig(String apiKey) {
|
||||||
|
this();
|
||||||
|
setApiKey(apiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModelName() {
|
||||||
|
return "openai";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package org.dromara.hutool.ai.model.openai;
|
||||||
|
|
||||||
|
|
||||||
|
import org.dromara.hutool.ai.core.AIConfig;
|
||||||
|
import org.dromara.hutool.ai.core.AIServiceProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建Openai服务实现类
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class OpenaiProvider implements AIServiceProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServiceName() {
|
||||||
|
return "openai";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OpenaiService create(AIConfig config) {
|
||||||
|
return new OpenaiServiceImpl(config);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,190 @@
|
|||||||
|
package org.dromara.hutool.ai.model.openai;
|
||||||
|
|
||||||
|
import org.dromara.hutool.ai.core.AIService;
|
||||||
|
import org.dromara.hutool.ai.core.Message;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* openai支持的扩展接口
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public interface OpenaiService extends AIService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图像理解:模型会依据传入的图片信息以及问题,给出回复。
|
||||||
|
*
|
||||||
|
* @param prompt 题词
|
||||||
|
* @param images 图片列表/或者图片Base64编码图片列表(URI形式)
|
||||||
|
* @param detail 手动设置图片的质量,取值范围high、low、auto,默认为auto
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String chatVision(String prompt, List<String> images, String detail);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图像理解:模型会依据传入的图片信息以及问题,给出回复。
|
||||||
|
*
|
||||||
|
* @param prompt 题词
|
||||||
|
* @param images 传入的图片列表地址/或者图片Base64编码图片列表(URI形式)
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
default String chatVision(String prompt, List<String> images) {
|
||||||
|
return chatVision(prompt, images, OpenaiCommon.OpenaiVision.AUTO.getDetail());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文生图 请设置config中model为支持图片功能的模型 DALL·E系列
|
||||||
|
*
|
||||||
|
* @param prompt 题词
|
||||||
|
* @return 包含生成图片的url
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String imagesGenerations(String prompt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片编辑 该方法仅支持 DALL·E 2 model
|
||||||
|
*
|
||||||
|
* @param prompt 题词
|
||||||
|
* @param image 需要编辑的图像必须是 PNG 格式
|
||||||
|
* @param mask 如果提供,则是一个与编辑图像大小相同的遮罩图像应该是灰度图,白色表示需要编辑的区域,黑色表示不需要编辑的区域。
|
||||||
|
* @return 包含生成图片的url
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String imagesEdits(String prompt, File image, File mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片编辑 该方法仅支持 DALL·E 2 model
|
||||||
|
*
|
||||||
|
* @param prompt 题词
|
||||||
|
* @param image 需要编辑的图像必须是 PNG 格式
|
||||||
|
* @return 包含生成图片的url
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
default String imagesEdits(String prompt, File image) {
|
||||||
|
return imagesEdits(prompt, image, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变形 该方法仅支持 DALL·E 2 model
|
||||||
|
*
|
||||||
|
* @param image 需要变形的图像必须是 PNG 格式
|
||||||
|
* @return 包含生成图片的url
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String imagesVariations(File image);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TTS文本转语音 请设置config中model为支持TTS功能的模型 TTS系列
|
||||||
|
*
|
||||||
|
* @param input 需要转成语音的文本
|
||||||
|
* @param voice AI的音色
|
||||||
|
* @return 返回的音频mp3文件流
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
InputStream textToSpeech(String input, OpenaiCommon.OpenaiSpeech voice);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TTS文本转语音 请设置config中model为支持TTS功能的模型 TTS系列
|
||||||
|
*
|
||||||
|
* @param input 需要转成语音的文本
|
||||||
|
* @return 返回的音频mp3文件流
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
default InputStream textToSpeech(String input) {
|
||||||
|
return textToSpeech(input, OpenaiCommon.OpenaiSpeech.ALLOY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* STT音频转文本 请设置config中model为支持STT功能的模型 whisper
|
||||||
|
*
|
||||||
|
* @param file 需要转成文本的音频文件
|
||||||
|
* @return 返回的文本内容
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String speechToText(File file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本向量化 请设置config中model为支持文本向量化功能的模型 text-embedding系列
|
||||||
|
*
|
||||||
|
* @param input 需要向量化的内容
|
||||||
|
* @return 处理后的向量信息
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String embeddingText(String input);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查文本或图像是否具有潜在的危害性
|
||||||
|
* 仅支持omni-moderation-latest和text-moderation-latest模型
|
||||||
|
*
|
||||||
|
* @param text 需要检查的文本
|
||||||
|
* @param imgUrl 需要检查的图片地址
|
||||||
|
* @return AI返回结果
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String moderations(String text, String imgUrl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查文本是否具有潜在的危害性
|
||||||
|
* 仅支持omni-moderation-latest和text-moderation-latest模型
|
||||||
|
*
|
||||||
|
* @param text 需要检查的文本
|
||||||
|
* @return AI返回结果
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
default String moderations(String text) {
|
||||||
|
return moderations(text, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推理chat
|
||||||
|
* 支持o3-mini和o1
|
||||||
|
*
|
||||||
|
* @param prompt 对话题词
|
||||||
|
* @param reasoningEffort 推理程度
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String chatReasoning(String prompt, String reasoningEffort);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推理chat
|
||||||
|
* 支持o3-mini和o1
|
||||||
|
*
|
||||||
|
* @param prompt 对话题词
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
default String chatReasoning(String prompt) {
|
||||||
|
return chatReasoning(prompt, OpenaiCommon.OpenaiReasoning.MEDIUM.getEffort());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推理chat
|
||||||
|
* 支持o3-mini和o1
|
||||||
|
*
|
||||||
|
* @param messages 消息列表
|
||||||
|
* @param reasoningEffort 推理程度
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
String chatReasoning(List<Message> messages, String reasoningEffort);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推理chat
|
||||||
|
* 支持o3-mini和o1
|
||||||
|
*
|
||||||
|
* @param messages 消息列表
|
||||||
|
* @return AI回答
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
default String chatReasoning(List<Message> messages) {
|
||||||
|
return chatReasoning(messages, OpenaiCommon.OpenaiReasoning.MEDIUM.getEffort());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,292 @@
|
|||||||
|
package org.dromara.hutool.ai.model.openai;
|
||||||
|
|
||||||
|
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.http.client.Response;
|
||||||
|
import org.dromara.hutool.json.JSONUtil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* openai服务,AI具体功能的实现
|
||||||
|
*
|
||||||
|
* @author elichow
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class OpenaiServiceImpl extends BaseAIService implements OpenaiService {
|
||||||
|
|
||||||
|
//对话
|
||||||
|
private final String CHAT_ENDPOINT = "/chat/completions";
|
||||||
|
//文生图
|
||||||
|
private final String IMAGES_GENERATIONS = "/images/generations";
|
||||||
|
//图片编辑
|
||||||
|
private final String IMAGES_EDITS = "/images/edits";
|
||||||
|
//图片变形
|
||||||
|
private final String IMAGES_VARIATIONS = "/images/variations";
|
||||||
|
//文本转语音
|
||||||
|
private final String TTS = "/audio/speech";
|
||||||
|
//语音转文本
|
||||||
|
private final String STT = "/audio/transcriptions";
|
||||||
|
//文本向量化
|
||||||
|
private final String EMBEDDINGS = "/embeddings";
|
||||||
|
//检查文本或图片
|
||||||
|
private final String MODERATIONS = "/moderations";
|
||||||
|
|
||||||
|
public OpenaiServiceImpl(AIConfig config) {
|
||||||
|
//初始化Openai客户端
|
||||||
|
super(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chat(String prompt) {
|
||||||
|
// 定义消息结构
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system", "You are a helpful assistant"));
|
||||||
|
messages.add(new Message("user", prompt));
|
||||||
|
return chat(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chat(List<Message> messages) {
|
||||||
|
String paramJson = buildChatRequestBody(messages);
|
||||||
|
Response response = sendPost(CHAT_ENDPOINT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chatVision(String prompt, List<String> images, String detail) {
|
||||||
|
String paramJson = buildChatVisionRequestBody(prompt, images, detail);
|
||||||
|
Response response = sendPost(CHAT_ENDPOINT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String imagesGenerations(String prompt) {
|
||||||
|
String paramJson = buildImagesGenerationsRequestBody(prompt);
|
||||||
|
Response response = sendPost(IMAGES_GENERATIONS, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String imagesEdits(String prompt, File image, File mask) {
|
||||||
|
Map<String, Object> paramMap = buildImagesEditsRequestBody(prompt, image, mask);
|
||||||
|
Response response = sendFormData(IMAGES_EDITS, paramMap);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String imagesVariations(File image) {
|
||||||
|
Map<String, Object> paramMap = buildImagesVariationsRequestBody(image);
|
||||||
|
Response response = sendFormData(IMAGES_VARIATIONS, paramMap);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream textToSpeech(String input, OpenaiCommon.OpenaiSpeech voice) {
|
||||||
|
String paramJson = buildTTSRequestBody(input, voice.getVoice());
|
||||||
|
Response response = sendPost(TTS, paramJson);
|
||||||
|
return response.bodyStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String speechToText(File file) {
|
||||||
|
Map<String, Object> paramMap = buildSTTRequestBody(file);
|
||||||
|
Response response = sendFormData(STT, paramMap);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String embeddingText(String input) {
|
||||||
|
String paramJson = buildEmbeddingTextRequestBody(input);
|
||||||
|
Response response = sendPost(EMBEDDINGS, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String moderations(String text, String imgUrl) {
|
||||||
|
String paramJson = buileModerationsRequestBody(text, imgUrl);
|
||||||
|
Response response = sendPost(MODERATIONS, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chatReasoning(String prompt, String reasoningEffort) {
|
||||||
|
// 定义消息结构
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system", "You are a helpful assistant"));
|
||||||
|
messages.add(new Message("user", prompt));
|
||||||
|
return chat(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chatReasoning(List<Message> messages, String reasoningEffort) {
|
||||||
|
String paramJson = buildChatReasoningRequestBody(messages, reasoningEffort);
|
||||||
|
Response response = sendPost(CHAT_ENDPOINT, paramJson);
|
||||||
|
return response.bodyStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建chat请求体
|
||||||
|
private String buildChatRequestBody(List<Message> messages) {
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("messages", messages);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建chatVision请求体
|
||||||
|
private String buildChatVisionRequestBody(String prompt, List<String> images, String detail) {
|
||||||
|
// 定义消息结构
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
List<Object> content = new ArrayList<>();
|
||||||
|
|
||||||
|
Map<String, String> contentMap = new HashMap<>();
|
||||||
|
contentMap.put("type", "text");
|
||||||
|
contentMap.put("text", prompt);
|
||||||
|
content.add(contentMap);
|
||||||
|
for (String img : images) {
|
||||||
|
HashMap<String, Object> imgUrlMap = new HashMap<>();
|
||||||
|
imgUrlMap.put("type", "image_url");
|
||||||
|
HashMap<String, String> urlMap = new HashMap<>();
|
||||||
|
urlMap.put("url", img);
|
||||||
|
urlMap.put("detail", detail);
|
||||||
|
imgUrlMap.put("image_url", urlMap);
|
||||||
|
content.add(imgUrlMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.add(new Message("user", content));
|
||||||
|
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("messages", messages);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建文生图请求体
|
||||||
|
private String buildImagesGenerationsRequestBody(String prompt) {
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("prompt", prompt);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建图片编辑请求体
|
||||||
|
private Map<String, Object> buildImagesEditsRequestBody(String prompt, File image, File mask) {
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("prompt", prompt);
|
||||||
|
paramMap.put("image", image);
|
||||||
|
if (mask != null) {
|
||||||
|
paramMap.put("mask", mask);
|
||||||
|
}
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return paramMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建图片变形请求体
|
||||||
|
private Map<String, Object> buildImagesVariationsRequestBody(File image) {
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("image", image);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return paramMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建TTS请求体
|
||||||
|
private String buildTTSRequestBody(String input, String voice) {
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("input", input);
|
||||||
|
paramMap.put("voice", voice);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建STT请求体
|
||||||
|
private Map<String, Object> buildSTTRequestBody(File file) {
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("file", file);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return paramMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建文本向量化请求体
|
||||||
|
private String buildEmbeddingTextRequestBody(String input) {
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("input", input);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建检查图片或文字请求体
|
||||||
|
private String buileModerationsRequestBody(String text, String imgUrl) {
|
||||||
|
//使用JSON工具
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
|
||||||
|
List<Object> input = new ArrayList<>();
|
||||||
|
//添加文本参数
|
||||||
|
if (!StrUtil.isBlank(text)) {
|
||||||
|
Map<String, String> textMap = new HashMap<>();
|
||||||
|
textMap.put("type", "text");
|
||||||
|
textMap.put("text", text);
|
||||||
|
input.add(textMap);
|
||||||
|
}
|
||||||
|
//添加图片参数
|
||||||
|
if (!StrUtil.isBlank(imgUrl)) {
|
||||||
|
HashMap<String, Object> imgUrlMap = new HashMap<>();
|
||||||
|
imgUrlMap.put("type", "image_url");
|
||||||
|
HashMap<String, String> urlMap = new HashMap<>();
|
||||||
|
urlMap.put("url", imgUrl);
|
||||||
|
imgUrlMap.put("image_url", urlMap);
|
||||||
|
input.add(imgUrlMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
paramMap.put("input", input);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建推理请求体
|
||||||
|
private String buildChatReasoningRequestBody(List<Message> messages, String reasoningEffort) {
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("model", config.getModel());
|
||||||
|
paramMap.put("messages", messages);
|
||||||
|
paramMap.put("reasoning_effort", reasoningEffort);
|
||||||
|
//合并其他参数
|
||||||
|
paramMap.putAll(config.getAdditionalConfigMap());
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
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,4 @@
|
|||||||
|
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
|
@ -0,0 +1,25 @@
|
|||||||
|
package org.dromara.hutool.ai;
|
||||||
|
|
||||||
|
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.*;
|
||||||
|
|
||||||
|
class AIServiceFactoryTest {
|
||||||
|
|
||||||
|
String key = "your key";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getAIService() {
|
||||||
|
AIService aiService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DEEPSEEK.getValue()).setApiKey(key).build());
|
||||||
|
assertNotNull(aiService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetAIService() {
|
||||||
|
DeepSeekService deepSeekService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DEEPSEEK.getValue()).setApiKey(key).build(), DeepSeekService.class);
|
||||||
|
assertNotNull(deepSeekService);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package org.dromara.hutool.ai;
|
||||||
|
|
||||||
|
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.openai.OpenaiService;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class AIUtilTest {
|
||||||
|
|
||||||
|
String key = "your key";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getAIService() {
|
||||||
|
DeepSeekService deepSeekService = AIUtil.getAIService(new AIConfigBuilder(ModelName.DEEPSEEK.getValue()).setApiKey(key).build(), DeepSeekService.class);
|
||||||
|
assertNotNull(deepSeekService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetAIService() {
|
||||||
|
AIService aiService = AIUtil.getAIService(new AIConfigBuilder(ModelName.OPENAI.getValue()).setApiKey(key).build());
|
||||||
|
assertNotNull(aiService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getDeepSeekService() {
|
||||||
|
DeepSeekService deepSeekService = AIUtil.getDeepSeekService(new AIConfigBuilder(ModelName.DEEPSEEK.getValue()).setApiKey(key).build());
|
||||||
|
assertNotNull(deepSeekService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getDoubaoService() {
|
||||||
|
DoubaoService doubaoService = AIUtil.getDoubaoService(new AIConfigBuilder(ModelName.DOUBAO.getValue()).setApiKey(key).build());
|
||||||
|
assertNotNull(doubaoService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getGrokService() {
|
||||||
|
GrokService grokService = AIUtil.getGrokService(new AIConfigBuilder(ModelName.GROK.getValue()).setApiKey(key).build());
|
||||||
|
assertNotNull(grokService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getOpenAIService() {
|
||||||
|
OpenaiService openAIService = AIUtil.getOpenAIService(new AIConfigBuilder(ModelName.OPENAI.getValue()).setApiKey(key).build());
|
||||||
|
assertNotNull(openAIService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void chat() {
|
||||||
|
String chat = AIUtil.chat(new AIConfigBuilder(ModelName.DEEPSEEK.getValue()).setApiKey(key).build(), "写一首赞美我的诗");
|
||||||
|
assertNotNull(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testChat() {
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system","你是财神爷,只会说“我是财神”"));
|
||||||
|
messages.add(new Message("user","你是谁啊?"));
|
||||||
|
String chat = AIUtil.chat(new AIConfigBuilder(ModelName.DEEPSEEK.getValue()).setApiKey(key).build(), messages);
|
||||||
|
System.out.println(chat);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package org.dromara.hutool.ai.model.deepseek;
|
||||||
|
|
||||||
|
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.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class DeepSeekServiceTest {
|
||||||
|
|
||||||
|
String key = "your key";
|
||||||
|
DeepSeekService deepSeekService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DEEPSEEK.getValue()).setApiKey(key).build(),DeepSeekService.class);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void chat(){
|
||||||
|
String chat = deepSeekService.chat("写一个疯狂星期四广告词");
|
||||||
|
System.out.println(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testChat(){
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system","你是个抽象大师,会说很抽象的话,最擅长说抽象的笑话"));
|
||||||
|
messages.add(new Message("user","给我说一个笑话"));
|
||||||
|
String chat = deepSeekService.chat(messages);
|
||||||
|
System.out.println(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void beta() {
|
||||||
|
String beta = deepSeekService.beta("写一个疯狂星期四广告词");
|
||||||
|
System.out.println(beta);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void models() {
|
||||||
|
String models = deepSeekService.models();
|
||||||
|
System.out.println(models);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void balance() {
|
||||||
|
String balance = deepSeekService.balance();
|
||||||
|
System.out.println(balance);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,163 @@
|
|||||||
|
package org.dromara.hutool.ai.model.doubao;
|
||||||
|
|
||||||
|
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.swing.img.ImgUtil;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class DoubaoServiceTest {
|
||||||
|
|
||||||
|
String key = "your key";
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue()).setModel(Models.Doubao.DOUBAO_1_5_LITE_32K.getModel()).setApiKey(key).build(), DoubaoService.class);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void chat(){
|
||||||
|
String chat = doubaoService.chat("写一个疯狂星期四广告词");
|
||||||
|
System.out.println(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testChat(){
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system","你是个抽象大师,会说很抽象的话,最擅长说抽象的笑话"));
|
||||||
|
messages.add(new Message("user","给我说一个笑话"));
|
||||||
|
String chat = doubaoService.chat(messages);
|
||||||
|
System.out.println(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void chatVision() {
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue())
|
||||||
|
.setApiKey(key).setModel(Models.Doubao.DOUBAO_1_5_VISION_PRO_32K.getModel()).build(), DoubaoService.class);
|
||||||
|
String base64 = ImgUtil.toBase64DataUri(Toolkit.getDefaultToolkit().createImage("your imageUrl"), "png");
|
||||||
|
String chatVision = doubaoService.chatVision("图片上有些什么?", Arrays.asList(base64));
|
||||||
|
System.out.println(chatVision);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testChatVision() {
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue())
|
||||||
|
.setApiKey(key).setModel(Models.Doubao.DOUBAO_1_5_VISION_PRO_32K.getModel()).build(), DoubaoService.class);
|
||||||
|
String chatVision = doubaoService.chatVision("图片上有些什么?", Arrays.asList("https://img2.baidu.com/it/u=862000265,4064861820&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1544"),DoubaoCommon.DoubaoVision.HIGH.getDetail());
|
||||||
|
System.out.println(chatVision);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void videoTasks() {
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue())
|
||||||
|
.setApiKey(key).setModel("your Endpoint ID").build(), DoubaoService.class);
|
||||||
|
String videoTasks = doubaoService.videoTasks("生成一段动画视频,主角是大耳朵图图,一个活泼可爱的小男孩。视频中图图在公园里玩耍," +
|
||||||
|
"画面采用明亮温暖的卡通风格,色彩鲜艳,动作流畅。背景音乐轻快活泼,带有冒险感,音效包括鸟叫声、欢笑声和山洞回声。", "https://img2.baidu.com/it/u=862000265,4064861820&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1544");
|
||||||
|
System.out.println(videoTasks);//cgt-20250306170051-6r9gk
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getVideoTasksInfo() {
|
||||||
|
//cgt-20250306170051-6r9gk
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue())
|
||||||
|
.setApiKey(key).build(), DoubaoService.class);
|
||||||
|
String videoTasksInfo = doubaoService.getVideoTasksInfo("cgt-20250306170051-6r9gk");
|
||||||
|
System.out.println(videoTasksInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void embeddingText() {
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue())
|
||||||
|
.setApiKey(key).setModel(Models.Doubao.DOUBAO_EMBEDDING_TEXT_240715.getModel()).build(), DoubaoService.class);
|
||||||
|
String embeddingText = doubaoService.embeddingText(new String[]{"阿斯顿", "马丁"});
|
||||||
|
System.out.println(embeddingText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void embeddingVision() {
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue())
|
||||||
|
.setApiKey(key).setModel(Models.Doubao.DOUBAO_EMBEDDING_VISION.getModel()).build(), DoubaoService.class);
|
||||||
|
String embeddingVision = doubaoService.embeddingVision("天空好难", "https://img2.baidu.com/it/u=862000265,4064861820&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1544");
|
||||||
|
System.out.println(embeddingVision);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void botsChat() {
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue())
|
||||||
|
.setApiKey(key).setModel("your bots id").build(), DoubaoService.class);
|
||||||
|
ArrayList<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system","你是什么都可以"));
|
||||||
|
messages.add(new Message("user","你想做些什么"));
|
||||||
|
String botsChat = doubaoService.botsChat(messages);
|
||||||
|
System.out.println(botsChat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void tokenization() {
|
||||||
|
String tokenization = doubaoService.tokenization(new String[]{"阿斯顿", "马丁"});
|
||||||
|
System.out.println(tokenization);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void batchChat() {
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue())
|
||||||
|
.setApiKey(key).setModel("your Endpoint ID").build(), DoubaoService.class);
|
||||||
|
String batchChat = doubaoService.batchChat("写首歌词");
|
||||||
|
System.out.println(batchChat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBatchChat() {
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue())
|
||||||
|
.setApiKey(key).setModel("your Endpoint ID").build(), DoubaoService.class);
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system","你是个抽象大师"));
|
||||||
|
messages.add(new Message("user","写一个KFC的抽象广告"));
|
||||||
|
String batchChat = doubaoService.batchChat(messages);
|
||||||
|
System.out.println(batchChat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createContext() {
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue())
|
||||||
|
.setApiKey(key).setModel("your Endpoint ID").build(), DoubaoService.class);
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system","你是个抽象大师,你真的很抽象"));
|
||||||
|
String context = doubaoService.createContext(messages);//ctx-20250307092153-cvslm
|
||||||
|
System.out.println(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreateContext() {
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue())
|
||||||
|
.setApiKey(key).setModel("your Endpoint ID").build(), DoubaoService.class);
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system","你是个抽象大师,你真的很抽象"));
|
||||||
|
String context = doubaoService.createContext(messages,DoubaoCommon.DoubaoContext.COMMON_PREFIX.getMode());
|
||||||
|
System.out.println(context);//ctx-20250307092153-cvslm
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void chatContext() {
|
||||||
|
//ctx-20250307092153-cvslm
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue())
|
||||||
|
.setApiKey(key).setModel("eyour Endpoint ID").build(), DoubaoService.class);
|
||||||
|
String chatContext = doubaoService.chatContext("你是谁?", "ctx-20250307092153-cvslm");
|
||||||
|
System.out.println(chatContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testChatContext() {
|
||||||
|
DoubaoService doubaoService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.DOUBAO.getValue())
|
||||||
|
.setApiKey(key).setModel("your Endpoint ID").build(), DoubaoService.class);
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("user","你怎么看待意大利面拌水泥?"));
|
||||||
|
String chatContext = doubaoService.chatContext(messages, "ctx-20250307092153-cvslm");
|
||||||
|
System.out.println(chatContext);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
package org.dromara.hutool.ai.model.grok;
|
||||||
|
|
||||||
|
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.swing.img.ImgUtil;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class GrokServiceTest {
|
||||||
|
|
||||||
|
String key = "your key";
|
||||||
|
GrokService grokService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.GROK.getValue()).setApiKey(key).build(), GrokService.class);
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void chat(){
|
||||||
|
String chat = grokService.chat("写一个疯狂星期四广告词");
|
||||||
|
System.out.println(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testChat(){
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system","你是个抽象大师,会说很抽象的话,最擅长说抽象的笑话"));
|
||||||
|
messages.add(new Message("user","给我说一个笑话"));
|
||||||
|
String chat = grokService.chat(messages);
|
||||||
|
System.out.println(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void message() {
|
||||||
|
String message = grokService.message("给我一个KFC的广告词", 4096);
|
||||||
|
System.out.println(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void chatVision() {
|
||||||
|
GrokService grokService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.GROK.getValue()).setModel(Models.Grok.GROK_2_VISION_1212.getModel()).setApiKey(key).build(), GrokService.class);
|
||||||
|
String base64 = ImgUtil.toBase64DataUri(Toolkit.getDefaultToolkit().createImage("your imageUrl"), "png");
|
||||||
|
String chatVision = grokService.chatVision("图片上有些什么?", Arrays.asList(base64));
|
||||||
|
System.out.println(chatVision);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testChatVision() {
|
||||||
|
GrokService grokService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.GROK.getValue()).setModel(Models.Grok.GROK_2_VISION_1212.getModel()).setApiKey(key).build(), GrokService.class);
|
||||||
|
String chatVision = grokService.chatVision("图片上有些什么?", Arrays.asList("https://img2.baidu.com/it/u=862000265,4064861820&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1544"));
|
||||||
|
System.out.println(chatVision);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void models() {
|
||||||
|
String models = grokService.models();
|
||||||
|
assertNotNull(models);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getModel() {
|
||||||
|
String model = grokService.getModel("");
|
||||||
|
assertNotNull(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void languageModels() {
|
||||||
|
String languageModels = grokService.languageModels();
|
||||||
|
assertNotNull(languageModels);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getLanguageModel() {
|
||||||
|
String language = grokService.getLanguageModel("");
|
||||||
|
assertNotNull(language);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void tokenizeText() {
|
||||||
|
String tokenizeText = grokService.tokenizeText(key);
|
||||||
|
assertNotNull(tokenizeText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void deferredCompletion() {
|
||||||
|
String deferred = grokService.deferredCompletion(key);
|
||||||
|
assertNotNull(deferred);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
package org.dromara.hutool.ai.model.openai;
|
||||||
|
|
||||||
|
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.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class OpenaiServiceTest {
|
||||||
|
|
||||||
|
String key = "your key";
|
||||||
|
OpenaiService openaiService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.OPENAI.getValue()).setApiKey(key).build(), OpenaiService.class);
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void chat(){
|
||||||
|
String chat = openaiService.chat("写一个疯狂星期四广告词");
|
||||||
|
System.out.println(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testChat(){
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system","你是个抽象大师,会说很抽象的话,最擅长说抽象的笑话"));
|
||||||
|
messages.add(new Message("user","给我说一个笑话"));
|
||||||
|
String chat = openaiService.chat(messages);
|
||||||
|
System.out.println(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void chatVision() {
|
||||||
|
OpenaiService openaiService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.OPENAI.getValue())
|
||||||
|
.setApiKey(key).setModel(Models.Openai.GPT_4O_MINI.getModel()).build(), OpenaiService.class);
|
||||||
|
String chatVision = openaiService.chatVision("图片上有些什么?", Arrays.asList("https://img2.baidu.com/it/u=862000265,4064861820&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1544","https://img2.baidu.com/it/u=1682510685,1244554634&fm=253&fmt=auto&app=138&f=JPEG?w=803&h=800"));
|
||||||
|
System.out.println(chatVision);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void imagesGenerations() {
|
||||||
|
OpenaiService openaiService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.OPENAI.getValue())
|
||||||
|
.setApiKey(key).setModel(Models.Openai.DALL_E_3.getModel()).build(), OpenaiService.class);
|
||||||
|
String imagesGenerations = openaiService.imagesGenerations("一位年轻的宇航员站在未来感十足的太空站内,透过巨大的弧形落地窗凝望浩瀚宇宙。窗外,璀璨的星河与五彩斑斓的星云交织,远处隐约可见未知星球的轮廓,仿佛在召唤着探索的脚步。宇航服上的呼吸灯与透明显示屏上的星图交相辉映,象征着人类科技与宇宙奥秘的碰撞。画面深邃而神秘,充满对未知的渴望与无限可能的想象。");
|
||||||
|
System.out.println(imagesGenerations);
|
||||||
|
//https://oaidalleapiprodscus.blob.core.windows.net/private/org-l99H6T0zCZejctB2TqdYrXFB/user-LilDVU1V8cUxJYwVAGRkUwYd/img-yA9kNatHnBiUHU5lZGim1hP2.png?st=2025-03-07T01%3A04%3A18Z&se=2025-03-07T03%3A04%3A18Z&sp=r&sv=2024-08-04&sr=b&rscd=inline&rsct=image/png&skoid=d505667d-d6c1-4a0a-bac7-5c84a87759f8&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2025-03-06T15%3A04%3A42Z&ske=2025-03-07T15%3A04%3A42Z&sks=b&skv=2024-08-04&sig=rjcRzC5U7Y3pEDZ4ME0CiviAPdIpoGO2rRTXw3m8rHw%3D
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void imagesEdits() {
|
||||||
|
OpenaiService openaiService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.OPENAI.getValue())
|
||||||
|
.setApiKey(key).setModel(Models.Openai.DALL_E_2.getModel()).build(), OpenaiService.class);
|
||||||
|
File file = FileUtil.file("your imgUrl");
|
||||||
|
String imagesEdits = openaiService.imagesEdits("茂密的森林中,有一只九色鹿若隐若现",file);
|
||||||
|
System.out.println(imagesEdits);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void imagesVariations() {
|
||||||
|
OpenaiService openaiService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.OPENAI.getValue())
|
||||||
|
.setApiKey(key).setModel(Models.Openai.DALL_E_2.getModel()).build(), OpenaiService.class);
|
||||||
|
File file = FileUtil.file("your imgUrl");
|
||||||
|
String imagesVariations = openaiService.imagesVariations(file);
|
||||||
|
System.out.println(imagesVariations);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void textToSpeech() {
|
||||||
|
OpenaiService openaiService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.OPENAI.getValue())
|
||||||
|
.setApiKey(key).setModel(Models.Openai.TTS_1_HD.getModel()).build(), OpenaiService.class);
|
||||||
|
InputStream inputStream = openaiService.textToSpeech("万里山河一夜白,\n" +
|
||||||
|
"千峰尽染玉龙哀。\n" +
|
||||||
|
"长风卷起琼花碎,\n" +
|
||||||
|
"直上九霄揽月来。", OpenaiCommon.OpenaiSpeech.NOVA);
|
||||||
|
|
||||||
|
String filePath = "your filePath";
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
try (FileOutputStream outputStream = new FileOutputStream(filePath)) {
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||||
|
outputStream.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void speechToText() {
|
||||||
|
OpenaiService openaiService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.OPENAI.getValue())
|
||||||
|
.setApiKey(key).setModel(Models.Openai.WHISPER_1.getModel()).build(), OpenaiService.class);
|
||||||
|
File file = FileUtil.file("your filePath");
|
||||||
|
String speechToText = openaiService.speechToText(file);
|
||||||
|
System.out.println(speechToText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void embeddingText() {
|
||||||
|
OpenaiService openaiService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.OPENAI.getValue())
|
||||||
|
.setApiKey(key).setModel(Models.Openai.TEXT_EMBEDDING_3_SMALL.getModel()).build(), OpenaiService.class);
|
||||||
|
String embeddingText = openaiService.embeddingText("萬里山河一夜白,千峰盡染玉龍哀,長風捲起瓊花碎,直上九霄闌月來");
|
||||||
|
System.out.println(embeddingText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void moderations() {
|
||||||
|
OpenaiService openaiService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.OPENAI.getValue())
|
||||||
|
.setApiKey(key).setModel(Models.Openai.OMNI_MODERATION_LATEST.getModel()).build(), OpenaiService.class);
|
||||||
|
String moderations = openaiService.moderations("你要杀人", "https://img2.baidu.com/it/u=862000265,4064861820&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1544");
|
||||||
|
System.out.println(moderations);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void chatReasoning() {
|
||||||
|
OpenaiService openaiService = AIServiceFactory.getAIService(new AIConfigBuilder(ModelName.OPENAI.getValue())
|
||||||
|
.setApiKey(key).setModel(Models.Openai.O3_MINI.getModel()).build(), OpenaiService.class);
|
||||||
|
List<Message> messages = new ArrayList<>();
|
||||||
|
messages.add(new Message("system","你是现代抽象家"));
|
||||||
|
messages.add(new Message("user","给我一个KFC疯狂星期四的文案"));
|
||||||
|
String chatReasoning = openaiService.chatReasoning(messages, OpenaiCommon.OpenaiReasoning.HIGH.getEffort());
|
||||||
|
System.out.println(chatReasoning);
|
||||||
|
}
|
||||||
|
}
|
@ -96,6 +96,11 @@
|
|||||||
<artifactId>hutool-swing</artifactId>
|
<artifactId>hutool-swing</artifactId>
|
||||||
<version>${project.parent.version}</version>
|
<version>${project.parent.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
|
<artifactId>hutool-ai</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user