logo
6

「实践案例」集成千帆大模型应用,实现企业微信被动消息聊天服务

一、IDEA构建springboot应用脚手架

引入springboot-coloud-star等基础依赖
基础技能相信学java都会。

二、企业微信自建应用与后台服务实现交互

  1. 已需要下载PC版企业微信,并且注册自己的企业,主要为了获取企业ID等与企业微信服务打通,登录企业管理后台企业微信
  2. 选择自建应用,新建自己的应用,如下,我自建一个小应用就叫【文心一言】
3.点击我的企业,获取企业scorpId
4.设置应用与自己的后台应用的消息接口API
该接口API就是企业微信自建应用与我后台交互的关键,具体实现步骤如下:
  • 在springboot项目的配置文件中配置当前企业微信的企业sCorpID、sToken、sEncodingAESKey,后两项可以通过API接收消息界面动态随机获取,也可以自己生成。
  • 关键代码,按照企业微信自建应用消息的开发文档,必须实现两个请求方式为GET和POST的相同接口URL的接口:
  • GET请求:
  
  
  
  
  
  
@GetMapping("/checkURL")
public String validEntWeChatURL(HttpServletRequest request) {
logger.info("AiManagerController validEntWeChatURL validEntWeChatURL={}", request);
String sReplyEchoStr = null;
//微信加签
String sMsg_signature = request.getParameter("msg_signature");
//解析url
String sTimestamp = request.getParameter("timestamp");
String SNonce = request.getParameter("nonce");
String SEchostr = request.getParameter("echostr");
try {
sReplyEchoStr = cryptUtil.getCrypt().VerifyURL(sMsg_signature, sTimestamp, SNonce, SEchostr);
} catch (AesException e) {
logger.error("AiManagerController validEntWeChatURL err={}", e);
}
logger.info("AiManagerController validEntWeChatURL sReplyEchoStr={},微信验签成功!", sReplyEchoStr);
return sReplyEchoStr;
}
POST请求
  
  
  
  
  
  
/**
* 接收企业微信的消息
*
* @param request
* @return
*/
@PostMapping("/checkURL")
public String getEntWXMsg(HttpServletRequest request, HttpServletResponse response) {
String respMsg = "";
//微信加签
String sMsg_signature = request.getParameter("msg_signature");
//解析url
String sTimestamp = request.getParameter("timestamp");
String SNonce = request.getParameter("nonce");
try {
ServletInputStream inputStream = request.getInputStream();
String sReqData = IoUtils.toString(inputStream, "UTF-8");
String sReplyEchoStr = cryptUtil.getCrypt().DecryptMsg(sMsg_signature, sTimestamp, SNonce, sReqData);
//解析xml数据
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
StringReader sr = new StringReader(sReplyEchoStr);
InputSource is = new InputSource(sr);
Document document = db.parse(is);
Element root = document.getDocumentElement();
NodeList nodelist1 = root.getElementsByTagName("Content");
String content = nodelist1.item(0).getTextContent();
//获取成员UserID
NodeList nodelist2 = root.getElementsByTagName("FromUserName");
String fromUserName = nodelist2.item(0).getTextContent();
//返回的消息内容
// logger.info("AiManagerController getEntWXMsg Content:{}", content);
String baiduRespMsg = baiduAPIUtil.call_ERNIEBot(content, fromUserName);
// logger.info("AiManagerController call_ERNIE_Bot baiduRespMsg:{}", baiduRespMsg);
//回复的消息
EntWXResp resp = new EntWXResp();
resp.setFromUserName(cryptUtil.getWxProperties().getSCorpID());
resp.setToUserName(fromUserName);
resp.setContent(baiduRespMsg);
resp.setMsgType("text");
resp.setCreateTime(DateUtil.date().toStringDefaultTimeZone());
//拼装被动消息返回体
//生成xml 字符串
String xmlMsg = "<xml>\n" +
" <ToUserName><![CDATA[" + resp.getToUserName() + "]]></ToUserName>\n" +
" <FromUserName><![CDATA[" + resp.getFromUserName() + "]]></FromUserName> \n" +
" <CreateTime>" + resp.getCreateTime() + "</CreateTime>\n" +
" <MsgType><![CDATA[" + resp.getMsgType() + "]]></MsgType>\n" +
" <Content><![CDATA[" + resp.getContent() + "]]></Content>\n" +
"</xml>\n";
// logger.info("AiManagerController call_ERNIE_Bot xmlMsg =:{}", xmlMsg);
//加密返回
respMsg = cryptUtil.getCrypt().EncryptMsg(xmlMsg, sTimestamp, SNonce);
logger.info("AiManagerController cryptUtil.EncryptMsg respMsg ={}", respMsg);
} catch (AesException e) {
logger.error("AiManagerController getEntWXMsg err={}", e);
} catch (ParserConfigurationException e) {
logger.error("AiManagerController getEntWXMsg err={}", e);
} catch (IOException e) {
logger.error("AiManagerController getEntWXMsg err={}", e);
} catch (SAXException e) {
logger.error("AiManagerController getEntWXMsg err={}", e);
}
return respMsg;
}

三、集成百度文心一言应用API

  • 登录,自建模型应用,获取AK,SK
在服务配置文件application.yml配置好该参数:
  
  
  
  
  
  
##百度文心千帆AI接口配置
baidu:
client_id: j3tpU0KhE3Iwewewew
client_secret: PLSEAb8yXTzGasewewewewnDA7wew
grant_type: client_credentials
  • 按照百度接口文档,开发相应API实现,调用API,zhiqian buxyo huoqu TOKEN
  
  
  
  
  
  
/**
* 获取百度云应用 的access_token
*
* @return
*/
public BaiduApiResp getBaiDuAccessToken() {
//设置百度缓存的 key
String reinsCacheToken = String.format(ACCEESS_TOKEN_KEY, CLIENT_ID);
if (redisService.hasKey(reinsCacheToken)) {
BaiduApiResp cacheObject = redisService.getCacheObject(reinsCacheToken);
logger.info("BaiduAPIUtil getBaiDuAccessToken ={}", cacheObject);
return cacheObject;
}
BaiduApiResp resp = new BaiduApiResp();
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("client_id", CLIENT_ID);
paramMap.put("client_secret", CLIENT_SECRET);
paramMap.put("grant_type", GRANT_TYPE);
String returnMsg = HttpUtil.post(BAIDU_URL, paramMap);
JSONObject respons = JSONUtil.parseObj(returnMsg);
if (!StrUtil.isEmptyIfStr(respons.getStr("error"))) {
logger.error("BaiduAPIUtil getBaiDuAccessToken err={},error_description={}",
respons.getStr("error"),
respons.getStr("error_description"));
return resp;
}
//获取token
String access_token = respons.getStr("access_token");
resp.setAccess_token(access_token);
//获取有效期
Integer expires_in = respons.getInt("expires_in");
resp.setExpires_in(expires_in);
//当如缓存,过期再取
redisService.setCacheObject(reinsCacheToken, resp, Long.valueOf(expires_in), TimeUnit.SECONDS);
return resp;
}
  
  
  
  
  
  
/**
* ERNIE-Bot是百度自行研发的大语言模型,
* 覆盖海量中文数据,具有更强的对话问答、内容创作生成等能力。
*
* @return
*/
public String call_ERNIEBot(String askStr, String userId) {
logger.info("BaiduAPIUtil call_ERNIEBot askStr={},userId={}", askStr, userId);
// 添加请求头信息
Map<String, String> heads = new HashMap<>();
heads.put("Content-Type", "application/json");
Map<String, String> urlParmMap = new HashMap<>();
urlParmMap.put("access_token", getBaiDuAccessToken().getAccess_token());
String realUrl = ERNIE_BOT_URL + URLUtil.buildQuery(urlParmMap, CharsetUtil.CHARSET_UTF_8);
//创建json对象作为requestBody
MessageVo message = new MessageVo();
message.setRole("user");
message.setContent(askStr);
List<MessageVo> messages = new ArrayList<>();
messages.add(message);
JSONObject jsonObject = new JSONObject();
jsonObject.set("messages", messages.toArray());
jsonObject.set("stream", Boolean.TRUE);
//用户id
jsonObject.set("user_id", userId);
System.out.println(JSONUtil.toJsonStr(jsonObject));
HttpResponse returnMsg = HttpRequest.post(realUrl).headerMap(heads, false)
.body(String.valueOf(jsonObject))
.execute();
String result = StrUtil.EMPTY;
JSONObject response = JSONUtil.parseObj(returnMsg);
String status = response.getStr("status");
if ("200".equals(status)) {
byte[] bytes = returnMsg.body().getBytes();
result = new String(bytes);
String[] split = result.split("\n");
StringBuffer buffer = new StringBuffer();
for (String s : split) {
if(s.contains("data")){
String subStr = s.substring(s.indexOf("{")-1);
JSONObject entries = JSONUtil.parseObj(subStr);
buffer.append(entries.getStr("result"));
}
}
logger.info("BaiduAPIUtil call_ERNIEBot result={}", buffer);
return buffer.toString();
}
return result;
}

四、最终实现效果:

注意点:
  • 企业微信设置API接收必须要是企业申请的域名URL,所以测试成本有点高,适合企业开发。
  • 其次,微信对接口响应有要求,对接百度的接口必须在1s内有响应,否则企业微信后台会丢弃该次请求。这会导致我们向企业微信发送消息不会有回应。之后在5s内,企业微信会幂等性的重试3次,所以我在实际业务中,调用边度文心一言的接口中加了缓存处理,保持5s内企业微信调用我们后台获取消息一定会有内容响应。
————————————————
版权声明:本文为CSDN博主「安吉弥勒」的原创文章
原文链接:https://blog.csdn.net/qq_20551879/article/details/132216726
如有侵权,请联系千帆社区进行删除
评论
用户头像