6
「实践案例」集成千帆大模型应用,实现企业微信被动消息聊天服务
大模型开发/实践案例
- 文心大模型
2023.11.0910428看过
一、IDEA构建springboot应用脚手架
引入springboot-coloud-star等基础依赖
基础技能相信学java都会。
二、企业微信自建应用与后台服务实现交互
-
已需要下载PC版企业微信,并且注册自己的企业,主要为了获取企业ID等与企业微信服务打通,登录企业管理后台企业微信
-
选择自建应用,新建自己的应用,如下,我自建一个小应用就叫【文心一言】
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");//解析urlString 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");//解析urlString 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();//获取成员UserIDNodeList 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: j3tpU0KhE3Iwewewewclient_secret: PLSEAb8yXTzGasewewewewnDA7wewgrant_type: client_credentials
-
按照百度接口文档,开发相应API实现,调用API,zhiqian buxyo huoqu TOKEN
/*** 获取百度云应用 的access_token** @return*/public BaiduApiResp getBaiDuAccessToken() {//设置百度缓存的 keyString 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;}//获取tokenString 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对象作为requestBodyMessageVo 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);//用户idjsonObject.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
如有侵权,请联系千帆社区进行删除
评论