2023最新!QQ接入ChatGpt!!!保姆级教程

这篇具有很好参考价值的文章主要介绍了2023最新!QQ接入ChatGpt!!!保姆级教程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

直接先上gitee!!! 基于go-cqhttp的qqbot: java实现基于cqhttp,ws连接 由于当前chatgpt热度不断,网上众多的基于chatgpt提供的api做到chat网站层出不穷,但这些网址每次都得找,有些麻烦,我就在想能不能直接QQ接入chatgpt,想法一出,开始找资料开干!

1.申请一个openai官网的key

这一步首先你得有一个翻墙梯子,去openai官网来注册一个账号,这一步不会的猿猿先去找找这种注册的教程。 注册完毕后,我们去openai官网个人首页去申请一个API keys

2023最新!QQ接入ChatGpt!!!保姆级教程

到此,就拿到了openai的APIkey

2.go-cqhttp的使用

使用 mirai 以及 MiraiGo 开发的 cqhttp golang 原生实现, 并在 cqhttp 原版 的基础上做了部分修改和拓展。 使用这个的目的是为了接入qq。 直接上它的git: GitHub - Mrs4s/go-cqhttp: cqhttp的golang实现,轻量、原生跨平台. 之后下载它 Releases · Mrs4s/go-cqhttp · GitHub

2023最新!QQ接入ChatGpt!!!保姆级教程

系统类型 可执行文件 压缩文件
Intel 版 Macos Not available go-cqhttp_darwin_amd64.tar.gz
M1 版 Macos Not available go-cqhttp_darwin_arm64.tar.gz
32 位 Linux Not available go-cqhttp_linux_386.tar.gz
64 位 Linux Not available go-cqhttp_linux_amd64.tar.gz
arm64 Linux Not available go-cqhttp_linux_arm64.tar.gz
armv7 Linux Not available go-cqhttp_linux_armv7.tar.gz
32 位 Windows go-cqhttp_windows_386.exe go-cqhttp_windows_386.zip
64 位 Windows go-cqhttp_windows_amd64.exe go-cqhttp_windows_amd64.zip
arm64 Windows go-cqhttp_windows_arm64.exe go-cqhttp_windows_arm64.zip
armv7 Windows go-cqhttp_windows_armv7.exe go-cqhttp_windows_armv7.zip

我先用window来进行讲解了:

2023最新!QQ接入ChatGpt!!!保姆级教程

cmd运行它,我们先使用正向websocket连接 选择完毕,我们可以看到一个config.yml配置文件 我们来进行配置: 修改device.json文件: 将这个protocol设为2(手表)或0(mac)才可以扫码登录! 修改完后,重新启动该程序,完成qq的登录验证,正常完成验证的情况下,就会出现登录成功! 注意一定要用扫码登录!由于QQ风控越来越严了,所以用密码登录会报错45或235 到此,这个go-cqhttp服务就已经启动成功了! 由于我们采用的是websocket正向连接,所以,我们就需要写一个websocket客户端来进行接收:

@ClientEndpoint
@Slf4j
public class BotClient {
    private Session session;
    public static BotClient instance;
    public static boolean isOpen = false;
    /*
     * 提供一个spring context上下文(解决方案)
     */
    private static ApplicationContext applicationContext;
    public static Count count;
    //    单例模式,只生成一个客户端连接对象
    private BotClient(String url) {
        try {
            session = ContainerProvider.getWebSocketContainer().connectToServer(this, URI.create(url));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void setApplicationContext(ApplicationContext applicationContext) {
       BotClient.applicationContext = applicationContext;
       count = applicationContext.getBean(Count.class);
    }
​
    /**
     * 创建连接
     * @param url
     * @return
     */
    public synchronized static boolean connect(String url) {
        instance = new  BotClient(url);
        return true;
    }
​
    /**
     * 连接前处理
     * @param session
     */
    @OnOpen
    public void onOpen(Session session) {
        isOpen = true;
        log.info("连接成功!");
    }
​
    /**
     * 连接关闭处理
     * @param session
     */
    @OnClose
    public void onClose(Session session) {
        isOpen = false;
        log.info("连接关闭!");
    }
​
    /**
     * 错误时处理
     * @param session
     * @param throwable
     */
    @OnError
    public void onError(Session session, Throwable throwable) {
        log.info("连接错误!");
    }
​
    /**
     * 接收到消息时处理
     * @param message
     */
    @OnMessage
    public void onMessage(String message) {
//        加好友
        if (message.contains("\"request_type\":\"friend\"")) {
            sendFriend(message);
        }
//        私信
        if (message.contains("\"post_type\":\"message\"") && message.contains("\"message_type\":\"private\"")) {
            sendMsg(message);
        }
//        群消息
        if (message.contains("\"post_type\":\"message\"")&& message.contains("\"message_type\":\"group\""))  {
            sendGroupMsg(message);
        }
    }
​
    /**
     * 好友请求
     */
    private synchronized void sendFriend(String msg) {
        Friend parseObject = JSONObject.parseObject(msg, Friend.class);
        log.info("收到好友请求:" + parseObject.getUser_id() + ",验证消息:" + parseObject.getComment());
        Request<Object> paramsRequest = new Request<>();
        paramsRequest.setAction(BotActionEnum.ADD_FRIEND_ACTION.getAction());
        Map<String, Object> params = new HashMap<>();
        params.put("flag", parseObject.getFlag());
        if (parseObject.getComment().equals(count.getAuthor())) {
            params.put("approve", true);
            log.info("已同意好友请求:" + parseObject.getUser_id());
        } else {
            params.put("approve", false);
            log.info("已拒绝好友请求:" + parseObject.getUser_id());
        }
        paramsRequest.setParams(params);
        instance.session.getAsyncRemote().sendText(JSONObject.toJSONString(paramsRequest));
    }
    /**
     * 群消息
     */
    public synchronized  void sendGroupMsg(String msg) {
        System.out.println(msg);
        Message parseObject = JSONObject.parseObject(msg, Message.class);
        log.info("收到群消息" + parseObject.getGroupId() + "的消息,发送者"+parseObject.getUserId()+"消息:"
                + parseObject.getMessage()+"消息id:"+parseObject.getMessageId()
        );
        System.out.println(parseObject.getMessage());
        String mes = parseObject.getMessage();
        if(mes.contains("[CQ:at,qq="+count.getBot_count()+"]")) {
            Request<Object> paramsRequest = new Request<>();
            paramsRequest.setAction(BotActionEnum.SEND_GROUP_MESSAGE.getAction());
            Map<String, Object> params = new HashMap<>();
            params.put("group_id", parseObject.getGroupId());
            String ai = AiOne(parseObject.getMessage(),parseObject.getMessageId());
            if (ai == null) {
                ai = "宝,回复失败!重新试试吧!";
            }
            params.put("message", ai);
            params.put("message_type", "group");
            params.put("auto_escape", false);
            paramsRequest.setParams(params);
            msg = JSONObject.toJSONString(paramsRequest);
            //        回复
            instance.session.getAsyncRemote().sendText(msg);
        }
​
    }
    /**
     * 私信好友消息
     */
    public synchronized void sendMsg(String msg) {
        Message parseObject = JSONObject.parseObject(msg, Message.class);
        log.info("收到好友" + parseObject.getUserId() + "的消息:" + parseObject.getMessage());
        System.out.println("消息:"+parseObject.getMessage());
        Request<Object> paramsRequest = new Request<>();
        paramsRequest.setAction(BotActionEnum.SEND_PRIVATE_MESSAGE.getAction());
        Map<String, Object> params = new HashMap<>();
        params.put("user_id", parseObject.getUserId());
        String ai = AiOne(parseObject.getMessage(),null);
        if (ai == null) {
            ai = "宝,回复失败!重新试试吧!";
        }
        params.put("message", ai);
        params.put("message_type", "private");
        params.put("auto_escape", false);
        paramsRequest.setParams(params);
        msg = JSONObject.toJSONString(paramsRequest);
//        回复
        instance.session.getAsyncRemote().sendText(msg);
    }
    public  String AiOne(String sendMsg,String mes_id) {
        CloseableHttpClient httpClient = null;
        try {
             httpClient= HttpClientBuilder.create().build();
            GptUtils gptUtils = applicationContext.getBean(GptUtils.class);
            if(sendMsg.contains("画一幅图:")){
                log.info("进入到绘图......");
                String initBody = gptUtils.getImageURl(httpClient,sendMsg);
                if(Objects.isNull(mes_id)){
                  String body =initBody;
                    log.info("body:"+body);
                  return body;
                }
                 String body = "[CQ:reply,id="+mes_id+"]"+initBody;
                log.info("body:"+body);
                return body;
            }
            String initBody = gptUtils.getAnswer(httpClient,sendMsg);
            String body = null;
            if(Objects.isNull(mes_id)){
                 body=initBody;
                log.info("body:"+body);
                return body;
            }
            body = "[CQ:reply,id="+mes_id+"]"+initBody;
            log.info("body:"+body);
                return body;
        } catch (Exception e) {
            log.error(e.toString());
            return null;
        }finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                log.error("httpclient关闭失败");
            }
        }
    }
​
}

对于ws连接,我们也可以根据go-cqhttp的api文档来自行定制 api文档:API | go-cqhttp 帮助中心 目前我实现的是群聊,私信的聊天,及生成图片,以及好友请求同意。 项目的技术栈: websocket:连接go-cqhttp httpclient: 请求chatgptapi fastjson:进行序列化/反序列化 oss:图片存储

​
    <dependencies>
 
        <dependency>
 
            <groupId>org.springframework.boot</groupId>
 
            <artifactId>spring-boot-starter</artifactId>
 
        </dependency>
 
​
 
        <dependency>
 
            <groupId>org.springframework.boot</groupId>
 
            <artifactId>spring-boot-devtools</artifactId>
 
            <scope>runtime</scope>
 
            <optional>true</optional>
 
        </dependency>
 
        <dependency>
 
            <groupId>org.springframework.boot</groupId>
 
            <artifactId>spring-boot-configuration-processor</artifactId>
 
            <optional>true</optional>
 
        </dependency>
 
        <dependency>
 
            <groupId>org.projectlombok</groupId>
 
            <artifactId>lombok</artifactId>
 
            <optional>true</optional>
 
        </dependency>
 
        <dependency>
 
            <groupId>org.springframework.boot</groupId>
 
            <artifactId>spring-boot-starter-test</artifactId>
 
            <scope>test</scope>
 
        </dependency>
 
<!--           websocket-->
 
        <dependency>
 
            <groupId>org.springframework.boot</groupId>
 
            <artifactId>spring-boot-starter-websocket</artifactId>
 
        </dependency>
 
<!--        fastjson-->
 
        <dependency>
 
            <groupId>com.alibaba</groupId>
 
            <artifactId>fastjson</artifactId>
 
            <version>1.2.76</version>
 
        </dependency>
 
<!--       httpclient用来请求自动回复API -->
 
        <dependency>
 
            <groupId>org.apache.httpcomponents</groupId>
 
            <artifactId>httpclient</artifactId>
 
            <version>4.5.13</version>
 
        </dependency>
 
        <!--         阿里云 OSS-->
 
        <dependency>
 
            <groupId>com.aliyun.oss</groupId>
 
            <artifactId>aliyun-sdk-oss</artifactId>
 
            <version>3.10.2</version>
 
        </dependency>
 
    </dependencies>
 

3.openAIAPI的使用

这里重点来说说使用openai提供的API的使用: 先到openai官网上,我们先看看官方给的api文档:

2023最新!QQ接入ChatGpt!!!保姆级教程

请求:

curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

参数:

{
  "model": "gpt-3.5-turbo",
  "messages": [{"role": "user", "content": "Hello!"}]
}

响应:

{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1677652288,
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "\n\nHello there, how may I assist you today?",
    },
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 12,
    "total_tokens": 21
  }
}

2023最新!QQ接入ChatGpt!!!保姆级教程

请求:

curl https://api.openai.com/v1/images/generations \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "prompt": "A cute baby sea otter",
    "n": 2,
    "size": "1024x1024"
  }'

参数:

{
  "prompt": "A cute baby sea otter",
  "n": 2,
  "size": "1024x1024"
}

响应:

{
  "created": 1589478378,
  "data": [
    {
      "url": "https://..."
    },
    {
      "url": "https://..."
    }
  ]
}

根据上面的请求响应,第一步肯定是编写VO,之后我们使用httpclient来进行请求的发送,和接收响应 VO类代码就不放这了,直接git上下载源码查看 由于 OpenAI 及 GFW 的双重限制,国内开发者无法访问 OpenAI 的 API,现提供代理服务地址供开发者免费使用. 教程:OpenAI API 代理 完毕,之后就能正常请求该接口了。 编写请求chat聊天的方法:

/**
     * 创建一个ChatGptRequestParameter,用于携带请求参数
     */
    private static ChatGptRequestParameter chatGptRequestParameter = new ChatGptRequestParameter();

    public String getAnswer(CloseableHttpClient client, String question) {
        // 创建一个HttpPost
        HttpPost httpPost = new HttpPost(chatUrl);

        // 设置请求参数
        chatGptRequestParameter.addMessages(new ChatGptMessage(role, question));
        chatGptRequestParameter.setModel(model);
        HttpEntity httpEntity = null;
        try {
            // 对象转换为json字符串
            httpEntity = new StringEntity(JSON.toJSONString(chatGptRequestParameter), charset);
        } catch (Exception e) {
            log.info(question + "->json转换异常");
            return null;
        }
        httpPost.setEntity(httpEntity);
        // 设置请求头
        httpPost.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
        // 设置登录凭证
        httpPost.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + apiKey);

        // 用于设置超时时间
        RequestConfig config = RequestConfig
                .custom()
                .setConnectTimeout(responseTimeout)
                .build();
        httpPost.setConfig(config);
//        接收返回值
        CloseableHttpResponse response = null;
        HttpEntity entity = null;
        try {
            response = client.execute(httpPost);
            entity = response.getEntity();
//            反序列化
            String responseMes = EntityUtils.toString(entity);
//            转为对象
            ChatGptResponseParameter responseParameter = JSON.parseObject(responseMes, ChatGptResponseParameter.class);
            // 遍历所有的Choices(一般都只有一个)
            String ans = "";
            for (Choices choice : responseParameter.getChoices()) {
                log.info("size:" + responseParameter.getChoices().size());
                ChatGptMessage message = choice.getMessage();
                chatGptRequestParameter.addMessages(new ChatGptMessage(message.getRole(), message.getContent()));
                String s = message.getContent().replaceAll("\n+", "\n");
                ans += s;
            }
            return ans;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
//        发生异常重置会话
        chatGptRequestParameter = new ChatGptRequestParameter();
        ;
        return "您当前的网络无法访问,会话已重置";
    }

编写按描述生成图片接口:

public String getImageURl(CloseableHttpClient client, String describe) {
        HttpPost httpPost = new HttpPost(imageGPTUrl);
        ImageGptMessage imageGptMessage = new ImageGptMessage(describe, size, num);
        String jsonString = JSON.toJSONString(imageGptMessage);
        HttpEntity httpEntity = new StringEntity(jsonString,charset);
        //        设置请求参数
        httpPost.setEntity(httpEntity);
        // 设置请求头
        httpPost.setHeader(org.apache.http.HttpHeaders.CONTENT_TYPE, "application/json");
        // 设置登录凭证
        httpPost.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + apiKey);
        //        设置请求超时时间
        RequestConfig timeOut = RequestConfig.custom().setConnectTimeout(responseTimeout).build();
        httpPost.setConfig(timeOut);
        //        发送请求
        CloseableHttpResponse response = null;
        InputStream stream = null;
        try{
            response = client.execute(httpPost);
            HttpEntity entity = response.getEntity();
//            反序列化
            String responseMes = EntityUtils.toString(entity);
//            转为对象
            ImageGptResponseParameter responseParameter = JSON.parseObject(responseMes, ImageGptResponseParameter.class);
            // 遍历所有的image(一般都只有一个)
            for (Image image : responseParameter.getData()) {
                HttpGet httpGet = new HttpGet(image.getUrl());
                response = client.execute(httpGet);
                HttpEntity en = response.getEntity();
                stream= en.getContent();
                String fileName = UUID.randomUUID()+".png";
                String lastUrl = uploadStrategyContext.executeUploadStrategy(fileName, stream, FilePathEnum.GPTIMG.getPath());
                String url = "[CQ:image,file="+lastUrl+"]";
//                String url = "[CQ:image,file=https://leyasuzhou-blog.oss-cn-beijing.aliyuncs.com/img/test.png]";
//                String url = image.getUrl();
                System.out.println(url);
                return url;
            }
        }catch (Exception e){
           log.info("图片生成出错了");
        }finally {
            try {
                stream.close();
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

}

这里原本可以直接使用cq码来进行url封装,但直接用该接口生成图片的url会报错cq码解析超时,最后我想了个办法是先将图片放到oss上,之后再从oss上拿。但这样该方法就执行的很慢,如果有人知道这个cq码解析超时咋解决私信博主!

4.lunix部署

  1. 通过 SSH 连接到服务器

  2. cd到解压目录

  3. 输入 ./go-cqhttp, Enter运行 , 此时将提示

[WARNING]: 尝试加载配置文件 config.yml 失败: 文件不存在
[INFO]: 默认配置文件已生成,请编辑 config.yml 后重启程序.

之后继续像windows一样修改config.xml和device.json文件。 这里会有一个小问题,就是在扫码登录时,会出现风控,不让你登录,这时候怎么办呢? 首先,我们先在windows上扫码登录账号,登录成功后我们发现出现了一个session.token文件

2023最新!QQ接入ChatGpt!!!保姆级教程

这个文件保存了我们的登录信息,这时候,我们将这个文件页上传到lunix服务器上同样位置,就不用扫码登录了 到此,整个项目就跑起来了。 本项目是一个client单会话的,如果一个回复错误,我这边采取的是重置会话。 欢迎交流技术问题 来体验你的qqbot吧!!!文章来源地址https://www.toymoban.com/news/detail-466711.html

到了这里,关于2023最新!QQ接入ChatGpt!!!保姆级教程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ​LaTex2023 软件下载+TeXstudio编辑器最新版+保姆级安装教程

    软件下载链接: 点击获取 LaTex(Win) LaTeX ,中文名为“拉泰赫”,是一种基于TEX的排版系统,或者说一种排版语言,由美国计算机学家莱斯利·兰伯特(Leslie Lamport)在20世纪80年代初期开发,可用于直接生成PDF文件。由于LaTeX能够有效生成表格和数学公式,同时具有结构清晰

    2024年02月09日
    浏览(55)
  • DataGrip 2023.1 最新变化 【附带ChatGPT教程】

    ChatGPT开源公众号:https://gitee.com/wy521a/astar-weixin-mp 在浏览器中打开最新变化 DBE-4469:我们修正了 SQL Formatter 不为 EXISTS 子句中的子查询应用正确样式的问题。 现在,它会按预期运作。 DataGrip 还可以在 EXISTS 和左圆括号之间添加一个空格,可以通过新设置切换。 如需保留

    2024年02月08日
    浏览(46)
  • IntelliJ IDEA 2023.1 最新变化 【附带ChatGPT教程】

    ChatGPT开源公众号:https://gitee.com/wy521a/astar-weixin-mp 最新变化 2023.1 主要更新 用户体验 编辑器 Java Scala 分析器 版本控制系统 构建工具 运行/调试 框架和技术 Docker Kubernetes 远程开发和协作 Web 开发 其他 在浏览器中打开 PreviousNext 新 UI 增强 测试版 根据有关 IDE 新 UI 的反馈,我们

    2023年04月08日
    浏览(59)
  • 【2023最新版】超详细Metasploit安装保姆级教程,Metasploit渗透测试使用,看完这一篇就够了

    Metasploit 官方介绍 Metasploit是一个渗透测试框架,可以帮助您发现和利用漏洞。 Metasploit还为您提供了一个开发平台,您可以编写自己的安全工具或利用代码。 今天,我将指导您了解如何使用Metasploit的基础知识:如何安装Metasploit,使用框架以及利用漏洞。 下载地址:https://

    2024年02月13日
    浏览(68)
  • 【2023最新版】超详细Sqlmap安装保姆级教程,SQL注入使用指南,收藏这一篇就够了

    一、sqlmap简介 sqlmap是一个自动化的SQL注入工具,其主要功能是扫描,发现并利用给定的URL进行SQL注入。目前支持的数据库有MySql、Oracle、Access、PostageSQL、SQL Server、IBM DB2、SQLite、Firebird、Sybase和SAP MaxDB等 Sqlmap采用了以下5种独特的SQL注入技术 基于布尔类型的盲注,即可以根据

    2024年02月10日
    浏览(60)
  • 2023最新可用QQ机器人框架整理

    官网:www.qvbot.com 稳定、高效、免费的QQ机器人框架。支持多种语言二次开发可现实群管、聊天、便民服务等多种功能。功能更强大,无限创意,QYBot因你而精彩 官网:http://www.myqqx.xyz 不多说 官网:http://www.myqqx.top 不多说 官网:https://ovqq.cc/ OVQQ目前拥有OPC(PC)、OAZ(移动)、OWe

    2024年02月05日
    浏览(57)
  • go-cqhttp,QQ机器人发语音+视频+表情+接入chatgpt

    windows布局go-cqhttp_哔哩哔哩_bilibili 注意:图片需要放到go-cqhttp的目录下的data/images下面,否则无法发送,网络图片可以直接发送

    2024年02月11日
    浏览(45)
  • OpenAI最新官方ChatGPT聊天插件接口《接入插件快速开始》全网最详细中英文实用指南和教程,助你零基础快速轻松掌握全新技术(二)(附源码)

    ChatGPT正在经历着一次革命性的改变,随着越来越多的小程序和第三方插件的引入,ChatGPT将变得更加强大、灵活和自由。这些插件不仅能够让用户实现更多更复杂的AI任务和目标,还会带来类似国内微信小程序般的疯狂,为用户和开发者带来更多惊喜和创新。 想象一下,当您

    2024年02月04日
    浏览(85)
  • 2023最新详细:使用selenium携带cookie登录QQ空间,爬取指定好友空间说说照片

    写在前面:最近学了爬虫,正好爬取一下指定好友的所有空间说说照片,之前使用selenium账号密码登录,模拟登录次数过多,会加验证码,甚至导致QQ冻结,所以采用cookie登录 思路 首先获取cookie,使用cookie登陆之后通过空间好友栏搜索指定好友,并进入好友空间,从而爬取说

    2024年02月13日
    浏览(45)
  • Gitee保姆级教程

    1.1 什么是Git Git是一个分布式版本控制工具,主要用于管理开发过程中的源代码文件(Java类、xml文件、html页面等),在软件开发过程中被广泛使用。 在IDEA开发工具中可以集成Git(后面会讲解Git安装和集成过程): 集成后在IDEA中可以看到Git相关图标:外链图片转存失败,源站

    2024年02月04日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包