# HTTP 框架使用和场景实战 - 结合ChatGLM自动回帖!

作者:小傅哥
博客:https://bugstack.cn (opens new window)

沉淀、分享、成长,让自己和他人都能有所收获!😄

本文的宗旨在于通过简单干净实践的方式教会读者,HTTP的常用框架使用,HTTP接口快速对接方式。以及在编码实战中练习 HTTP 对数据的采集、ChatGLM对接、问题回答。这样的场景学习,非常适合以后大家在做一些智能化问答进行参考使用。

本文涉及的工程:

# 一、案例背景

虽然在分布式架构的微服务内部是RPC调用,但在对外的Web/H5等场景下,则需要使用HTTP协议进行调用。因而我们在对接公司以外的其他服务时,通常都是HTTP协议,包括你对接微信支付、ChatGLM等。当然也有少部分使用 websocket 协议。

但众所周知HTTP的调用,会涉及较多的信息配置。包括;请求头、入参、出参,而这些内容都是非对象化的设计。很多人在对接特别多的 HTTP 请求以后,自己的工程代码就会变得非常混乱。所以我们需要用一些 HTTP 框架,来解决这个场景问题,让 HTTP 的调用更加优雅。

那么本章节小傅哥会结合知识星球的接口进行案例场景学习;

  1. 星球免费加入https://wx.zsxq.com/dweb2/index/group/28885518425541 (opens new window)
  2. 本章节所提供的课程源码,即可复现截图中的展示内容。自动化Ai回复问答。

# 二、接口提取

接下来,小傅哥会告诉如何非常快速的使用Java代码对接上HTTP调用。—— 把🐘大象装冰箱统共分3步;

# 1. 第一步

# 2. 第二步

  • 首先,打开 ApiPost (opens new window) 工具中,如果没有可以下载一个。
  • 之后,点击左侧的导入接口,这个里面可以直接把 cURL 格式接口导入进去。
  • 最后,点击立即导入 - 导入后你就可以点击发送按钮测试验证了。

# 3. 第三步

  • 首先,点击生成代码,会弹出一个各类语言对接代码案例。
  • 之后,在你需要的类型代码上复制生成的代码。
  • 最后,把代码粘贴到Java工程中测试。这部分代码可以参考案例工程 cn.bugstack.xfg.dev.tech.test#HttpClientTest|OKHttpTest|Retrofit2Test

除此之外,你还可以使用Ai工具,来生成对接的测试代码。

  • 这样的方式也是非常好用的,而且如果有运行问题,你还可以继续提问。
  • 用编程经验的人用 OpenAi 会更舒服,没有编程经验的人完全依赖 OpenAi 也会遇到各种错误。

# 三、玩个场景

# 1. 需求说明

接下来,我结合所学技术锻炼下。结合星球完成一个自动Ai回贴的功能,通过定时任务扫描星球接口帖子,并对未回答且圈【@小傅哥】的帖子进行采集回答。

# 2. 工程结构

  • 首先,你可以下载工程代码,按照这个结构来看代码。
  • 之后,工程中对接了 ChatGLM SDK 并做了相关的配置在YML中。此外 YML中的 ChatGLM SDK 需要的 ApiSecretKey 可以通过官网申请。之后星球的 cookie 可以通过 F12 请求头中复制 Cookie 信息。
  • 最后,是 ZSXQJob 的开发使用。

# 3. 代码实现

# 4.1 ChatGLM SDK 对接

源码cn.bugstack.xfg.dev.tech.config.ChatGLMSDKConfig

@Bean
@ConditionalOnProperty(value = "chatglm.sdk.config.enabled", havingValue = "true", matchIfMissing = false)
public OpenAiSession openAiSession(ChatGLMSDKConfigProperties properties) {
    // 1. 配置文件
    cn.bugstack.chatglm.session.Configuration configuration = new cn.bugstack.chatglm.session.Configuration();
    configuration.setApiHost(properties.getApiHost());
    configuration.setApiSecretKey(properties.getApiSecretKey());
    // 2. 会话工厂
    OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);
    // 3. 开启会话
    return factory.openSession();
}
1
2
3
4
5
6
7
8
9
10
11
12
  • 因为我们需要一个自动的智能Ai回帖,所以需要使用到 ChatGLM (opens new window)。当然你也可以对接其他大厂开发的 OpenAi SDK 使用。

# 4.2 流程串联

源码cn.bugstack.xfg.dev.tech.job.ZSXQJob

@Scheduled(cron = "0/10 * * * * ?")
public void exec() throws Exception {
    Response response = getResponse(cookie);
    RespData respData = response.getRespData();
    List<TopicsItem> topics = respData.getTopics();
    for (TopicsItem topicsItem : topics) {
        // 是否回答过判断
        if (!isCommentDone(topicsItem)) continue;
        // 找到圈我我帖子
        long topicId = topicsItem.getTopicId();
        Talk talk = topicsItem.getTalk();
        // "<e type="mention" uid="241858242255511" title="%40%E5%B0%8F%E5%82%85%E5%93%A5" /> 提问 java 冒泡排序"
        String text = talk.getText();
        // 正在匹配处理
        String regex = "<e type=\"mention\" uid=\"(\\d+)\" title=\"(.*?)\" /> (.*)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);
        if (matcher.find()) {
            String uid = matcher.group(1);
            String remainingText = matcher.group(3);
            if ("241858242255511".equals(uid)) {
                if (null == openAiSession) {
                    log.info("你没有开启 ChatGLM 参考yml配置文件来开启");
                    // 你可以使用 ChatGLM SDK 进行回答,回复问题;
                    comment(cookie, topicId, "【测试,只回答圈我的帖子】对接 ChatGLM SDK https://bugstack.cn/md/project/chatgpt/sdk/chatglm-sdk-java.html 回答:" + remainingText);
                } else {
                    log.info("ChatGLM 进入回答 {} {}", topicId, remainingText);
                    if (topicIds.contains(topicId)){
                        continue;
                    } else {
                        topicIds.add(topicId);
                    }
                    new Thread(() -> {
                    
                        // 入参;模型、请求信息
                        ChatCompletionRequest request = new ChatCompletionRequest();
                        request.setModel(Model.CHATGLM_LITE); // chatGLM_6b_SSE、chatglm_lite、chatglm_lite_32k、chatglm_std、chatglm_pro
                        request.setPrompt(new ArrayList<ChatCompletionRequest.Prompt>() {
                            private static final long serialVersionUID = -7988151926241837899L;
                            {
                                add(ChatCompletionRequest.Prompt.builder()
                                        .role(Role.user.getCode())
                                        .content(remainingText)
                                        .build());
                            }
                        });
                        
                        // 请求
                        try {
                            StringBuilder content = new StringBuilder();
                            openAiSession.completions(request, new EventSourceListener() {
                                @Override
                                public void onEvent(EventSource eventSource, @Nullable String id, @Nullable String type, String data) {
                                    ChatCompletionResponse chatCompletionResponse = com.alibaba.fastjson.JSON.parseObject(data, ChatCompletionResponse.class);
                                    log.info("测试结果 onEvent:{}", chatCompletionResponse.getData());
                                    // type 消息类型,add 增量,finish 结束,error 错误,interrupted 中断
                                    if (EventType.finish.getCode().equals(type)) {
                                        ChatCompletionResponse.Meta meta = com.alibaba.fastjson.JSON.parseObject(chatCompletionResponse.getMeta(), ChatCompletionResponse.Meta.class);
                                        log.info("[输出结束] Tokens {}", com.alibaba.fastjson.JSON.toJSONString(meta));
                                    }
                                    content.append(chatCompletionResponse.getData());
                                }
                                @Override
                                public void onClosed(EventSource eventSource) {
                                    log.info("对话完成");
                                    // 你可以使用 ChatGLM SDK 进行回答,回复问题;
                                    comment(cookie, topicId, "ChatGLM 回答:" + content);
                                    topicIds.remove(topicId);
                                }
                            });
                        } catch (JsonProcessingException e) {
                            throw new RuntimeException(e);
                        }
                    }).start();
                }
            }
        }
    }
}    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
  • 以上代码就是自动智能Ai回贴的流程代码,因为是做示例,所以没有按照职责边界做拆分。
  • 这段代码中会扫码帖子,并对符合流程需要我【@小傅哥】回答的帖子,进行采集和回答。
  • 回答帖子会创建一个线程,调用 ChatGLM 并对返回的流式数据最封装。最后在完成时候,进行回答操作。
  • 注意,这里因为限定的判断了 uId = 241858242255511 所以只有@小傅哥,才会回答。你也可以通过回复帖子,查看自己的 uId 替换。
  • 此外,更多的细节代码,可以参考工程。

# 四、测试验证

# 1. 环境配置

chatglm:
  sdk:
    config:
      # 状态;true = 开启、false 关闭
      enabled: true
      # 官网地址
      api-host: https://open.bigmodel.cn/
      # 官网申请 https://open.bigmodel.cn/usercenter/apikeys
      api-secret-key: 4e087e4135306ef4a676f0cce*****.sgP2D*****
      # 知识星球 Cookie 你需要获取你的 cookie 登录
      cookie: zsxq_access_token=86EB23*****
1
2
3
4
5
6
7
8
9
10
11
  • 首先你需要在 application-dev.yml 配置相关的信息,这些信息可以从下面的说明中获取。
  • 如果你暂时又申请不到 ChatGLM 还想测试,可以把 enabled 配置为 false

# 1.1 获取 ChatGLM ApiSecretKey

# 2. 启动程序和回贴

# 2.1 发个帖子

  • 注意要圈小傅哥发帖子,如果你程序中修改了uId 为自己,那么可以圈你提问。

# 2.2 回复帖子

- 这个是你就会看到后台会快速运行检测帖子和回答。 - 好啦,运行到这就全部完成了。你也可以去做做测试了。