SpringBoot接入豆包AI 数据流式返回前端

  1. maven引入依赖
		<dependency>
			<groupId>com.volcengine</groupId>
			<artifactId>volcengine-java-sdk-ark-runtime</artifactId>
			<version>LATEST</version>
		</dependency>
  1. 代码

AI实现类

package com.hpp.common.AIChat;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import com.google.gson.Gson;
import com.hpp.common.redisson.RedisCache;
import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionRequest;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessage;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessageRole;
import com.volcengine.ark.runtime.service.ArkService;

@Component
public class AIChatDouBao {
	private static final Logger LOGGER = LoggerFactory.getLogger(AIChatDouBao.class);
	@Autowired
	private RedisCache redisCache;
	private Gson gson = new Gson();
	private String apiKey = "xxxxxxxxxxxxxxxx";
	
	public SseEmitter conversation(String question) {
		// 创建ArkService实例
		ArkService arkService = ArkService.builder().apiKey(apiKey).build();
		// 初始化消息列表
		List<ChatMessage> chatMessages = new ArrayList<>();
		// 创建用户消息
		ChatMessage userMessage = ChatMessage.builder().role(ChatMessageRole.USER) // 设置消息角色为用户
				.content(question) // 设置消息内容
				.build();
		// 将用户消息添加到消息列表
		chatMessages.add(userMessage);
		// 创建聊天完成请求
		ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder().model("ep-xxxxxxxxxxxx")// 需要替换为您的推理接入点ID
				.messages(chatMessages) // 设置消息列表
				.build();
		// 发送聊天完成请求并打印响应
		// 获取响应并打印每个选择的消息内容
		SseEmitter emitter = new SseEmitter();
		try {
			new Thread(() -> {
				arkService.streamChatCompletion(chatCompletionRequest).doOnError(Throwable::printStackTrace)
						.doFinally(() -> {
							LOGGER.info("完成");
							emitter.complete();
						}).blockingForEach(choice -> {
							if (choice.getChoices().size() > 0) {
								ChatMessage message = choice.getChoices().get(0).getMessage();
								// 判断是否触发深度推理,触发则打印模型输出的思维链内容
								if (message.getReasoningContent() != null && !message.getReasoningContent().isEmpty()) {
									LOGGER.info(message.getReasoningContent());
									emitter.send(message.getReasoningContent());
								}
								// 打印模型输出的回答内容
								emitter.send(message.getContent().toString());
								LOGGER.info(message.getContent().toString());
							}
						});

			}).start();
		} catch (Exception e) {
			LOGGER.error("ai回复异常", e);
			emitter.completeWithError(e); // 发生错误时,通知客户端
		} finally {

		}
		return emitter;
	}

	public String getAccessToken() throws IOException {
		return "";
	}

}

controller层

@RestController
@RequestMapping(value = "chat")
public class ChatController {
	private static final Logger LOGGER = LoggerFactory.getLogger(ChatController.class);
	@Autowired
	private AIChatDouBao aiChatDouBao;

	@GetMapping("/event-stream")
	public SseEmitter streamEvents(HttpServletRequest req, @RequestParam String question) {
		return aiChatDouBao.conversation(question);
	}

}
### Spring Boot 中集成豆包 SSE (Server-Sent Events) 在Spring Boot应用程序中实现服务器发送事件(SSE),可以采用如下方法: #### 使用 `SseEmitter` 实现 通过创建并返回一个 `SseEmitter` 对象来处理客户端连接请求。这允许服务器向浏览器推送更新而无需每次都需要新的HTTP请求。 ```java import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.http.MediaType; import java.io.IOException; @RestController public class SseController { @GetMapping(value = "/streamFlux", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter handleSse() { final var emitter = new SseEmitter(); // 设置超时时间,防止长时间不活跃被关闭 emitter.onCompletion(() -> System.out.println("Connection closed")); try { for(int i=0; i<10 ;i++) { Thread.sleep(1000); // 模拟延迟 emitter.send(String.valueOf(i)); } emitter.complete(); } catch(IOException e) { emitter.completeWithError(e); } return emitter; } } ``` 此代码片段展示了如何配置控制器以响应来自前端的订阅请求,并每隔一秒发送一次消息直到计数结束[^3]。 对于更复杂的场景,比如当数据源不是固定的而是动态变化时,则可能需要用到Reactor库中的 Flux 来简化异步编程模型下的流传输操作。 #### 利用 WebFlux 和 Reactor 的 Flux 进行优化 如果希望进一步提升性能以及更好地管理资源,在现代Web应用开发中推荐使用基于反应的框架如Spring WebFlux配合Reactor核心组件——`Flux<T>`来进行广播通知等功能扩展。 ```java import reactor.core.publisher.Flux; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.http.MediaType; @RestController public class ReactiveSseController { private static final int MAX_MESSAGES = 9; @GetMapping("/reactiveStream") Flux<String> streamMessages(){ return Flux.<String>generate(sink -> sink.next(Integer.toString((int)(Math.random()*MAX_MESSAGES)))) .take(MAX_MESSAGES).delayElements(Duration.ofSeconds(1L)) .log(); } } ``` 上述例子利用了`Flux.generate()`函数生成随机整数值序列作为模拟的消息体;并通过`.take(n)`限制最大输出数量,最后加上日志记录以便调试观察[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值