在全民AI的大势下,很多类Chat GPT的聊天对话吐字形式的产品层出不穷,服务端与前端都需要对生成式Stream的技术方案进行了解,本篇内容简单Java工程师如何借助Spring WebClient开发响应式接口
首先引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>2.7.16</version> # 修改为自己的版本
</dependency>
创建WebClient配置类
@Configuration
public class WebClientConfig {
@Bean(name = "webClient")
WebClient webClient() {
ExchangeStrategies strategies = ExchangeStrategies.builder() // 创建一个ExchangeStrategies构建器,用于配置HTTP消息的编码和解码策略
.codecs(configurer -> // 使用codecs方法来配置编解码器
configurer.defaultCodecs() // 获取默认的编解码器配置
.jackson2JsonDecoder(new Jackson2JsonDecoder()) // 使用Jackson 2 JSON解码器,并传入一个新的实例作为参数
)
.build(); // 构建ExchangeStrategies对象
return WebClient.builder() // 创建一个WebClient构建器
.exchangeStrategies(strategies) // 设置之前构建的ExchangeStrategies,用于处理消息编码和解码
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) // 为所有请求设置默认的HTTP头,这里设置Content-Type为application/json,并指定UTF-8编码
.build(); // 构建WebClient实例
}
}
GPT相关Entity
@Data
public class CompletionRequest {
// 对话的消息列表
private List<Message> messages;
// 聊天完成中可以生成的最大令牌数
@SerializedName("max_tokens")
public int maxTokens;
// temperature范围 0 - 2,值越高,响应结果越随机(What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.)
private Double temperature;
private String model;
}
@Data
@AllArgsConstructor
public class Message {
private String role;
private String content;
}
@Data
public class CompletionResponse {
private Long created;
private String model;
private List<Choice> choices;
}
@Data
public class Choice {
private Delta delta;
private int index;
private String finish_reason;
}
@Data
public class Delta {
private String role;
private String content;
}
创建Controller,这里与平时接口不同的是媒体类型不再是 application/json ,而是text/event-stream
@ApiOperation(value = "发送补全对话", notes = "wheelmouse", httpMethod = "POST",
produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@PostMapping(value = "/completion", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<CompletionResponse> completion(@RequestBody CompletionRequest request) {
return gptService.completion(request);
}
编写Service方法
@Autowired
WebClient webClient;
// 发起GET请求
Mono<String> response = webClient.get() // 指定GET请求
.uri("/api/data") // 指定请求的路径
.retrieve() // 获取响应
.bodyToMono(String.class); // 将响应体转换为字符串
// 订阅并消费响应
response.subscribe(
result -> System.out.println("GET请求结果:" + result), // 处理成功的结果
error -> System.out.println("GET请求错误:" + error.getMessage()) // 处理错误
);
// 发起POST请求
public Flux<CompletionResponse> completion(CompletionRequest request) {
return webClient
.post() // 创建一个POST请求
.uri("localhost:8080/stream/api") // 设置请求的URL为第三方接口的URL
.body(BodyInserters.fromObject(JacksonUtils.objToJson(chatBotCompletion))) // 将请求体设置为chatBotCompletion对象转换为JSON字符串的结果
.retrieve() // 触发实际的HTTP请求并获取响应
.bodyToFlux(String.class) // 将响应体转换为字符串类型的Flux流,这意味着响应可以是多个字符串消息
.onErrorResume(WebClientResponseException.class, ex -> { // 当发生WebClientResponseException异常时,执行以下操作
HttpStatus status = ex.getStatusCode(); // 获取异常中的HTTP状态码
String res = ex.getResponseBodyAsString(); // 获取异常中的响应体字符串
logger.error("OpenAI API error: {} {}", status, res); // 使用日志记录器记录错误信息
return Mono.just(""); // 返回一个空的Mono以继续处理流程
})
.map(eventStream -> { // 对流中的每个字符串元素应用map操作,将其转换为其他对象
return processEventStream(eventStream); // 调用processEventStream方法处理事件流
})
.doOnNext(responseList::add) // 当流中有新的元素时,将其添加到responseList集合中
.doOnComplete(() -> handleResponse(conversationId, responseList)) // 当流完成时,调用handleResponse方法处理最终的响应
// 补充响应条数
.concatWith(Flux.just(new CompletionResponse())); // 将这个新对象作为流的一部分,追加到现有的流中
}
private CompletionResponse processEventStream(String eventStream) {
CompletionResponse response = JacksonUtils.jsonToPojo(eventStream,
CompletionResponse.class);
if (response == null) {
response = new CompletionResponse();
}
return response;
}
private void handleResponse(Long conversationId, List<CompletionResponse> responseList) {
// do anything
}
效果展示:
使用postman测试接口,可以看到是吐字的方式返回响应
总结
通过以上介绍,我们可以看到Spring中的WebClient是一个非常强大和灵活的工具,可以方便地与React接口进行交互。它支持各种HTTP方法,可以处理不同类型的请求和响应,同时还提供了错误处理的机制。希望这篇文章能够帮助您更好地理解如何使用Spring中的WebClient来调用React接口。