【通义千问】重新对接阿里云通义前文。
This commit is contained in:
parent
64b6b45bc6
commit
be8d9c1a5f
|
@ -22,13 +22,23 @@ public class AiChatModalDO extends BaseDO {
|
||||||
*/
|
*/
|
||||||
private Long id;
|
private Long id;
|
||||||
/**
|
/**
|
||||||
* 模型名字
|
* 模型key
|
||||||
*/
|
*/
|
||||||
private Long modelName;
|
private String modelKey;
|
||||||
/**
|
/**
|
||||||
* 模型类型(qianwen、yiyan、xinghuo、openai)
|
* 模型类型 参考:{@link cn.iocoder.yudao.framework.ai.AiPlatformEnum}
|
||||||
|
*/
|
||||||
|
private String modelPlatform;
|
||||||
|
/**
|
||||||
|
* 模型类型
|
||||||
|
* {@link cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatModel}
|
||||||
|
* {@link cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatModel}
|
||||||
*/
|
*/
|
||||||
private String modelType;
|
private String modelType;
|
||||||
|
/**
|
||||||
|
* 模型名字
|
||||||
|
*/
|
||||||
|
private String modelName;
|
||||||
/**
|
/**
|
||||||
* 模型照片
|
* 模型照片
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -20,7 +20,7 @@ public class AiChatModalListRes {
|
||||||
/**
|
/**
|
||||||
* 模型名字
|
* 模型名字
|
||||||
*/
|
*/
|
||||||
private Long modelName;
|
private String modelName;
|
||||||
/**
|
/**
|
||||||
* 模型类型(qianwen、yiyan、xinghuo、openai)
|
* 模型类型(qianwen、yiyan、xinghuo、openai)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
|
||||||
|
### chat call
|
||||||
|
GET {{baseUrl}}/ai/chat/modal/list
|
||||||
|
Authorization: {{token}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### chat call
|
||||||
|
PUT {{baseUrl}}/ai/chat/modal
|
||||||
|
Content-Type: application/json
|
||||||
|
Authorization: {{token}}
|
||||||
|
|
||||||
|
{
|
||||||
|
"modelName": "小红书Ai写作大模型",
|
||||||
|
"modelType": "yiyan",
|
||||||
|
"modalImage": "",
|
||||||
|
"modelConfig": ""
|
||||||
|
}
|
|
@ -110,9 +110,9 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- 阿里云 通义千问 -->
|
<!-- 阿里云 通义千问 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.aliyun</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>broadscope-bailian-sdk-java</artifactId>
|
<artifactId>dashscope-sdk-java</artifactId>
|
||||||
<version>1.3.0</version>
|
<version>2.11.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
@ -129,6 +129,11 @@
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
|
<artifactId>fastjson2</artifactId>
|
||||||
|
<version>2.0.45</version>
|
||||||
|
</dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
|
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.squareup.okhttp3</groupId>
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
|
|
@ -4,13 +4,7 @@ import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 讯飞星火 模型
|
* ai 模型平台
|
||||||
*
|
|
||||||
* 文档地址:https://www.xfyun.cn/doc/spark/Web.html#_1-%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E
|
|
||||||
*
|
|
||||||
* 1tokens 约等于1.5个中文汉字 或者 0.8个英文单词
|
|
||||||
* 星火V1.5支持[搜索]内置插件;星火V2.0、V3.0和V3.5支持[搜索]、[天气]、[日期]、[诗词]、[字词]、[股票]六个内置插件
|
|
||||||
* 星火V3.5 现已支持system、Function Call 功能。
|
|
||||||
*
|
*
|
||||||
* author: fansili
|
* author: fansili
|
||||||
* time: 2024/3/11 10:12
|
* time: 2024/3/11 10:12
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
package cn.iocoder.yudao.framework.ai.chatqianwen;
|
package cn.iocoder.yudao.framework.ai.chatqianwen;
|
||||||
|
|
||||||
import cn.hutool.core.util.IdUtil;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import cn.iocoder.yudao.framework.ai.chat.*;
|
import cn.iocoder.yudao.framework.ai.chat.*;
|
||||||
import cn.iocoder.yudao.framework.ai.chat.messages.MessageType;
|
|
||||||
import cn.iocoder.yudao.framework.ai.chat.prompt.ChatOptions;
|
import cn.iocoder.yudao.framework.ai.chat.prompt.ChatOptions;
|
||||||
import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt;
|
import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt;
|
||||||
import cn.iocoder.yudao.framework.ai.chatqianwen.api.QianWenApi;
|
import cn.iocoder.yudao.framework.ai.chatqianwen.api.QianWenApi;
|
||||||
|
import cn.iocoder.yudao.framework.ai.chatqianwen.api.QianWenChatCompletionRequest;
|
||||||
import cn.iocoder.yudao.framework.ai.chatyiyan.exception.YiYanApiException;
|
import cn.iocoder.yudao.framework.ai.chatyiyan.exception.YiYanApiException;
|
||||||
import com.aliyun.broadscope.bailian.sdk.models.*;
|
import com.alibaba.dashscope.aigc.generation.GenerationResult;
|
||||||
|
import com.alibaba.dashscope.aigc.generation.models.QwenParam;
|
||||||
|
import com.alibaba.dashscope.common.Message;
|
||||||
|
import io.reactivex.Flowable;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.retry.RetryCallback;
|
import org.springframework.retry.RetryCallback;
|
||||||
|
@ -23,9 +24,9 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 阿里 通义千问 client
|
* 阿里 通义千问 client
|
||||||
*
|
* <p>
|
||||||
* 文档地址:https://help.aliyun.com/document_detail/2587494.html?spm=a2c4g.2587492.0.0.53f33c566sXskp
|
* 文档地址:https://help.aliyun.com/document_detail/2587494.html?spm=a2c4g.2587492.0.0.53f33c566sXskp
|
||||||
*
|
* <p>
|
||||||
* author: fansili
|
* author: fansili
|
||||||
* time: 2024/3/13 21:06
|
* time: 2024/3/13 21:06
|
||||||
*/
|
*/
|
||||||
|
@ -37,7 +38,9 @@ public class QianWenChatClient implements ChatClient, StreamingChatClient {
|
||||||
private QianWenOptions qianWenOptions;
|
private QianWenOptions qianWenOptions;
|
||||||
|
|
||||||
|
|
||||||
public QianWenChatClient() {}
|
public QianWenChatClient() {
|
||||||
|
}
|
||||||
|
|
||||||
public QianWenChatClient(QianWenApi qianWenApi) {
|
public QianWenChatClient(QianWenApi qianWenApi) {
|
||||||
this.qianWenApi = qianWenApi;
|
this.qianWenApi = qianWenApi;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +62,7 @@ public class QianWenChatClient implements ChatClient, StreamingChatClient {
|
||||||
public <T extends Object, E extends Throwable> void onError(RetryContext context,
|
public <T extends Object, E extends Throwable> void onError(RetryContext context,
|
||||||
RetryCallback<T, E> callback, Throwable throwable) {
|
RetryCallback<T, E> callback, Throwable throwable) {
|
||||||
log.warn("重试异常:" + context.getRetryCount(), throwable);
|
log.warn("重试异常:" + context.getRetryCount(), throwable);
|
||||||
};
|
}
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -68,21 +71,21 @@ public class QianWenChatClient implements ChatClient, StreamingChatClient {
|
||||||
return this.retryTemplate.execute(ctx -> {
|
return this.retryTemplate.execute(ctx -> {
|
||||||
// ctx 会有重试的信息
|
// ctx 会有重试的信息
|
||||||
// 创建 request 请求,stream模式需要供应商支持
|
// 创建 request 请求,stream模式需要供应商支持
|
||||||
CompletionsRequest request = this.createRequest(prompt, false);
|
QianWenChatCompletionRequest request = this.createRequest(prompt, false);
|
||||||
// 调用 callWithFunctionSupport 发送请求
|
// 调用 callWithFunctionSupport 发送请求
|
||||||
ResponseEntity<CompletionsResponse> responseEntity = qianWenApi.chatCompletionEntity(request);
|
ResponseEntity<GenerationResult> responseEntity = qianWenApi.chatCompletionEntity(request);
|
||||||
// 获取结果封装 chatCompletion
|
// 获取结果封装 chatCompletion
|
||||||
CompletionsResponse response = responseEntity.getBody();
|
GenerationResult response = responseEntity.getBody();
|
||||||
if (!response.isSuccess()) {
|
// if (!response.isSuccess()) {
|
||||||
return new ChatResponse(List.of(new Generation(String.format("failed to create completion, requestId: %s, code: %s, message: %s\n",
|
// return new ChatResponse(List.of(new Generation(String.format("failed to create completion, requestId: %s, code: %s, message: %s\n",
|
||||||
response.getRequestId(), response.getCode(), response.getMessage()))));
|
// response.getRequestId(), response.getCode(), response.getMessage()))));
|
||||||
}
|
// }
|
||||||
// 转换为 Generation 返回
|
// 转换为 Generation 返回
|
||||||
return new ChatResponse(List.of(new Generation(response.getData().getText())));
|
return new ChatResponse(List.of(new Generation(response.getOutput().getText())));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletionsRequest createRequest(Prompt prompt, boolean stream) {
|
private QianWenChatCompletionRequest createRequest(Prompt prompt, boolean stream) {
|
||||||
// 两个都为null 则没有配置文件
|
// 两个都为null 则没有配置文件
|
||||||
if (qianWenOptions == null && prompt.getOptions() == null) {
|
if (qianWenOptions == null && prompt.getOptions() == null) {
|
||||||
throw new ChatException("ChatOptions 未配置参数!");
|
throw new ChatException("ChatOptions 未配置参数!");
|
||||||
|
@ -93,61 +96,40 @@ public class QianWenChatClient implements ChatClient, StreamingChatClient {
|
||||||
options = (ChatOptions) prompt.getOptions();
|
options = (ChatOptions) prompt.getOptions();
|
||||||
}
|
}
|
||||||
// Prompt 里面是一个 ChatOptions,用户可以随意传入,这里做一下判断
|
// Prompt 里面是一个 ChatOptions,用户可以随意传入,这里做一下判断
|
||||||
if (!(options instanceof QianWenOptions)) {
|
if (!(options instanceof QianWenOptions qianWenOptions)) {
|
||||||
throw new ChatException("Prompt 传入的不是 QianWenOptions!");
|
throw new ChatException("Prompt 传入的不是 QianWenOptions!");
|
||||||
}
|
}
|
||||||
QianWenOptions qianWenOptions = (QianWenOptions) options;
|
return (QianWenChatCompletionRequest) QianWenChatCompletionRequest.builder()
|
||||||
// 需要额外处理
|
.model(qianWenApi.getQianWenChatModal().getValue())
|
||||||
if (!stream) {
|
.apiKey(qianWenApi.getApiKey())
|
||||||
// 如果不需要 stream 输出,那么需要将这个设置为false,不然只会输出最后几个文字
|
.messages(prompt.getInstructions().stream().map(m -> {
|
||||||
if (qianWenOptions.getParameters() == null) {
|
Message message = new Message();
|
||||||
qianWenOptions.setParameters(new CompletionsRequest.Parameter().setIncrementalOutput(false));
|
message.setRole(m.getMessageType().getValue());
|
||||||
} else {
|
message.setContent(m.getContent());
|
||||||
qianWenOptions.getParameters().setIncrementalOutput(false);
|
return message;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 如果不需要 stream 输出,设置为true这样不会输出累加内容
|
|
||||||
if (qianWenOptions.getParameters() == null) {
|
|
||||||
qianWenOptions.setParameters(new CompletionsRequest.Parameter().setIncrementalOutput(true));
|
|
||||||
} else {
|
|
||||||
qianWenOptions.getParameters().setIncrementalOutput(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建request
|
|
||||||
return new CompletionsRequest()
|
|
||||||
// 请求唯一标识,请确保RequestId不重复。
|
|
||||||
.setRequestId(IdUtil.getSnowflakeNextIdStr())
|
|
||||||
// 设置 appid
|
|
||||||
.setAppId(qianWenOptions.getAppId())
|
|
||||||
.setMessages(prompt.getInstructions().stream().map(m -> {
|
|
||||||
// 转换成 千问 对于的请求message
|
|
||||||
if (MessageType.USER == m.getMessageType()) {
|
|
||||||
return new ChatUserMessage(m.getContent());
|
|
||||||
} else if (MessageType.SYSTEM == m.getMessageType()) {
|
|
||||||
return new ChatSystemMessage(m.getContent());
|
|
||||||
} else if (MessageType.ASSISTANT == m.getMessageType()) {
|
|
||||||
return new ChatAssistantMessage(m.getContent());
|
|
||||||
}
|
|
||||||
throw new ChatException(String.format("存在不能适配的消息! %s", JSONUtil.toJsonPrettyStr(m)));
|
|
||||||
}).collect(Collectors.toList()))
|
}).collect(Collectors.toList()))
|
||||||
// 返回choice message结果
|
.resultFormat(QwenParam.ResultFormat.MESSAGE)
|
||||||
.setParameters(qianWenOptions.getParameters())
|
// 动态改变的三个参数
|
||||||
// 设置 ChatOptions 里面公共的参数
|
.topP(Double.valueOf(qianWenOptions.getTopP()))
|
||||||
.setTopP(options.getTopP() == null ? null : options.getTopP().doubleValue())
|
.topK(qianWenOptions.getTopK())
|
||||||
// 设置输出方式
|
.temperature(qianWenOptions.getTemperature())
|
||||||
.setStream(stream);
|
.incrementalOutput(true)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<ChatResponse> stream(Prompt prompt) {
|
public Flux<ChatResponse> stream(Prompt prompt) {
|
||||||
// ctx 会有重试的信息
|
// ctx 会有重试的信息
|
||||||
// 创建 request 请求,stream模式需要供应商支持
|
// 创建 request 请求,stream模式需要供应商支持
|
||||||
CompletionsRequest request = this.createRequest(prompt, true);
|
QianWenChatCompletionRequest request = this.createRequest(prompt, true);
|
||||||
// 调用 callWithFunctionSupport 发送请求
|
// 调用 callWithFunctionSupport 发送请求
|
||||||
Flux<CompletionsResponse> response = this.qianWenApi.chatCompletionStream(request);
|
Flowable<GenerationResult> responseResult = this.qianWenApi.chatCompletionStream(request);
|
||||||
return response.map(res -> {
|
return Flux.create(fluxSink ->
|
||||||
return new ChatResponse(List.of(new Generation(res.getData().getText())));
|
responseResult.subscribe(
|
||||||
});
|
value -> fluxSink.next(new ChatResponse(List.of(new Generation(value.getOutput().getText())))),
|
||||||
|
error -> fluxSink.error(error),
|
||||||
|
() -> fluxSink.complete()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import lombok.Getter;
|
||||||
* 千问 chat 模型
|
* 千问 chat 模型
|
||||||
*
|
*
|
||||||
* 模型地址:https://help.aliyun.com/document_detail/2712576.html
|
* 模型地址:https://help.aliyun.com/document_detail/2712576.html
|
||||||
|
* 模型介绍:https://help.aliyun.com/document_detail/2666503.html?spm=a2c4g.2701795.0.0.26eb34dfKzcWN4
|
||||||
*
|
*
|
||||||
* @author fansili
|
* @author fansili
|
||||||
* @time 2024/4/26 10:15
|
* @time 2024/4/26 10:15
|
||||||
|
@ -16,18 +17,22 @@ import lombok.Getter;
|
||||||
@Getter
|
@Getter
|
||||||
public enum QianWenChatModal {
|
public enum QianWenChatModal {
|
||||||
|
|
||||||
qwen_turbo("通义千问超大规模语言模型", "qwen-turbo"),
|
// 千问付费模型
|
||||||
qwen_plus("通义千问超大规模语言模型增强版", "qwen-plus"),
|
QWEN_TURBO("通义千问超大规模语言模型", "qwen-turbo"),
|
||||||
qwen_max("通义千问千亿级别超大规模语言模型", "qwen-max"),
|
QWEN_PLUS("通义千问超大规模语言模型增强版", "qwen-plus"),
|
||||||
qwen_max_0403("通义千问千亿级别超大规模语言模型-0403", "qwen-max-0403"),
|
QWEN_MAX("通义千问千亿级别超大规模语言模型", "qwen-max"),
|
||||||
qwen_max_0107("通义千问千亿级别超大规模语言模型-0107", "qwen-max-0107"),
|
QWEN_MAX_0403("通义千问千亿级别超大规模语言模型-0403", "qwen-max-0403"),
|
||||||
qwen_max_1201("通义千问千亿级别超大规模语言模型-1201", "qwen-max-1201"),
|
QWEN_MAX_0107("通义千问千亿级别超大规模语言模型-0107", "qwen-max-0107"),
|
||||||
qwen_max_longcontext("通义千问千亿级别超大规模语言模型-28k tokens", "qwen-max-longcontext"),
|
QWEN_MAX_1201("通义千问千亿级别超大规模语言模型-1201", "qwen-max-1201"),
|
||||||
|
QWEN_MAX_LONGCONTEXT("通义千问千亿级别超大规模语言模型-28k tokens", "qwen-max-longcontext"),
|
||||||
|
|
||||||
|
// 开源模型
|
||||||
|
// https://help.aliyun.com/document_detail/2666503.html?spm=a2c4g.2701795.0.0.26eb34dfKzcWN4
|
||||||
|
QWEN_72B_CHAT("通义千问1.5对外开源的72B规模参数量的经过人类指令对齐的chat模型", "qwen-72b-chat"),
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private String value;
|
private String value;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package cn.iocoder.yudao.framework.ai.chatqianwen;
|
package cn.iocoder.yudao.framework.ai.chatqianwen;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.ai.chat.prompt.ChatOptions;
|
import cn.iocoder.yudao.framework.ai.chat.prompt.ChatOptions;
|
||||||
import com.aliyun.broadscope.bailian.sdk.models.CompletionsRequest;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
@ -34,22 +33,18 @@ public class QianWenOptions implements ChatOptions {
|
||||||
* 默认值为0.8。注意,取值不要大于等于1
|
* 默认值为0.8。注意,取值不要大于等于1
|
||||||
*/
|
*/
|
||||||
private Float topP;
|
private Float topP;
|
||||||
/**
|
|
||||||
* 模型参数设置。
|
|
||||||
*/
|
|
||||||
private CompletionsRequest.Parameter parameters = new CompletionsRequest.Parameter();
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 适配 ChatOptions
|
// 适配 ChatOptions
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Float getTemperature() {
|
public Float getTemperature() {
|
||||||
return Float.parseFloat(this.parameters.getTemperature().toString());
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTemperature(Float temperature) {
|
public void setTemperature(Float temperature) {
|
||||||
this.parameters.setTemperature(Double.valueOf(temperature.toString()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -59,12 +54,12 @@ public class QianWenOptions implements ChatOptions {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer getTopK() {
|
public Integer getTopK() {
|
||||||
return this.parameters.getTopK();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTopK(Integer topK) {
|
public void setTopK(Integer topK) {
|
||||||
this.parameters.setTopK(topK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
|
|
@ -1,64 +1,63 @@
|
||||||
package cn.iocoder.yudao.framework.ai.chatqianwen.api;
|
package cn.iocoder.yudao.framework.ai.chatqianwen.api;
|
||||||
|
|
||||||
import com.aliyun.broadscope.bailian.sdk.AccessTokenClient;
|
import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenChatModal;
|
||||||
import com.aliyun.broadscope.bailian.sdk.ApplicationClient;
|
import cn.iocoder.yudao.framework.ai.exception.AiException;
|
||||||
import com.aliyun.broadscope.bailian.sdk.models.CompletionsRequest;
|
import com.alibaba.dashscope.aigc.generation.Generation;
|
||||||
import com.aliyun.broadscope.bailian.sdk.models.CompletionsResponse;
|
import com.alibaba.dashscope.aigc.generation.GenerationResult;
|
||||||
|
import com.alibaba.dashscope.common.Message;
|
||||||
|
import com.alibaba.dashscope.common.Role;
|
||||||
|
import com.alibaba.dashscope.exception.InputRequiredException;
|
||||||
|
import com.alibaba.dashscope.exception.NoApiKeyException;
|
||||||
|
import io.reactivex.Flowable;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.springframework.http.HttpStatusCode;
|
import org.springframework.http.HttpStatusCode;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import reactor.core.publisher.Flux;
|
|
||||||
|
|
||||||
// TODO done @fansili:是不是挪到 api 包里?按照 spring ai 的结构;根目录只放 client 和 options
|
// TODO done @fansili:是不是挪到 api 包里?按照 spring ai 的结构;根目录只放 client 和 options
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 阿里 通义千问
|
* 阿里 通义千问
|
||||||
*
|
* <p>
|
||||||
* https://www.aliyun.com/search?k=%E9%80%9A%E4%B9%89%E5%A4%A7%E6%A8%A1%E5%9E%8B&scene=all
|
|
||||||
*
|
|
||||||
* author: fansili
|
* author: fansili
|
||||||
* time: 2024/3/13 21:09
|
* time: 2024/3/13 21:09
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public class QianWenApi {
|
public class QianWenApi {
|
||||||
|
|
||||||
/**
|
// api key 获取地址:https://bailian.console.aliyun.com/?spm=5176.28197581.0.0.38db29a4G3GcVb&apiKey=1#/api-key
|
||||||
* accessKeyId、accessKeySecret、agentKey、appId 获取方式如下链接
|
private String apiKey = "sk-Zsd81gZYg7";
|
||||||
* https://help.aliyun.com/document_detail/2587494.html?spm=a2c4g.2587492.0.0.53f33c566sXskp
|
private Generation gen = new Generation();
|
||||||
*/
|
private QianWenChatModal qianWenChatModal;
|
||||||
private String accessKeyId;
|
|
||||||
private String accessKeySecret;
|
|
||||||
private String agentKey;
|
|
||||||
private String appId;
|
|
||||||
private String endpoint = "bailian.cn-beijing.aliyuncs.com";
|
|
||||||
private String token;
|
|
||||||
private ApplicationClient client;
|
|
||||||
|
|
||||||
public QianWenApi(String accessKeyId, String accessKeySecret, String agentKey, String endpoint) {
|
public QianWenApi(String apiKey, QianWenChatModal qianWenChatModal) {
|
||||||
this.accessKeyId = accessKeyId;
|
this.apiKey = apiKey;
|
||||||
this.accessKeySecret = accessKeySecret;
|
this.qianWenChatModal = qianWenChatModal;
|
||||||
this.agentKey = agentKey;
|
}
|
||||||
|
|
||||||
if (endpoint != null) {
|
public ResponseEntity<GenerationResult> chatCompletionEntity(QianWenChatCompletionRequest request) {
|
||||||
this.endpoint = endpoint;
|
Message userMsg = Message.builder().role(Role.USER.getValue()).content("用萝卜、土豆、茄子做饭,给我个菜谱").build();
|
||||||
|
|
||||||
|
GenerationResult call;
|
||||||
|
try {
|
||||||
|
call = gen.call(request);
|
||||||
|
} catch (NoApiKeyException e) {
|
||||||
|
throw new AiException("没有找到apiKey!" + e.getMessage());
|
||||||
|
} catch (InputRequiredException e) {
|
||||||
|
throw new AiException("chat缺少必填字段!" + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取token
|
|
||||||
AccessTokenClient accessTokenClient = new AccessTokenClient(accessKeyId, accessKeySecret, agentKey);
|
|
||||||
token = accessTokenClient.getToken();
|
|
||||||
// 构建client
|
|
||||||
client = ApplicationClient.builder()
|
|
||||||
.token(token)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity<CompletionsResponse> chatCompletionEntity(CompletionsRequest request) {
|
|
||||||
// 发送请求
|
|
||||||
CompletionsResponse response = client.completions(request);
|
|
||||||
// 阿里云的这个 http code 随便设置,外面判断是否成功用的 CompletionsResponse.isSuccess
|
// 阿里云的这个 http code 随便设置,外面判断是否成功用的 CompletionsResponse.isSuccess
|
||||||
return new ResponseEntity<>(response, HttpStatusCode.valueOf(200));
|
return new ResponseEntity<>(call, HttpStatusCode.valueOf(200));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Flux<CompletionsResponse> chatCompletionStream(CompletionsRequest request) {
|
public Flowable<GenerationResult> chatCompletionStream(QianWenChatCompletionRequest request) {
|
||||||
return client.streamCompletions(request);
|
Flowable<GenerationResult> resultFlowable;
|
||||||
|
try {
|
||||||
|
resultFlowable = gen.streamCall(request);
|
||||||
|
} catch (NoApiKeyException e) {
|
||||||
|
throw new AiException("没有找到apiKey!" + e.getMessage());
|
||||||
|
} catch (InputRequiredException e) {
|
||||||
|
throw new AiException("chat缺少必填字段!" + e.getMessage());
|
||||||
|
}
|
||||||
|
return resultFlowable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package cn.iocoder.yudao.framework.ai.chatqianwen.api;
|
package cn.iocoder.yudao.framework.ai.chatqianwen.api;
|
||||||
|
|
||||||
import com.aliyun.broadscope.bailian.sdk.models.CompletionsResponse;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* author: fansili
|
* author: fansili
|
||||||
* time: 2024/3/13 21:07
|
* time: 2024/3/13 21:07
|
||||||
*/
|
*/
|
||||||
public class QianWenChatCompletion extends CompletionsResponse {
|
public class QianWenChatCompletion {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
package cn.iocoder.yudao.framework.ai.chatqianwen.api;
|
package cn.iocoder.yudao.framework.ai.chatqianwen.api;
|
||||||
|
|
||||||
import com.aliyun.broadscope.bailian.sdk.models.ChatRequestMessage;
|
import com.alibaba.dashscope.aigc.generation.models.QwenParam;
|
||||||
import com.aliyun.broadscope.bailian.sdk.models.ChatUserMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 千问
|
||||||
|
*
|
||||||
* author: fansili
|
* author: fansili
|
||||||
* time: 2024/3/13 21:07
|
* time: 2024/3/13 21:07
|
||||||
*/
|
*/
|
||||||
public class QianWenChatCompletionRequest extends ChatRequestMessage {
|
public class QianWenChatCompletionRequest extends QwenParam {
|
||||||
|
|
||||||
|
protected QianWenChatCompletionRequest(QwenParamBuilder<?, ?> b) {
|
||||||
|
super(b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package cn.iocoder.yudao.framework.ai.config;
|
package cn.iocoder.yudao.framework.ai.config;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenChatClient;
|
import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenChatClient;
|
||||||
|
import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenChatModal;
|
||||||
import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenOptions;
|
import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenOptions;
|
||||||
import cn.iocoder.yudao.framework.ai.chatqianwen.api.QianWenApi;
|
import cn.iocoder.yudao.framework.ai.chatqianwen.api.QianWenApi;
|
||||||
import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatClient;
|
import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatClient;
|
||||||
|
@ -45,10 +46,8 @@ public class YudaoAiAutoConfiguration {
|
||||||
YudaoAiProperties.QianWenProperties qianWenProperties = yudaoAiProperties.getQianwen();
|
YudaoAiProperties.QianWenProperties qianWenProperties = yudaoAiProperties.getQianwen();
|
||||||
return new QianWenChatClient(
|
return new QianWenChatClient(
|
||||||
new QianWenApi(
|
new QianWenApi(
|
||||||
qianWenProperties.getAccessKeyId(),
|
|
||||||
qianWenProperties.getAccessKeySecret(),
|
|
||||||
qianWenProperties.getAgentKey(),
|
qianWenProperties.getAgentKey(),
|
||||||
qianWenProperties.getEndpoint()
|
QianWenChatModal.QWEN_72B_CHAT
|
||||||
),
|
),
|
||||||
new QianWenOptions()
|
new QianWenOptions()
|
||||||
.setAppId(qianWenProperties.getAppId())
|
.setAppId(qianWenProperties.getAppId())
|
||||||
|
|
|
@ -2,13 +2,13 @@ package cn.iocoder.yudao.framework.ai.midjourney.api;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig;
|
import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig;
|
||||||
import cn.iocoder.yudao.framework.ai.midjourney.util.MidjourneyUtil;
|
|
||||||
import cn.iocoder.yudao.framework.ai.midjourney.api.req.AttachmentsReq;
|
import cn.iocoder.yudao.framework.ai.midjourney.api.req.AttachmentsReq;
|
||||||
import cn.iocoder.yudao.framework.ai.midjourney.api.req.DescribeReq;
|
import cn.iocoder.yudao.framework.ai.midjourney.api.req.DescribeReq;
|
||||||
import cn.iocoder.yudao.framework.ai.midjourney.api.req.ReRollReq;
|
import cn.iocoder.yudao.framework.ai.midjourney.api.req.ReRollReq;
|
||||||
import cn.iocoder.yudao.framework.ai.midjourney.api.res.UploadAttachmentsRes;
|
import cn.iocoder.yudao.framework.ai.midjourney.api.res.UploadAttachmentsRes;
|
||||||
import com.alibaba.fastjson.JSON;
|
import cn.iocoder.yudao.framework.ai.midjourney.util.MidjourneyUtil;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.core.io.FileSystemResource;
|
import org.springframework.core.io.FileSystemResource;
|
||||||
|
|
|
@ -11,7 +11,7 @@ import cn.iocoder.yudao.framework.ai.midjourney.constants.MidjourneyConstants;
|
||||||
import cn.iocoder.yudao.framework.ai.midjourney.constants.MidjourneyGennerateStatusEnum;
|
import cn.iocoder.yudao.framework.ai.midjourney.constants.MidjourneyGennerateStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.ai.midjourney.constants.MidjourneyMessageTypeEnum;
|
import cn.iocoder.yudao.framework.ai.midjourney.constants.MidjourneyMessageTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.ai.midjourney.util.MidjourneyUtil;
|
import cn.iocoder.yudao.framework.ai.midjourney.util.MidjourneyUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.dv8tion.jda.api.utils.data.DataObject;
|
import net.dv8tion.jda.api.utils.data.DataObject;
|
||||||
|
|
||||||
|
@ -45,13 +45,13 @@ public class MidjourneyMessageListener {
|
||||||
// 转换 components
|
// 转换 components
|
||||||
if (!data.getArray(MidjourneyConstants.MSG_COMPONENTS).isEmpty()) {
|
if (!data.getArray(MidjourneyConstants.MSG_COMPONENTS).isEmpty()) {
|
||||||
String componentsJson = StrUtil.str(data.getArray(MidjourneyConstants.MSG_COMPONENTS).toJson(), "UTF-8");
|
String componentsJson = StrUtil.str(data.getArray(MidjourneyConstants.MSG_COMPONENTS).toJson(), "UTF-8");
|
||||||
List<MidjourneyMessage.ComponentType> components = JSON.parseArray(componentsJson, MidjourneyMessage.ComponentType.class);
|
List<MidjourneyMessage.ComponentType> components = JsonUtils.parseArray(componentsJson, MidjourneyMessage.ComponentType.class);
|
||||||
mjMessage.setComponents(components);
|
mjMessage.setComponents(components);
|
||||||
}
|
}
|
||||||
// 转换附件
|
// 转换附件
|
||||||
if (!data.getArray(MidjourneyConstants.MSG_ATTACHMENTS).isEmpty()) {
|
if (!data.getArray(MidjourneyConstants.MSG_ATTACHMENTS).isEmpty()) {
|
||||||
String attachmentsJson = StrUtil.str(data.getArray(MidjourneyConstants.MSG_ATTACHMENTS).toJson(), "UTF-8");
|
String attachmentsJson = StrUtil.str(data.getArray(MidjourneyConstants.MSG_ATTACHMENTS).toJson(), "UTF-8");
|
||||||
List<MidjourneyMessage.Attachment> attachments = JSON.parseArray(attachmentsJson, MidjourneyMessage.Attachment.class);
|
List<MidjourneyMessage.Attachment> attachments = JsonUtils.parseArray(attachmentsJson, MidjourneyMessage.Attachment.class);
|
||||||
mjMessage.setAttachments(attachments);
|
mjMessage.setAttachments(attachments);
|
||||||
}
|
}
|
||||||
// 转换状态
|
// 转换状态
|
||||||
|
|
Loading…
Reference in New Issue