尝试使用Qt调用OpenAI API
2023年6月26日目前经过浅浅的尝试,已经可以成功调用OpenAI的API了。
验证
首先是通过Python进行测试:
OpenAI的API通过HTTP进行调用,所以可以使用Python的request库来操作。
当然,用requset库还有一个原因是它可以很方便地做ChatGPT的流式输出
简单的代码如下:
# 准备API以及模型信息
url = 'https://api.openai.com/v1/chat/completions'
headers = {
"Content-type": "application/json",
"Authorization": "Bearer sk-******"
}
data_base = {
"model": "gpt-3.5-turbo",
"temperature": 0.7,
"top_p": 1,
"n": 1,
"max_tokens": 512,
"presence_penalty": 0,
"frequency_penalty": 0,
"stream": True
}
# 储存历史记录
chats = [
]
# 解析接收的流式数据
def parse_data(data: bytes):
if data == b'\n':
return False
s = data.decode('utf_8')
p = s.find(':')
s = s[p + 2:]
if s == '[DONE]\n':
return True
j = json.loads(s)
return j['choices'][0]['delta']
# Chat主要逻辑
while True:
user = input("User: ")
if len(user) != 0:
chats.append({
'role': 'user',
'content': user
})
send = copy.deepcopy(data_base)
send['messages'] = chats
send_json = json.dumps(send)
req = urllib.request.Request(url, send_json.encode('utf_8'), headers)
print("Assistant: ", end='')
ass = {
'role': '',
'content': ''
}
# 处理流式数据
with urllib.request.urlopen(req) as resp:
for line in resp:
# print('line:', line)
get = parse_data(line)
if get != False and get != True:
for i in get:
ass[i] = ass.get(i, '') + get[i]
if i == 'content':
print(get[i], end='')
elif get == True:
print()
chats.append(ass)
于是就用Python简单实现了该功能。
实践
当然,在这里实现和在Qt中的实现还是有很大差距的。
在Qt中,我们需要使用QNetworkAccessManager
QNetworkRequest
QNetworkReply
这几个类来实现流的功能。
在Qt中,创建一个Request,然后让manager发送request,会返回一个Reply对象,通过连接信号readyRead可以处理所有发送来的数据,这样就可以实现流式输出了。
在对话显示上,我用了别人写的MarkDown高亮显示(QMarkdownTextEdit),甚至支持很多代码的高亮显示,刚好能满足要求。
最后还是做出了一点好东西
尾声
不过Qt代码还是存在问题
如果接收到的消息是不完整的,这一轮对话会直接报错,但事实上在正常运行,这会消耗我的API调用次数,增加开销。而且没有做自动token计数和token裁剪,导致使用体验不佳。
不过,好歹还是可以用的。后来又给它加了一个可以修改服务器地址的功能,这样就可以直接调用国内的代理了。
这个项目大概就这样了吧。
——Majjcom