目录
一、项目展示:
二、项目介绍:
本项目采用pyqt来构建界面,调用了讯飞星火平台的api,来完成gpt智能问答系统,并且支持prompt提示优化,具有历史记录功能,还可以打包成成.exe文件供朋友使用。
三、项目实现:
第一步:申领api
注册完账号,进入主页,点击服务管理
点击创建新应用
给应用起名字
创建完成后,点击创建好的应用
点击立即购买
选择创建好的应用,选择第一个,点击购买,完成实名认证
实名认证完后会送200w tokens,完全够用了,接下来记住这些信息
第二步:安装配置库
pip install pyqt5
pip install urllib
pip install websocket
pip install configparser
缺啥补啥就对了,另外如果后续想自己设计页面,需要看看博客教程配置一下qtDesigner
第三步:编写代码
1.创建名为wsPram.py的文件,将如下代码cv进去,代码的功能就是生成api链接的
from datetime import datetime
from time import mktime
from urllib.parse import urlencode
from wsgiref.handlers import format_date_time
from urllib.parse import urlparse
import base64
import hashlib
import hmac
class Ws_Param(object):
# 初始化
def __init__(self, APPID, APIKey, APISecret, gpt_url):
self.APPID = APPID
self.APIKey = APIKey
self.APISecret = APISecret
self.host = urlparse(gpt_url).netloc
self.path = urlparse(gpt_url).path
self.gpt_url = gpt_url
# 生成url
def create_url(self):
# 生成RFC1123格式的时间戳
now = datetime.now()
date = format_date_time(mktime(now.timetuple()))
# 拼接字符串
signature_origin = "host: " + self.host + "\n"
signature_origin += "date: " + date + "\n"
signature_origin += "GET " + self.path + " HTTP/1.1"
# 进行hmac-sha256进行加密
signature_sha = hmac.new(self.APISecret.encode('utf-8'), signature_origin.encode('utf-8'),
digestmod=hashlib.sha256).digest()
signature_sha_base64 = base64.b64encode(signature_sha).decode(encoding='utf-8')
authorization_origin = f'api_key="{self.APIKey}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature_sha_base64}"'
authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8')
v = {
"authorization": authorization,
"date": date,
"host": self.host
}
# 拼接鉴权参数,生成url
url = self.gpt_url + '?' + urlencode(v)
# 此处打印出建立连接时候的url,参考本demo的时候可取消上方打印的注释,比对相同参数时生成的url与自己代码生成的url是否一致
return url
2. 调用接口,实现与gpt互动交流
也可以根据官方教程下载代码,自己改进
因为gpt不能一下子生成全部回复,生成的回复是一段一段的,于是采用webscoket来接收相应回复,实现实时回复效果。这里我使用列表,将每次回复都添加进列表里,回复完成后输出列表,就是一整段话了。
import _thread as thread
import json
import ssl
import websocket
import configparser
from wsPram import Ws_Param
class GptMsg():
def __init__(self):
self.config = configparser.ConfigParser()
self.config.read('cfig/config.ini', encoding='utf-8')
self.APPID = self.config['DEFAULT']['APPID']
self.APISecret =self. config['DEFAULT']['APISecret']
self.APIKey = self.config['DEFAULT']['APIKey']
self.gpt_url = 'wss://spark-api.xf-yun.com/v3.5/chat'
self.domain='generalv3.5'
self.msg = []
self.txt = self.config['DEFAULT']['TXT']
self.name = self.config['DEFAULT']['NAME']
self.history_text = [{"role":"system","content": self.txt}]
print('gpt初始化成功')
def send_msg(self, question):
# 获取url
wsParam = Ws_Param(self.APPID, self.APIKey, self.APISecret, self.gpt_url)
websocket.enableTrace(False)
wsUrl = wsParam.create_url()
# 消息加入
ques_json = {"role": "user", "content": question}
self.history_text.append(ques_json)
# 发送消息
ws = websocket.WebSocketApp(wsUrl, on_message=self.on_message, on_error=self.on_error, on_close=self.on_close, on_open=self.on_open)
ws.appid = self.APPID
ws.domain = self.domain
ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
# 收到websocket错误的处理
def on_error(self, ws, error):
print("### error:", error)
# 收到websocket关闭的处理
def on_close(self, ws, *args):
print("### closed ###")
# 收到websocket连接建立的处理
def on_open(self, ws):
thread.start_new_thread(self.run, (ws,))
def run(self, ws, *args):
data = json.dumps(self.gen_params(appid=ws.appid, domain=ws.domain))
ws.send(data)
def gen_params(self, appid, domain):
# print(window.history_text)
if len(self.history_text) >= 60:
self.history_text.pop(1)
self.history_text.pop(2)
data = {
"header": {
"app_id": appid,
"uid": "1234",
},
"parameter": {
"chat": {
"domain": domain,
"temperature": 0.5,
"max_tokens": 4096,
"auditing": "default",
}
},
"payload": {
"message": {
"text": self.history_text
}
}
}
return data
# 收到websocket消息的处理
def on_message(self, ws, message):
data = json.loads(message)
code = data['header']['code']
if code != 0:
print(f'请求错误: {code}, {data}')
ws.close()
else:
choices = data["payload"]["choices"]
status = choices["status"]
content = choices["text"][0]["content"]
self.msg.append(content)
print(content)
if status == 2:
self.msg.append('`')
ws.close()
if __name__ == '__main__':
gpt = GptMsg()
while True:
question = input('请输入问题:')
gpt.send_msg(question)
print('完整回答:', gpt.msg)
效果如图所示:
3.编写界面
界面使用的是pyqt,使用qrdesigner设计的界面
import sys
from threading import Thread
from PySide2.QtCore import QObject, QFile, Signal, QTimer
from PySide2.QtGui import QImage, QPixmap, QIcon
from PySide2.QtWidgets import *
from PySide2.QtUiTools import QUiLoader
from PySide2 import QtCore
from GPT.gptMsg import GptMsg
class GptWindow(QMainWindow):
def __init__(self):
super().__init__()
qfile = QFile("ui/gpt.ui")
qfile.open(QFile.ReadOnly)
qfile.close()
self.ui = QUiLoader().load(qfile)
self.gpt = GptMsg()
self.ai_answer_list = []
self.initStyle()
self.initBtn()
self.timer()
def initStyle(self):
self.ui.setStyleSheet('font-size:16px; font-weight: bold; background-color: rgb(248,252,255);')
self.ui.textBrowser.setStyleSheet('background-color: rgb(202,232,234);')
self.ui.lineEdit.setStyleSheet('height:30px;background-color: rgb(233,247,249);')
self.ui.pushButton.setStyleSheet('background-color: rgb(61,192,246);')
self.ui.pushButton_2.setStyleSheet('background-color: rgb(82,222,148);')
def initBtn(self):
self.ui.pushButton_2.clicked.connect(self.send)
self.ui.lineEdit.returnPressed.connect(self.send)
self.ui.pushButton.clicked.connect(self.clear)
def send(self):
question = self.ui.lineEdit.text()
self.ui.lineEdit.setText('')
self.gpt.msg.append('您的输入:' + question)
self.gpt.msg.append('`')
self.gpt.msg.append(f'{self.gpt.name}回复:')
Thread(target=self.send_msg, args=(question,)).start()
def send_msg(self, question):
self.gpt.send_msg(question)
def clear(self):
self.ui.textBrowser.setPlainText('')
self.gpt.history_text = [{"role":"system","content": self.gpt.txt}]
def timer(self):
self.timer = QTimer(self)
self.timer.timeout.connect(self.show_msg)
self.timer.start(30) # 定时器开始计时30ms
def show_msg(self):
if len(self.gpt.msg) != 0:
text = self.gpt.msg[0]
self.gpt.msg.pop(0)
if text != '`':
self.ui.textBrowser.insertPlainText(text)
self.ai_answer_list.append(text)
if text == '`':
self.ui.textBrowser.append('')
self.ui.textBrowser.append('')
ai_answer = "".join(self.ai_answer_list)
self.ai_answer_list = []
if f'{self.gpt.name}回复:' in ai_answer:
ai_answer = ai_answer.split(':')[1]
ai_dict = {"role": "assistant", "content": ai_answer}
self.gpt.history_text.append(ai_dict)
if __name__ == '__main__':
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
app = QApplication(sys.argv)
app.setWindowIcon(QIcon('cfig/logo.png'))
window = GptWindow()
window.ui.show()
sys.exit(app.exec_())
config.ini配置文件
上面三条换成申领api的信息
txt就是prompt语句,你可以让机器人成为任何你指定的人
NAME就是机器人的名字
[DEFAULT] APPID = 你的id APISecret = 你的APISecret APIKey = 你的key TXT = 你是一个乐于助人的机器人 NAME = AI
运行结果