mirror of
https://github.com/LC044/WeChatMsg
synced 2025-02-22 02:22:17 +08:00
新增年度报告功能
This commit is contained in:
parent
1708a4649a
commit
1381f9bd8c
@ -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'))
|
@ -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}
|
||||||
|
|
||||||
# 转换为词云数据格式
|
# 转换为词云数据格式
|
||||||
|
@ -12,6 +12,24 @@ wxid
|
|||||||
喔
|
喔
|
||||||
行
|
行
|
||||||
拿
|
拿
|
||||||
|
裂开
|
||||||
|
苦涩
|
||||||
|
叹气
|
||||||
|
让我看看
|
||||||
|
酷
|
||||||
|
奋斗
|
||||||
|
疑问
|
||||||
|
擦汗
|
||||||
|
抠鼻
|
||||||
|
鄙视
|
||||||
|
勾引
|
||||||
|
奸笑
|
||||||
|
嘿哈
|
||||||
|
捂脸
|
||||||
|
机智
|
||||||
|
加油
|
||||||
|
吃瓜
|
||||||
|
尴尬
|
||||||
乡村
|
乡村
|
||||||
炸弹
|
炸弹
|
||||||
腹肌
|
腹肌
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
@ -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
@ -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)
|
||||||
|
@ -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')
|
||||||
|
@ -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/)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
Loading…
Reference in New Issue
Block a user