新增年度报告功能

This commit is contained in:
shuaikangzhou 2023-12-05 00:13:20 +08:00
parent 1708a4649a
commit 1381f9bd8c
10 changed files with 5107 additions and 3674 deletions

View File

@ -93,7 +93,7 @@ class Msg:
from MSG from MSG
where StrTalker = ? and localId < ? where StrTalker = ? and localId < ?
order by CreateTime desc order by CreateTime desc
limit 10 limit 10
''' '''
result = None result = None
if not self.open_flag: if not self.open_flag:
@ -170,6 +170,24 @@ class Msg:
return res return res
def get_first_time_of_message(self, username_):
if not self.open_flag:
return None
sql = '''
select StrContent,strftime('%Y-%m-%d %H:%M:%S',CreateTime,'unixepoch','localtime') as StrTime
from MSG
where StrTalker=?
order by CreateTime
limit 1
'''
try:
lock.acquire(True)
self.cursor.execute(sql, [username_])
result = self.cursor.fetchone()
finally:
lock.release()
return result
def close(self): def close(self):
if self.open_flag: if self.open_flag:
try: try:
@ -195,3 +213,4 @@ if __name__ == '__main__':
pprint(msg.get_message_by_num('wxid_0o18ef858vnu22', local_id)) pprint(msg.get_message_by_num('wxid_0o18ef858vnu22', local_id))
print(msg.get_messages_by_keyword(wxid, '干嘛')) print(msg.get_messages_by_keyword(wxid, '干嘛'))
pprint(msg.get_messages_by_keyword(wxid, '干嘛')[0]) pprint(msg.get_messages_by_keyword(wxid, '干嘛')[0])
print(msg.get_first_time_of_message('wxid_0o18ef858vnu22'))

View File

@ -1,11 +1,15 @@
from collections import Counter from collections import Counter
from PyQt5.QtCore import QFile, QTextStream, QIODevice
from app.DataBase import msg_db, MsgType from app.DataBase import msg_db, MsgType
from app.person_pc import ContactPC from app.person_pc import ContactPC
import jieba import jieba
from pyecharts import options as opts from pyecharts import options as opts
from pyecharts.charts import Pie, WordCloud, Calendar, Bar, Line, Timeline, Grid from pyecharts.charts import Pie, WordCloud, Calendar, Bar, Line, Timeline, Grid
from app.resources import resource_rc
var = resource_rc.qt_resource_name
charts_width = 800 charts_width = 800
charts_height = 450 charts_height = 450
wordcloud_width = 780 wordcloud_width = 780
@ -22,9 +26,18 @@ def wordcloud(wxid):
# 统计词频 # 统计词频
word_count = Counter(words) word_count = Counter(words)
# 过滤停用词 # 过滤停用词
stopwords_file = '../data/stopwords.txt' stopwords_file = './app/data/stopwords.txt'
with open(stopwords_file, "r", encoding="utf-8") as stopword_file: try:
stopwords = set(stopword_file.read().splitlines()) with open(stopwords_file, "r", encoding="utf-8") as stopword_file:
stopwords = set(stopword_file.read().splitlines())
except:
file = QFile(':/data/stopwords.txt')
if file.open(QIODevice.ReadOnly | QIODevice.Text):
stream = QTextStream(file)
stream.setCodec('utf-8')
content = stream.readAll()
file.close()
stopwords = set(content.splitlines())
filtered_word_count = {word: count for word, count in word_count.items() if len(word) > 1 and word not in stopwords} filtered_word_count = {word: count for word, count in word_count.items() if len(word) > 1 and word not in stopwords}
# 转换为词云数据格式 # 转换为词云数据格式

View File

@ -12,6 +12,24 @@ wxid
裂开
苦涩
叹气
让我看看
奋斗
疑问
擦汗
抠鼻
鄙视
勾引
奸笑
嘿哈
捂脸
机智
加油
吃瓜
尴尬
乡村 乡村
炸弹 炸弹
腹肌 腹肌

View File

@ -168,12 +168,6 @@ def resource_path(relative_path):
@log @log
def get_info(VERSION_LIST): def get_info(VERSION_LIST):
# try:
# with open(VERSION_LIST_PATH, "r", encoding="utf-8") as f:
# VERSION_LIST = json.load(f)
# except:
# with open(resource_path(VERSION_LIST_PATH), "r", encoding="utf-8") as f:
# VERSION_LIST = json.load(f)
result = read_info(VERSION_LIST, True) # 读取微信信息 result = read_info(VERSION_LIST, True) # 读取微信信息
return result return result

View File

@ -1,3 +1,4 @@
import os.path
from typing import Dict from typing import Dict
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
@ -61,6 +62,18 @@ class ContactPC:
self.avatar.loadFromData(img_bytes, format='jfif') self.avatar.loadFromData(img_bytes, format='jfif')
self.avatar.scaled(60, 60, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) self.avatar.scaled(60, 60, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
def save_avatar(self, path=None):
if not self.avatar:
return
if path:
save_path = path
else:
os.makedirs('./data/avatar', exist_ok=True)
save_path = os.path.join(f'data/avatar/', self.wxid + '.png')
self.avatar_path = save_path
self.avatar.save(save_path)
print('保存头像', save_path)
if __name__ == '__main__': if __name__ == '__main__':
p1 = MePC() p1 = MePC()

View File

@ -25,5 +25,6 @@
</qresource> </qresource>
<qresource prefix="/data"> <qresource prefix="/data">
<file>version_list.json</file> <file>version_list.json</file>
<file>stopwords.txt</file>
</qresource> </qresource>
</RCC> </RCC>

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,12 @@
from PyQt5.QtCore import pyqtSignal, QUrl from PyQt5.QtCore import pyqtSignal, QUrl, QThread
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWidgets import QWidget, QMenu, QAction, QToolButton, QMessageBox from PyQt5.QtWidgets import QWidget, QMenu, QAction, QToolButton, QMessageBox
from app.DataBase.output_pc import Output from app.DataBase.output_pc import Output
from app.ui_pc.Icon import Icon from app.ui_pc.Icon import Icon
from .contactInfoUi import Ui_Form from .contactInfoUi import Ui_Form
from .userinfo import userinfo from .userinfo import userinfo
from ...person_pc import ContactPC
class ContactInfo(QWidget, Ui_Form): class ContactInfo(QWidget, Ui_Form):
@ -15,7 +17,7 @@ class ContactInfo(QWidget, Ui_Form):
def __init__(self, contact, parent=None): def __init__(self, contact, parent=None):
super(ContactInfo, self).__init__(parent) super(ContactInfo, self).__init__(parent)
self.setupUi(self) self.setupUi(self)
self.contact = contact self.contact:ContactPC = contact
self.view_userinfo = userinfo.UserinfoController(self.contact) self.view_userinfo = userinfo.UserinfoController(self.contact)
self.btn_back.clicked.connect(self.back) self.btn_back.clicked.connect(self.back)
self.init_ui() self.init_ui()
@ -66,14 +68,17 @@ class ContactInfo(QWidget, Ui_Form):
self.view_analysis.start() self.view_analysis.start()
def annual_report(self): def annual_report(self):
QMessageBox.warning( # QMessageBox.warning(
self, # self,
"提示", # "提示",
"敬请期待" # "敬请期待"
) # )
return # return
# self.report = report.ReportController(self.contact) self.contact.save_avatar()
# self.report.show() 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"))
def emotionale_Analysis(self): def emotionale_Analysis(self):
QMessageBox.warning(self, QMessageBox.warning(self,
@ -136,3 +141,17 @@ class ContactInfo(QWidget, Ui_Form):
def set_progressBar_range(self, value): def set_progressBar_range(self, value):
self.view_userinfo.progressBar.setVisible(True) self.view_userinfo.progressBar.setVisible(True)
self.view_userinfo.progressBar.setRange(0, value) self.view_userinfo.progressBar.setRange(0, value)
class ReportThread(QThread):
okSignal = pyqtSignal(bool)
def __init__(self, contact):
super().__init__()
self.contact = contact
def run(self):
from app.web_ui import web
web.contact = self.contact
web.run(port='21314')
self.okSignal.emit(True)

View File

@ -1,15 +1,21 @@
import json import json
import os
import sys
from flask import Flask, render_template from flask import Flask, render_template, send_file
from pyecharts import options as opts from pyecharts import options as opts
from pyecharts.charts import Bar from pyecharts.charts import Bar
from pyecharts.globals import ThemeType from pyecharts.globals import ThemeType
from app.DataBase import msg_db from app.DataBase import msg_db
from app.analysis import analysis from app.analysis import analysis
from app.person_pc import ContactPC, MePC
app = Flask(__name__) app = Flask(__name__)
wxid = ''
contact: ContactPC = None
@app.route("/") @app.route("/")
def index(): def index():
@ -37,24 +43,22 @@ def index0():
def home(): def home():
data = { data = {
'sub_title': '二零二三年度报告', 'sub_title': '二零二三年度报告',
'avatar_path': "static/my_resource/avatar.png", 'avatar_path': contact.avatar_path,
'nickname': '司小远', 'nickname': contact.remark,
'first_time': '2023-09-18 20:39:08', 'first_time': msg_db.get_first_time_of_message(contact.wxid)[1],
} }
return render_template('home.html', **data) return render_template('home.html', **data)
@app.route('/message_num') @app.route('/wordcloud')
def one(): def one():
msg_db.init_database(path='../DataBase/Msg/MSG.db') wxid = contact.wxid
wxid = 'wxid_0o18ef858vnu22'
wxid = 'wxid_8piw6sb4hvfm22'
# wxid = 'wxid_lltzaezg38so22' # wxid = 'wxid_lltzaezg38so22'
world_cloud_data = analysis.wordcloud(wxid) world_cloud_data = analysis.wordcloud(wxid)
# 创建一个简单的柱状图
with open('message_num_test.html','w',encoding='utf-8') as f: with open('wordcloud.html', 'w', encoding='utf-8') as f:
f.write(render_template('message_num.html', **world_cloud_data)) f.write(render_template('wordcloud.html', **world_cloud_data))
return render_template('message_num.html', **world_cloud_data) return render_template('wordcloud.html', **world_cloud_data)
@app.route('/test') @app.route('/test')
@ -68,5 +72,24 @@ def test():
return bar.dump_options_with_quotes() return bar.dump_options_with_quotes()
def run(port=21314):
app.run(debug=True, host='0.0.0.0', port=port, use_reloader=False)
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
@app.route('/data/avatar/<filename>')
def get_image(filename):
try:
# 返回动态生成的图片
return send_file(os.path.join("../../data/avatar/", filename), mimetype='image/png')
except:
return send_file(os.path.join(f"{os.getcwd()}/data/avatar/", filename), mimetype='image/png')
if __name__ == "__main__": if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0') app.run(debug=True, host='0.0.0.0')

View File

@ -288,7 +288,7 @@ python main.py
# 🏆致谢 # 🏆致谢
* PC微信解密工具:[https://github.com/xaoyaoo/PyWxDump](https://github.com/xaoyaoo/PyWxDump) * PC微信解密工具:[https://github.com/xaoyaoo/PyWxDump](https://github.com/xaoyaoo/PyWxDump)
* PyQt组件库[https://github.com/PyQt5/CustomWidgets](https://github.com/PyQt5/CustomWidgets) * PyQt组件库:[https://github.com/PyQt5/CustomWidgets](https://github.com/PyQt5/CustomWidgets)
* 我的得力助手:[ChatGPT](https://chat.openai.com/) * 我的得力助手:[ChatGPT](https://chat.openai.com/)
--- ---