Discord机器人接入GPT 3.0

Discord机器人接入GPT 3.0

Discord机器人接入GPT 3.0 由于GPT 3.0没有任何限制,可以用来搞涩涩以及写长文,所以我决定给discord接入GPT 3.0 这玩意也是真的贵,接完之后玩了会就花了好多钱,不敢玩了 申请API Key 这个直接去官网申请,我的梯子之前被openai封了,不知道为什么最近又解封了 首

Discord机器人接入GPT 3.0

由于GPT 3.0没有任何限制,可以用来搞涩涩以及写长文,所以我决定给discord接入GPT 3.0

这玩意也是真的贵,接完之后玩了会就花了好多钱,不敢玩了

申请API Key

这个直接去官网申请,我的梯子之前被openai封了,不知道为什么最近又解封了

首先登录 openai.com

然后来到 这个页面

点击 Create new secret key 就可以申请一个api key,api key应该是sk-开头的

搭建环境

首先使用pip安装openai官方的库

pip install openai

然后在代码里设置API key

import openai

openai.api_key = "sk-XXXXXX" #你的API key

编写主体代码

参考上文 Discord机器人

我们这边想实现一个消息监听式的回复,当用户@机器人时自动生成对应的回复

首先写一个处理主要逻辑的函数

生成请求内容

因为我这个机器人要放在多个群聊里用,所以需要根据channel id分离每个对话的上下文

interactions 库里面的消息监听器会给我们提供channel id,所以只需要在这个函数里写一个参数接收就好

# 这个字典用来储存和AI交互的上下文
completion_prompts = {}
# completion_prompts: {'{channel id}': XXX}

id = str(channel_id)
if id not in messages:
    completion_prompts[id] = "" #初始化
# content 是传进来的参数,用户输入的内容,这里需要稍微格式化一下,使输出更稳定
# 直接在结尾处追加内容,有时候单次对话会有太多上下文,可能会很耗token
completion_prompts[id]+=f"\n用户: {content}\nAI: "

# 接下来就是请求API的耗时操作,需要先发送一个消息提醒用户
# event 是传进来的参数,消息监听器提供的
# 这里直接发送一条消息,并且存到变量里,为后面修改做准备
message = await event.message.channel.send("处理中...")

请求API并流式传输

因为GPT 3.0是一个大语言续写模型,所以单次生成的内容会很长,这时候应该使用openai提供的流式传输功能

首先请求API

resp = openai.Completion.create(
        model = "text-davinci-003",
        prompt = completion_prompts[id],
        max_tokens = 700, #单次生成的最大token数
        stream = True #启用流式传输
    )

接下来接收流式传输的内容并修改消息

completion = ""
buffer = 0
for chunk in resp:
    buffer += 1
    completion += chunk['choices'][0]['text'] # 追加返回的内容
    if buffer % 10 == 0: # 每生成10个字就修改一下discord里的消息
        completion = completion.replace("AI: ","")  # 有时候他自己会说多个"AI: ",把这个删掉
        await message.edit(content = completion) # 修改消息
# 最后再追加一次
await message.edit(content = completion)
# 把AI的回复加入上下文中
completion_prompts[id] += f"\nAI: {completion}"

自此,整个请求部分的函数写完了,总体是这样的:

import openai
import interactions

openai.api_key = "sk-XXXXX"

async def getCompletionReply(channel_id: int, content: str, event: interactions.events.MessageCreate):
    id = str(channel_id)
    if id not in completion_prompts:
        completion_prompts[id] = ""
    completion_prompts[id]+=f"\n用户: {content}\nAI: "

    message = await event.message.channel.send("处理中...")

    resp = openai.Completion.create(
        model = "text-davinci-003",
        prompt = completion_prompts[id],
        max_tokens = 700,
        stream = True
    )

    completion = ""
    buffer = 0
    for chunk in resp:
        buffer += 1
        completion += chunk['choices'][0]['text']
        if buffer % 10 == 0:
            completion = completion.replace("AI: ","")
            await message.edit(content = completion)

    await message.edit(content = completion)

    completion_prompts[id] += f"\nAI: {completion}"
    

注册Discord监听器和指令

接下来需要使用interactions库的监听器,监听用户的消息

监听器

我们想要只在用户@机器人的情况下回复,在Discord中@人的文本是用<@[bot id]>表示,比如我的bot id是1114511148474179624,就是<@1114511148474179624>

具体实现代码如下

@interactions.listen()
async def on_message_create(event: interactions.events.MessageCreate):
    if event.message.content and event.message.contains_mention('<@1114511148474179624>'): #判断是否@
        message = event.message.content.replace('<@1114511148474179624>', '') # 删除@的文本
        id = str(event.message.channel.id)
        await Chat.getCompletionReply(event.message.channel.id, message, event); # 调用刚才写的函数

这段代码直接放在注册Bot的代码里

指令

这里需要注册一个指令用来重置对话内容(也就是清空那个上下文的变量)

@interactions.slash_command(
    name = "openai",
    description = "控制OpenAI对话选项",
    scopes = scopes
)
async def chat(ctx: interactions.SlashContext):
    pass

@chat.subcommand(
    sub_cmd_name = "reset",
    sub_cmd_description = "重置当前对话内容"
)
async def chat_reset(ctx: interactions.SlashContext):
    await ctx.defer()
    completion_prompts[str(ctx.channel_id)] = ""
    await ctx.send('**已重置对话内容**')

这样就注册了一个指令/openai reset 用于重置对话

LICENSED UNDER CC BY-NC-SA 4.0
Comment