1
0
mirror of https://github.com/chatopera/cosin.git synced 2025-06-16 18:30:03 +08:00

#998 enable chatbot writing status

Signed-off-by: Hai Liang Wang <hai@chatopera.com>
This commit is contained in:
Hai Liang Wang 2024-01-17 16:13:14 +08:00
parent 0797a90fdd
commit f0220ef91c
7 changed files with 210 additions and 41 deletions

View File

@ -1,14 +1,14 @@
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* 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.
* Copyright (C) 2019-Jun. 2023 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* Copyright (C) 2019-Jun. 2023 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.plugins.chatbot;
@ -130,21 +130,31 @@ public class ChatbotEventHandler {
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")) {
if ((!faqhotdata.getBoolean("logic_is_fallback"))) {
// 返回有效值不是兜底回复
ChatMessage faqhotmsg = new ChatMessage();
faqhotmsg.setCalltype(MainContext.CallType.OUT.toString());
faqhotmsg.setAppid(appid);
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);
if (faqhotdata.has("string") &&
faqhotdata.has("params") &&
faqhotdata.has("service") &&
StringUtils.equals(faqhotdata.getJSONObject("service").getString("provider"), "conversation")) {
// 多轮对话返回的热门问题
faqhotmsg.setMessage(faqhotdata.getString("string"));
faqhotmsg.setExpmsg(faqhotdata.getJSONArray("params").toString());
faqhotmsg.setUpdatetime(System.currentTimeMillis());
client.sendEvent(MainContext.MessageType.MESSAGE.toString(), faqhotmsg);
} else if (faqhotdata.has("string") && StringUtils.isNotBlank(faqhotdata.getString("string"))) {
faqhotmsg.setMessage(faqhotdata.getString("string"));
faqhotmsg.setUpdatetime(System.currentTimeMillis());
client.sendEvent(MainContext.MessageType.MESSAGE.toString(), faqhotmsg);
}
}
}
} else if (result.getRc() == 999 || result.getRc() == 998) {
@ -322,7 +332,7 @@ public class ChatbotEventHandler {
getAgentUserRes().save(p);
// 发送消息给Bot
getChatbotProxy().publishMessage(data, Constants.CHATBOT_EVENT_TYPE_CHAT);
getChatbotProxy().publishMessageDelayed(data, Constants.CHATBOT_EVENT_TYPE_CHAT, 2);
});

View File

@ -61,6 +61,17 @@ public class ChatbotProxy {
brokerPublisher.send(Constants.INSTANT_MESSAGING_MQ_QUEUE_CHATBOT, SerializeUtil.serialize(data));
}
/**
* Publish message in delayed manner.
* @param data
* @param eventType
* @param delayedSeconds
*/
public void publishMessageDelayed(final ChatMessage data, final String eventType, int delayedSeconds) {
logger.info("[publishMessageDelayed] eventType {}", eventType);
brokerPublisher.send(Constants.INSTANT_MESSAGING_MQ_QUEUE_CHATBOT, SerializeUtil.serialize(data), false, delayedSeconds);
}
/**
* 使用chatbotID得到snsid
*

View File

@ -1153,3 +1153,54 @@ p.submitBtnWrap{
color: rgba(35, 39, 50, 0.8);
background: url(/images/circle.png) no-repeat left 8px;
}
.loading{
margin: -3px auto;
}
.loading span{
display: inline-block;
width: 7px;
height: 7px;
margin-right: 5px;
border-radius: 50%;
background-color: #19a55d !important;
-webkit-animation: load 1.04s ease infinite;
}
.loading span:last-child{
margin-right: 0px;
}
@-webkit-keyframes load{
0%{
opacity: 1;
}
100%{
opacity: 0;
}
}
.loading span:nth-child(1){
-webkit-animation-delay:0.13s;
}
.loading span:nth-child(2){
-webkit-animation-delay:0.26s;
}
.loading span:nth-child(3){
-webkit-animation-delay:0.39s;
}
.loading span:nth-child(4){
-webkit-animation-delay:0.52s;
}
.chat-writing-message{
font-size: 13px;
margin-top:8px;
margin-left:5px;
border-radius: 3px;
padding: 2px 4px 6px;
margin-bottom: 5px;
line-height: 25px;
padding-right: 5px;
padding-left: 5px;
background-color: #EFEFEF !important;
border: 1px solid #EFEFEF;
float: left;
min-width: 25px;
}

View File

@ -30,6 +30,7 @@ html
script(src='/js/jquery-1.10.2.min.js')
script(type='text/javascript', src='/im/js/kindeditor/kindeditor.js')
script(type='text/javascript', src='/im/js/kindeditor/lang/zh-CN.js')
script(type='text/javascript', src='/js/template.js')
script(src='/im/js/socket.io.js')
script(src='/im/js/dayjs.min.js')
script(type='text/javascript').
@ -265,6 +266,17 @@ html
return false;
}
function outputElementAndScroll(element, scroll, msgType){
$('#above').append(element);
if (scroll == null || scroll == true) {
if (msgType && msgType == "image") {
chatScorllBottom("above")
} else {
document.getElementById("above").scrollTop = document.getElementById("above").scrollHeight
}
}
}
function output(message, clazz, scroll, msgType) {
if (clazz == "message connect-message") {
var messages = document.getElementsByClassName("connect-message");
@ -275,14 +287,7 @@ html
}
var element = $("<div class='clearfix " + clazz + "'></div>");
element.append(message);
$('#above').append(element);
if (scroll == null || scroll == true) {
if (msgType && msgType == "image") {
chatScorllBottom("above")
} else {
document.getElementById("above").scrollTop = document.getElementById("above").scrollHeight
}
}
outputElementAndScroll(element, scroll, msgType);
}
function update(id, message) {
@ -438,6 +443,7 @@ html
}
body.ukefu-point-text(style='overflow:hidden; background:#E8E8E8')
include ../templates/chatbot_tpls
.large.ukefu-im-theme(style='background: white;', class=(type == 'text' ? 'ukefu-theme-border-' + inviteData.consult_dialog_color : ''))
#containter.clearfix
#header(class='theme' + inviteData.consult_dialog_color)
@ -676,20 +682,43 @@ html
}
})
socket.on('message', function (data) {
socket.on("message", function (data) {
// append message
var chat = document.getElementsByClassName('chatting-left').innerText;
data.createtime = dayjs(data.createtime).format('YYYY-MM-DD HH:mm:ss');
chat = data.message;
if (data.msgtype == "image") {
chat = "<a href='" + data.message + "&original=true' target='_blank'><img src='" + data.message + "' class='ukefu-media-image'/></a>";
} else if (data.msgtype == "file") {
chat = "<div class='ukefu-message-file'><div class='ukefu-file-icon'><img src='/im/img/file.png'></div><div class='ukefu-file-desc'><a href='" + data.message + "' target='_blank'><div>" + data.filename + "</div><div>" + (data.filesize / 1024).toFixed(3) + "Kb</div></a></div></div>";
}
if (data.calltype == "呼入") {
output('<div class="chat-right"> <img class="user-img" src="/im/img/user.png" alt=""><div class="chat-message"><label class="time">' + data.createtime + '</label><label class="user">' + data.username + '</label> </div><div class="chatting-right"><i class="arrow arrow#{inviteData.consult_dialog_colo}"></i><div class="chat-content theme#{inviteData.consult_dialog_color}">' + chat + '</div></div>', "chat-block", true,data.msgtype
)
;
// Receive User's own sent message back from socket.io
output('<div class="chat-right"> <img class="user-img" src="/im/img/user.png" alt=""><div class="chat-message"><label class="time">' + data.createtime + '</label><label class="user">' + data.username + '</label> </div><div class="chatting-right"><i class="arrow arrow#{inviteData.consult_dialog_colo}"></i><div class="chat-content theme#{inviteData.consult_dialog_color}">' + chat + '</div></div>', "chat-block", true, data.msgtype);
setTimeout(() => {
// botwriting: make sure bot writing on
if($('#writing').length > 0){
// console.log("bot writing is already on.");
} else {
// botwriting: now, set bot writing on
// console.log("bot writing is off, now set it on.");
var tplParams = {};
tplParams.calltype = "呼出";
tplParams.type = "writing";
tplParams.createtime = data.createtime;
tplParams.username = "#{inviteData.ainame ? inviteData.ainame : '小松'}";
var msgWriting = template($('#chatbot_writing').html(), {data: tplParams});
outputElementAndScroll($(msgWriting), true, data.msgtype);
}
}, 500); // on the backend, would wait 2 seconds to ensure the time window
} else if (data.calltype == "呼出") {
// botwriting: end bot writing message
if ($('#writing').length > 0) {
$('#writing').remove();
}
if (data.expmsg) {
showExtmsg(data.username, data.createtime, data.message, data.expmsg);
} else {
@ -710,11 +739,10 @@ html
}
});
function sendDisconnect() {
socket.disconnect();
}
function sendMessage() {
editor.sync();
var count = editor.count("text");
@ -752,8 +780,8 @@ html
// POI:function(){
// }
}
// 回车事件
document.onkeyup = function (e) {
if (!e) e = window.event;
@ -761,7 +789,7 @@ html
document.getElementById('sent').click();
}
}
window.onresize = function () {
R3Helper.resize();
};
};

View File

@ -30,6 +30,7 @@ html
script(src='/js/jquery.form.js')
script(type='text/javascript', src='/im/js/kindeditor/kindeditor.js')
script(type='text/javascript', src='/im/js/kindeditor/lang/zh-CN.js')
script(type='text/javascript', src='/js/template.js')
style.
* {
-webkit-box-sizing: border-box;
@ -158,6 +159,16 @@ html
}
}
function outputElementAndScroll(element, msgType){
$('#above').append(element);
if (msgType && msgType == "image") {
chatScorllBottom("above")
} else {
document.getElementById("above").scrollTop = document.getElementById("above").scrollHeight
}
//$("#welcome-message").html(document.getElementById('above').scrollHeight);
}
function output(message, clazz, msgType) {
if (clazz == "message connect-message") {
var messages = document.getElementsByClassName("connect-message");
@ -168,13 +179,7 @@ html
}
var element = $("<div class='clearfix " + clazz + "'></div>");
element.append(message);
$('#above').append(element);
if (msgType && msgType == "image") {
chatScorllBottom("above")
} else {
document.getElementById("above").scrollTop = document.getElementById("above").scrollHeight
}
//$("#welcome-message").html(document.getElementById('above').scrollHeight);
outputElementAndScroll(element, msgType);
}
function update(id, message) {
@ -352,6 +357,7 @@ html
// kindeditor
body.ukefu-im-theme.ukefu-point-text(style='width:100%;overflow:hidden;height:100%;max-height:100%;position: fixed;/* 或者scroll */-webkit-overflow-scrolling: touch;/* 解决ios滑动不流畅问题 */')
include ../templates/chatbot_tpls
#header(class="theme" + inviteData.consult_dialog_color)
- var dialog_logo=inviteData.consult_dialog_logo?(inviteData.consult_dialog_logo.startsWith("http://") || inviteData.consult_dialog_logo.startsWith("https://")?inviteData.consult_dialog_logo:'/res/image.html?id='+inviteData.consult_dialog_logo):'/images/logo.png'
img(src=dialog_logo, style='height:50px;padding:10px;')
@ -482,10 +488,12 @@ html
}
})
socket.on('message', function (data) {
socket.on("message", function (data) {
// append message
var chat = document.getElementsByClassName('chatting-left').innerText;
data.createtime = dayjs(data.createtime).format('YYYY-MM-DD HH:mm:ss');
chat = data.message;
if (data.msgtype == "image") {
chat = "<a href='" + data.message + "&original=true' target='_blank'><img src='" + data.message + "' class='ukefu-media-image'/></a>";
} else if (data.msgtype == "cooperation") {
@ -494,9 +502,32 @@ html
//检查访客是否在协作页面上,如果在协作页面上,就开始执行重绘,否则不做处理
drawCanvasImage(data.attachmentid);
}
if (data.calltype == "呼入") {
// Receive User's own sent message back from socket.io
output('<div class="chat-right"> <img class="user-img" src="/im/img/user.png" alt=""><div class="chat-message"><label class="time">' + data.createtime + '</label><label class="user">' + data.username + '</label> </div><div class="chatting-right"><i class="arrow arrow#{inviteData.consult_dialog_color}"></i><div class="chat-content theme#{inviteData.consult_dialog_color}">' + chat + '</div></div>', "chat-block", data.msgtype);
setTimeout(() => {
// botwriting: make sure bot writing on
if($('#writing').length > 0){
// console.log("bot writing is already on.");
} else {
// botwriting: now, set bot writing on
// console.log("bot writing is off, now set it on.");
var tplParams = {};
tplParams.calltype = "呼出";
tplParams.type = "writing";
tplParams.createtime = data.createtime;
tplParams.username = "#{inviteData.ainame ? inviteData.ainame : '小松'}";
var msgWriting = template($('#chatbot_writing').html(), {data: tplParams});
outputElementAndScroll($(msgWriting), true, data.msgtype);
}
}, 500); // on the backend, would wait 2 seconds to ensure the time window
} else if (data.calltype == "呼出") {
// botwriting: end bot writing message
if ($('#writing').length > 0) {
$('#writing').remove();
}
if (data.expmsg) {
showExtmsg(data.username, data.createtime, data.message, data.expmsg);
} else {
@ -508,9 +539,11 @@ html
socket.on('disconnect', function () {
output('<span id="connect-message">连接坐席失败,在线咨询服务不可用</span>', 'message connect-message');
});
function sendDisconnect() {
socket.disconnect();
}
function acceptInvite(msgid, fileid) {
document.getElementById("cooperation").style.display = "block";
document.getElementById("ukefu_img_ctx").src = "/res/image.html?id=" + fileid + "&cooperation=true&original=true";
@ -547,9 +580,11 @@ html
};
}
}
function offCoop() {
document.getElementById("cooperation").style.display = "none";
}
function sendMessage() {
var count = document.getElementById('message').value.length;
if (count > 0 && service_end == false) {
@ -562,6 +597,7 @@ html
}
closeFaceDialog(0);
}
function sendMessageText(message) {
if (message != "") {
socket.emit('message', {
@ -599,6 +635,4 @@ html
// POI:function(){
// }
}
}

View File

@ -0,0 +1,13 @@
//- Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
//- <https://www.chatopera.com>, Licensed under the Chunsong Public
//- License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
//- 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.
//- Copyright (C) 2018-Jun. 2023 Chatopera Inc, <https://www.chatopera.com>
//- Licensed under the Apache License, Version 2.0
//- http://www.apache.org/licenses/LICENSE-2.0
script#chatbot_writing(type="text/html")
include chatbot_writing.tpl

View File

@ -0,0 +1,22 @@
<div class="clearfix chat-block" <%if(data.type == 'writing'){%>id="writing"<%}%>>
<div class="<% if(data.calltype == '呼出'){%>chat-left<%}else{%>chat-right<%}%>">
<img alt="" src="<% if(data.calltype == '呼出'){%>/images/agent.png<%}else{%><% if(data.headimgurl && data.headimgurl !=''){%><%=data.headimgurl%><%}else{%>/im/img/user.png<%} %><%} %>" class="user-img" style="width:45px;height:45px;">
<div class="chat-message">
<span class="user"><%=data.username%></span>
<span class="time"><%=data.createtime%></span>
</div>
<div class="<% if(data.calltype == '呼出'){%>chatting-left<%}else{%>chatting-right<%}%>">
<i class="arrow"></i>
<%if(data.type == 'writing'){%>
<div class="chat-writing-message" title="正在输入...">
<span class="loading">
<span></span>
<span></span>
<span></span>
<span></span>
</span>
</div>
<%}%>
</div>
</div>
</div>