增加阿里 通义千问

This commit is contained in:
cherishsince 2024-03-14 20:16:07 +08:00
parent de32611794
commit 0f73b61db2
9 changed files with 308 additions and 2 deletions

View File

@ -108,6 +108,12 @@
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<!-- 阿里云 通义千问 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>broadscope-bailian-sdk-java</artifactId>
<version>1.3.0</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,82 @@
package cn.iocoder.yudao.framework.ai.chatqianwen;
import com.aliyun.broadscope.bailian.sdk.AccessTokenClient;
import com.aliyun.broadscope.bailian.sdk.ApplicationClient;
import com.aliyun.broadscope.bailian.sdk.models.ChatRequestMessage;
import com.aliyun.broadscope.bailian.sdk.models.CompletionsRequest;
import com.aliyun.broadscope.bailian.sdk.models.CompletionsResponse;
import lombok.Getter;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import reactor.core.publisher.Flux;
import java.util.List;
/**
* 阿里 通义千问
*
* 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
* time: 2024/3/13 21:09
*/
@Getter
public class QianWenApi {
/**
* accessKeyIdaccessKeySecretagentKeyappId 获取方式如下链接
* https://help.aliyun.com/document_detail/2587494.html?spm=a2c4g.2587492.0.0.53f33c566sXskp
*/
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 appId, String endpoint) {
this.accessKeyId = accessKeyId;
this.accessKeySecret = accessKeySecret;
this.agentKey = agentKey;
this.appId = appId;
if (endpoint != null) {
this.endpoint = endpoint;
}
// 获取token
AccessTokenClient accessTokenClient = new AccessTokenClient(accessKeyId, accessKeySecret, agentKey);
token = accessTokenClient.getToken();
// 构建client
client = ApplicationClient.builder()
.token(token)
.build();
}
public ResponseEntity<CompletionsResponse> chatCompletionEntity(ChatRequestMessage message) {
// 创建request
CompletionsRequest request = new CompletionsRequest()
.setAppId(appId)
.setMessages(List.of(message))
.setParameters(new CompletionsRequest.Parameter().setResultFormat("message"));
//
CompletionsResponse response = client.completions(request);
int httpCode = 200;
if (!response.isSuccess()) {
System.out.printf("failed to create completion, requestId: %s, code: %s, message: %s\n",
response.getRequestId(), response.getCode(), response.getMessage());
httpCode = 500;
}
return new ResponseEntity<>(response, HttpStatusCode.valueOf(httpCode));
}
public Flux<CompletionsResponse> chatCompletionStream(ChatRequestMessage message) {
return client.streamCompletions(
new CompletionsRequest()
.setAppId(appId)
.setMessages(List.of(message))
.setParameters(new CompletionsRequest.Parameter().setIncrementalOutput(true))
);
}
}

View File

@ -0,0 +1,128 @@
package cn.iocoder.yudao.framework.ai.chatqianwen;
import cn.iocoder.yudao.framework.ai.chat.ChatClient;
import cn.iocoder.yudao.framework.ai.chat.ChatResponse;
import cn.iocoder.yudao.framework.ai.chat.Generation;
import cn.iocoder.yudao.framework.ai.chat.StreamingChatClient;
import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt;
import cn.iocoder.yudao.framework.ai.chatqianwen.api.QianWenChatCompletionMessage;
import cn.iocoder.yudao.framework.ai.chatqianwen.api.QianWenChatCompletionRequest;
import cn.iocoder.yudao.framework.ai.chatyiyan.api.YiYanChatCompletion;
import cn.iocoder.yudao.framework.ai.chatyiyan.api.YiYanChatCompletionRequest;
import cn.iocoder.yudao.framework.ai.chatyiyan.exception.YiYanApiException;
import cn.iocoder.yudao.framework.ai.model.function.AbstractFunctionCallSupport;
import cn.iocoder.yudao.framework.ai.model.function.FunctionCallbackContext;
import com.aliyun.broadscope.bailian.sdk.models.ChatRequestMessage;
import com.aliyun.broadscope.bailian.sdk.models.ChatUserMessage;
import com.aliyun.broadscope.bailian.sdk.models.CompletionsResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
import org.springframework.retry.support.RetryTemplate;
import reactor.core.publisher.Flux;
import java.time.Duration;
import java.util.List;
import java.util.stream.Collectors;
/**
* 阿里 通义千问 client
*
* 文档地址https://help.aliyun.com/document_detail/2587494.html?spm=a2c4g.2587492.0.0.53f33c566sXskp
*
* author: fansili
* time: 2024/3/13 21:06
*/
@Slf4j
public class QianWenChatClient extends AbstractFunctionCallSupport<QianWenChatCompletionMessage, ChatRequestMessage, ResponseEntity<CompletionsResponse>>
implements ChatClient, StreamingChatClient {
private QianWenApi qianWenApi;
public QianWenChatClient(QianWenApi qianWenApi) {
super(null);
this.qianWenApi = qianWenApi;
}
public final RetryTemplate retryTemplate = RetryTemplate.builder()
// 最大重试次数 10
.maxAttempts(10)
.retryOn(YiYanApiException.class)
// 最大重试5次第一次间隔3000ms第二次3000ms * 2第三次3000ms * 3以此类推最大间隔3 * 60000ms
.exponentialBackoff(Duration.ofMillis(3000), 2, Duration.ofMillis(3 * 60000))
.withListener(new RetryListener() {
@Override
public <T extends Object, E extends Throwable> void onError(RetryContext context,
RetryCallback<T, E> callback, Throwable throwable) {
log.warn("重试异常:" + context.getRetryCount(), throwable);
};
})
.build();
public QianWenChatClient(FunctionCallbackContext functionCallbackContext) {
super(functionCallbackContext);
}
@Override
public ChatResponse call(Prompt prompt) {
return this.retryTemplate.execute(ctx -> {
// ctx 会有重试的信息
// 创建 request 请求stream模式需要供应商支持
ChatRequestMessage request = this.createRequest(prompt, false);
// 调用 callWithFunctionSupport 发送请求
ResponseEntity<CompletionsResponse> responseEntity = this.callWithFunctionSupport(request);
// 获取结果封装 chatCompletion
CompletionsResponse response = responseEntity.getBody();
if (!response.isSuccess()) {
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()))));
}
List<Generation> generations = response.getData().getChoices().stream()
.map(item -> new Generation(item.getMessage().getContent())).collect(Collectors.toList());
return new ChatResponse(generations);
});
}
private ChatRequestMessage createRequest(Prompt prompt, boolean b) {
return new ChatUserMessage(prompt.getContents());
}
@Override
public Flux<ChatResponse> stream(Prompt prompt) {
// ctx 会有重试的信息
// 创建 request 请求stream模式需要供应商支持
ChatRequestMessage request = this.createRequest(prompt, true);
// 调用 callWithFunctionSupport 发送请求
Flux<CompletionsResponse> response = this.qianWenApi.chatCompletionStream(request);
return response.map(res -> {
return new ChatResponse(List.of(new Generation(res.getData().getText())));
});
}
@Override
protected QianWenChatCompletionRequest doCreateToolResponseRequest(ChatRequestMessage previousRequest, QianWenChatCompletionMessage responseMessage, List<QianWenChatCompletionMessage> conversationHistory) {
return null;
}
@Override
protected List<QianWenChatCompletionMessage> doGetUserMessages(ChatRequestMessage request) {
return null;
}
@Override
protected QianWenChatCompletionMessage doGetToolResponseMessage(ResponseEntity<CompletionsResponse> response) {
return null;
}
@Override
protected ResponseEntity<CompletionsResponse> doChatCompletion(ChatRequestMessage request) {
return qianWenApi.chatCompletionEntity(request);
}
@Override
protected boolean isToolFunctionCall(ResponseEntity<CompletionsResponse> response) {
return false;
}
}

View File

@ -0,0 +1,10 @@
package cn.iocoder.yudao.framework.ai.chatqianwen.api;
import com.aliyun.broadscope.bailian.sdk.models.CompletionsResponse;
/**
* author: fansili
* time: 2024/3/13 21:07
*/
public class QianWenChatCompletion extends CompletionsResponse {
}

View File

@ -0,0 +1,8 @@
package cn.iocoder.yudao.framework.ai.chatqianwen.api;
/**
* author: fansili
* time: 2024/3/13 21:07
*/
public class QianWenChatCompletionMessage {
}

View File

@ -0,0 +1,12 @@
package cn.iocoder.yudao.framework.ai.chatqianwen.api;
import com.aliyun.broadscope.bailian.sdk.models.ChatRequestMessage;
import com.aliyun.broadscope.bailian.sdk.models.ChatUserMessage;
/**
* author: fansili
* time: 2024/3/13 21:07
*/
public class QianWenChatCompletionRequest extends ChatRequestMessage {
}

View File

@ -0,0 +1,9 @@
/**
* 阿里的 通义千问
*
* 链接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
* time: 2024/3/13 21:05
*/
package cn.iocoder.yudao.framework.ai.chatqianwen;

View File

@ -132,8 +132,6 @@ public class XingHuoApi {
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException(e);
}
System.err.println(authUrl);
System.err.println(JSONUtil.toJsonPrettyStr(request));
// wss 请求的 URI
URI uri = URI.create(authUrl);
// 发起 wss 请求并处理响应

View File

@ -0,0 +1,53 @@
package cn.iocoder.yudao.framework.ai.chat;
import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt;
import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenApi;
import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenChatClient;
import org.junit.Before;
import org.junit.Test;
import reactor.core.publisher.Flux;
import java.util.Scanner;
import java.util.function.Consumer;
/**
* author: fansili
* time: 2024/3/13 21:37
*/
public class QianWenChatClientTests {
private QianWenChatClient qianWenChatClient;
@Before
public void setup() {
QianWenApi qianWenApi = new QianWenApi(
"",
"",
"",
"",
null
);
qianWenChatClient = new QianWenChatClient(qianWenApi);
}
@Test
public void callTest() {
ChatResponse call = qianWenChatClient.call(new Prompt("Java语言怎么样"));
System.err.println(call.getResult());
}
@Test
public void streamTest() {
Flux<ChatResponse> flux = qianWenChatClient.stream(new Prompt("Java语言怎么样"));
flux.subscribe(new Consumer<ChatResponse>() {
@Override
public void accept(ChatResponse chatResponse) {
System.err.print(chatResponse.getResult().getOutput().getContent());
}
});
// 阻止退出
Scanner scanner = new Scanner(System.in);
scanner.nextLine();
}
}