1
0
mirror of https://github.com/chatopera/cosin.git synced 2025-06-25 02:47:10 +08:00
cosin/public/plugins/chatbot/classes/ChatbotEventHandler.java
2021-02-10 17:14:00 +08:00

378 lines
17 KiB
Java

/*
* Copyright (C) 2018-2019 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chatopera.cc.plugins.chatbot;
import com.chatopera.bot.sdk.Response;
import com.chatopera.cc.acd.ACDServiceRouter;
import com.chatopera.cc.basic.Constants;
import com.chatopera.cc.basic.MainContext;
import com.chatopera.cc.basic.MainUtils;
import com.chatopera.cc.model.*;
import com.chatopera.cc.persistence.repository.AgentUserRepository;
import com.chatopera.cc.persistence.repository.ChatbotRepository;
import com.chatopera.cc.persistence.repository.OnlineUserRepository;
import com.chatopera.cc.proxy.OnlineUserProxy;
import com.chatopera.cc.socketio.client.NettyClients;
import com.chatopera.cc.socketio.message.AgentStatusMessage;
import com.chatopera.cc.socketio.message.ChatMessage;
import com.chatopera.cc.socketio.message.Message;
import com.chatopera.cc.socketio.util.IMServiceUtils;
import com.chatopera.cc.util.IP;
import com.chatopera.cc.util.IPTools;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import org.apache.commons.lang.StringUtils;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.net.InetSocketAddress;
import java.util.Date;
public class ChatbotEventHandler {
private static final Logger logger = LoggerFactory.getLogger(ChatbotEventHandler.class);
protected SocketIOServer server;
private static AgentUserRepository agentUserRes;
private static OnlineUserRepository onlineUserRes;
private static ChatbotRepository chatbotRes;
private static ChatbotProxy chatbotProxy;
@Autowired
public ChatbotEventHandler(SocketIOServer server) {
this.server = server;
}
@OnConnect
public void onConnect(SocketIOClient client) {
try {
String user = client.getHandshakeData().getSingleUrlParam("userid");
String nickname = client.getHandshakeData().getSingleUrlParam("nickname");
String orgi = client.getHandshakeData().getSingleUrlParam("orgi");
String session = MainUtils.getContextID(client.getHandshakeData().getSingleUrlParam("session"));
String appid = client.getHandshakeData().getSingleUrlParam("appid");
String aiid = client.getHandshakeData().getSingleUrlParam("aiid");
logger.info(
"[onConnect] userid {}, nickname {}, session {}, appid {}, aiid {}", user, nickname, session, appid,
aiid);
client.set("aiid", aiid);
client.set("session", session);
client.set("userid", user);
client.set("appid", appid);
client.set("orgi", orgi);
Date now = new Date();
if (StringUtils.isNotBlank(user)) {
/**
* 加入到 缓存列表
*/
NettyClients.getInstance().putChatbotEventClient(user, client);
CousultInvite invite = OnlineUserProxy.consult(appid, orgi);
/**
* 更新坐席服务类型
*/
IMServiceUtils.shiftOpsType(user, orgi, MainContext.OptType.CHATBOT);
// send out tip
Message tip = new Message();
tip.setMessage("您正在使用机器人客服!");
tip.setMessageType(MainContext.MessageType.MESSAGE.toString());
tip.setCalltype(MainContext.CallType.IN.toString());
tip.setCreatetime(MainUtils.dateFormate.format(now));
client.sendEvent(MainContext.MessageType.STATUS.toString(), tip);
// send out welcome message
if (invite != null) {
Chatbot chatbot = getChatbotRes().findOne(invite.getAiid());
com.chatopera.bot.sdk.Chatbot bot = new com.chatopera.bot.sdk.Chatbot(
chatbot.getClientId(), chatbot.getSecret(), chatbot.getBaseUrl());
Response result = bot.command("GET", "/");
// 发送欢迎语
if (result.getRc() == 0) {
JSONObject details = (JSONObject) result.getData();
ChatMessage welcome = new ChatMessage();
String welcomeTextMessage = details.getString("welcome");
if (StringUtils.isNotBlank(welcomeTextMessage)) {
welcome.setCalltype(MainContext.CallType.OUT.toString());
welcome.setAppid(appid);
welcome.setOrgi(orgi);
welcome.setAiid(aiid);
welcome.setMessage(welcomeTextMessage);
welcome.setTouser(user);
welcome.setMsgtype(MainContext.MessageType.MESSAGE.toString());
welcome.setUserid(user);
welcome.setUsername(invite.getAiname());
welcome.setUpdatetime(System.currentTimeMillis());
client.sendEvent(MainContext.MessageType.MESSAGE.toString(), welcome);
}
// 发送常见问题列表
JSONObject faqhotresp = bot.conversation(user, "__faq_hot_list");
logger.info("faqhot {}", faqhotresp.toString());
if (faqhotresp.getInt("rc") == 0) {
JSONObject faqhotdata = faqhotresp.getJSONObject("data");
if ((!faqhotdata.getBoolean("logic_is_fallback")) &&
faqhotdata.has("string") &&
faqhotdata.has("params")) {
ChatMessage faqhotmsg = new ChatMessage();
faqhotmsg.setCalltype(MainContext.CallType.OUT.toString());
faqhotmsg.setAppid(appid);
faqhotmsg.setOrgi(orgi);
faqhotmsg.setAiid(aiid);
faqhotmsg.setMessage(faqhotdata.getString("string"));
faqhotmsg.setExpmsg(faqhotdata.getJSONArray("params").toString());
faqhotmsg.setTouser(user);
faqhotmsg.setMsgtype(MainContext.MessageType.MESSAGE.toString());
faqhotmsg.setUserid(user);
faqhotmsg.setUsername(invite.getAiname());
faqhotmsg.setUpdatetime(System.currentTimeMillis());
client.sendEvent(MainContext.MessageType.MESSAGE.toString(), faqhotmsg);
}
}
}
}
InetSocketAddress address = (InetSocketAddress) client.getRemoteAddress();
String ip = MainUtils.getIpAddr(client.getHandshakeData().getHttpHeaders(), address.getHostString());
OnlineUser onlineUser = getOnlineUserRes().findOne(user);
if (onlineUser == null) {
onlineUser = new OnlineUser();
onlineUser.setAppid(appid);
if (StringUtils.isNotBlank(nickname)) {
onlineUser.setUsername(nickname);
} else {
onlineUser.setUsername(Constants.GUEST_USER + "_" + MainUtils.genIDByKey(user));
}
onlineUser.setSessionid(session);
onlineUser.setOptype(MainContext.OptType.CHATBOT.toString());
onlineUser.setUserid(user);
onlineUser.setId(user);
onlineUser.setOrgi(orgi);
onlineUser.setChannel(MainContext.ChannelType.WEBIM.toString());
onlineUser.setIp(ip);
onlineUser.setUpdatetime(now);
onlineUser.setLogintime(now);
onlineUser.setCreatetime(now);
IP ipdata = IPTools.getInstance().findGeography(ip);
onlineUser.setCity(ipdata.getCity());
onlineUser.setCountry(ipdata.getCountry());
onlineUser.setProvince(ipdata.getProvince());
onlineUser.setIsp(ipdata.getIsp());
onlineUser.setRegion(ipdata.getRegion());
onlineUser.setStatus(MainContext.OnlineUserStatusEnum.ONLINE.toString());
}
// 在线客服访客咨询记录
AgentUser agentUser = new AgentUser(
onlineUser.getId(),
MainContext.ChannelType.WEBIM.toString(), // callout
onlineUser.getId(),
onlineUser.getUsername(),
Constants.SYSTEM_ORGI,
appid);
agentUser.setServicetime(now);
agentUser.setCreatetime(now);
agentUser.setUpdatetime(now);
agentUser.setSessionid(session);
agentUser.setRegion(onlineUser.getRegion());
// 聊天机器人处理的请求
agentUser.setOpttype(MainContext.OptType.CHATBOT.toString());
agentUser.setAgentno(aiid); // 聊天机器人ID
agentUser.setAgentname(invite != null ? invite.getAiname() : "机器人客服");
agentUser.setCity(onlineUser.getCity());
agentUser.setProvince(onlineUser.getProvince());
agentUser.setCountry(onlineUser.getCountry());
AgentService agentService = ACDServiceRouter.getAcdChatbotService().processChatbotService(
invite != null ? invite.getAiname() : "机器人客服", agentUser, orgi);
agentUser.setAgentserviceid(agentService.getId());
// 标记为机器人坐席
agentUser.setChatbotops(true);
// 保存到MySQL
getAgentUserRes().save(agentUser);
getOnlineUserRes().save(onlineUser);
}
} catch (Exception e) {
logger.info("[onConnect] error", e);
}
}
// 添加 @OnDisconnect 事件,客户端断开连接时调用,刷新客户端信息
@OnDisconnect
public void onDisconnect(SocketIOClient client) {
String user = client.getHandshakeData().getSingleUrlParam("userid");
String orgi = client.getHandshakeData().getSingleUrlParam("orgi");
if (StringUtils.isNotBlank(user)) {
NettyClients.getInstance().removeChatbotEventClient(
user, MainUtils.getContextID(client.getSessionId().toString()));
OnlineUser onlineUser = MainContext.getCache().findOneOnlineUserByUserIdAndOrgi(user, orgi);
MainContext.getCache().findOneAgentUserByUserIdAndOrgi(user, orgi).ifPresent(p -> {
ACDServiceRouter.getAcdChatbotService().processChatbotService(null, p, orgi);
MainContext.getCache().deleteAgentUserByUserIdAndOrgi(p, orgi);
MainContext.getCache().deleteOnlineUserByIdAndOrgi(user, orgi);
p.setStatus(MainContext.AgentUserStatusEnum.END.toString());
onlineUser.setStatus(MainContext.OnlineUserStatusEnum.OFFLINE.toString());
getAgentUserRes().save(p);
getOnlineUserRes().save(onlineUser);
});
}
client.disconnect();
}
// 消息接收入口,网站有新用户接入对话
@OnEvent(value = "new")
public void onEvent(SocketIOClient client, AckRequest request, Message data) {
}
// 消息接收入口,坐席状态更新
@OnEvent(value = "agentstatus")
public void onEvent(SocketIOClient client, AckRequest request, AgentStatusMessage data) {
logger.info("[onEvent] agentstatus: ", data.getMessage());
}
// 消息接收入口,收发消息,用户向机器人发送消息
@OnEvent(value = "message")
public void onEvent(SocketIOClient client, AckRequest request, ChatMessage data) {
String orgi = client.get("orgi");
String aiid = client.get("aiid");
String user = client.get("userid");
String sessionid = client.get("session");
String appid = client.get("appid");
logger.info(
"[onEvent] message: session {}, aiid {}, userid {}, dataType {}, appid {}, orgi {}", sessionid, aiid,
user, data.getType(), appid, orgi);
// ignore event if dataType is not message.
if (!StringUtils.equals(data.getType(), Constants.IM_MESSAGE_TYPE_MESSAGE)) {
return;
}
MainContext.getCache().findOneAgentUserByUserIdAndOrgi(user, orgi).ifPresent(p -> {
/**
* 以下代码主要用于检查 访客端的字数限制
*/
CousultInvite invite = OnlineUserProxy.consult(data.getAppid(), data.getOrgi());
// ignore event if no invite found.
if (invite == null) {
return;
}
// ignore if Chatbot is turnoff.
if (!invite.isAi()) {
return;
}
Date now = new Date();
if (invite.getMaxwordsnum() > 0) {
if (StringUtils.isNotBlank(data.getMessage()) && data.getMessage().length() > invite.getMaxwordsnum()) {
data.setMessage(data.getMessage().substring(0, invite.getMaxwordsnum()));
}
} else if (StringUtils.isNotBlank(data.getMessage()) && data.getMessage().length() > 300) {
data.setMessage(data.getMessage().substring(0, 300));
}
data.setUsession(user); // 绑定唯一用户
data.setSessionid(sessionid);
data.setMessage(MainUtils.processEmoti(data.getMessage())); // 处理表情
data.setTouser(aiid);
data.setUsername(p.getUsername());
data.setAiid(aiid);
data.setAgentserviceid(p.getAgentserviceid());
data.setChannel(p.getChannel());
data.setContextid(p.getAgentserviceid()); // 一定要设置 ContextID
data.setCalltype(MainContext.CallType.IN.toString());
// 保存并发送消息给访客
getChatbotProxy().createTextMessage(
data,
MainContext.CallType.IN.toString());
// 更新访客咨询记录
p.setUpdatetime(now);
p.setLastmessage(now);
p.setLastmsg(data.getMessage());
getAgentUserRes().save(p);
// 发送消息给Bot
getChatbotProxy().publishMessage(data, Constants.CHATBOT_EVENT_TYPE_CHAT);
});
}
/**
* Lazy load
*
* @return
*/
private AgentUserRepository getAgentUserRes() {
if (agentUserRes == null) {
agentUserRes = MainContext.getContext().getBean(AgentUserRepository.class);
}
return agentUserRes;
}
/**
* Lazy load
*
* @return
*/
private ChatbotProxy getChatbotProxy() {
if (chatbotProxy == null) {
chatbotProxy = MainContext.getContext().getBean(ChatbotProxy.class);
}
return chatbotProxy;
}
private OnlineUserRepository getOnlineUserRes() {
if (onlineUserRes == null) {
onlineUserRes = MainContext.getContext().getBean(OnlineUserRepository.class);
}
return onlineUserRes;
}
private ChatbotRepository getChatbotRes() {
if (chatbotRes == null) {
chatbotRes = MainContext.getContext().getBean(ChatbotRepository.class);
}
return chatbotRes;
}
}