From 7048cbf17045c1daaac382063f1424f0a372eaf7 Mon Sep 17 00:00:00 2001 From: shuaikangzhou <863909694@qq.com> Date: Sat, 27 Jan 2024 00:12:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E2=80=9D=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E2=80=9C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/DataBase/msg.py | 17 +++++++--- app/analysis/analysis.py | 56 +++++++++++++++++++++++++++++++- app/resources/icons/down.svg | 1 + app/resources/icons/up.svg | 1 + app/resources/icons/update.svg | 1 + app/ui/contact/contactInfo.py | 6 +++- app/ui/mainview.py | 2 +- app/ui/menu/export.py | 3 +- app/ui/menu/export_time_range.py | 19 ++++++++++- app/web_ui/templates/charts.html | 37 +++++++++++++++++++++ app/web_ui/web.py | 44 +++++++++++++++++++++++++ 11 files changed, 176 insertions(+), 11 deletions(-) create mode 100644 app/resources/icons/down.svg create mode 100644 app/resources/icons/up.svg create mode 100644 app/resources/icons/update.svg create mode 100644 app/web_ui/templates/charts.html diff --git a/app/DataBase/msg.py b/app/DataBase/msg.py index 8288987..8209680 100644 --- a/app/DataBase/msg.py +++ b/app/DataBase/msg.py @@ -240,6 +240,13 @@ class Msg: return parser_chatroom_message(result) if username_.__contains__('@chatroom') else result def get_messages_by_type(self, username_, type_, year_='all', time_range=None): + """ + @param username_: + @param type_: + @param year_: + @param time_range: Tuple(timestamp:开始时间戳,timestamp:结束时间戳) + @return: + """ if not self.open_flag: return None if time_range: @@ -260,11 +267,11 @@ class Msg: lock.release() else: sql = ''' - select localId,TalkerId,Type,SubType,IsSender,CreateTime,Status,StrContent,strftime('%Y-%m-%d %H:%M:%S',CreateTime,'unixepoch','localtime') as StrTime,MsgSvrID,BytesExtra,CompressContent,DisplayContent - from MSG - where StrTalker=? and Type=? and strftime('%Y', CreateTime, 'unixepoch', 'localtime') = ? - order by CreateTime - ''' + select localId,TalkerId,Type,SubType,IsSender,CreateTime,Status,StrContent,strftime('%Y-%m-%d %H:%M:%S',CreateTime,'unixepoch','localtime') as StrTime,MsgSvrID,BytesExtra,CompressContent,DisplayContent + from MSG + where StrTalker=? and Type=? and strftime('%Y', CreateTime, 'unixepoch', 'localtime') = ? + order by CreateTime + ''' try: lock.acquire(True) self.cursor.execute(sql, [username_, type_, year_]) diff --git a/app/analysis/analysis.py b/app/analysis/analysis.py index a4d279b..d39340f 100644 --- a/app/analysis/analysis.py +++ b/app/analysis/analysis.py @@ -73,6 +73,60 @@ def wordcloud(wxid, is_Annual_report=False, year='2023', who='1'): } +def wordcloud_(wxid, is_Annual_report=False, time_range=None): + import jieba + txt_messages = msg_db.get_messages_by_type(wxid, MsgType.TEXT, time_range=time_range) + if not txt_messages: + return { + 'chart_data': None, + 'keyword': "没有聊天你想分析啥", + 'max_num': "0", + 'dialogs': [] + } + # text = ''.join(map(lambda x: x[7], txt_messages)) + text = ''.join(map(lambda x: x[7], txt_messages)) # 1“我”说的话,0“Ta”说的话 + + total_msg_len = len(text) + # 使用jieba进行分词,并加入停用词 + words = jieba.cut(text) + # 统计词频 + word_count = Counter(words) + # 过滤停用词 + stopwords_file = './app/data/stopwords.txt' + with open(stopwords_file, "r", encoding="utf-8") as stopword_file: + stopwords1 = set(stopword_file.read().splitlines()) + # 构建 FFmpeg 可执行文件的路径 + stopwords = set() + stopwords_file = './app/resources/data/stopwords.txt' + if not os.path.exists(stopwords_file): + resource_dir = getattr(sys, '_MEIPASS', os.path.abspath(os.path.dirname(__file__))) + stopwords_file = os.path.join(resource_dir, 'app', 'resources', 'data', 'stopwords.txt') + with open(stopwords_file, "r", encoding="utf-8") as stopword_file: + stopwords = set(stopword_file.read().splitlines()) + stopwords = stopwords.union(stopwords1) + filtered_word_count = {word: count for word, count in word_count.items() if len(word) > 1 and word not in stopwords} + + # 转换为词云数据格式 + data = [(word, count) for word, count in filtered_word_count.items()] + # text_data = data + data.sort(key=lambda x: x[1], reverse=True) + + text_data = data[:100] if len(data) > 100 else data + # 创建词云图 + keyword, max_num = text_data[0] + w = ( + WordCloud(init_opts=opts.InitOpts(width=f"{wordcloud_width}px", height=f"{wordcloud_height}px")) + .add(series_name="聊天文字", data_pair=text_data, word_size_range=[5, 100]) + ) + # return w.render_embed() + return { + 'chart_data': w.dump_options_with_quotes(), + 'keyword': keyword, + 'max_num': str(max_num), + 'dialogs': msg_db.get_messages_by_keyword(wxid, keyword, num=5, max_len=12) + } + + def wordcloud_christmas(wxid, year='2023'): import jieba txt_messages = msg_db.get_messages_by_type(wxid, MsgType.TEXT, year) @@ -99,7 +153,7 @@ def wordcloud_christmas(wxid, year='2023'): stopwords_file = './app/resources/data/stopwords.txt' if not os.path.exists(stopwords_file): resource_dir = getattr(sys, '_MEIPASS', os.path.abspath(os.path.dirname(__file__))) - stopwords_file = os.path.join(resource_dir, 'app', 'resources', 'data','stopwords.txt') + stopwords_file = os.path.join(resource_dir, 'app', 'resources', 'data', 'stopwords.txt') with open(stopwords_file, "r", encoding="utf-8") as stopword_file: stopwords = set(stopword_file.read().splitlines()) stopwords = stopwords.union(stopwords1) diff --git a/app/resources/icons/down.svg b/app/resources/icons/down.svg new file mode 100644 index 0000000..7c8b4a4 --- /dev/null +++ b/app/resources/icons/down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/resources/icons/up.svg b/app/resources/icons/up.svg new file mode 100644 index 0000000..f3b5d91 --- /dev/null +++ b/app/resources/icons/up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/resources/icons/update.svg b/app/resources/icons/update.svg new file mode 100644 index 0000000..6eb22e7 --- /dev/null +++ b/app/resources/icons/update.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/ui/contact/contactInfo.py b/app/ui/contact/contactInfo.py index df09a99..bae8e18 100644 --- a/app/ui/contact/contactInfo.py +++ b/app/ui/contact/contactInfo.py @@ -60,7 +60,11 @@ class ContactInfo(QWidget, Ui_Form): self.toolButton_output.showMenu() def analysis(self): - QDesktopServices.openUrl(QUrl("https://memotrace.lc044.love/")) + # QDesktopServices.openUrl(QUrl("https://memotrace.lc044.love/")) + self.report_thread = ReportThread(self.contact) + # self.report_thread.okSignal.connect(lambda x: QDesktopServices.openUrl(QUrl("http://127.0.0.1:21314"))) + self.report_thread.start() + QDesktopServices.openUrl(QUrl("http://127.0.0.1:21314/charts")) def annual_report(self): if 'room' in self.contact.wxid: diff --git a/app/ui/mainview.py b/app/ui/mainview.py index 465e33a..8f539ea 100644 --- a/app/ui/mainview.py +++ b/app/ui/mainview.py @@ -199,7 +199,7 @@ QComboBox::down-arrow:on QLineEdit { background:transparent; - border-radius:15px; + border-radius:10px; border-top: 0px solid #b2e281; border-bottom: 1px solid rgb(227,228,222); border-right: 1px solid rgb(227,228,222); diff --git a/app/ui/menu/export.py b/app/ui/menu/export.py index d8db9d3..7db8901 100644 --- a/app/ui/menu/export.py +++ b/app/ui/menu/export.py @@ -6,12 +6,11 @@ from typing import List from PyQt5 import QtWidgets from PyQt5.QtCore import QTimer, QThread, pyqtSignal, QObject from PyQt5.QtGui import QTextCursor -from PyQt5.QtWidgets import QApplication, QDialog, QCheckBox, QMessageBox, QCalendarWidget +from PyQt5.QtWidgets import QApplication, QDialog, QCheckBox, QMessageBox from app.DataBase import micro_msg_db, misc_db from app.DataBase.output_pc import Output from app.components import ScrollBar -from app.components.calendar_dialog import CalendarDialog from app.components.export_contact_item import ContactQListWidgetItem from app.person import Contact from app.ui.menu.exportUi import Ui_Dialog diff --git a/app/ui/menu/export_time_range.py b/app/ui/menu/export_time_range.py index eeb5098..47b3254 100644 --- a/app/ui/menu/export_time_range.py +++ b/app/ui/menu/export_time_range.py @@ -1,6 +1,7 @@ from datetime import datetime from PyQt5 import QtWidgets -from PyQt5.QtCore import QTimer, QThread, pyqtSignal +from PyQt5.QtCore import QTimer, QThread, pyqtSignal, Qt, QPoint +from PyQt5.QtGui import QMouseEvent from PyQt5.QtWidgets import QApplication, QDialog, QCheckBox, QMessageBox, QCalendarWidget, QWidget, QVBoxLayout, QLabel from app.components.calendar_dialog import CalendarDialog @@ -33,6 +34,7 @@ class TimeRangeDialog(QDialog, Ui_Dialog): self.calendar = None self.setupUi(self) self.setWindowTitle('选择日期范围') + # self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) self.setStyleSheet(Stylesheet) self.toolButton_start_time.clicked.connect(self.select_date_start) self.toolButton_end_time.clicked.connect(self.select_date_end) @@ -77,6 +79,21 @@ class TimeRangeDialog(QDialog, Ui_Dialog): self.calendar.set_end_date() self.calendar.show() + def mouseMoveEvent(self, e: QMouseEvent): # 重写移动事件 + if self._tracking: + self._endPos = e.pos() - self._startPos + self.move(self.pos() + self._endPos) + + def mousePressEvent(self, e: QMouseEvent): + if e.button() == Qt.LeftButton: + self._startPos = QPoint(e.x(), e.y()) + self._tracking = True + + def mouseReleaseEvent(self, e: QMouseEvent): + if e.button() == Qt.LeftButton: + self._tracking = False + self._startPos = None + self._endPos = None if __name__ == '__main__': import sys diff --git a/app/web_ui/templates/charts.html b/app/web_ui/templates/charts.html new file mode 100644 index 0000000..979e45c --- /dev/null +++ b/app/web_ui/templates/charts.html @@ -0,0 +1,37 @@ + + +
+ + +