feat: ai调整
parent
38d47a0bca
commit
33d27fdedc
|
@ -1,6 +1,6 @@
|
|||
package com.mcwl.web.controller.communityCenter;
|
||||
|
||||
import com.mcwl.communityCenter.webSocket.ChatWebSocketPoint;
|
||||
import com.mcwl.communityCenter.webSocket.ChatWebSocket;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -11,15 +11,11 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
@RequestMapping("/chat")
|
||||
public class ChatController {
|
||||
|
||||
private final ChatWebSocketPoint chatWebSocketPoint;
|
||||
private final ChatWebSocket chatWebSocket;
|
||||
|
||||
@GetMapping("/switchUserMode")
|
||||
public void switchUserMode(String sessionId, Boolean isCustomer) throws Exception {
|
||||
if (isCustomer == null) {
|
||||
chatWebSocketPoint.switchUserMode(sessionId, false);
|
||||
} else {
|
||||
chatWebSocketPoint.switchUserMode(sessionId, isCustomer);
|
||||
}
|
||||
public void switchUserMode(String sessionId) throws Exception {
|
||||
chatWebSocket.switchUserMode(sessionId);
|
||||
}
|
||||
|
||||
}
|
|
@ -154,6 +154,8 @@ mall:
|
|||
notifyUrl: https://53a65908.r27.cpolar.top/ali/pay/notify
|
||||
# 沙箱支付宝网关
|
||||
gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do
|
||||
# 绑定回调
|
||||
bindUrl: https://4b0ca615.r27.cpolar.top/ali/pay/callback
|
||||
|
||||
huawei:
|
||||
obs:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.mcwl.communityCenter.config;
|
||||
|
||||
import com.mcwl.communityCenter.webSocket.ChatWebSocketPoint;
|
||||
import com.mcwl.communityCenter.webSocket.ChatWebSocket;
|
||||
import com.mcwl.communityCenter.webSocket.HumanWebSocket;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||
|
@ -13,13 +14,19 @@ public class WebSocketConfig implements WebSocketConfigurer {
|
|||
|
||||
@Override
|
||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||
registry.addHandler(chatWebSocketPoint(), "/chat")
|
||||
registry.addHandler(chatWebSocket(), "/chat")
|
||||
.addHandler(humanWebSocket(), "/chat/human")
|
||||
.setAllowedOrigins("*");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ChatWebSocketPoint chatWebSocketPoint() {
|
||||
return new ChatWebSocketPoint();
|
||||
public ChatWebSocket chatWebSocket() {
|
||||
return new ChatWebSocket();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HumanWebSocket humanWebSocket() {
|
||||
return new HumanWebSocket();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.mcwl.communityCenter.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
// 消息实体类
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ChatMessage {
|
||||
private String role; // "user" 或 "assistant"
|
||||
private String content;
|
||||
private LocalDateTime timestamp;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package com.mcwl.communityCenter.service;
|
||||
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface CustomerService {
|
||||
void transferToHuman(String userId, WebSocketSession session);
|
||||
|
||||
void handleCustomerMessage(String userId, String message) throws IOException;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.mcwl.communityCenter.service;
|
||||
|
||||
import com.mcwl.communityCenter.domain.ChatMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public interface HumanService {
|
||||
void transferToHuman(String userId, WebSocketSession session);
|
||||
|
||||
void handleHumanMessage(String userId, String message) throws IOException;
|
||||
|
||||
void transferToAgent(String sessionId, List<ChatMessage> history);
|
||||
}
|
|
@ -55,7 +55,7 @@ public class AIServiceImpl implements AIService {
|
|||
.bodyToFlux(String.class) // 原始数据流
|
||||
.takeUntil(data -> data.contains("[DONE]")) // 遇到结束标记停止
|
||||
.flatMap(json -> parseContentFromJson(json)) // 解析内容
|
||||
.onErrorResume(e -> Flux.just("服务暂时不可用"));// 错误处理
|
||||
.onErrorResume(e -> Flux.just(""));// 错误处理
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
package com.mcwl.communityCenter.service.impl;
|
||||
|
||||
import com.mcwl.communityCenter.service.CustomerService;
|
||||
import com.mcwl.communityCenter.domain.ChatMessage;
|
||||
import com.mcwl.communityCenter.service.HumanService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Service
|
||||
public class CustomerServiceImpl implements CustomerService {
|
||||
public class HumanServiceImpl implements HumanService {
|
||||
|
||||
// 已上线的客服,key为用户ID,value为WebSocketSession
|
||||
private static final Map<String, WebSocketSession> activeSessions = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
|
@ -21,7 +23,7 @@ public class CustomerServiceImpl implements CustomerService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void handleCustomerMessage(String userId, String message) throws IOException {
|
||||
public void handleHumanMessage(String userId, String message) throws IOException {
|
||||
// 应实现消息队列或持久化存储
|
||||
// 先返回固定响应
|
||||
WebSocketSession session = activeSessions.get(userId);
|
||||
|
@ -29,4 +31,10 @@ public class CustomerServiceImpl implements CustomerService {
|
|||
session.sendMessage(new TextMessage("[客服] 您好,当前为人工服务模式"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferToAgent(String sessionId, List<ChatMessage> history) {
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package com.mcwl.communityCenter.webSocket;
|
||||
|
||||
import com.mcwl.communityCenter.service.AIService;
|
||||
import com.mcwl.communityCenter.service.CustomerService;
|
||||
import com.mcwl.communityCenter.service.HumanService;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.socket.CloseStatus;
|
||||
|
@ -18,7 +18,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
|
||||
@ServerEndpoint("/chat")
|
||||
@NoArgsConstructor
|
||||
public class ChatWebSocketPoint extends AbstractWebSocketHandler {
|
||||
public class ChatWebSocket extends AbstractWebSocketHandler {
|
||||
private final Map<String, Boolean> userModes = new ConcurrentHashMap<>();
|
||||
|
||||
// 存储会话与订阅的映射关系
|
||||
|
@ -27,38 +27,32 @@ public class ChatWebSocketPoint extends AbstractWebSocketHandler {
|
|||
@Autowired
|
||||
private AIService aiService;
|
||||
|
||||
@Autowired
|
||||
private CustomerService customerService;
|
||||
|
||||
// 构造函数注入服务...
|
||||
|
||||
@Override
|
||||
public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||
String userId = session.getId();
|
||||
String userMessage = message.getPayload();
|
||||
// 判断当前模式
|
||||
if (userModes.getOrDefault(userId, false)) {
|
||||
// 人工模式
|
||||
customerService.handleCustomerMessage(userId, userMessage);
|
||||
} else {
|
||||
|
||||
// AI 流式响应模式
|
||||
Flux<String> responseStream = aiService.getDeepSeekResponseStream(userMessage);
|
||||
|
||||
// 订阅响应流并存储 Disposable
|
||||
Disposable disposable = responseStream
|
||||
.doOnNext(chunk -> sendText(session, chunk))
|
||||
.doOnComplete(() -> sendText(session, "[END]"))
|
||||
.doOnNext(chunk -> sendText(session, chunk)) // 发送每个数据块到客户端
|
||||
.doOnComplete(() -> sendText(session, "[END]")) // 当流处理完成时,发送结束标记
|
||||
.doOnError(e -> sendText(session, "[ERROR] " + e.getMessage()))
|
||||
.subscribe();
|
||||
|
||||
sessionSubscriptions.put(userId, disposable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||
super.afterConnectionEstablished(session);
|
||||
userModes.put(session.getId(), false);
|
||||
// userModes.put(session.getId(), false);
|
||||
session.sendMessage(new TextMessage("[AI] 您好,请问有什么问题?"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,15 +60,14 @@ public class ChatWebSocketPoint extends AbstractWebSocketHandler {
|
|||
// 清理订阅资源
|
||||
String sessionId = session.getId();
|
||||
Disposable disposable = sessionSubscriptions.remove(sessionId);
|
||||
if (disposable != null && !disposable.isDisposed()) {
|
||||
if (disposable != null && disposable.isDisposed()) {
|
||||
disposable.dispose();
|
||||
System.out.println("已清理会话资源: " + sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加模式切换方法(根据业务需求)
|
||||
public void switchUserMode(String sessionId, boolean isHumanMode) {
|
||||
userModes.put(sessionId, isHumanMode);
|
||||
public void switchUserMode(String sessionId) {
|
||||
|
||||
}
|
||||
|
||||
// 线程安全的发送方法
|
|
@ -0,0 +1,55 @@
|
|||
package com.mcwl.communityCenter.webSocket;
|
||||
|
||||
import com.mcwl.common.utils.SecurityUtils;
|
||||
import com.mcwl.communityCenter.service.HumanService;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.socket.CloseStatus;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
|
||||
import reactor.core.Disposable;
|
||||
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@ServerEndpoint("/chat/human")
|
||||
@NoArgsConstructor
|
||||
public class HumanWebSocket extends AbstractWebSocketHandler {
|
||||
|
||||
@Autowired
|
||||
private HumanService humanService;
|
||||
|
||||
// 构造函数注入服务...
|
||||
|
||||
@Override
|
||||
public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||
String userId = session.getId();
|
||||
String userMessage = message.getPayload();
|
||||
|
||||
humanService.handleHumanMessage(userId, userMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||
super.afterConnectionEstablished(session);
|
||||
humanService.transferToHuman(SecurityUtils.getUserId().toString(), session);
|
||||
System.out.println("客服:" + SecurityUtils.getUsername() + " 已上线");
|
||||
}
|
||||
|
||||
|
||||
// 线程安全的发送方法
|
||||
private void sendText(WebSocketSession session, String text) {
|
||||
try {
|
||||
if (session.isOpen()) {
|
||||
synchronized (session) { // WebSocketSession 非线程安全
|
||||
session.sendMessage(new TextMessage(text));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.out.println("WebSocket 发送失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue