You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

164 lines
5.9 KiB
Java

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.supervision.service.danmaku;
import cn.hutool.core.lang.Assert;
import com.hankcs.hanlp.seg.common.Term;
import com.hankcs.hanlp.tokenizer.StandardTokenizer;
import com.supervision.domain.LivetalkingChatDTO;
import com.supervision.domain.UserDetail;
import com.supervision.dto.DanmakuMessage;
import com.supervision.service.DigitalHumanDialogueLogService;
import com.supervision.service.LivetalkingService;
import com.supervision.util.UserUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.concurrent.Flow;
@Slf4j
@Service
@RequiredArgsConstructor
public class DanmakuWebSocketHandler extends TextWebSocketHandler {
private final WebSocketSessionManager sessionManager;
private final DigitalHumanDialogueLogService dialogueLogService;
private final LivetalkingService livetalkingService;
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage textMessage) {
// 解析客户端消息
DanmakuMessage danmaku = DanmakuMessage.fromJson(textMessage.getPayload());
String roomId = getRoomIdFromSession(session);
danmaku.setRoomId(roomId);
// 验证消息
validateDanmaku(danmaku);
// 保存到日志
String messageId = dialogueLogService.saveLog(danmaku);
// 判断是否需要回复
if (isQuestion(danmaku.getContent())) {
log.info("检测到问题: {}", danmaku.getContent());
LivetalkingChatDTO livetalkingChatDTO = new LivetalkingChatDTO(danmaku);
livetalkingChatDTO.setMessageId(messageId);
livetalkingService.chat(livetalkingChatDTO);
}
// 发布到消息中心
DanmakuPublisher.getInstance().publish(danmaku);
}
@Override
public void afterConnectionEstablished(WebSocketSession session) {
String roomId = getRoomIdFromSession(session);
sessionManager.addSession(roomId, session);
// 为该会话创建订阅者
Flow.Subscriber<DanmakuMessage> subscriber = createSubscriber(session);
Flow.Subscription subscription = DanmakuPublisher.getInstance()
.subscribe(roomId, subscriber);
// 将会话与订阅关系保存,方便在连接关闭时取消订阅
session.getAttributes().put("subscription", subscription);
try {
UserDetail userDetail = UserUtil.currentUser(session);
DanmakuMessage message = new DanmakuMessage();
message.setUserId(userDetail.getUserId());
message.setNickname(userDetail.getNickname());
message.setContent(userDetail.getNickname() + "来了");
DanmakuPublisher.getInstance().publish(message);
}catch (Exception e){
log.error("获取用户信息失败: {}", e.getMessage());
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
String roomId = getRoomIdFromSession(session);
sessionManager.removeSession(roomId, session);
// 取消订阅
Flow.Subscription subscription = (Flow.Subscription)
session.getAttributes().get("subscription");
if (subscription != null) {
subscription.cancel();
}
}
private Flow.Subscriber<DanmakuMessage> createSubscriber(WebSocketSession session) {
return new Flow.Subscriber<>() {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
subscription.request(Long.MAX_VALUE); // 不限制请求数量
}
@Override
public void onNext(DanmakuMessage danmaku) {
try {
if (session.isOpen()) {
session.sendMessage(new TextMessage(danmaku.toJson()));
}
} catch (IOException e) {
subscription.cancel();
}
}
@Override
public void onError(Throwable throwable) {
// 处理错误
log.info("WebSocket错误: {}", throwable.getMessage());
}
@Override
public void onComplete() {
// 发布者关闭
log.info("WebSocket连接已关闭: {}", session.getId());
}
};
}
private String getRoomIdFromSession(WebSocketSession session) {
// 从URI获取roomId如 ws://localhost:8080/ws/danmaku?roomId=123
String query = session.getUri().getQuery();
return query.split("=")[1];
}
private void validateDanmaku(DanmakuMessage danmaku) {
// 验证逻辑...
Assert.notEmpty(danmaku.getRoomId(), "房间ID不能为空");
Assert.notEmpty(danmaku.getContent(), "弹幕内容不能为空");
Assert.notEmpty(danmaku.getUserId(), "用户ID不能为空");
}
private boolean isQuestion(String sentence) {
String[] questionWords = {"什么", "为什么", "如何", "哪", "谁", "多少", "是否", "能否", "是不是"};
String[] questionEndings = {"吗", "呢", "", "?"};
// 结尾判断
for (String end : questionEndings) {
if (sentence.trim().endsWith(end)) {
return true;
}
}
// 分词判断
for (Term term : StandardTokenizer.segment(sentence)) {
for (String qw : questionWords) {
if (term.word.equals(qw)) {
return true;
}
}
}
return false;
}
}