init
This commit is contained in:
1
app/ui/chat/__init__.py
Normal file
1
app/ui/chat/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .chat_window import ChatWindow
|
||||
217
app/ui/chat/ai_chat.py
Normal file
217
app/ui/chat/ai_chat.py
Normal file
@@ -0,0 +1,217 @@
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import requests
|
||||
from PyQt5.QtCore import QThread, pyqtSignal, QSize, Qt
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QHBoxLayout, QApplication, QTextBrowser, QMessageBox
|
||||
|
||||
from app import config
|
||||
from app.config import SERVER_API_URL
|
||||
from app.log import logger
|
||||
from app.ui.Icon import Icon
|
||||
|
||||
try:
|
||||
from .chatInfoUi import Ui_Form
|
||||
except:
|
||||
from chatInfoUi import Ui_Form
|
||||
from app.components.bubble_message import BubbleMessage
|
||||
from app.person import Me, ContactDefault
|
||||
|
||||
|
||||
class Message(QWidget):
|
||||
def __init__(self, is_send=False, text='', parent=None):
|
||||
super().__init__(parent)
|
||||
self.avatar = QLabel(self)
|
||||
|
||||
self.textBrowser = QTextBrowser(self)
|
||||
self.textBrowser.setText(text)
|
||||
|
||||
layout = QHBoxLayout(self)
|
||||
if is_send:
|
||||
pixmap = Me().avatar.scaled(45, 45)
|
||||
self.textBrowser.setLayoutDirection(Qt.RightToLeft)
|
||||
self.textBrowser.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
self.avatar.setPixmap(pixmap)
|
||||
layout.addWidget(self.textBrowser)
|
||||
layout.addWidget(self.avatar)
|
||||
else:
|
||||
pixmap = QPixmap(Icon.Default_avatar_path).scaled(45, 45)
|
||||
self.avatar.setPixmap(pixmap)
|
||||
layout.addWidget(self.avatar)
|
||||
layout.addWidget(self.textBrowser)
|
||||
# self.textBrowser.setFixedHeight(int(self.textBrowser.document().size().height()))
|
||||
self.textBrowser.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
self.avatar.setFixedSize(QSize(60, 60))
|
||||
|
||||
def append(self, text: str):
|
||||
self.textBrowser.insertPlainText(text)
|
||||
self.textBrowser.setFixedHeight(int(self.textBrowser.document().size().height()))
|
||||
|
||||
|
||||
class AIChat(QWidget, Ui_Form):
|
||||
def __init__(self, contact, parent=None):
|
||||
super().__init__(parent)
|
||||
self.now_message: Message = None
|
||||
self.setupUi(self)
|
||||
self.last_timestamp = 0
|
||||
self.last_str_time = ''
|
||||
self.last_pos = 0
|
||||
self.contact = contact
|
||||
self.init_ui()
|
||||
self.show_chats()
|
||||
self.pushButton.clicked.connect(self.send_msg)
|
||||
self.toolButton.clicked.connect(self.tool)
|
||||
self.btn_clear.clicked.connect(self.clear_dialog)
|
||||
self.btn_clear.setIcon(Icon.Clear_Icon)
|
||||
|
||||
def init_ui(self):
|
||||
self.textEdit.installEventFilter(self)
|
||||
|
||||
def tool(self):
|
||||
QMessageBox.information(self, "温馨提示", "暂未接入聊天数据,您可进行基础的AI对话,后续更新敬请期待")
|
||||
|
||||
def chat(self, text):
|
||||
self.now_message.append(text)
|
||||
self.scrollArea.verticalScrollBar().setValue(self.scrollArea.verticalScrollBar().maximum())
|
||||
|
||||
def send_msg(self):
|
||||
msg = self.textEdit.toPlainText().strip()
|
||||
self.textEdit.setText('')
|
||||
if not msg:
|
||||
return
|
||||
print(msg)
|
||||
bubble_message = BubbleMessage(
|
||||
msg,
|
||||
Me().avatar,
|
||||
1,
|
||||
True,
|
||||
)
|
||||
self.verticalLayout_message.addWidget(bubble_message)
|
||||
message1 = Message(False)
|
||||
self.verticalLayout_message.addWidget(message1)
|
||||
self.show_chat_thread.msg = msg
|
||||
self.now_message = message1
|
||||
self.show_chat_thread.start()
|
||||
self.scrollArea.verticalScrollBar().setValue(self.scrollArea.verticalScrollBar().maximum())
|
||||
|
||||
def clear_dialog(self):
|
||||
self.show_chat_thread.history = []
|
||||
while self.verticalLayout_message.count():
|
||||
item = self.verticalLayout_message.takeAt(0)
|
||||
widget = item.widget()
|
||||
if widget is not None:
|
||||
widget.deleteLater()
|
||||
else:
|
||||
del item
|
||||
|
||||
def show_chats(self):
|
||||
# return
|
||||
self.show_chat_thread = AIChatThread()
|
||||
self.show_chat_thread.msgSignal.connect(self.chat)
|
||||
|
||||
def update_history_messages(self):
|
||||
print('开始发送信息')
|
||||
message1 = Message(False)
|
||||
msg = '你好!'
|
||||
self.verticalLayout_message.addWidget(message1)
|
||||
self.show_chat_thread.msg = msg
|
||||
self.now_message = message1
|
||||
self.show_chat_thread.start()
|
||||
|
||||
def add_message(self, message):
|
||||
print('message', message)
|
||||
# self.textBrowser.append(message)
|
||||
self.textBrowser.insertPlainText(message)
|
||||
self.textBrowser.setFixedHeight(int(self.textBrowser.document().size().height()))
|
||||
|
||||
def eventFilter(self, obj, event):
|
||||
if obj == self.textEdit and event.type() == event.KeyPress:
|
||||
key = event.key()
|
||||
if key == 16777220: # 回车键的键值
|
||||
self.send_msg()
|
||||
self.textEdit.setText('')
|
||||
return True
|
||||
return super().eventFilter(obj, event)
|
||||
|
||||
|
||||
class AIChatThread(QThread):
|
||||
msgSignal = pyqtSignal(str)
|
||||
showSingal = pyqtSignal(tuple)
|
||||
finishSingal = pyqtSignal(int)
|
||||
msg_id = 0
|
||||
|
||||
# heightSingal = pyqtSignal(int)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.msg = ''
|
||||
self.history = []
|
||||
|
||||
def run(self) -> None:
|
||||
url = urljoin(SERVER_API_URL, 'chat')
|
||||
data = {
|
||||
'username': Me().wxid,
|
||||
'token': Me().token,
|
||||
'version': config.version,
|
||||
'messages': [
|
||||
*self.history,
|
||||
{
|
||||
'role': 'user',
|
||||
"content": self.msg
|
||||
}
|
||||
]
|
||||
}
|
||||
message = '''
|
||||
幼儿园三班一共有35人,上个月34人满勤。\n其中1月15日,小明同学感冒了,他的妈妈给他请了一天的病假。
|
||||
'''
|
||||
try:
|
||||
# for s in message:
|
||||
# self.msgSignal.emit(s)
|
||||
# time.sleep(0.05)
|
||||
# return
|
||||
resp = requests.post(url, json=data, stream=True)
|
||||
message = {
|
||||
'role': 'user',
|
||||
'content': self.msg
|
||||
}
|
||||
resp_message = {
|
||||
'role': 'assistant',
|
||||
'content': ''
|
||||
}
|
||||
if resp.status_code == 200:
|
||||
for line in resp.iter_lines():
|
||||
if line:
|
||||
trunk = line.decode('utf-8')
|
||||
try:
|
||||
data = json.loads(trunk.strip('data: '))
|
||||
answer = data.get('answer')
|
||||
print(answer)
|
||||
if isinstance(answer, str):
|
||||
resp_message['content'] += answer
|
||||
self.msgSignal.emit(answer)
|
||||
except:
|
||||
print(trunk)
|
||||
resp_message['content'] += trunk
|
||||
self.msgSignal.emit(trunk)
|
||||
else:
|
||||
print(resp.text)
|
||||
error = resp.json().get('error')
|
||||
logger.error(f'ai请求错误:{error}')
|
||||
self.msgSignal.emit(error)
|
||||
self.history.append(message)
|
||||
self.history.append(resp_message)
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
logger.error(f'ai请求错误:{error}{traceback.format_exc()}')
|
||||
self.msgSignal.emit(error)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
contact = ContactDefault('1')
|
||||
dialog = AIChat(contact)
|
||||
dialog.show()
|
||||
sys.exit(app.exec_())
|
||||
74
app/ui/chat/chatInfoUi.py
Normal file
74
app/ui/chat/chatInfoUi.py
Normal file
@@ -0,0 +1,74 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'chatInfoUi.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.10
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_Form(object):
|
||||
def setupUi(self, Form):
|
||||
Form.setObjectName("Form")
|
||||
Form.resize(817, 748)
|
||||
self.horizontalLayout_7 = QtWidgets.QHBoxLayout(Form)
|
||||
self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_7.setSpacing(0)
|
||||
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
|
||||
self.frame = QtWidgets.QFrame(Form)
|
||||
self.frame.setFrameShape(QtWidgets.QFrame.NoFrame)
|
||||
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||
self.frame.setObjectName("frame")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.label_reamrk = QtWidgets.QLabel(self.frame)
|
||||
self.label_reamrk.setObjectName("label_reamrk")
|
||||
self.horizontalLayout_2.addWidget(self.label_reamrk)
|
||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem)
|
||||
self.btn_clear = QtWidgets.QPushButton(self.frame)
|
||||
self.btn_clear.setObjectName("btn_clear")
|
||||
self.horizontalLayout_2.addWidget(self.btn_clear)
|
||||
self.toolButton = QtWidgets.QToolButton(self.frame)
|
||||
self.toolButton.setObjectName("toolButton")
|
||||
self.horizontalLayout_2.addWidget(self.toolButton)
|
||||
self.verticalLayout_2.addLayout(self.horizontalLayout_2)
|
||||
self.scrollArea = QtWidgets.QScrollArea(self.frame)
|
||||
self.scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame)
|
||||
self.scrollArea.setWidgetResizable(True)
|
||||
self.scrollArea.setObjectName("scrollArea")
|
||||
self.scrollAreaWidgetContents = QtWidgets.QWidget()
|
||||
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 799, 564))
|
||||
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
|
||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.verticalLayout_message = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout_message.setObjectName("verticalLayout_message")
|
||||
self.verticalLayout_3.addLayout(self.verticalLayout_message)
|
||||
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
|
||||
self.verticalLayout_2.addWidget(self.scrollArea)
|
||||
self.textEdit = QtWidgets.QTextEdit(self.frame)
|
||||
self.textEdit.setMaximumSize(QtCore.QSize(16777215, 100))
|
||||
self.textEdit.setObjectName("textEdit")
|
||||
self.verticalLayout_2.addWidget(self.textEdit)
|
||||
self.pushButton = QtWidgets.QPushButton(self.frame)
|
||||
self.pushButton.setObjectName("pushButton")
|
||||
self.verticalLayout_2.addWidget(self.pushButton)
|
||||
self.horizontalLayout_7.addWidget(self.frame)
|
||||
|
||||
self.retranslateUi(Form)
|
||||
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Form.setWindowTitle(_translate("Form", "Form"))
|
||||
self.label_reamrk.setText(_translate("Form", "EmoAi"))
|
||||
self.btn_clear.setText(_translate("Form", "清除对话"))
|
||||
self.toolButton.setText(_translate("Form", "..."))
|
||||
self.pushButton.setText(_translate("Form", "发送"))
|
||||
66
app/ui/chat/chatUi.py
Normal file
66
app/ui/chat/chatUi.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'chatUi.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.10
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_Form(object):
|
||||
def setupUi(self, Form):
|
||||
Form.setObjectName("Form")
|
||||
Form.resize(840, 752)
|
||||
Form.setStyleSheet("background: rgb(240, 240, 240);")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(Form)
|
||||
self.horizontalLayout_2.setSpacing(6)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout_2.setSpacing(6)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.label = QtWidgets.QLabel(Form)
|
||||
self.label.setText("")
|
||||
self.label.setObjectName("label")
|
||||
self.horizontalLayout.addWidget(self.label)
|
||||
self.lineEdit = QtWidgets.QLineEdit(Form)
|
||||
self.lineEdit.setMinimumSize(QtCore.QSize(200, 30))
|
||||
self.lineEdit.setMaximumSize(QtCore.QSize(200, 16777215))
|
||||
self.lineEdit.setStyleSheet("")
|
||||
self.lineEdit.setCursorMoveStyle(QtCore.Qt.VisualMoveStyle)
|
||||
self.lineEdit.setObjectName("lineEdit")
|
||||
self.horizontalLayout.addWidget(self.lineEdit)
|
||||
self.label_2 = QtWidgets.QLabel(Form)
|
||||
self.label_2.setMinimumSize(QtCore.QSize(30, 0))
|
||||
self.label_2.setText("")
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.horizontalLayout.addWidget(self.label_2)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
self.verticalLayout_2.addLayout(self.verticalLayout)
|
||||
self.listWidget = QtWidgets.QListWidget(Form)
|
||||
self.listWidget.setMinimumSize(QtCore.QSize(250, 0))
|
||||
self.listWidget.setMaximumSize(QtCore.QSize(250, 16777215))
|
||||
self.listWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
self.listWidget.setObjectName("listWidget")
|
||||
self.verticalLayout_2.addWidget(self.listWidget)
|
||||
self.verticalLayout_2.setStretch(1, 1)
|
||||
self.horizontalLayout_2.addLayout(self.verticalLayout_2)
|
||||
self.stackedWidget = QtWidgets.QStackedWidget(Form)
|
||||
self.stackedWidget.setObjectName("stackedWidget")
|
||||
self.horizontalLayout_2.addWidget(self.stackedWidget)
|
||||
self.horizontalLayout_2.setStretch(1, 1)
|
||||
|
||||
self.retranslateUi(Form)
|
||||
self.stackedWidget.setCurrentIndex(-1)
|
||||
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Form.setWindowTitle(_translate("Form", "Form"))
|
||||
188
app/ui/chat/chat_info.py
Normal file
188
app/ui/chat/chat_info.py
Normal file
@@ -0,0 +1,188 @@
|
||||
import traceback
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QHBoxLayout
|
||||
|
||||
from app.DataBase import msg_db, hard_link_db
|
||||
from app.components.bubble_message import BubbleMessage, ChatWidget, Notice
|
||||
from app.person import Me
|
||||
from app.util import get_abs_path
|
||||
from app.util.emoji import get_emoji
|
||||
|
||||
|
||||
class ChatInfo(QWidget):
|
||||
def __init__(self, contact, parent=None):
|
||||
super().__init__(parent)
|
||||
self.last_timestamp = 0
|
||||
self.last_str_time = ''
|
||||
self.last_pos = 0
|
||||
self.contact = contact
|
||||
self.init_ui()
|
||||
self.show_chats()
|
||||
|
||||
def init_ui(self):
|
||||
self.label_reamrk = QLabel(self.contact.remark)
|
||||
|
||||
self.hBoxLayout = QHBoxLayout()
|
||||
self.hBoxLayout.addWidget(self.label_reamrk)
|
||||
|
||||
self.vBoxLayout = QVBoxLayout()
|
||||
self.vBoxLayout.setSpacing(0)
|
||||
self.vBoxLayout.addLayout(self.hBoxLayout)
|
||||
|
||||
self.chat_window = ChatWidget()
|
||||
self.chat_window.scrollArea.verticalScrollBar().valueChanged.connect(self.verticalScrollBar)
|
||||
self.vBoxLayout.addWidget(self.chat_window)
|
||||
self.setLayout(self.vBoxLayout)
|
||||
|
||||
def show_chats(self):
|
||||
# Me().save_avatar()
|
||||
# self.contact.save_avatar()
|
||||
self.show_chat_thread = ShowChatThread(self.contact)
|
||||
self.show_chat_thread.showSingal.connect(self.add_message)
|
||||
self.show_chat_thread.finishSingal.connect(self.show_finish)
|
||||
# self.show_chat_thread.start()
|
||||
|
||||
def show_finish(self, ok):
|
||||
self.setScrollBarPos()
|
||||
self.show_chat_thread.quit()
|
||||
|
||||
def verticalScrollBar(self, pos):
|
||||
"""
|
||||
滚动条到0之后自动更新聊天记录
|
||||
:param pos:
|
||||
:return:
|
||||
"""
|
||||
# print(pos)
|
||||
if pos > 0:
|
||||
return
|
||||
|
||||
# 记录当前滚动条最大值
|
||||
self.last_pos = self.chat_window.verticalScrollBar().maximum()
|
||||
self.update_history_messages()
|
||||
|
||||
def update_history_messages(self):
|
||||
self.show_chat_thread.start()
|
||||
|
||||
def setScrollBarPos(self):
|
||||
"""
|
||||
将滚动条位置设置为上次看到的地方
|
||||
:param pos:
|
||||
:return:
|
||||
"""
|
||||
self.chat_window.update()
|
||||
self.chat_window.show()
|
||||
pos = self.chat_window.verticalScrollBar().maximum() - self.last_pos
|
||||
self.chat_window.set_scroll_bar_value(pos)
|
||||
|
||||
def is_5_min(self, timestamp):
|
||||
if abs(timestamp - self.last_timestamp) > 300:
|
||||
self.last_timestamp = timestamp
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_avatar_path(self, is_send, message, is_absolute_path=False) -> str:
|
||||
if self.contact.is_chatroom:
|
||||
avatar = message[13].smallHeadImgUrl
|
||||
else:
|
||||
avatar = Me().smallHeadImgUrl if is_send else self.contact.smallHeadImgUrl
|
||||
if is_absolute_path:
|
||||
if self.contact.is_chatroom:
|
||||
# message[13].save_avatar()
|
||||
avatar = message[13].avatar
|
||||
else:
|
||||
avatar = Me().avatar if is_send else self.contact.avatar
|
||||
return avatar
|
||||
|
||||
def get_display_name(self, is_send, message) -> str:
|
||||
if self.contact.is_chatroom:
|
||||
if is_send:
|
||||
display_name = Me().name
|
||||
else:
|
||||
display_name = message[13].remark
|
||||
else:
|
||||
display_name = None
|
||||
return display_name
|
||||
|
||||
def add_message(self, message):
|
||||
try:
|
||||
type_ = message[2]
|
||||
str_content = message[7]
|
||||
str_time = message[8]
|
||||
# print(type_, type(type_))
|
||||
is_send = message[4]
|
||||
avatar = self.get_avatar_path(is_send, message,True)
|
||||
display_name = self.get_display_name(is_send, message)
|
||||
timestamp = message[5]
|
||||
BytesExtra = message[10]
|
||||
if type_ == 1:
|
||||
if self.is_5_min(timestamp):
|
||||
time_message = Notice(self.last_str_time)
|
||||
self.last_str_time = str_time
|
||||
self.chat_window.add_message_item(time_message, 0)
|
||||
bubble_message = BubbleMessage(
|
||||
str_content,
|
||||
avatar,
|
||||
type_,
|
||||
is_send,
|
||||
display_name=display_name
|
||||
)
|
||||
self.chat_window.add_message_item(bubble_message, 0)
|
||||
elif type_ == 3:
|
||||
# return
|
||||
if self.is_5_min(timestamp):
|
||||
time_message = Notice(self.last_str_time)
|
||||
self.last_str_time = str_time
|
||||
self.chat_window.add_message_item(time_message, 0)
|
||||
image_path = hard_link_db.get_image(content=str_content, bytesExtra=BytesExtra, up_dir=Me().wx_dir,thumb=False)
|
||||
image_path = get_abs_path(image_path)
|
||||
bubble_message = BubbleMessage(
|
||||
image_path,
|
||||
avatar,
|
||||
type_,
|
||||
is_send
|
||||
)
|
||||
self.chat_window.add_message_item(bubble_message, 0)
|
||||
elif type_ == 47:
|
||||
return
|
||||
if self.is_5_min(timestamp):
|
||||
time_message = Notice(self.last_str_time)
|
||||
self.last_str_time = str_time
|
||||
self.chat_window.add_message_item(time_message, 0)
|
||||
image_path = get_emoji(str_content, thumb=True)
|
||||
bubble_message = BubbleMessage(
|
||||
image_path,
|
||||
avatar,
|
||||
3,
|
||||
is_send
|
||||
)
|
||||
self.chat_window.add_message_item(bubble_message, 0)
|
||||
elif type_ == 10000:
|
||||
str_content = str_content.lstrip('<revokemsg>').rstrip('</revokemsg>')
|
||||
message = Notice(str_content)
|
||||
self.chat_window.add_message_item(message, 0)
|
||||
except:
|
||||
print(message)
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
|
||||
class ShowChatThread(QThread):
|
||||
showSingal = pyqtSignal(tuple)
|
||||
finishSingal = pyqtSignal(int)
|
||||
msg_id = 0
|
||||
|
||||
# heightSingal = pyqtSignal(int)
|
||||
def __init__(self, contact):
|
||||
super().__init__()
|
||||
self.last_message_id = 9999999999
|
||||
self.wxid = contact.wxid
|
||||
|
||||
def run(self) -> None:
|
||||
messages = msg_db.get_message_by_num(self.wxid, self.last_message_id)
|
||||
if messages:
|
||||
self.last_message_id = messages[-1][0]
|
||||
for message in messages:
|
||||
self.showSingal.emit(message)
|
||||
self.msg_id += 1
|
||||
self.finishSingal.emit(1)
|
||||
186
app/ui/chat/chat_window.py
Normal file
186
app/ui/chat/chat_window.py
Normal file
@@ -0,0 +1,186 @@
|
||||
import shutil
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtWidgets import QWidget, QMessageBox, QAction, QLineEdit
|
||||
|
||||
from app.DataBase import micro_msg_db, misc_db, msg_db, close_db
|
||||
from app.components import ContactQListWidgetItem, ScrollBar
|
||||
from app.person import Contact, Me
|
||||
from app.ui.Icon import Icon
|
||||
from app.util import search
|
||||
from .ai_chat import AIChat
|
||||
from .chatUi import Ui_Form
|
||||
from .chat_info import ChatInfo
|
||||
|
||||
# 美化样式表
|
||||
Stylesheet = """
|
||||
|
||||
/*去掉item虚线边框*/
|
||||
QListWidget, QListView, QTreeWidget, QTreeView {
|
||||
outline: 0px;
|
||||
border:none;
|
||||
}
|
||||
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
|
||||
QListWidget {
|
||||
min-width: 250px;
|
||||
max-width: 250px;
|
||||
min-height: 80px;
|
||||
max-height: 1200px;
|
||||
color: black;
|
||||
border:none;
|
||||
}
|
||||
QListWidget::item{
|
||||
height:60px;
|
||||
width:250px;
|
||||
}
|
||||
/*被选中时的背景颜色和左边框颜色*/
|
||||
QListWidget::item:selected {
|
||||
background: rgb(230, 235, 240);
|
||||
border-left:none;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class ChatWindow(QWidget, Ui_Form):
|
||||
load_finish_signal = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.show_thread = None
|
||||
self.setupUi(self)
|
||||
self.ok_flag = False
|
||||
self.setStyleSheet(Stylesheet)
|
||||
self.contacts = [[], []]
|
||||
self.init_ui()
|
||||
self.show_chats()
|
||||
self.visited = set()
|
||||
self.now_index = 0
|
||||
|
||||
def init_ui(self):
|
||||
search_action = QAction(self.lineEdit)
|
||||
search_action.setIcon(Icon.Search_Icon)
|
||||
self.lineEdit.addAction(search_action, QLineEdit.LeadingPosition)
|
||||
self.lineEdit.returnPressed.connect(self.search_contact)
|
||||
self.listWidget.clear()
|
||||
self.listWidget.setVerticalScrollBar(ScrollBar())
|
||||
self.listWidget.currentRowChanged.connect(self.setCurrentIndex)
|
||||
self.listWidget.setCurrentRow(0)
|
||||
self.stackedWidget.setCurrentIndex(0)
|
||||
pixmap = QPixmap(Icon.Default_avatar_path).scaled(45, 45)
|
||||
contact_item = ContactQListWidgetItem('AI小助手', '', pixmap)
|
||||
self.listWidget.addItem(contact_item)
|
||||
self.listWidget.setItemWidget(contact_item, contact_item.widget)
|
||||
chat_info_window = AIChat(Me())
|
||||
self.stackedWidget.addWidget(chat_info_window)
|
||||
|
||||
def show_chats(self):
|
||||
# return
|
||||
if self.ok_flag:
|
||||
return
|
||||
msg_db.init_database()
|
||||
micro_msg_db.init_database()
|
||||
if not msg_db.open_flag:
|
||||
QMessageBox.critical(self, "错误", "数据库不存在\n请先解密数据库")
|
||||
self.show_thread = ShowThread()
|
||||
self.show_thread.load_finish_signal.connect(self.load_finish_signal)
|
||||
self.show_thread.start()
|
||||
return
|
||||
self.show_thread = ShowContactThread()
|
||||
self.show_thread.showSingal.connect(self.show_chat)
|
||||
self.show_thread.load_finish_signal.connect(self.stop_loading)
|
||||
self.show_thread.start()
|
||||
self.ok_flag = True
|
||||
|
||||
def search_contact(self):
|
||||
content = self.lineEdit.text()
|
||||
if not content:
|
||||
return
|
||||
index = self.search_contact_index(content)
|
||||
self.select_contact_by_index(index)
|
||||
|
||||
def search_contact_index(self, content: str) -> int:
|
||||
return search.search_by_content(content, self.contacts)
|
||||
|
||||
def select_contact_by_index(self, index):
|
||||
self.stackedWidget.setCurrentIndex(index)
|
||||
self.listWidget.setCurrentRow(index)
|
||||
|
||||
def show_chat(self, contact):
|
||||
# return
|
||||
self.contacts[0].append(contact.remark)
|
||||
self.contacts[1].append(contact.nickName)
|
||||
contact_item = ContactQListWidgetItem(contact.remark, contact.smallHeadImgUrl, contact.smallHeadImgBLOG)
|
||||
self.listWidget.addItem(contact_item)
|
||||
self.listWidget.setItemWidget(contact_item, contact_item.widget)
|
||||
chat_info_window = ChatInfo(contact)
|
||||
self.stackedWidget.addWidget(chat_info_window)
|
||||
|
||||
def setCurrentIndex(self, row):
|
||||
# print(row)
|
||||
item = self.listWidget.item(self.now_index)
|
||||
item.dis_select()
|
||||
self.stackedWidget.setCurrentIndex(row)
|
||||
item = self.listWidget.item(row)
|
||||
item.select()
|
||||
self.now_index = row
|
||||
if row not in self.visited:
|
||||
chat_info_window = self.stackedWidget.currentWidget()
|
||||
chat_info_window.update_history_messages()
|
||||
self.visited.add(row)
|
||||
|
||||
def stop_loading(self, a0):
|
||||
# self.label.setVisible(False)
|
||||
self.load_finish_signal.emit(True)
|
||||
|
||||
|
||||
class ShowContactThread(QThread):
|
||||
showSingal = pyqtSignal(Contact)
|
||||
load_finish_signal = pyqtSignal(bool)
|
||||
|
||||
# heightSingal = pyqtSignal(int)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def run(self) -> None:
|
||||
contact_info_lists = micro_msg_db.get_contact()
|
||||
if not contact_info_lists:
|
||||
self.load_finish_signal.emit(True)
|
||||
# QMessageBox.critical(None, "错误", "数据库错误,请重启电脑后重试")
|
||||
close_db()
|
||||
try:
|
||||
shutil.rmtree('./app/Database/Msg')
|
||||
except:
|
||||
pass
|
||||
return
|
||||
for contact_info_list in contact_info_lists:
|
||||
# UserName, Alias,Type,Remark,NickName,PYInitial,RemarkPYInitial,ContactHeadImgUrl.smallHeadImgUrl,ContactHeadImgUrl,bigHeadImgUrl
|
||||
contact_info = {
|
||||
'UserName': contact_info_list[0],
|
||||
'Alias': contact_info_list[1],
|
||||
'Type': contact_info_list[2],
|
||||
'Remark': contact_info_list[3],
|
||||
'NickName': contact_info_list[4],
|
||||
'smallHeadImgUrl': contact_info_list[7]
|
||||
}
|
||||
contact = Contact(contact_info)
|
||||
contact.smallHeadImgBLOG = misc_db.get_avatar_buffer(contact.wxid)
|
||||
contact.set_avatar(contact.smallHeadImgBLOG)
|
||||
self.showSingal.emit(contact)
|
||||
# pprint(contact.__dict__)
|
||||
self.load_finish_signal.emit(True)
|
||||
|
||||
|
||||
class ShowThread(QThread):
|
||||
showSingal = pyqtSignal(Contact)
|
||||
load_finish_signal = pyqtSignal(bool)
|
||||
|
||||
# heightSingal = pyqtSignal(int)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def run(self) -> None:
|
||||
QThread.sleep(1)
|
||||
self.load_finish_signal.emit(True)
|
||||
Reference in New Issue
Block a user