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
用于重置对话