最终效果图:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-56EWw2Ki-1589776377292)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200518110659979.png)]](https://i-blog.csdnimg.cn/blog_migrate/aaee7fad12977dbfe5d6b3cee0d5a590.png)
图1.聊天情况
1.百度UNIT聊天API的使用
代码示例1
# -*- coding=utf-8 -*-
import requests
class UNIT:
def __init__(self, api_key, api_secret):
self.access_token = None
self.url = None
self.set_access_token(api_key, api_secret)
def set_access_token(self, api_key, api_secret):
host = 'https://aip.baidubce.com/oauth/2.0/token?' \
'grant_type=client_credentials&' \
'client_id={0}&' \
'client_secret={1}'.format(api_key, api_secret)
response = requests.post(host)
if response:
self.access_token = response.json()['access_token']
def query(self, query_text):
self.url = 'https://aip.baidubce.com/rpc/2.0/unit/service/chat?access_token=' + self.access_token
post_data = """{
"bot_session": "",
"log_id": "7758521",
"service_id": "S29640", # 你的聊天机器人的ID
"request": {
"bernard_level": 1,
"client_session": "{\\\"client_results\\\":\\\"\\\", \\\"candidate_options\\\": []}",
"query": "%s", # 要查询的文字
"query_info": {
"asr_candidates": [],
"source": "KEYBOARD",
"type": "TEXT"
},
"updates": "",
"user_id": "88888"
},
"session_id": "",
"version": "2.0"
}""" % query_text
post_data = post_data.encode('utf-8')
headers = {'content-type': 'application/x-www-form-urlencoded'}
response = requests.post(self.url, data=post_data, headers=headers)
if response:
return response.json()['result']['response_list'][0]['action_list'][0]['say']
需要自己去百度UNIT获取自己的API_KEY和API_SECRET,然后调用set_access_token获取access_token来访问聊天API。
2. QT中UI线程与工作线程的双向通信
发现网上讲的基本都是工作线程向UI线程传递数据,却没有讲UI线程如何传递数据给工作线程。以下给出了一种思路。
代码示例2
UI线程点击按钮,向工作线程发送信息;工作线程处理好信息后通过信号传出。
# -*- coding=utf-8 -*-
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QThread
class WorkerThread(QThread):
response_signal = pyqtSignal(str) # 向UI线程发出的信号
receive_string = None # 用于接受来自UI线程的信息
def __init__(self):
super(WorkerThread, self).__init__()
def run(self) -> None:
# 处理UI线程传来的信息,然后发出信号
self.response_signal[str].emit(self.receive_string + ",I got this")
class MyWidget(QWidget):
def __init__(self):
super(MyWidget, self).__init__()
self.button = QPushButton("send", self)
self.button.clicked.connect(self.on_send_message)
self.worker = WorkerThread() # 实例化子线程
self.worker.response_signal[str].connect(self.on_response) # 绑定子线程的信号与UI线程的槽on_response
@pyqtSlot() # 据PYQT官网描述,加上装饰器可以减少内存消耗
def on_send_message(self):
self.worker.receive_string = "你好" # 往子线程传递信息
self.worker.start() # 启动子线程
@pyqtSlot(str)
def on_response(self, text):
print(text)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyWidget()
window.show()
sys.exit(app.exec_())
运行结果:
你好,I got this
你好,I got this
你好,I got this
你好,I got this
3.UI
部分个人觉得比较重要的实现:
聊天框使用QListWidget实现,每一条聊天内容使用QListWidgetItem实现。
聊天内容:图标+时间+消息。
def get_encapsulated_message(self):
message_item = QListWidgetItem() # 实例化一个QListWidgetItem对象
time = QDateTime.currentDateTime().time().toString('hh:mm:ss') # 获取当前时间
message_item.setText(time + " " + self.input_text.text()) # 设置文本内容
message_item.setIcon(QIcon('image/me.png')) # 添加图标
return message_item
有时候文本内容太长,需要设置自动换行:
self.chat_message_box.setWordWrap(True) # 开启长文本自动换行
chat_message_box是QListWidget类的对象。
在QListWidget中,每次内容都停留在顶部,无法自动下滑到最新的消息处:
self.chat_message_box.scrollToBottom() # chat_message_box是QListWidget对象
在往QListWidget中添加QListWidgetItem后,调用QListWidget.scrollToBottom()即可。