引子
最近最火的莫过于ChatGPT了,在自己体验后就想着如何其他同事也能方便的起起来,毕竟独乐乐不如众乐乐,自己注册又是V-P-N,又是国外手机验证,对于大部分同事来说门槛还是高的。现在也有不少小程序,公众号集成了这个能力,但工作中大家还是在企微中,如果能让大家在企微,钉钉这样的工作台上使用,与工作无缝对接,这岂不快哉。
本来周末遛娃一天已经筋疲力尽了,收拾完娃子也跟着睡觉了,哪成想,等把他们哄睡后,23点突然来了精神,就开始捣鼓起来了。
创建企微应用
最近公司刚把内部沟通平台从钉钉切换到企微了,就开始摸索可能的对接方式。 一开始想着和钉钉一样,@机器人时,解析内容,自动回复。结果一查,企微的群机器人没这个功能,只能配置有限的规则,自动回复。在无奈之时,甚至想先用钉钉对接起来,但是没能过了心里这关,毕竟本月刚刚完成了钉钉到企微的全面迁移,迁移过程还问题多多。原本以为此路不通,即将放弃之时,突然看了社区有个回复自建应用可以实现接收用户的消息并主动回复内容(接口文档点这里),一开始觉得用群,热闹一些,效果好些;不过从后来大家问的问题来看,单独应用时,大家放得开些。 喧闹与寂静从来都是相辅相成。企微走了通了,全链路也就用了。(因为国内无法使用的情况,要有一个服务器做请求代理)
话不多说,进入企微后台,进入“应用管理”模块,创建自建应用,如下图。我创建了一个GTP机器应用,配置消息回调地址,IP限制等信息就可以了,配置回调地址时,会有数据验证,下面会说到。
配置代理服务器
因为一些原因,国内无法直接访问,于是购买了一台香港的服务器,安装JKD jdk-8u202-linux-x64.tar.gz,使用RestTemplate发起Http请求, 测试代码比较简单。 代码如下,
HttpHeaders headers = new HttpHeaders(); headers.add("Content-Type", "application/json;charset=UTF-8"); headers.add("Authorization", "Bearer key"); headers.add("OpenAI-Organization", "org-id"); JSONObject textMsg=new JSONObject(); textMsg.put("model", question.getModel()); textMsg.put("temperature",0.7); JSONArray messages = new JSONArray(); JSONObject message = new JSONObject(); message.put("role", "user"); message.put("content", question.getQuestion()); messages.add(message); textMsg.put("messages", messages); HttpEntity<String> request = new HttpEntity<>(JSONObject.toJSONString(textMsg), headers); ResponseEntity<JSONObject> responseBody = restTemplate.postForEntity(URL, request, JSONObject.class); JSONObject httpBody = responseBody.getBody(); String answer = httpBody.getJSONArray("choices").getJSONObject(0).getJSONObject("message").getString("content"); System.out.println("接口返回参数:" + httpBody.toJSONString());
其中 key 从api keys 中生成,ogi-id 在组织配置中查询。
通过 Artifacts 方式生成jar, 通过命令 nohup java -jar gpt-test.jar & 跑起来,验证下接口,一次通过,抬头看时间已经2点多了,看起来简单的事儿,也用了快3小时了,真是须知书上得来终觉浅、绝知此事要躬行。
内容回复
之前对接企微时,数据加解密代码已经完成,后面的流程就非常简单了。因为调用GPT接口比较慢,而自建应用要求在5s内回复,所以需要使用异步调用接口,主动回复自建应用。
验证URL有效性
应用配置回调域名时,有一个get 请求校验合法性: 解码收的加密内容,回复消息的明文。
String method = httpServletRequest.getMethod(); if (!"POST".equals(method)) { if (StrUtil.isNotBlank(sVerifyEchoStr)) { String sEchoStr = ""; try { sEchoStr = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce, sVerifyEchoStr); log.info("verifyurl echostr: " + sEchoStr); } catch (Exception e) { //验证URL失败,错误原因请查看异常 log.error("验证失败", e); } response.getWriter().print(sEchoStr); } }
回复
因为等待GPT的时间比较长,所以我们查以先回复一条:“回复正在生成中”,提升下体验,本来可以使用被动回复内容,一直没成功,无奈也用主动回复来完成了。 接着发送一个异步事件,完成接口调用与回复。
String accessToken = this.getAccessToken(sendPersonMessageParam); String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN".replace("ACCESS_TOKEN",accessToken); MessageBody m