mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-30 09:48:43 +08:00 
			
		
		
		
	增加阿里 通义千问
This commit is contained in:
		| @@ -108,6 +108,12 @@ | |||||||
|             <groupId>cn.hutool</groupId> |             <groupId>cn.hutool</groupId> | ||||||
|             <artifactId>hutool-all</artifactId> |             <artifactId>hutool-all</artifactId> | ||||||
|         </dependency> |         </dependency> | ||||||
|  |         <!--    阿里云 通义千问    --> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>com.aliyun</groupId> | ||||||
|  |             <artifactId>broadscope-bailian-sdk-java</artifactId> | ||||||
|  |             <version>1.3.0</version> | ||||||
|  |         </dependency> | ||||||
|     </dependencies> |     </dependencies> | ||||||
|  |  | ||||||
| </project> | </project> | ||||||
| @@ -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 { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * accessKeyId、accessKeySecret、agentKey、appId 获取方式如下链接 | ||||||
|  |      * 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)) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -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; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -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 { | ||||||
|  | } | ||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | package cn.iocoder.yudao.framework.ai.chatqianwen.api; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * author: fansili | ||||||
|  |  * time: 2024/3/13 21:07 | ||||||
|  |  */ | ||||||
|  | public class QianWenChatCompletionMessage { | ||||||
|  | } | ||||||
| @@ -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 { | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -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; | ||||||
| @@ -132,8 +132,6 @@ public class XingHuoApi { | |||||||
|         } catch (NoSuchAlgorithmException | InvalidKeyException e) { |         } catch (NoSuchAlgorithmException | InvalidKeyException e) { | ||||||
|             throw new RuntimeException(e); |             throw new RuntimeException(e); | ||||||
|         } |         } | ||||||
|         System.err.println(authUrl); |  | ||||||
|         System.err.println(JSONUtil.toJsonPrettyStr(request)); |  | ||||||
|         // wss 请求的 URI |         // wss 请求的 URI | ||||||
|         URI uri = URI.create(authUrl); |         URI uri = URI.create(authUrl); | ||||||
|         // 发起 wss 请求并处理响应 |         // 发起 wss 请求并处理响应 | ||||||
|   | |||||||
| @@ -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(); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 cherishsince
					cherishsince