Commit de32611794f0ec3282109dcc8d799b37ab8d3a7c
1 parent
1828d195
增加讯飞星火
Showing
14 changed files
with
861 additions
and
0 deletions
yudao-module-ai/pom.xml
| @@ -14,6 +14,7 @@ | @@ -14,6 +14,7 @@ | ||
| 14 | <modules> | 14 | <modules> |
| 15 | <module>yudao-module-ai-api</module> | 15 | <module>yudao-module-ai-api</module> |
| 16 | <module>yudao-module-ai-biz</module> | 16 | <module>yudao-module-ai-biz</module> |
| 17 | + <module>yudao-spring-boot-starter-ai</module> | ||
| 17 | </modules> | 18 | </modules> |
| 18 | 19 | ||
| 19 | <properties> | 20 | <properties> |
yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml
| @@ -100,6 +100,14 @@ | @@ -100,6 +100,14 @@ | ||
| 100 | <version>4.12.0</version> | 100 | <version>4.12.0</version> |
| 101 | <scope>test</scope> | 101 | <scope>test</scope> |
| 102 | </dependency> | 102 | </dependency> |
| 103 | + <dependency> | ||
| 104 | + <groupId>io.projectreactor.netty</groupId> | ||
| 105 | + <artifactId>reactor-netty</artifactId> | ||
| 106 | + </dependency> | ||
| 107 | + <dependency> | ||
| 108 | + <groupId>cn.hutool</groupId> | ||
| 109 | + <artifactId>hutool-all</artifactId> | ||
| 110 | + </dependency> | ||
| 103 | </dependencies> | 111 | </dependencies> |
| 104 | 112 | ||
| 105 | </project> | 113 | </project> |
| 106 | \ No newline at end of file | 114 | \ No newline at end of file |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chatxinghuo; | ||
| 2 | + | ||
| 3 | +import cn.hutool.http.HttpUtil; | ||
| 4 | +import cn.hutool.json.JSONUtil; | ||
| 5 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.api.XingHuoChatCompletion; | ||
| 6 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.api.XingHuoChatCompletionRequest; | ||
| 7 | +import lombok.Data; | ||
| 8 | +import org.springframework.http.HttpStatusCode; | ||
| 9 | +import org.springframework.http.ResponseEntity; | ||
| 10 | +import org.springframework.web.reactive.function.client.WebClient; | ||
| 11 | +import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient; | ||
| 12 | +import reactor.core.publisher.Flux; | ||
| 13 | +import reactor.core.publisher.Mono; | ||
| 14 | + | ||
| 15 | +import javax.crypto.Mac; | ||
| 16 | +import javax.crypto.spec.SecretKeySpec; | ||
| 17 | +import java.net.URI; | ||
| 18 | +import java.nio.charset.Charset; | ||
| 19 | +import java.security.InvalidKeyException; | ||
| 20 | +import java.security.NoSuchAlgorithmException; | ||
| 21 | +import java.text.SimpleDateFormat; | ||
| 22 | +import java.util.*; | ||
| 23 | +import java.util.stream.Collectors; | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * 讯飞星火 属性、api | ||
| 27 | + * <p> | ||
| 28 | + * 文档地址:https://www.xfyun.cn/doc/spark/Web.html#_1-%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E | ||
| 29 | + * <p> | ||
| 30 | + * author: fansili | ||
| 31 | + * time: 2024/3/11 10:12 | ||
| 32 | + */ | ||
| 33 | +@Data | ||
| 34 | +public class XingHuoApi { | ||
| 35 | + | ||
| 36 | + private static final String DEFAULT_BASE_URL = "wss://spark-api.xf-yun.com"; | ||
| 37 | + | ||
| 38 | + private String appId; | ||
| 39 | + private String appKey; | ||
| 40 | + private String secretKey; | ||
| 41 | + private WebClient webClient; | ||
| 42 | + private XingHuoChatModel useChatModel; | ||
| 43 | + // 创建 WebSocketClient 实例 | ||
| 44 | + private ReactorNettyWebSocketClient socketClient = new ReactorNettyWebSocketClient(); | ||
| 45 | + | ||
| 46 | + public XingHuoApi(String appId, String appKey, String secretKey, XingHuoChatModel useChatModel) { | ||
| 47 | + this.appId = appId; | ||
| 48 | + this.appKey = appKey; | ||
| 49 | + this.secretKey = secretKey; | ||
| 50 | + this.useChatModel = useChatModel; | ||
| 51 | + | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + public ResponseEntity<XingHuoChatCompletion> chatCompletionEntity(XingHuoChatCompletionRequest request) { | ||
| 55 | + String authUrl; | ||
| 56 | + try { | ||
| 57 | + authUrl = getAuthorizationUrl("spark-api.xf-yun.com", useChatModel.getUri()); | ||
| 58 | + } catch (NoSuchAlgorithmException | InvalidKeyException e) { | ||
| 59 | + throw new RuntimeException(e); | ||
| 60 | + } | ||
| 61 | + // wss 请求的 URI | ||
| 62 | + URI uri = URI.create(authUrl); | ||
| 63 | + // 发起 wss 请求并处理响应 | ||
| 64 | + Flux<XingHuoChatCompletion> messageFlux = Flux.create(sink -> { | ||
| 65 | + socketClient.execute(uri, session -> | ||
| 66 | + session.send(Mono.just(session.textMessage(JSONUtil.toJsonStr(request)))) | ||
| 67 | + .thenMany(session.receive() | ||
| 68 | + .map(WebSocketMessage -> { | ||
| 69 | + return JSONUtil.toBean(WebSocketMessage.getPayloadAsText(), XingHuoChatCompletion.class); | ||
| 70 | + }) | ||
| 71 | + .doOnNext(sink::next) // 将接收到的消息推送到 Flux 中 | ||
| 72 | + .doOnError(sink::error) // 处理错误 | ||
| 73 | + .doOnTerminate(sink::complete)) // 完成时关闭 sink | ||
| 74 | + .then()) | ||
| 75 | + .subscribe(); // 订阅以开始会话 | ||
| 76 | + }); | ||
| 77 | + // 阻塞获取所有结果 | ||
| 78 | + List<XingHuoChatCompletion> responseList = messageFlux.collectList().block(); | ||
| 79 | + // 拼接 content | ||
| 80 | + String responseContent = responseList.stream().map(item -> { | ||
| 81 | + // 获取 content | ||
| 82 | + return item.getPayload().getChoices().getText().stream().map(XingHuoChatCompletion.Text::getContent).collect(Collectors.joining()); | ||
| 83 | + }).collect(Collectors.joining()); | ||
| 84 | + // 将多个合并成一个 | ||
| 85 | + XingHuoChatCompletion xingHuoChatCompletion = new XingHuoChatCompletion(); | ||
| 86 | + xingHuoChatCompletion.setPayload(new XingHuoChatCompletion.Payload().setChoices(new XingHuoChatCompletion.Choices().setText(List.of(new XingHuoChatCompletion.Text().setContent(responseContent))))); | ||
| 87 | + return new ResponseEntity<>(xingHuoChatCompletion, HttpStatusCode.valueOf(200)); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + | ||
| 91 | + /** | ||
| 92 | + * 获取验证请求url | ||
| 93 | + * | ||
| 94 | + * @return | ||
| 95 | + */ | ||
| 96 | + public String getAuthorizationUrl(String host, String path) throws NoSuchAlgorithmException, InvalidKeyException { | ||
| 97 | + // 获取鉴权时间 date | ||
| 98 | + SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); | ||
| 99 | + format.setTimeZone(TimeZone.getTimeZone("GMT")); | ||
| 100 | + String date = format.format(new Date()); | ||
| 101 | + | ||
| 102 | + // 获取signature_origin字段 | ||
| 103 | + StringBuilder builder = new StringBuilder("host: ").append(host).append("\n"). | ||
| 104 | + append("date: ").append(date).append("\n"). | ||
| 105 | + append("GET ").append(path).append(" HTTP/1.1"); | ||
| 106 | + | ||
| 107 | + // 获得signatue | ||
| 108 | + Charset charset = Charset.forName("UTF-8"); | ||
| 109 | + Mac mac = Mac.getInstance("hmacsha256"); | ||
| 110 | + SecretKeySpec sp = new SecretKeySpec(secretKey.getBytes(charset), "hmacsha256"); | ||
| 111 | + mac.init(sp); | ||
| 112 | + byte[] basebefore = mac.doFinal(builder.toString().getBytes(charset)); | ||
| 113 | + String signature = Base64.getEncoder().encodeToString(basebefore); | ||
| 114 | + //获得 authorization_origin | ||
| 115 | + String authorization_origin = String.format("api_key=\"%s\",algorithm=\"%s\",headers=\"%s\",signature=\"%s\"", appKey, "hmac-sha256", "host date request-line", signature); | ||
| 116 | + //获得authorization | ||
| 117 | + String authorization = Base64.getEncoder().encodeToString(authorization_origin.getBytes(charset)); | ||
| 118 | + // 获取httpUrl | ||
| 119 | + Map<String, Object> param = new HashMap<>(); | ||
| 120 | + param.put("authorization", authorization); | ||
| 121 | + param.put("date", date); | ||
| 122 | + param.put("host", host); | ||
| 123 | + | ||
| 124 | + String toParams = HttpUtil.toParams(param); | ||
| 125 | + return "wss://" + host + path + "?" + toParams; | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + public Flux<XingHuoChatCompletion> chatCompletionStream(XingHuoChatCompletionRequest request) { | ||
| 129 | + String authUrl; | ||
| 130 | + try { | ||
| 131 | + authUrl = getAuthorizationUrl("spark-api.xf-yun.com", useChatModel.getUri()); | ||
| 132 | + } catch (NoSuchAlgorithmException | InvalidKeyException e) { | ||
| 133 | + throw new RuntimeException(e); | ||
| 134 | + } | ||
| 135 | + System.err.println(authUrl); | ||
| 136 | + System.err.println(JSONUtil.toJsonPrettyStr(request)); | ||
| 137 | + // wss 请求的 URI | ||
| 138 | + URI uri = URI.create(authUrl); | ||
| 139 | + // 发起 wss 请求并处理响应 | ||
| 140 | + // 创建一个 Flux 来处理接收到的消息 | ||
| 141 | + Flux<XingHuoChatCompletion> messageFlux = Flux.create(sink -> { | ||
| 142 | + socketClient.execute(uri, session -> | ||
| 143 | + session.send(Mono.just(session.textMessage(JSONUtil.toJsonStr(request)))) | ||
| 144 | + .thenMany(session.receive() | ||
| 145 | + .map(WebSocketMessage -> JSONUtil.toBean(WebSocketMessage.getPayloadAsText(), XingHuoChatCompletion.class)) | ||
| 146 | + .doOnNext(sink::next) // 将接收到的消息推送到 Flux 中 | ||
| 147 | + .doOnError(sink::error) // 处理错误 | ||
| 148 | + .doOnTerminate(sink::complete)) // 完成时关闭 sink | ||
| 149 | + .then()) | ||
| 150 | + .subscribe(); // 订阅以开始会话 | ||
| 151 | + }); | ||
| 152 | + return messageFlux; | ||
| 153 | + } | ||
| 154 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoChatClient.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chatxinghuo; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.ai.chat.ChatClient; | ||
| 4 | +import cn.iocoder.yudao.framework.ai.chat.ChatResponse; | ||
| 5 | +import cn.iocoder.yudao.framework.ai.chat.Generation; | ||
| 6 | +import cn.iocoder.yudao.framework.ai.chat.StreamingChatClient; | ||
| 7 | +import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; | ||
| 8 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.api.XingHuoChatCompletion; | ||
| 9 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.api.XingHuoChatCompletionMessage; | ||
| 10 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.api.XingHuoChatCompletionRequest; | ||
| 11 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.exception.XingHuoApiException; | ||
| 12 | +import cn.iocoder.yudao.framework.ai.model.function.AbstractFunctionCallSupport; | ||
| 13 | +import lombok.extern.slf4j.Slf4j; | ||
| 14 | +import org.springframework.http.ResponseEntity; | ||
| 15 | +import org.springframework.retry.RetryCallback; | ||
| 16 | +import org.springframework.retry.RetryContext; | ||
| 17 | +import org.springframework.retry.RetryListener; | ||
| 18 | +import org.springframework.retry.support.RetryTemplate; | ||
| 19 | +import reactor.core.publisher.Flux; | ||
| 20 | + | ||
| 21 | +import java.time.Duration; | ||
| 22 | +import java.util.List; | ||
| 23 | +import java.util.stream.Collectors; | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * 讯飞星火 client | ||
| 27 | + * <p> | ||
| 28 | + * author: fansili | ||
| 29 | + * time: 2024/3/11 10:19 | ||
| 30 | + */ | ||
| 31 | +@Slf4j | ||
| 32 | +public class XingHuoChatClient extends AbstractFunctionCallSupport<XingHuoChatCompletionMessage, XingHuoChatCompletionRequest, ResponseEntity<XingHuoChatCompletion>> | ||
| 33 | + implements ChatClient, StreamingChatClient { | ||
| 34 | + | ||
| 35 | + private XingHuoApi xingHuoApi; | ||
| 36 | + | ||
| 37 | + public final RetryTemplate retryTemplate = RetryTemplate.builder() | ||
| 38 | + // 最大重试次数 10 | ||
| 39 | + .maxAttempts(10) | ||
| 40 | + .retryOn(XingHuoApiException.class) | ||
| 41 | + // 最大重试5次,第一次间隔3000ms,第二次3000ms * 2,第三次3000ms * 3,以此类推,最大间隔3 * 60000ms | ||
| 42 | + .exponentialBackoff(Duration.ofMillis(3000), 2, Duration.ofMillis(3 * 60000)) | ||
| 43 | + .withListener(new RetryListener() { | ||
| 44 | + @Override | ||
| 45 | + public <T extends Object, E extends Throwable> void onError(RetryContext context, | ||
| 46 | + RetryCallback<T, E> callback, Throwable throwable) { | ||
| 47 | + log.warn("重试异常:" + context.getRetryCount(), throwable); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + ; | ||
| 51 | + }) | ||
| 52 | + .build(); | ||
| 53 | + | ||
| 54 | + public XingHuoChatClient(XingHuoApi xingHuoApi) { | ||
| 55 | + super(null); | ||
| 56 | + this.xingHuoApi = xingHuoApi; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + @Override | ||
| 60 | + public ChatResponse call(Prompt prompt) { | ||
| 61 | + | ||
| 62 | + return this.retryTemplate.execute(ctx -> { | ||
| 63 | + // ctx 会有重试的信息 | ||
| 64 | + // 创建 request 请求,stream模式需要供应商支持 | ||
| 65 | + XingHuoChatCompletionRequest request = this.createRequest(prompt, false); | ||
| 66 | + // 调用 callWithFunctionSupport 发送请求 | ||
| 67 | + ResponseEntity<XingHuoChatCompletion> response = this.callWithFunctionSupport(request); | ||
| 68 | + // 获取结果封装 ChatResponse | ||
| 69 | + return new ChatResponse(List.of(new Generation(response.getBody().getPayload().getChoices().getText().get(0).getContent()))); | ||
| 70 | + }); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + private XingHuoChatCompletionRequest createRequest(Prompt prompt, boolean b) { | ||
| 74 | + // 创建 header | ||
| 75 | + XingHuoChatCompletionRequest.Header header = new XingHuoChatCompletionRequest.Header().setApp_id(xingHuoApi.getAppId()); | ||
| 76 | + // 创建 params | ||
| 77 | + XingHuoChatCompletionRequest.Parameter parameter = new XingHuoChatCompletionRequest.Parameter() | ||
| 78 | + .setChat(new XingHuoChatCompletionRequest.Parameter.Chat().setDomain(xingHuoApi.getUseChatModel().getValue())); | ||
| 79 | + // 创建 payload text 信息 | ||
| 80 | + XingHuoChatCompletionRequest.Payload.Message.Text text = new XingHuoChatCompletionRequest.Payload.Message.Text(); | ||
| 81 | + text.setRole(XingHuoChatCompletionRequest.Payload.Message.Text.Role.USER.getName()); | ||
| 82 | + text.setContent(prompt.getContents()); | ||
| 83 | + // 创建 payload | ||
| 84 | + XingHuoChatCompletionRequest.Payload payload = new XingHuoChatCompletionRequest.Payload() | ||
| 85 | + .setMessage(new XingHuoChatCompletionRequest.Payload.Message().setText(List.of(text))); | ||
| 86 | + // 创建 request | ||
| 87 | + return new XingHuoChatCompletionRequest() | ||
| 88 | + .setHeader(header) | ||
| 89 | + .setParameter(parameter) | ||
| 90 | + .setPayload(payload); | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + @Override | ||
| 94 | + public Flux<ChatResponse> stream(Prompt prompt) { | ||
| 95 | + // 创建 request 请求,stream模式需要供应商支持 | ||
| 96 | + XingHuoChatCompletionRequest request = this.createRequest(prompt, false); | ||
| 97 | + // 发送请求 | ||
| 98 | + Flux<XingHuoChatCompletion> response = this.xingHuoApi.chatCompletionStream(request); | ||
| 99 | + return response.map(res -> { | ||
| 100 | + String content = res.getPayload().getChoices().getText().stream() | ||
| 101 | + .map(item -> item.getContent()).collect(Collectors.joining()); | ||
| 102 | + return new ChatResponse(List.of(new Generation(content))); | ||
| 103 | + }); | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + @Override | ||
| 107 | + protected XingHuoChatCompletionRequest doCreateToolResponseRequest(XingHuoChatCompletionRequest previousRequest, XingHuoChatCompletionMessage responseMessage, List<XingHuoChatCompletionMessage> conversationHistory) { | ||
| 108 | + return null; | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + @Override | ||
| 112 | + protected List<XingHuoChatCompletionMessage> doGetUserMessages(XingHuoChatCompletionRequest request) { | ||
| 113 | + return null; | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + @Override | ||
| 117 | + protected XingHuoChatCompletionMessage doGetToolResponseMessage(ResponseEntity<XingHuoChatCompletion> response) { | ||
| 118 | + return null; | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + @Override | ||
| 122 | + protected ResponseEntity<XingHuoChatCompletion> doChatCompletion(XingHuoChatCompletionRequest request) { | ||
| 123 | + return xingHuoApi.chatCompletionEntity(request); | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + @Override | ||
| 127 | + protected boolean isToolFunctionCall(ResponseEntity<XingHuoChatCompletion> response) { | ||
| 128 | + return false; | ||
| 129 | + } | ||
| 130 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/XingHuoChatModel.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chatxinghuo; | ||
| 2 | + | ||
| 3 | +import lombok.Getter; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 讯飞星火 模型 | ||
| 7 | + * | ||
| 8 | + * 文档地址:https://www.xfyun.cn/doc/spark/Web.html#_1-%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E | ||
| 9 | + * | ||
| 10 | + * 1tokens 约等于1.5个中文汉字 或者 0.8个英文单词 | ||
| 11 | + * 星火V1.5支持[搜索]内置插件;星火V2.0、V3.0和V3.5支持[搜索]、[天气]、[日期]、[诗词]、[字词]、[股票]六个内置插件 | ||
| 12 | + * 星火V3.5 现已支持system、Function Call 功能。 | ||
| 13 | + * | ||
| 14 | + * author: fansili | ||
| 15 | + * time: 2024/3/11 10:12 | ||
| 16 | + */ | ||
| 17 | +@Getter | ||
| 18 | +public enum XingHuoChatModel { | ||
| 19 | + | ||
| 20 | +// 文档地址:https://www.xfyun.cn/doc/spark/Web.html#_1-%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E | ||
| 21 | +// general指向V1.5版本; | ||
| 22 | +// generalv2指向V2版本; | ||
| 23 | +// generalv3指向V3版本; | ||
| 24 | +// generalv3.5指向V3.5版本; | ||
| 25 | + | ||
| 26 | + XING_HUO_1_5("星火大模型1.5", "general", "/v1.1/chat"), | ||
| 27 | + XING_HUO_2_0("星火大模型2.0", "generalv2", "/v2.1/chat"), | ||
| 28 | + XING_HUO_3_0("星火大模型3.0", "generalv3", "/v3.1/chat"), | ||
| 29 | + XING_HUO_3_5("星火大模型3.5", "generalv3.5", "/v3.5/chat"), | ||
| 30 | + | ||
| 31 | + ; | ||
| 32 | + | ||
| 33 | + XingHuoChatModel(String name, String value, String uri) { | ||
| 34 | + this.name = name; | ||
| 35 | + this.value = value; | ||
| 36 | + this.uri = uri; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + private String name; | ||
| 40 | + | ||
| 41 | + private String value; | ||
| 42 | + | ||
| 43 | + private String uri; | ||
| 44 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/api/XingHuoChatCompletion.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chatxinghuo.api; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import lombok.experimental.Accessors; | ||
| 5 | + | ||
| 6 | +import java.util.List; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * author: fansili | ||
| 10 | + * time: 2024/3/11 10:20 | ||
| 11 | + */ | ||
| 12 | +@Data | ||
| 13 | +@Accessors(chain = true) | ||
| 14 | +public class XingHuoChatCompletion { | ||
| 15 | + private Header header; | ||
| 16 | + private Payload payload; | ||
| 17 | + | ||
| 18 | + @Data | ||
| 19 | + @Accessors(chain = true) | ||
| 20 | + public static class Header { | ||
| 21 | + private int code; | ||
| 22 | + private String message; | ||
| 23 | + private String sid; | ||
| 24 | + private int status; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + @Data | ||
| 28 | + @Accessors(chain = true) | ||
| 29 | + public static class Payload { | ||
| 30 | + private Choices choices; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + @Data | ||
| 34 | + @Accessors(chain = true) | ||
| 35 | + public static class Choices { | ||
| 36 | + private int status; | ||
| 37 | + private int seq; | ||
| 38 | + private List<Text> text; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + @Data | ||
| 42 | + @Accessors(chain = true) | ||
| 43 | + public static class Text { | ||
| 44 | + private String content; | ||
| 45 | + private String role; | ||
| 46 | + private int index; | ||
| 47 | + } | ||
| 48 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/api/XingHuoChatCompletionMessage.java
0 → 100644
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/api/XingHuoChatCompletionRequest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chatxinghuo.api; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import lombok.Getter; | ||
| 5 | +import lombok.experimental.Accessors; | ||
| 6 | + | ||
| 7 | +import java.util.List; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * 讯飞星火 request | ||
| 11 | + * | ||
| 12 | + * author: fansili | ||
| 13 | + * time: 2024/3/11 10:20 | ||
| 14 | + */ | ||
| 15 | +@Data | ||
| 16 | +@Accessors(chain = true) | ||
| 17 | +public class XingHuoChatCompletionRequest { | ||
| 18 | + | ||
| 19 | + private Header header; | ||
| 20 | + private Parameter parameter; | ||
| 21 | + private Payload payload; | ||
| 22 | + | ||
| 23 | + @Data | ||
| 24 | + @Accessors(chain = true) | ||
| 25 | + public static class Header { | ||
| 26 | + private String app_id; | ||
| 27 | + private String uid; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + @Data | ||
| 31 | + @Accessors(chain = true) | ||
| 32 | + public static class Parameter { | ||
| 33 | + private Chat chat; | ||
| 34 | + | ||
| 35 | + @Data | ||
| 36 | + @Accessors(chain = true) | ||
| 37 | + public static class Chat { | ||
| 38 | + /** | ||
| 39 | + * https://www.xfyun.cn/doc/spark/Web.html#_1-%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E | ||
| 40 | + * | ||
| 41 | + * 指定访问的领域: | ||
| 42 | + * general指向V1.5版本; | ||
| 43 | + * generalv2指向V2版本; | ||
| 44 | + * generalv3指向V3版本; | ||
| 45 | + * generalv3.5指向V3.5版本; | ||
| 46 | + * 注意:不同的取值对应的url也不一样! | ||
| 47 | + */ | ||
| 48 | + private String domain = "general"; | ||
| 49 | + private Double temperature = 0.5; | ||
| 50 | + private Integer max_tokens = 2048; | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Data | ||
| 55 | + @Accessors(chain = true) | ||
| 56 | + public static class Payload { | ||
| 57 | + private Message message; | ||
| 58 | + | ||
| 59 | + @Data | ||
| 60 | + @Accessors(chain = true) | ||
| 61 | + public static class Message { | ||
| 62 | + private List<Text> text; | ||
| 63 | + | ||
| 64 | + | ||
| 65 | + @Data | ||
| 66 | + @Accessors(chain = true) | ||
| 67 | + public static class Text { | ||
| 68 | + /** | ||
| 69 | + * 角色 | ||
| 70 | + */ | ||
| 71 | + private String role; | ||
| 72 | + /** | ||
| 73 | + * 消息内容 | ||
| 74 | + */ | ||
| 75 | + private String content; | ||
| 76 | + private Integer index; | ||
| 77 | + | ||
| 78 | + @Getter | ||
| 79 | + public static enum Role { | ||
| 80 | + SYSTEM("system"), | ||
| 81 | + USER("user"), | ||
| 82 | + ASSISTANT("assistant"); | ||
| 83 | + private String name; | ||
| 84 | + | ||
| 85 | + private Role(String name) { | ||
| 86 | + this.name = name; | ||
| 87 | + } | ||
| 88 | + } | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatxinghuo/exception/XingHuoApiException.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chatxinghuo.exception; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 讯飞星火 exception | ||
| 5 | + * | ||
| 6 | + * author: fansili | ||
| 7 | + * time: 2024/3/11 10:22 | ||
| 8 | + */ | ||
| 9 | +public class XingHuoApiException extends RuntimeException { | ||
| 10 | + | ||
| 11 | + public XingHuoApiException(String message) { | ||
| 12 | + super(message); | ||
| 13 | + } | ||
| 14 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/XingHuoChatClientMainTests.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chat; | ||
| 2 | + | ||
| 3 | +import cn.hutool.http.HttpUtil; | ||
| 4 | +import cn.hutool.json.JSONUtil; | ||
| 5 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.api.XingHuoChatCompletion; | ||
| 6 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.api.XingHuoChatCompletionRequest; | ||
| 7 | +import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient; | ||
| 8 | +import org.springframework.web.reactive.socket.client.WebSocketClient; | ||
| 9 | +import reactor.core.publisher.Flux; | ||
| 10 | + | ||
| 11 | +import javax.crypto.Mac; | ||
| 12 | +import javax.crypto.spec.SecretKeySpec; | ||
| 13 | +import java.net.MalformedURLException; | ||
| 14 | +import java.net.URI; | ||
| 15 | +import java.nio.charset.Charset; | ||
| 16 | +import java.security.InvalidKeyException; | ||
| 17 | +import java.security.NoSuchAlgorithmException; | ||
| 18 | +import java.text.SimpleDateFormat; | ||
| 19 | +import java.util.*; | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * author: fansili | ||
| 23 | + * time: 2024/3/13 20:47 | ||
| 24 | + */ | ||
| 25 | +public class XingHuoChatClientMainTests { | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + private static final String HOST_URL = "http://spark-api.xf-yun.com/v3.5/chat"; | ||
| 29 | + private static final String API_KEY = "cb6415c19d6162cda07b47316fcb0416"; | ||
| 30 | + private static final String API_SECRET = "Y2JiYTIxZjA3MDMxMjNjZjQzYzVmNzdh"; | ||
| 31 | + | ||
| 32 | + public static void main(String[] args) throws MalformedURLException, NoSuchAlgorithmException, InvalidKeyException { | ||
| 33 | + String authUrl = getAuthorizationUrl("spark-api.xf-yun.com", "/v3.5/chat"); | ||
| 34 | + System.err.println(authUrl); | ||
| 35 | + | ||
| 36 | + XingHuoChatCompletionRequest.Header header = new XingHuoChatCompletionRequest.Header().setApp_id("13c8cca6"); | ||
| 37 | + XingHuoChatCompletionRequest.Parameter parameter | ||
| 38 | + = new XingHuoChatCompletionRequest.Parameter() | ||
| 39 | + .setChat(new XingHuoChatCompletionRequest.Parameter.Chat().setDomain("generalv3.5")); | ||
| 40 | + | ||
| 41 | + | ||
| 42 | + XingHuoChatCompletionRequest.Payload.Message.Text text = new XingHuoChatCompletionRequest.Payload.Message.Text(); | ||
| 43 | + text.setRole(XingHuoChatCompletionRequest.Payload.Message.Text.Role.USER.getName()); | ||
| 44 | + text.setContent("世界上最好的开发语言是什么?"); | ||
| 45 | + XingHuoChatCompletionRequest.Payload payload = new XingHuoChatCompletionRequest.Payload() | ||
| 46 | + .setMessage(new XingHuoChatCompletionRequest.Payload.Message().setText(List.of(text))); | ||
| 47 | + XingHuoChatCompletionRequest request = new XingHuoChatCompletionRequest() | ||
| 48 | + .setHeader(header) | ||
| 49 | + .setParameter(parameter) | ||
| 50 | + .setPayload(payload); | ||
| 51 | + | ||
| 52 | + System.err.println(JSONUtil.toJsonPrettyStr(request)); | ||
| 53 | + | ||
| 54 | + | ||
| 55 | + // 创建 WebSocketClient 实例 | ||
| 56 | + WebSocketClient client = new ReactorNettyWebSocketClient(); | ||
| 57 | + | ||
| 58 | + // wss 请求的 URI | ||
| 59 | + URI uri = URI.create(authUrl); | ||
| 60 | + | ||
| 61 | + // 发起 wss 请求并处理响应 | ||
| 62 | + client.execute(uri, session -> | ||
| 63 | + // 使用会话发送消息,并接收回应 | ||
| 64 | + session.send(Flux.just(session.textMessage(JSONUtil.toJsonStr(request)))) | ||
| 65 | + .thenMany(session.receive() | ||
| 66 | + .map(WebSocketMessage -> { | ||
| 67 | + System.err.println(WebSocketMessage.getPayloadAsText()); | ||
| 68 | + return JSONUtil.toBean(WebSocketMessage.getPayloadAsText(), XingHuoChatCompletion.class); | ||
| 69 | + }) | ||
| 70 | + .log()) // 打印接收到的消息 | ||
| 71 | + .then()) | ||
| 72 | + .block(); // 等待操作完成或超时 | ||
| 73 | + | ||
| 74 | + // 阻止退出 | ||
| 75 | + Scanner scanner = new Scanner(System.in); | ||
| 76 | + scanner.nextLine(); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + | ||
| 80 | + /** | ||
| 81 | + * 获取验证请求url | ||
| 82 | + * | ||
| 83 | + * @return | ||
| 84 | + */ | ||
| 85 | + public static String getAuthorizationUrl(String host, String path) throws NoSuchAlgorithmException, InvalidKeyException { | ||
| 86 | + // 获取鉴权时间 date | ||
| 87 | + SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); | ||
| 88 | + format.setTimeZone(TimeZone.getTimeZone("GMT")); | ||
| 89 | + String date = format.format(new Date()); | ||
| 90 | + | ||
| 91 | + // 获取signature_origin字段 | ||
| 92 | + StringBuilder builder = new StringBuilder("host: ").append(host).append("\n"). | ||
| 93 | + append("date: ").append(date).append("\n"). | ||
| 94 | + append("GET ").append(path).append(" HTTP/1.1"); | ||
| 95 | + | ||
| 96 | + // 获得signatue | ||
| 97 | + Charset charset = Charset.forName("UTF-8"); | ||
| 98 | + Mac mac = Mac.getInstance("hmacsha256"); | ||
| 99 | + SecretKeySpec sp = new SecretKeySpec(API_SECRET.getBytes(charset), "hmacsha256"); | ||
| 100 | + mac.init(sp); | ||
| 101 | + byte[] basebefore = mac.doFinal(builder.toString().getBytes(charset)); | ||
| 102 | + String signature = Base64.getEncoder().encodeToString(basebefore); | ||
| 103 | + //获得 authorization_origin | ||
| 104 | + String authorization_origin = String.format("api_key=\"%s\",algorithm=\"%s\",headers=\"%s\",signature=\"%s\"", API_KEY, "hmac-sha256", "host date request-line", signature); | ||
| 105 | + //获得authorization | ||
| 106 | + String authorization = Base64.getEncoder().encodeToString(authorization_origin.getBytes(charset)); | ||
| 107 | + // 获取httpUrl | ||
| 108 | + Map<String, Object> param = new HashMap<>(); | ||
| 109 | + param.put("authorization", authorization); | ||
| 110 | + param.put("date", date); | ||
| 111 | + param.put("host", host); | ||
| 112 | + | ||
| 113 | + String toParams = HttpUtil.toParams(param); | ||
| 114 | + return "wss://" + host + path + "?" + toParams; | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/XingHuoChatClientTests.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chat; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; | ||
| 4 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoApi; | ||
| 5 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatClient; | ||
| 6 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatModel; | ||
| 7 | +import org.junit.Before; | ||
| 8 | +import org.junit.Test; | ||
| 9 | +import reactor.core.publisher.Flux; | ||
| 10 | + | ||
| 11 | +import java.util.Scanner; | ||
| 12 | +import java.util.function.Consumer; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * 讯飞星火 tests | ||
| 16 | + * <p> | ||
| 17 | + * author: fansili | ||
| 18 | + * time: 2024/3/11 11:00 | ||
| 19 | + */ | ||
| 20 | +public class XingHuoChatClientTests { | ||
| 21 | + | ||
| 22 | + private XingHuoChatClient xingHuoChatClient; | ||
| 23 | + | ||
| 24 | + @Before | ||
| 25 | + public void setup() { | ||
| 26 | + // 初始化 xingHuoChatClient | ||
| 27 | + xingHuoChatClient = new XingHuoChatClient( | ||
| 28 | + new XingHuoApi( | ||
| 29 | + "13c8cca6", | ||
| 30 | + "cb6415c19d6162cda07b47316fcb0416", | ||
| 31 | + "Y2JiYTIxZjA3MDMxMjNjZjQzYzVmNzdh", | ||
| 32 | + XingHuoChatModel.XING_HUO_3_5 | ||
| 33 | + ) | ||
| 34 | + ); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + @Test | ||
| 38 | + public void callTest() { | ||
| 39 | + ChatResponse call = xingHuoChatClient.call(new Prompt("java和go那个性能更好!")); | ||
| 40 | + System.err.println(call.getResult()); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + @Test | ||
| 44 | + public void streamTest() { | ||
| 45 | + Flux<ChatResponse> stream = xingHuoChatClient.stream(new Prompt("java和go那个性能更好!")); | ||
| 46 | + stream.subscribe(new Consumer<ChatResponse>() { | ||
| 47 | + @Override | ||
| 48 | + public void accept(ChatResponse chatResponse) { | ||
| 49 | + System.err.print(chatResponse.getResult().getOutput().getContent()); | ||
| 50 | + } | ||
| 51 | + }); | ||
| 52 | + // 阻止退出 | ||
| 53 | + Scanner scanner = new Scanner(System.in); | ||
| 54 | + scanner.nextLine(); | ||
| 55 | + } | ||
| 56 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/XingHuoOkHttpTests.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chat; | ||
| 2 | + | ||
| 3 | +import cn.hutool.http.HttpUtil; | ||
| 4 | +import cn.hutool.json.JSONUtil; | ||
| 5 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatClient; | ||
| 6 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.api.XingHuoChatCompletion; | ||
| 7 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.api.XingHuoChatCompletionRequest; | ||
| 8 | +import okhttp3.*; | ||
| 9 | +import org.jetbrains.annotations.NotNull; | ||
| 10 | + | ||
| 11 | +import javax.crypto.Mac; | ||
| 12 | +import javax.crypto.spec.SecretKeySpec; | ||
| 13 | +import java.net.MalformedURLException; | ||
| 14 | +import java.nio.charset.Charset; | ||
| 15 | +import java.security.InvalidKeyException; | ||
| 16 | +import java.security.NoSuchAlgorithmException; | ||
| 17 | +import java.text.SimpleDateFormat; | ||
| 18 | +import java.util.*; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * 讯飞星火 tests | ||
| 22 | + * <p> | ||
| 23 | + * author: fansili | ||
| 24 | + * time: 2024/3/11 11:00 | ||
| 25 | + */ | ||
| 26 | +public class XingHuoOkHttpTests { | ||
| 27 | + | ||
| 28 | + private static final String HOST_URL = "http://spark-api.xf-yun.com/v3.5/chat"; | ||
| 29 | + private static final String API_KEY = "cb6415c19d6162cda07b47316fcb0416"; | ||
| 30 | + private static final String API_SECRET = "Y2JiYTIxZjA3MDMxMjNjZjQzYzVmNzdh"; | ||
| 31 | + | ||
| 32 | + private XingHuoChatClient xingHuoChatClient; | ||
| 33 | + | ||
| 34 | + public static void main(String[] args) throws MalformedURLException, NoSuchAlgorithmException, InvalidKeyException { | ||
| 35 | + String authUrl = getAuthorizationUrl("spark-api.xf-yun.com", "/v3.5/chat"); | ||
| 36 | + System.err.println(authUrl); | ||
| 37 | + | ||
| 38 | + XingHuoChatCompletionRequest.Header header = new XingHuoChatCompletionRequest.Header().setApp_id("13c8cca6"); | ||
| 39 | + XingHuoChatCompletionRequest.Parameter parameter | ||
| 40 | + = new XingHuoChatCompletionRequest.Parameter() | ||
| 41 | + .setChat(new XingHuoChatCompletionRequest.Parameter.Chat().setDomain("generalv3.5")); | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + XingHuoChatCompletionRequest.Payload.Message.Text text = new XingHuoChatCompletionRequest.Payload.Message.Text(); | ||
| 45 | + text.setRole(XingHuoChatCompletionRequest.Payload.Message.Text.Role.USER.getName()); | ||
| 46 | + text.setContent("世界上最好的开发语言是什么?"); | ||
| 47 | + XingHuoChatCompletionRequest.Payload payload = new XingHuoChatCompletionRequest.Payload() | ||
| 48 | + .setMessage(new XingHuoChatCompletionRequest.Payload.Message().setText(List.of(text))); | ||
| 49 | + XingHuoChatCompletionRequest request = new XingHuoChatCompletionRequest() | ||
| 50 | + .setHeader(header) | ||
| 51 | + .setParameter(parameter) | ||
| 52 | + .setPayload(payload); | ||
| 53 | + | ||
| 54 | + System.err.println(JSONUtil.toJsonPrettyStr(request)); | ||
| 55 | + | ||
| 56 | + OkHttpClient client = new OkHttpClient(); | ||
| 57 | + Request request2 = new Request.Builder() | ||
| 58 | + .url(authUrl) // 替换为你的 wss URL | ||
| 59 | + .build(); | ||
| 60 | + | ||
| 61 | + WebSocketListener webSocketListener = new WebSocketListener() { | ||
| 62 | + | ||
| 63 | + @Override | ||
| 64 | + public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) { | ||
| 65 | + boolean send = webSocket.send(JSONUtil.toJsonStr(request)); | ||
| 66 | + System.err.println("发送 -> " + send); | ||
| 67 | + System.err.println("链接成功!"); | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + @Override | ||
| 71 | + public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) { | ||
| 72 | + super.onMessage(webSocket, text); | ||
| 73 | +// System.err.println(text); | ||
| 74 | + XingHuoChatCompletion response = JSONUtil.toBean(text, XingHuoChatCompletion.class); | ||
| 75 | + for (XingHuoChatCompletion.Text text1 : response.getPayload().getChoices().getText()) { | ||
| 76 | + System.err.print(text1.getContent()); | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + }; | ||
| 80 | + | ||
| 81 | + WebSocket webSocket = client.newWebSocket(request2, webSocketListener); | ||
| 82 | +// webSocket.send(JSONUtil.toJsonStr(request)); | ||
| 83 | + | ||
| 84 | + | ||
| 85 | + // Trigger shutdown of the dispatcher's executor so this process can exit cleanly. | ||
| 86 | + client.dispatcher().executorService().shutdown(); | ||
| 87 | + // 阻止退出 | ||
| 88 | + Scanner scanner = new Scanner(System.in); | ||
| 89 | + scanner.nextLine(); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + | ||
| 93 | + /** | ||
| 94 | + * 获取验证请求url | ||
| 95 | + * | ||
| 96 | + * @return | ||
| 97 | + */ | ||
| 98 | + public static String getAuthorizationUrl(String host, String path) throws NoSuchAlgorithmException, InvalidKeyException { | ||
| 99 | + // 获取鉴权时间 date | ||
| 100 | + SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); | ||
| 101 | + format.setTimeZone(TimeZone.getTimeZone("GMT")); | ||
| 102 | + String date = format.format(new Date()); | ||
| 103 | + | ||
| 104 | + // 获取signature_origin字段 | ||
| 105 | + StringBuilder builder = new StringBuilder("host: ").append(host).append("\n"). | ||
| 106 | + append("date: ").append(date).append("\n"). | ||
| 107 | + append("GET ").append(path).append(" HTTP/1.1"); | ||
| 108 | + | ||
| 109 | + // 获得signatue | ||
| 110 | + Charset charset = Charset.forName("UTF-8"); | ||
| 111 | + Mac mac = Mac.getInstance("hmacsha256"); | ||
| 112 | + SecretKeySpec sp = new SecretKeySpec(API_SECRET.getBytes(charset), "hmacsha256"); | ||
| 113 | + mac.init(sp); | ||
| 114 | + byte[] basebefore = mac.doFinal(builder.toString().getBytes(charset)); | ||
| 115 | + String signature = Base64.getEncoder().encodeToString(basebefore); | ||
| 116 | + //获得 authorization_origin | ||
| 117 | + String authorization_origin = String.format("api_key=\"%s\",algorithm=\"%s\",headers=\"%s\",signature=\"%s\"", API_KEY, "hmac-sha256", "host date request-line", signature); | ||
| 118 | + //获得authorization | ||
| 119 | + String authorization = Base64.getEncoder().encodeToString(authorization_origin.getBytes(charset)); | ||
| 120 | + // 获取httpUrl | ||
| 121 | + Map<String, Object> param = new HashMap<>(); | ||
| 122 | + param.put("authorization", authorization); | ||
| 123 | + param.put("date", date); | ||
| 124 | + param.put("host", host); | ||
| 125 | + | ||
| 126 | + String toParams = HttpUtil.toParams(param); | ||
| 127 | + return "wss://" + host + path + "?" + toParams; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/YiYanChatTests.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chat; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; | ||
| 4 | +import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanApi; | ||
| 5 | +import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatClient; | ||
| 6 | +import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatModel; | ||
| 7 | +import org.junit.Before; | ||
| 8 | +import org.junit.Test; | ||
| 9 | +import reactor.core.publisher.Flux; | ||
| 10 | + | ||
| 11 | +import java.util.Scanner; | ||
| 12 | +import java.util.function.Consumer; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * chat 文心一言 | ||
| 16 | + * | ||
| 17 | + * author: fansili | ||
| 18 | + * time: 2024/3/12 20:59 | ||
| 19 | + */ | ||
| 20 | +public class YiYanChatTests { | ||
| 21 | + | ||
| 22 | + private YiYanChatClient yiYanChatClient; | ||
| 23 | + | ||
| 24 | + @Before | ||
| 25 | + public void setup() { | ||
| 26 | + YiYanApi yiYanApi = new YiYanApi( | ||
| 27 | + "x0cuLZ7XsaTCU08vuJWO87Lg", | ||
| 28 | + "R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK", | ||
| 29 | + YiYanChatModel.ERNIE4_3_5_8K, | ||
| 30 | + 86400 | ||
| 31 | + ); | ||
| 32 | + yiYanChatClient = new YiYanChatClient(yiYanApi); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + @Test | ||
| 36 | + public void callTest() { | ||
| 37 | + ChatResponse call = yiYanChatClient.call(new Prompt("什么编程语言最好?")); | ||
| 38 | + System.err.println(call.getResult()); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + @Test | ||
| 42 | + public void streamTest() { | ||
| 43 | + Flux<ChatResponse> fluxResponse = yiYanChatClient.stream(new Prompt("用java帮我写一个快排算法?")); | ||
| 44 | + fluxResponse.subscribe(new Consumer<ChatResponse>() { | ||
| 45 | + @Override | ||
| 46 | + public void accept(ChatResponse chatResponse) { | ||
| 47 | + System.err.print(chatResponse.getResult().getOutput().getContent()); | ||
| 48 | + } | ||
| 49 | + }); | ||
| 50 | + // 阻止退出 | ||
| 51 | + Scanner scanner = new Scanner(System.in); | ||
| 52 | + scanner.nextLine(); | ||
| 53 | + } | ||
| 54 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/package-info.java
0 → 100644