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

562 lines
24 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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.exception.ChatbotException;
import com.chatopera.cc.basic.Constants;
import com.chatopera.cc.basic.MainUtils;
import com.chatopera.cc.controller.Handler;
import com.chatopera.cc.controller.api.request.RestUtils;
import com.chatopera.cc.model.Chatbot;
import com.chatopera.cc.model.CousultInvite;
import com.chatopera.cc.model.SNSAccount;
import com.chatopera.cc.model.User;
import com.chatopera.cc.persistence.repository.ChatbotRepository;
import com.chatopera.cc.persistence.repository.ConsultInviteRepository;
import com.chatopera.cc.persistence.repository.SNSAccountRepository;
import com.chatopera.cc.persistence.repository.UserRepository;
import com.chatopera.cc.proxy.OnlineUserProxy;
import com.chatopera.cc.util.Menu;
import com.chatopera.cc.util.SystemEnvHelper;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
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 org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.util.Date;
import java.util.List;
/**
* 聊天机器人
* 请求聊天机器人服务
*/
@RestController
@RequestMapping("/api/chatbot")
public class ApiChatbotController extends Handler {
private final static Logger logger = LoggerFactory.getLogger(ApiChatbotController.class);
@Autowired
private ChatbotRepository chatbotRes;
@Autowired
private SNSAccountRepository snsAccountRes;
@Autowired
private UserRepository userRes;
@Autowired
private ConsultInviteRepository consultInviteRes;
private final static String botServiecProvider = SystemEnvHelper.getenv(
ChatbotConstants.BOT_PROVIDER, ChatbotConstants.DEFAULT_BOT_PROVIDER);
/**
* 聊天机器人
*
* @param request
* @param body
* @return
* @throws Exception
*/
@RequestMapping(method = RequestMethod.POST)
@Menu(type = "apps", subtype = "chatbot", access = true)
public ResponseEntity<String> operations(HttpServletRequest request, @RequestBody final String body) throws Exception {
final JsonObject j = (new JsonParser()).parse(body).getAsJsonObject();
logger.info("[chatbot] operations payload {}", j.toString());
JsonObject json = new JsonObject();
HttpHeaders headers = RestUtils.header();
final User logined = super.getUser(request);
final String orgi = logined.getOrgi();
if (!j.has("ops")) {
json.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_1);
json.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的请求参数。");
} else {
switch (StringUtils.lowerCase(j.get("ops").getAsString())) {
case "create":
// TODO 支持将一个用户添加到多个部门后此处需要在Payload中传入部门ID ,即 organ
// 2019-10-10 Wang Hai Liang
json = create(j, logined.getId(), logined.getOrgi());
break;
case "delete":
json = delete(j, logined.getId(), logined.getOrgi());
break;
case "fetch":
json = fetch(
j, logined.getId(), logined.isAdmin(), orgi, super.getP(request), super.getPs(request));
break;
case "update":
json = update(j);
break;
case "enable":
json = enable(j, true);
break;
case "disable":
json = enable(j, false);
break;
case "vacant":
json = vacant(j, orgi, logined.isAdmin());
break;
default:
json.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_2);
json.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的操作。");
}
}
return new ResponseEntity<String>(json.toString(), headers, HttpStatus.OK);
}
/**
* 获取空缺聊天机器人的网站渠道列表
*
* @param j
* @param orgi
* @return
*/
private JsonObject vacant(final JsonObject j, String orgi, boolean isSuperuser) {
JsonObject resp = new JsonObject();
if (!isSuperuser) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "您不具有访问该资源的权限。");
return resp;
}
List<SNSAccount> records = snsAccountRes.findBySnstypeAndOrgi(Constants.CHANNEL_TYPE_WEBIM, orgi);
JsonArray ja = new JsonArray();
for (SNSAccount r : records) {
if (!chatbotRes.existsBySnsAccountIdentifierAndOrgi(r.getSnsid(), orgi)) {
JsonObject o = new JsonObject();
o.addProperty("id", r.getId());
o.addProperty("snsid", r.getSnsid());
o.addProperty("snsType", r.getSnstype());
o.addProperty("snsurl", r.getBaseURL());
ja.add(o);
}
}
resp.add("data", ja);
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
return resp;
}
/**
* Enable Chatbot
*
* @param j
* @return
*/
private JsonObject enable(JsonObject j, boolean isEnabled) {
JsonObject resp = new JsonObject();
if ((!j.has("id")) || StringUtils.isBlank(j.get("id").getAsString())) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的操作id不能为空。");
return resp;
}
final String id = j.get("id").getAsString();
Chatbot c = chatbotRes.findOne(id);
if (c == null) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_4);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "该聊天机器人不存在。");
return resp;
}
try {
com.chatopera.bot.sdk.Chatbot bot = new com.chatopera.bot.sdk.Chatbot(
c.getClientId(), c.getSecret(), botServiecProvider);
if (bot.exists()) {
c.setEnabled(isEnabled);
chatbotRes.save(c);
// 更新访客网站配置
CousultInvite invite = OnlineUserProxy.consult(c.getSnsAccountIdentifier(), c.getOrgi());
invite.setAi(isEnabled);
consultInviteRes.save(invite);
OnlineUserProxy.cacheConsult(invite);
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
resp.addProperty(RestUtils.RESP_KEY_DATA, "完成。");
} else {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_7);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "智能问答引擎不存在该聊天机器人,未能正确设置。");
}
} catch (MalformedURLException e) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_6);
resp.addProperty(RestUtils.RESP_KEY_DATA, "设置不成功,智能问答引擎地址不合法。");
} catch (ChatbotException e) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_5);
resp.addProperty(RestUtils.RESP_KEY_DATA, "设置不成功,智能问答引擎服务异常。");
}
return resp;
}
/**
* 更新聊天机器人
*
* @param j
* @return
*/
private JsonObject update(JsonObject j) throws Exception {
JsonObject resp = new JsonObject();
if (!j.has("id")) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "非法参数id不能为空。");
return resp;
}
final String id = j.get("id").getAsString();
Chatbot c = chatbotRes.findOne(id);
if (c == null) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_4);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "该聊天机器人不存在。");
return resp;
}
// update clientId and secret
if (j.has("clientId")) {
c.setClientId(j.get("clientId").getAsString());
} else {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的参数未传入【clientId】。");
return resp;
}
if (j.has("secret")) {
c.setSecret(j.get("secret").getAsString());
} else {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的参数未传入【secret】。");
return resp;
}
// 更新访客网站配置
CousultInvite invite = OnlineUserProxy.consult(c.getSnsAccountIdentifier(), c.getOrgi());
if (j.has("workmode") && Constants.CHATBOT_VALID_WORKMODELS.contains(j.get("workmode").getAsString())) {
c.setWorkmode(j.get("workmode").getAsString());
invite.setAifirst(!StringUtils.equals(Constants.CHATBOT_HUMAN_FIRST, c.getWorkmode()));
}
if (j.has("enabled")) {
boolean enabled = j.get("enabled").getAsBoolean();
c.setEnabled(enabled);
invite.setAi(enabled);
}
try {
com.chatopera.bot.sdk.Chatbot bot = new com.chatopera.bot.sdk.Chatbot(
c.getClientId(), c.getSecret(), botServiecProvider);
if (bot.exists()) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
JsonObject data = new JsonObject();
data.addProperty("id", c.getId());
resp.add(RestUtils.RESP_KEY_DATA, data);
resp.addProperty(RestUtils.RESP_KEY_MSG, "更新成功。");
JSONObject botDetails = bot.details();
c.setDescription(botDetails.getJSONObject("data").getString("description"));
c.setFallback(botDetails.getJSONObject("data").getString("fallback"));
c.setWelcome(botDetails.getJSONObject("data").getString("welcome"));
invite.setAisuccesstip(botDetails.getJSONObject("data").getString("welcome"));
c.setName(botDetails.getJSONObject("data").getString("name"));
invite.setAiname(c.getName());
} else {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_6);
resp.addProperty(
RestUtils.RESP_KEY_ERROR,
"Chatopera云服务无法访问该机器人请确认【1】该服务器可以访问互联网【2】该聊天机器人已经创建【3】clientId和Secret正确设置。提示该机器人不存在请先创建机器人, 登录 https://bot.chatopera.com");
return resp;
}
} catch (ChatbotException e) {
logger.error("bot create error", e);
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_5);
resp.addProperty(
RestUtils.RESP_KEY_ERROR,
"Chatopera云服务无法访问该机器人请确认【1】该服务器可以访问互联网【2】该聊天机器人已经创建【3】clientId和Secret正确设置。");
return resp;
} catch (MalformedURLException e) {
logger.error("bot request error", e);
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_7);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "更新智能问答引擎失败。" + e.toString());
return resp;
}
c.setUpdatetime(new Date());
chatbotRes.save(c);
consultInviteRes.save(invite);
OnlineUserProxy.cacheConsult(invite);
return resp;
}
/**
* 获取聊天机器人列表
*
* @param j
* @param id
* @param orgi
* @param p
* @param ps
* @return
*/
private JsonObject fetch(JsonObject j, String id, boolean isSuperuser, String orgi, int p, int ps) {
JsonObject resp = new JsonObject();
if (!isSuperuser) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "当前登录用户不是管理员,无权访问机器人客服资源。");
return resp;
}
Page<Chatbot> records = chatbotRes.findWithPagination(
new PageRequest(p, ps, Sort.Direction.DESC, "createtime"));
JsonArray ja = new JsonArray();
for (Chatbot c : records) {
JsonObject o = new JsonObject();
o.addProperty("id", c.getId());
o.addProperty("name", c.getName());
o.addProperty("primaryLanguage", c.getPrimaryLanguage());
o.addProperty("description", c.getDescription());
o.addProperty("fallback", c.getFallback());
o.addProperty("welcome", c.getWelcome());
o.addProperty("workmode", c.getWorkmode());
o.addProperty("channel", c.getChannel());
o.addProperty("snsid", c.getSnsAccountIdentifier());
o.addProperty("enabled", c.isEnabled());
// SNSAccount
SNSAccount snsAccount = snsAccountRes.findBySnsidAndOrgi(c.getSnsAccountIdentifier(), orgi);
if (snsAccount == null) {
chatbotRes.delete(c); // 删除不存在snsAccount的机器人
continue; // 忽略不存在snsAccount的机器人
}
o.addProperty("snsurl", snsAccount.getBaseURL());
// 创建人
User user = userRes.findById(c.getCreater());
if (user != null) {
o.addProperty("creater", c.getCreater());
o.addProperty("creatername", user.getUname());
}
ja.add(o);
}
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
resp.add("data", ja);
resp.addProperty("size", records.getSize()); // 每页条数
resp.addProperty("number", records.getNumber()); // 当前页
resp.addProperty("totalPage", records.getTotalPages()); // 所有页
resp.addProperty("totalElements", records.getTotalElements()); // 所有检索结果数量
return resp;
}
/**
* 删除聊天机器人
*
* @param j
* @param uid
* @param orgi
* @return
*/
private JsonObject delete(final JsonObject j, final String uid, final String orgi) {
JsonObject resp = new JsonObject();
if ((!j.has("id")) || StringUtils.isBlank(j.get("id").getAsString())) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的参数未传入id。");
return resp;
}
final String id = j.get("id").getAsString();
Chatbot c = chatbotRes.findOne(id);
if (c == null) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的参数,不存在该聊天机器人。");
return resp;
}
// 更新访客网站配置
CousultInvite invite = OnlineUserProxy.consult(c.getSnsAccountIdentifier(), c.getOrgi());
if (invite != null) {
invite.setAi(false);
invite.setAiname(null);
invite.setAisuccesstip(null);
invite.setAifirst(false);
invite.setAiid(null);
consultInviteRes.save(invite);
OnlineUserProxy.cacheConsult(invite);
}
chatbotRes.delete(c);
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
resp.addProperty(RestUtils.RESP_KEY_DATA, "删除成功。");
return resp;
}
/**
* 创建聊天机器人
*
* @param j
* @param creater
* @param orgi
* @return
*/
private JsonObject create(final JsonObject j, final String creater, final String orgi) throws Exception {
JsonObject resp = new JsonObject();
String snsid = null;
String workmode = null;
String clientId = null;
String secret = null;
if ((!j.has("clientId")) || StringUtils.isBlank(j.get("clientId").getAsString())) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的参数未传入【clientId】。");
return resp;
} else {
clientId = j.get("clientId").getAsString();
}
if ((!j.has("secret")) || StringUtils.isBlank(j.get("secret").getAsString())) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的参数未传入【secret】。");
return resp;
} else {
secret = j.get("secret").getAsString();
}
if (!(j.has("workmode") && Constants.CHATBOT_VALID_WORKMODELS.contains(j.get("workmode").getAsString()))) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的参数未传入有效【workmode】。");
return resp;
} else {
workmode = j.get("workmode").getAsString();
}
if ((!j.has("snsid")) || StringUtils.isBlank(j.get("snsid").getAsString())) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的参数未传入【snsid】。");
return resp;
} else {
snsid = j.get("snsid").getAsString();
// #TODO 仅支持webim
if (!snsAccountRes.existsBySnsidAndSnstypeAndOrgi(snsid, Constants.CHANNEL_TYPE_WEBIM, orgi)) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的参数不存在【snsid】对应的网站渠道。");
return resp;
}
if (chatbotRes.existsBySnsAccountIdentifierAndOrgi(snsid, orgi)) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的参数该渠道【snsid】已经存在聊天机器人。");
return resp;
}
}
if (chatbotRes.existsByClientIdAndOrgi(clientId, orgi)) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的参数,数据库中存在该聊天机器人。");
return resp;
}
try {
logger.info("create bot with url {}", botServiecProvider);
com.chatopera.bot.sdk.Chatbot bot = new com.chatopera.bot.sdk.Chatbot(clientId, secret, botServiecProvider);
if (bot.exists()) { // 该机器人存在clientId 和 Secret配对成功
// 创建成功
Chatbot c = new Chatbot();
JSONObject botDetails = bot.details();
c.setId(MainUtils.getUUID());
c.setClientId(clientId);
c.setSecret(secret);
c.setBaseUrl(botServiecProvider);
c.setDescription(botDetails.getJSONObject("data").getString("description"));
c.setFallback(botDetails.getJSONObject("data").getString("fallback"));
c.setPrimaryLanguage(botDetails.getJSONObject("data").getString("primaryLanguage"));
c.setName(botDetails.getJSONObject("data").getString("name"));
c.setWelcome(botDetails.getJSONObject("data").getString("welcome"));
c.setCreater(creater);
c.setOrgi(orgi);
c.setChannel(Constants.CHANNEL_TYPE_WEBIM);
c.setSnsAccountIdentifier(snsid);
Date dt = new Date();
c.setCreatetime(dt);
c.setUpdatetime(dt);
c.setWorkmode(workmode);
// 默认不开启
boolean enabled = false;
c.setEnabled(enabled);
// 更新访客网站配置
CousultInvite invite = OnlineUserProxy.consult(c.getSnsAccountIdentifier(), c.getOrgi());
invite.setAi(enabled);
invite.setAifirst(StringUtils.equals(Constants.CHATBOT_CHATBOT_FIRST, workmode));
invite.setAiid(c.getId());
invite.setAiname(c.getName());
invite.setAisuccesstip(c.getWelcome());
consultInviteRes.save(invite);
OnlineUserProxy.cacheConsult(invite);
chatbotRes.save(c);
JsonObject data = new JsonObject();
data.addProperty("id", c.getId());
resp.add(RestUtils.RESP_KEY_DATA, data);
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
return resp;
} else {
// 创建失败
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_6);
resp.addProperty(
RestUtils.RESP_KEY_ERROR, "Chatopera云服务该机器人不存在请先创建机器人, 登录 https://bot.chatopera.com");
return resp;
}
} catch (ChatbotException e) {
logger.error("bot create error", e);
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_5);
resp.addProperty(
RestUtils.RESP_KEY_ERROR,
"Chatopera云服务无法访问该机器人请确认【1】该服务器可以访问互联网【2】该聊天机器人已经创建【3】clientId和Secret正确设置。");
return resp;
} catch (MalformedURLException e) {
logger.error("bot request error", e);
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_4);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "Chatopera云服务不合法的聊天机器人服务URL。");
return resp;
}
}
}