ChatGPT est devenu un grand succès récemment, et le patron est également prêt à nous demander de connecter ChatGPT à Feishu. Après une matinée de recherche, nous avons finalement réussi à enregistrer et à connecter le robot Feishu à ChatGPT.
Ce qui suit partagera avec vous les étapes détaillées pour accéder à Feishu.
L'interaction entre Feishu et chatgpt est la suivante. Notre service personnalisé agit comme intermédiaire pour transférer les messages.
1 Entrez dans la plateforme ouverte Feishu et choisissez de créer une application auto-construite pour l'entreprise.
2. Après avoir créé l'application, cliquez pour accéder à l'application et ajouter le robot.
3. Configurez les autorisations liées aux messages pour le robot Si vous n'êtes pas sûr des autorisations requises, vous pouvez d'abord les activer.
4. Configurez l'abonnement à l'événement. L'abonnement à l'événement nécessite d'abord de développer une interface que Feishu doit vérifier. L'interface doit être accessible depuis le réseau public.
Le code de cette interface peut être référencé comme suit :
@PostMapping(value = "/message") public FeishuEventDTO message(@RequestBody String body) { log.info("收到消息:{}", body); FeishuEventParams feishuEventParams = JSON.parseObject(body, FeishuEventParams.class); FeishuEventDTO eventDTO = new FeishuEventDTO(); eventDTO.setChallenge(feishuEventParams.getChallenge()); return eventDTO; } @Data public class FeishuEventParams { private String challenge; private String token; private String type; } @Data public class FeishuEventDTO { private String challenge; }
Une chose à noter est que cette interface de vérification a la même adresse que l'interface ci-dessous pour recevoir les messages Feishu, mais le corps du message est différent.
C'est-à-dire que l'interface de vérification est à usage unique. Après vérification, cette interface doit être modifiée.
Nous publions d'abord cette interface sur un projet accessible depuis le réseau public. Par exemple, l'adresse de l'interface est
https://www.php.cn/link/4aee31b0ec9f7bb7885473d95961e9a6
OK, la configuration de Feishu se fait essentiellement ici. Voici la logique que nous devons traiter.
Tout d'abord, parlons de la logique générale de l'amarrage de notre entreprise pour votre référence.
Après qu'un utilisateur envoie un message à Feishu, Feishu transmettra le message à notre propre service.
Mais il y aura un problème ici, c'est-à-dire que lorsque plusieurs utilisateurs lancent des conversations simultanément, ou lorsque de nombreuses personnes dans un grand groupe sont @notre robot, nous devons nous souvenir de la réponse de chacun après que chatgpt ait interrogé les résultats, répondez à cette personne. avec précision.
Étant donné que notre société l'utilise actuellement pour des tests internes et ne souhaite pas que la mise en œuvre soit trop compliquée, l'idée que nous adoptons est la suivante : lorsque la session de chaque utilisateur est transmise à notre service, le contenu de la session est d'abord enregistré dans une file d'attente globale ConcurrentLinkedQueue. , puis démarrez un thread et consommez continuellement cette file d'attente.
Le type générique de file d'attente est un objet construit à l'avance. Cet objet stocke l'ID du message en cours, l'expéditeur, le contenu de la question, etc.
Chaque fois qu'un objet est consommé, le contenu de la question de l'objet est envoyé à chatgpt Après avoir obtenu le résultat de la réponse, l'interface de réponse de session fournie par Feishu est appelée pour répondre à l'utilisateur. (Si le degré de concurrence est relativement important, il peut être rendu asynchrone ici).
D'accord, c'est tout pour l'idée générale, jetons un œil au code spécifique.
1. Ouvrez notre projet et présentez le pot fourni par chatgpt.
<dependency> <groupId>com.theokanning.openai-gpt3-java</groupId> <artifactId>service</artifactId> <version>0.10.0</version> </dependency>
2, réécrivez l'interface de vérification ci-dessus et modifiez-la pour recevoir les messages Feishu. (Ne changez pas le chemin de l'interface)
@Slf4j @RestController @RequestMapping(value = "/query") public class QureyController { public static ConcurrentLinkedQueue<FeishuResponse> consumer = new ConcurrentLinkedQueue<>(); @PostMapping(value = "/message") public String message(@RequestBody String body) { log.info("收到飞书消息:{}", body); JSONObject jsonObject = JSONObject.parseObject(body); JSONObject header = jsonObject.getJSONObject("header"); String eventType = header.getString("event_type"); if ("im.message.receive_v1".equals(eventType)) { JSONObject event = jsonObject.getJSONObject("event"); JSONObject message = event.getJSONObject("message"); String messageType = message.getString("message_type"); if ("text".equals(messageType)) { String messageId = message.getString("message_id"); String content = message.getString("content"); JSONObject contentJson = JSON.parseObject(content); String text = contentJson.getString("text"); FeishuResponse feishuResponse = new FeishuResponse(); feishuResponse.setMessageId(messageId); feishuResponse.setQuery(text); log.info("投递用户消息,{}", JSON.toJSON(feishuResponse)); consumer.add(feishuResponse); } else { log.info("非文本消息"); } } return "suc"; } }
La structure de FeishuResponse est la suivante.
@Data public class FeishuResponse { private String messageId; private String query; }
3. Écrivez un fil de discussion.
@Slf4j public class AutoSendTask implements Runnable { //你的chatgpt的key public static final String token = ""; public static OpenAiService openAiService = null; static { openAiService = new OpenAiService(token, Duration.ofSeconds(60)); } @Override public void run() { while (true) { try { FeishuResponse poll = consumer.poll(); if (poll == null) { log.info("no query,sleep 2s"); TimeUnit.SECONDS.sleep(2); } else { String query = this.query(poll.getQuery()); this.reply(poll, query); } } catch (InterruptedException e) { log.error("Thread exception...", e); } } } private String query(String q) { log.info("开始提问:{}", q); CompletionRequest completionRequest = CompletionRequest.builder() .prompt(q) .model("text-davinci-003") .maxTokens(2048) .echo(false) .build(); StringBuilder sb = new StringBuilder(); CompletionResult completion = openAiService.createCompletion(completionRequest); log.info("q:{},获取响应:{}", q, JSON.toJSONString(completion)); completion.getChoices().forEach(v -> { sb.append(v.getText()); }); String rs = sb.toString(); if (rs.startsWith("?")) { rs = rs.replaceFirst("?", ""); } if (rs.startsWith("nn")) { rs = rs.replaceFirst("nn", ""); } log.info("格式化后的rs:{}", rs); return rs; } private String reply(FeishuResponse poll, String rs) { JSONObject params = new JSONObject(); params.put("uuid", RandomUtil.randomNumbers(10)); params.put("msg_type", "text"); JSONObject content = new JSONObject(); content.put("text", rs); params.put("content", content.toJSONString()); String url = String.format("https://open.feishu.cn/open-apis/im/v1/messages/%s/reply", poll.getMessageId()); String tenantAccessToken = FeishuUtils.getTenantAccessToken(); String body = null; try (HttpResponse authorization = HttpUtil.createPost(url) .header("Authorization", "Bearer " + tenantAccessToken) .body(params.toJSONString()) .execute()) { body = authorization.body(); } return body; } }
La classe d'outils pour obtenir le jeton Feishu est la suivante :
@Slf4j public class FeishuUtils { public static final String tokenUrl = "https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal/"; //构建一个cache 缓存飞书的token static Cache<String, String> tokenCache = CacheBuilder.newBuilder().expireAfterWrite(Duration.ofSeconds(3500)).build(); //这个是飞书应用的appid和key,可以在创建的飞书应用中找到 public static final String appId = ""; public static final String appKey = ""; public static String getTenantAccessToken() { String token = null; try { token = tokenCache.get("token", () -> { JSONObject params = new JSONObject(); params.put("app_id", appId); params.put("app_secret", appKey); String body; try (HttpResponse execute = HttpUtil.createPost(tokenUrl) .body(params.toJSONString()).execute()) { body = execute.body(); } log.info("获取飞书token:{}", body); if (StrUtil.isNotBlank(body)) { String tenantAccessToken = JSON.parseObject(body).getString("tenant_access_token"); tokenCache.put("token", tenantAccessToken); return tenantAccessToken; } return null; }); } catch (ExecutionException e) { throw new RuntimeException(e); } return token; } }
4. Démarrez simplement la classe de fil.
Enfin, pour des raisons de confidentialité, l'effet de la conversation de groupe chatgpt ne sera pas affiché. Montrons l'effet du robot de conversation directe.
Puisque nous n'avons introduit chatgpt qu'avec une attitude d'essai, le code est relativement approximatif s'il y a quelque chose de mal écrit, j'espère que tout le monde me pardonnera.
Les fichiers jar supplémentaires introduits dans le code de cet article incluent : guava, hutool-all et fastjson.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!