qq机器人实现gpt对接教程

发布于 2023-11-21  8455 次阅读


这篇文可能会比较长,因为想尽力覆盖所有可能出现的问题。

前情提要

使用框架:go-cqhttp(基于miral)

环境:windows

简单来说,go-cqhttp模拟了qq的客户端,同时提供了一系列的接口,用来收发信息。

处理流程:go-cqhttp从获取登录账号的qq时间,通过http或者websocket传给后台(编写后台程序就是我们的工作)进行处理,后台通过openai的api和gpt对话,并将对话结果进行处理(比如敏感词处理啥的),等后台处理完之后,通过go-cqhttp的接口向qq发消息。

下载并安装与配置go-cqhttp

go-cqhttp版本下载地址传送门:https://github.com/Mrs4s/go-cqh,一般来说选择这个就可以了。

下载后点击运行,生成配置文件和.bat文件

接着运行.bat文件,选择通信模式

然后你应该能看到生成的config文件了......

输入你的qq账号和本地ip,第一步就完成啦!

注册谷歌账号并获取鉴权码

注册谷歌账号很简单,这里就不详细说了......

拥有谷歌账号后,你就可以畅通无阻的登陆openai了,在个人信息栏找到apikey,如下图

接着创建并复制你的密钥。

恭喜你,完成了准备工作。

编写后台程序-1

我使用flask框架写后端,个人感觉这是最适合python后端的框架了,下面给出示例,可以自行修改。

import socket
from multiprocessing import Process,Pool
from socket import*
import requests
from threading import *
from flask import Flask,request
from 机器人数据解析api import *

url="http://127.0.0.1:5700"
app = Flask(__name__)

def send_message():
    while True:
        while q.empty()==False:
            print("弹出队列")
            data=q.get()
            print(data)
            requests.get(url+data[0],params=data[1])
@app.route('/', methods=["POST"])
def post_data():
    print("执行")
    data=request.get_json()
    response=get_result(data)#get_result方法在数据解析那个文件中
    if response!="bad":
        requests.get(url+response[0],params=response[1])
    else:
        print("心跳")

    return "OK"

if __name__=="__main__":
    Thread(target=send_message).start()
    app.run(debug=False,host="localhost",port=8000)


    # Main=main()
    # Main.begin()

post_data负责接收get和post请求(多半是对方说的话),将请求送到数据解析.py中进行处理, 处理完毕后将结果推入q队列,并用request.get发出去。

编写后台程序-2

接下来给出数据解析的代码,不过说实话写的挺乱,将就着看吧ψ(`∇´)ψ

def get_result(data):

    if data.get("meta_event_type")=="heartbeat":#心跳无意义
        return "bad"

    post_type=data.get("post_type")
    if post_type=="message":
        if data.get("message_type")=="group":#判断是群消息
            group_id = str(data.get("group_id"))#获取是哪个群
            if os.path.exists("person/"+group_id)==False:
                os.mkdir("person/"+group_id)
                person_dict[group_id]={}
            params_dict={
                "group_id":group_id,
                "auto_escape":False
            }#将要返回的字典

            person=data.get("user_id")#获取到底是哪个人发的
            message=data.get("message")#获取发的信息
            print(message)

            sign=message.split(" ")[0]
            if sign=="[CQ:at,qq=机器人的qq号]":#如果艾特机器人,就回答他
                if message.split(" ")[1]=="重置":#判断如果内容是重置,则清空机器人缓存记忆
                    print("已重置")
                    chat_data[group_id][person]=init_chat.copy()
                else:
                    prompt=message.split(" ")[1]
                    Thread(target=get_chat, args=(person, group_id,"/send_group_msg", params_dict, prompt)).start()#多线程调用get_chat方法
                    return ("/send_group_msg", params_dict.copy())#注意,列表是引用类型,一定要copy一下再发,当初我在这里卡了很久才发现这个问题的呜呜呜

上面的代码涉及到了多线程,不懂的朋友可以自行搜索,挺容易的.....下面给出get_chat函数

init_chat=[{"role":"system","content":"you are a good assistant"}]
def get_chat(person,group,terminal,params_dict,prompt):
    print("in")
    if (group in chat_data.keys())==False:
        chat_data[group]=dict()
    print(chat_data)
    if (person in chat_data[group].keys())==False:
        chat_data[group][person]=init_chat.copy()

    chat_data[group][person].append({"role":"user","content":prompt})
    dict_copy = params_dict.copy()
    try:
        ans=get_answer(chat_data[group][person])#获取对话结果
        chat_data[group][person].append({"role":"assistant","content":ans})

        dict_copy["message"]="[CQ:at,qq=%s]"%person+ans

    except Exception as e:
        print(e)
        dict_copy["message"]="[CQ:at,qq=%s]"%person+"数据过长,请发送重置或缩短数据"
    finally:
        print(chat_data)
        q.put((terminal, dict_copy))


解释一下上面的代码,由于我使用的是gpt-3.5,chatcompletion,也就是给出一段情景对话,返回下一句该说的话,所以会有一个初始情景init_chat,因为token是有限的,而每次请求api都要将之前所说的所有话都发过去,时间久了token就超了,所以要用户发出重置口令重置记忆,下面给出get_answer函数。

import openai
api_key="你的apikey"
openai.api_key=api_key
def get_answer(data):
    result=openai.ChatCompletion.create(
      model="gpt-3.5-turbo",
      messages=data
    )
    ans=result["choices"][0]["message"]["content"]

    return ans

结尾

到了这里,相信聪明的你应该已经学会了如何配置go-cqhttp机器人以及如何对接chatgpt,然而go-cqhttp的神奇之处不仅于此,更多内容请查看go-cqhttp手册(包含了cq码等高级功能)

参考文章列表:


北京邮电大学大一学生,喜欢做游戏和写算法题,qq1358275285