init
This commit is contained in:
0
app/web_ui/__init__.py
Normal file
0
app/web_ui/__init__.py
Normal file
155
app/web_ui/templates/charts.html
Normal file
155
app/web_ui/templates/charts.html
Normal file
@@ -0,0 +1,155 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>微信年度聊天报告</title>
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts@latest/dist/echarts.min.js"></script>
|
||||
<script type="text/javascript" src="https://assets.pyecharts.org/assets/v5/echarts-wordcloud.min.js"></script>
|
||||
<style>
|
||||
body{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{{my_nickname}}——{{ta_nickname}}</h1>
|
||||
<div>
|
||||
<p class="mt-3">我们第一次聊天在</p>
|
||||
<p id="first_time" class="first-time">{{first_time}}</p>
|
||||
<p class="mt-3">距今已有</p>
|
||||
<div class="mt-3">
|
||||
<span id="t_d"></span>
|
||||
<span id="t_h"></span>
|
||||
<span id="t_m"></span>
|
||||
<span id="t_s"></span>
|
||||
</div>
|
||||
<div><br></div>
|
||||
</div>
|
||||
<div id="echarts-month_count" style="width: 800px; height: 600px;"></div>
|
||||
<div>
|
||||
<h2>消息统计</h2>
|
||||
<div id="echarts-sender" style="width: 800px; height: 600px;"></div>
|
||||
<div id="echarts-types" style="width: 800px; height: 600px;"></div>
|
||||
<div id="echarts-weekday" style="width: 800px; height: 600px;"></div>
|
||||
</div>
|
||||
<div id="echarts-wordcloud" style="width: 800px; height: 800px;"></div>
|
||||
<div id="echarts-calendar" style="width: 800px; height: 300px;"></div>
|
||||
|
||||
|
||||
<script type="text/javascript"> function getRTime() {
|
||||
var tt = document.getElementById("first_time").innerText;
|
||||
var EndTime = new Date(tt);
|
||||
var NowTime = new Date();
|
||||
var t = NowTime.getTime()-EndTime.getTime();
|
||||
var d = Math.floor(t / 1000 / 60 / 60 / 24);
|
||||
var h = Math.floor(t / 1000 / 60 / 60 % 24);
|
||||
var m = Math.floor(t / 1000 / 60 % 60);
|
||||
var s = Math.floor(t / 1000 % 60);
|
||||
document.getElementById("t_d").innerHTML = d + " 天";
|
||||
document.getElementById("t_h").innerHTML = h + " 时";
|
||||
document.getElementById("t_m").innerHTML = m + " 分";
|
||||
document.getElementById("t_s").innerHTML = s + " 秒";
|
||||
}
|
||||
setInterval(getRTime, 1000);
|
||||
|
||||
</script>
|
||||
<script>
|
||||
var wxid = '{{wxid}}';
|
||||
function month_count(time_range){
|
||||
const requestData = {
|
||||
wxid: wxid,
|
||||
time_range: time_range
|
||||
};
|
||||
fetch('/month_count',{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(chartOptions => {
|
||||
// 在这里使用 ECharts 渲染图表
|
||||
var myChart = echarts.init(document.getElementById('echarts-month_count'));
|
||||
var option = chartOptions.chart_data;
|
||||
myChart.setOption(JSON.parse(option));
|
||||
});
|
||||
}
|
||||
function wordcloud(time_range){
|
||||
const requestData = {
|
||||
wxid: wxid,
|
||||
time_range: time_range
|
||||
};
|
||||
fetch('/wordcloud',{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(chartOptions => {
|
||||
// 在这里使用 ECharts 渲染图表
|
||||
var myChart = echarts.init(document.getElementById('echarts-wordcloud'));
|
||||
var option = chartOptions.chart_data;
|
||||
myChart.setOption(JSON.parse(option));
|
||||
});
|
||||
}
|
||||
function calendar(time_range){
|
||||
const requestData = {
|
||||
wxid: wxid,
|
||||
time_range: time_range
|
||||
};
|
||||
fetch('/calendar',{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(chartOptions => {
|
||||
// 在这里使用 ECharts 渲染图表
|
||||
var myChart = echarts.init(document.getElementById('echarts-calendar'));
|
||||
var option = chartOptions.chart_data;
|
||||
myChart.setOption(JSON.parse(option));
|
||||
});
|
||||
}
|
||||
function message_counter(time_range){
|
||||
const requestData = {
|
||||
wxid: wxid,
|
||||
time_range: time_range
|
||||
};
|
||||
fetch('/message_counter',{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(chartOptions => {
|
||||
// 在这里使用 ECharts 渲染图表
|
||||
var myChart = echarts.init(document.getElementById('echarts-sender'));
|
||||
var option = chartOptions.chart_data_sender;
|
||||
myChart.setOption(JSON.parse(option));
|
||||
var myChart1 = echarts.init(document.getElementById('echarts-types'));
|
||||
var option = chartOptions.chart_data_types;
|
||||
myChart1.setOption(JSON.parse(option));
|
||||
var myChart2 = echarts.init(document.getElementById('echarts-weekday'));
|
||||
var option = chartOptions.chart_data_weekday;
|
||||
myChart2.setOption(JSON.parse(option));
|
||||
});
|
||||
}
|
||||
var time_range=['1997-01-01 00:00:00','2035-01-01 00:00:00']
|
||||
message_counter(time_range);
|
||||
month_count(time_range);
|
||||
calendar(time_range);
|
||||
wordcloud(time_range);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
383
app/web_ui/templates/christmas.html
Normal file
383
app/web_ui/templates/christmas.html
Normal file
@@ -0,0 +1,383 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>微信年度聊天报告</title>
|
||||
<link rel="stylesheet" href="https://memotrace.cn/static/css/style.css">
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts@latest/dist/echarts.min.js"></script>
|
||||
<script type="text/javascript" src="https://assets.pyecharts.org/assets/v5/echarts-wordcloud.min.js"></script>
|
||||
<link rel="stylesheet" href="https://memotrace.cn/static/css/fullpage.min.css" />
|
||||
<script type="text/javascript" src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
|
||||
<script type="text/javascript" src="https://memotrace.cn/static/js/fullpage.min.js"></script>
|
||||
<script type="text/javascript" src="https://davidshimjs.github.io/qrcodejs/qrcode.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="snow"></div>
|
||||
<!-- Your content goes here -->
|
||||
<div id="fullpage">
|
||||
<div class="section">
|
||||
<div>
|
||||
<img class="Mountain-Image" src="https://www.freeimg.cn/i/2023/12/20/6582c04711cd2.png" alt="Mountain Image">
|
||||
<img class="corner-light light-top-left" src="https://www.freeimg.cn/i/2023/12/20/6582c05d9dcbb.png" alt="Top Left Light">
|
||||
<img class="corner-light light-top-right" src="https://www.freeimg.cn/i/2023/12/20/6582c07b257db.png" alt="Bottom Right Light">
|
||||
<img src="https://www.freeimg.cn/i/2023/12/20/6582c0514c518.png" alt="Left Bottom Image" class="corner-image left-bottom">
|
||||
<img src="https://www.freeimg.cn/i/2023/12/20/6582c04946138.png" alt="Right Top Image" class="corner-image right-bottom">
|
||||
|
||||
<div class="center-container">
|
||||
<div>
|
||||
<img src="https://www.freeimg.cn/i/2023/12/20/6582c05a78e58.png">
|
||||
</div>
|
||||
<div class="user-container">
|
||||
<div class="user">
|
||||
<img class="avatar" src="{{my_avatar_path}}">
|
||||
<span class="nickname">{{my_nickname}}</span>
|
||||
</div>
|
||||
|
||||
<img src="https://memotrace.cn/static/img/铃铛.png" alt="Right Top Image" class="spliter-img">
|
||||
<div class="user">
|
||||
<img class="avatar" src="{{ta_avatar_path}}">
|
||||
<span class="nickname">{{ta_nickname}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mt-3">我们第一次聊天在</p>
|
||||
<p id="first_time" class="first-time">{{first_time}}</p>
|
||||
<p class="mt-3">距今已有</p>
|
||||
<div class="mt-3">
|
||||
<span id="t_d"></span>
|
||||
<span id="t_h"></span>
|
||||
<span id="t_m"></span>
|
||||
<span id="t_s"></span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div>
|
||||
<img src="img/雪人.gif">
|
||||
</div>
|
||||
<div>
|
||||
<img src="img/雪人1.gif">
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div>
|
||||
<img class="Mountain-Image" src="https://www.freeimg.cn/i/2023/12/20/6582c04711cd2.png" alt="Mountain Image">
|
||||
<img class="corner-light light-top-left" src="https://www.freeimg.cn/i/2023/12/20/6582c05d9dcbb.png" alt="Top Left Light">
|
||||
<img class="corner-light light-top-right" src="https://www.freeimg.cn/i/2023/12/20/6582c07b257db.png" alt="Bottom Right Light">
|
||||
<img src="https://www.freeimg.cn/i/2023/12/20/6582c07223f22.png" alt="礼袋" class="corner-image left-bottom-gift">
|
||||
<img src="https://www.freeimg.cn/i/2023/12/20/6582c055cc6df.png" alt="圣诞老人" class="corner-image right-bottom-oldman">
|
||||
</div>
|
||||
<div class="wordcloud">
|
||||
<div id="word_cloud" class="chart-container"></div>
|
||||
</div>
|
||||
<div class="keyword-container">
|
||||
<div class="tp1">二〇二三</div>
|
||||
<div class="tp1">你们说的最多的是</div>
|
||||
<div class="keyword">“{{keyword}}”<span class="keyword-num">{{keyword_max_num}}</span><span class="tp1">次</span></div>
|
||||
<!-- <img src="static/img/窗雪.png"> -->
|
||||
</div>
|
||||
<div class="dialog-container">
|
||||
{% for dialog in dialogs %}
|
||||
<div class="item item-center">{{dialog[0][3]}}</div>
|
||||
{% if dialog[0][0]==0: %}
|
||||
<div class="item item-left">
|
||||
<img class="bubble-avatar" src="{{ta_avatar_path}}">
|
||||
<div class="bubble bubble-left">
|
||||
{% for p in dialog[0][2][:-1] %}
|
||||
{{p}}<span style="color:red">{{keyword}}</span>
|
||||
{% endfor %}
|
||||
{{dialog[0][2][-1]}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item item-right">
|
||||
<div class="bubble bubble-right">
|
||||
{{dialog[1][2]}}
|
||||
</div>
|
||||
<img class="bubble-avatar" src="{{my_avatar_path}}">
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if dialog[0][0]==1: %}
|
||||
<div class="item item-right">
|
||||
<div class="bubble bubble-right">
|
||||
{% for p in dialog[0][2][:-1] %}
|
||||
{{p}}<span style="color:red">{{keyword}}</span>
|
||||
{% endfor %}
|
||||
{{dialog[0][2][-1]}}
|
||||
</div>
|
||||
<img class="bubble-avatar" src="{{my_avatar_path}}">
|
||||
</div>
|
||||
<div class="item item-left">
|
||||
<img class="bubble-avatar" src="{{ta_avatar_path}}">
|
||||
<div class="bubble bubble-left">
|
||||
{{dialog[1][2]}}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div>
|
||||
<img class="Mountain-Image" src="https://www.freeimg.cn/i/2023/12/20/6582c04711cd2.png" alt="Mountain Image">
|
||||
<img class="corner-light light-top-left txt" src="https://www.freeimg.cn/i/2023/12/20/6582c05d9dcbb.png" alt="Top Left Light">
|
||||
<img class="corner-light light-top-right txt" src="https://www.freeimg.cn/i/2023/12/20/6582c07b257db.png" alt="Bottom Right Light">
|
||||
<img src="https://www.freeimg.cn/i/2023/12/20/6582c04589c47.png" alt="Left Bottom Image" class="corner-image left-bottom">
|
||||
<img src="https://www.freeimg.cn/i/2023/12/21/65831360a36d4.gif" alt="Right Top Image" class="corner-image right-bottom" style="max-height: 500px;">
|
||||
<img src="https://www.freeimg.cn/i/2023/12/20/6582c054816cf.png" alt="圣诞老人" class="center-top-time">
|
||||
<img src="https://memotrace.cn/static/img/平安夜.png" alt="Right Top Image" class="left-time">
|
||||
<div class="time-container">
|
||||
<div class="text112">{{latest_time}}</div>
|
||||
<div class="text112">这么晚了你们还在聊天</div>
|
||||
<div class="text112">那天一定有你们<span style="color: brown;">难忘的回忆</span>吧</div>
|
||||
<div><br></div>
|
||||
<div class="text112">你们都是<span style="color: brown;">{{chat_time_label}}</span></div>
|
||||
<div class="text113">{{chat_time}}</div>
|
||||
<div class="text112">你们一共发送了<span style="color: brown;">{{chat_time_num}}</span>条消息</div>
|
||||
</div>
|
||||
<div class="parent">
|
||||
<div class="dialog-container-time">
|
||||
<div class="item item-center">{{latest_time}}</div>
|
||||
{% for dialog in latest_time_dialog %}
|
||||
{% if dialog[0]==0: %}
|
||||
<div class="item item-left">
|
||||
<img class="bubble-avatar" src="{{ta_avatar_path}}">
|
||||
<div class="bubble bubble-left">
|
||||
{{dialog[1]}}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if dialog[0]==1: %}
|
||||
<div class="item item-right">
|
||||
<div class="bubble bubble-right">
|
||||
{{dialog[1]}}
|
||||
</div>
|
||||
<img class="bubble-avatar" src="{{my_avatar_path}}">
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div>
|
||||
<img class="Mountain-Image" src="https://www.freeimg.cn/i/2023/12/20/6582c04711cd2.png" alt="Mountain Image">
|
||||
<img class="corner-light light-top-left txt" src="https://www.freeimg.cn/i/2023/12/20/6582c05d9dcbb.png" alt="Top Left Light">
|
||||
<img class="corner-light light-top-right txt" src="https://www.freeimg.cn/i/2023/12/20/6582c07b257db.png" alt="Bottom Right Light">
|
||||
<img src="https://www.freeimg.cn/i/2023/12/20/6582c03ce4548.png" alt="Left Bottom Image" class="corner-image left-bottom">
|
||||
<img src="https://www.freeimg.cn/i/2023/12/20/6582c05a9a4bd.png" alt="滑雪的小女孩" class="corner-image right-bottom">
|
||||
<img src="https://www.freeimg.cn/i/2023/12/20/6582c04d5151f.png" alt="Right Top Image" class="snow-ball">
|
||||
<img src="https://memotrace.cn/static/img/礼盒1.png" alt="Right Top Image" class="ttq">
|
||||
<div class="time-container">
|
||||
<div class="text112">过去的一年里</div>
|
||||
<div class="text112">你们一共发送了<span style="color: brown;">{{total_msg_num}}</span>条消息</div>
|
||||
<div class="text112">总计<span style="color: brown;">{{total_num}}</span>字</div>
|
||||
<div><br></div>
|
||||
<div class="text112">你们的聊天似乎没有规律</div>
|
||||
<div class="text112">
|
||||
<span style="color: brown;">{{max_month}}</span>
|
||||
一共发送了
|
||||
<span style="color: brown;">{{max_month_num}}</span>
|
||||
条消息
|
||||
</div>
|
||||
<div class="text112">对你的话说不完</div>
|
||||
<div><br></div>
|
||||
<div class="text112">
|
||||
<span style="color: brown;">{{min_month}}</span>
|
||||
只有
|
||||
<span style="color: brown;">{{min_month_num}}</span>
|
||||
条消息
|
||||
</div>
|
||||
<div class="text112">有时候你们也想静静</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div>
|
||||
<img class="Mountain-Image" src="https://www.freeimg.cn/i/2023/12/20/6582c04711cd2.png" alt="Mountain Image">
|
||||
<img class="corner-light light-top-left txt" src="https://www.freeimg.cn/i/2023/12/20/6582c05d9dcbb.png" alt="Top Left Light">
|
||||
<img class="corner-light light-top-right txt" src="https://www.freeimg.cn/i/2023/12/20/6582c07b257db.png" alt="Bottom Right Light">
|
||||
<img src="https://www.freeimg.cn/i/2023/12/20/6582c064276db.png" alt="包饺子" class="corner-image left-bottom">
|
||||
<img src="https://www.freeimg.cn/i/2023/12/21/658313714609b.png" alt="Right Top Image" class="corner-image right-bottom">
|
||||
<div class="calendar-container">
|
||||
<div class="text012">{{year}}年</div>
|
||||
<div class="text012">
|
||||
我们有
|
||||
<span style="color: brown;">{{chat_days}}</span>
|
||||
天在聊天
|
||||
</div>
|
||||
<div class="text012">有你在的日子里</div>
|
||||
<div class="text012">
|
||||
都很有
|
||||
<span style="color: brown;">意义</span>!
|
||||
</div>
|
||||
<div><br></div>
|
||||
<div class="text012">这一年</div>
|
||||
<div class="text012">
|
||||
一共发送了
|
||||
<span style="color: brown;">{{emoji_total_num}}</span>
|
||||
个表情包
|
||||
</div>
|
||||
<div class="text012">Ta最常用的表情包是</div>
|
||||
<img src="{{emoji_url}}" class="emoji">
|
||||
<div class="text012">
|
||||
一共
|
||||
<span style="color: brown;">{{emoji_num}}</span>次
|
||||
</div>
|
||||
</div>
|
||||
<div id="calendar-chart" class="calendar-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" style="text-align: center;display:flex;justify-content: center;align-items: center;">
|
||||
<h1>分享此页面</h1>
|
||||
<div>
|
||||
<a id="share" href="https://memotrace.cn/" target="_blank">https://memotrace.cn/</a>
|
||||
</div>
|
||||
<button onclick="confirmUpload()">上传并显示二维码</button>
|
||||
<div id="qrcode"></div>
|
||||
<a href="https://memotrace.cn/" target="_blank">点击生成我的年度聊天报告</a>
|
||||
<div style="height:400px"></div>
|
||||
<div>
|
||||
<img src="https://memotrace.cn/img/logo3.0.png" alt="Logo">
|
||||
<p class="text-larger mb-2">Copyrights © 2022-2024 <a href="https://memotrace.cn/">SiYuan</a> 版权所有. Inc.</p>
|
||||
<!-- <span class="op-07">请遵守所在国家的相关法律法规</span> -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- Add more sections as needed -->
|
||||
</div>
|
||||
<script>
|
||||
function confirmUpload() {
|
||||
var userConfirmed = confirm("注意!!!\n本页面将会上传至云端,别人可通过链接查看该网页,该操作不会上传您的其他任何信息,页面将在下个版本更新之后删除,请注意链接生效时间。\n点击“确认”代表您同意上传,否则请点击“取消");
|
||||
|
||||
if (userConfirmed) {
|
||||
// User clicked OK, perform the upload and display QR code
|
||||
uploadAndDisplayQRCode();
|
||||
} else {
|
||||
// User clicked Cancel or closed the dialog
|
||||
alert("Upload canceled.");
|
||||
}
|
||||
}
|
||||
|
||||
function uploadAndDisplayQRCode() {
|
||||
// Simulate a GET request to the server endpoint
|
||||
fetch('http://127.0.0.1:21314/upload')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
displayQRCode(data.url);
|
||||
} else {
|
||||
if(data.code==201){
|
||||
displayQRCode(data.url);
|
||||
alert(data.errmsg);
|
||||
}
|
||||
else{
|
||||
alert(data.errmsg);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error: Unable to fetch data from the server.\n'+error);
|
||||
});
|
||||
}
|
||||
|
||||
function displayQRCode(url) {
|
||||
var qrcode = new QRCode(document.getElementById("qrcode"), {
|
||||
text: url,
|
||||
width: 128,
|
||||
height: 128
|
||||
});
|
||||
var aObj = document.getElementById("share");
|
||||
aObj.href = url;
|
||||
//根据id获取超链接,设置文字内容
|
||||
aObj.innerText = url;
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
// JavaScript 代码用于生成聊天内容和雪花动画
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const snowContainer = document.getElementById('snow');
|
||||
// 生成雪花动画
|
||||
for (let i = 0; i < 50; i++) {
|
||||
const snowflake = document.createElement('div');
|
||||
snowflake.className = 'snowflake';
|
||||
var ran = Math.random();
|
||||
var ran0 = 1-ran;
|
||||
snowflake.style.left = `${Math.random() * 150}vw`;
|
||||
snowflake.style.animationDuration = `${ran0 * 20 + 7}s`;
|
||||
snowflake.style.setProperty('--animation-order', i);
|
||||
|
||||
// 设置雪花的随机大小
|
||||
const size = ran * 20 + 10; // 随机大小在 10 到 30 之间
|
||||
snowflake.style.width = `${size}px`;
|
||||
snowflake.style.height = `${size}px`;
|
||||
|
||||
snowContainer.appendChild(snowflake);
|
||||
}
|
||||
});
|
||||
function createSnowflake(top, left) {
|
||||
const snowflake = document.createElement('div');
|
||||
snowflake.className = 'snowflake0';
|
||||
snowflake.style.top = `${top}vh`;
|
||||
snowflake.style.left = `${left}vw`;
|
||||
// 设置雪花的随机大小
|
||||
const size = Math.random() * 20 + 10; // 随机大小在 10 到 30 之间
|
||||
snowflake.style.width = `${size}px`;
|
||||
snowflake.style.height = `${size}px`;
|
||||
document.body.appendChild(snowflake);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
var chart = echarts.init(document.getElementById('word_cloud'), 'white', {renderer: 'canvas'});
|
||||
var result = {{wordcloud_chart_data|safe}};
|
||||
// 获取屏幕宽度
|
||||
const screenWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||
|
||||
// 根据屏幕宽度设置字体范围
|
||||
let fontSizeRange;
|
||||
if (screenWidth < 768) { // 手机屏幕
|
||||
fontSizeRange = [5, 40];
|
||||
} else { // 电脑屏幕
|
||||
fontSizeRange = [10, 100];
|
||||
}
|
||||
result.series[0].sizeRange = fontSizeRange;
|
||||
chart.setOption(result);
|
||||
</script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#fullpage').fullpage();
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript"> function getRTime() {
|
||||
var tt = document.getElementById("first_time").innerText;
|
||||
var EndTime = new Date(tt);
|
||||
var NowTime = new Date();
|
||||
var t = NowTime.getTime()-EndTime.getTime();
|
||||
var d = Math.floor(t / 1000 / 60 / 60 / 24);
|
||||
var h = Math.floor(t / 1000 / 60 / 60 % 24);
|
||||
var m = Math.floor(t / 1000 / 60 % 60);
|
||||
var s = Math.floor(t / 1000 % 60);
|
||||
document.getElementById("t_d").innerHTML = d + " 天";
|
||||
document.getElementById("t_h").innerHTML = h + " 时";
|
||||
document.getElementById("t_m").innerHTML = m + " 分";
|
||||
document.getElementById("t_s").innerHTML = s + " 秒";
|
||||
}
|
||||
setInterval(getRTime, 1000);
|
||||
|
||||
</script>
|
||||
<script>
|
||||
var chart_51ebd4312946429e9c32b2b55b96a479 = echarts.init(
|
||||
document.getElementById('calendar-chart'), 'white', {renderer: 'canvas'});
|
||||
var result = {{calendar_chart_data|safe}};
|
||||
// 根据屏幕宽度设置字体范围
|
||||
let cellSize;
|
||||
if (screenWidth < 768) { // 手机屏幕
|
||||
result.calendar.cellSize = 10;
|
||||
} else { // 电脑屏幕
|
||||
result.calendar.cellSize = 15;
|
||||
}
|
||||
chart_51ebd4312946429e9c32b2b55b96a479.setOption(result);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
177
app/web_ui/templates/home.html
Normal file
177
app/web_ui/templates/home.html
Normal file
File diff suppressed because one or more lines are too long
441
app/web_ui/templates/index.html
Normal file
441
app/web_ui/templates/index.html
Normal file
@@ -0,0 +1,441 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>微信年度聊天报告</title>
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<link rel="stylesheet" href="https://memotrace.cn/static/css/fullpage.min.css" />
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts@latest/dist/echarts.min.js"></script>
|
||||
<script type="text/javascript" src="https://assets.pyecharts.org/assets/v5/echarts-wordcloud.min.js"></script>
|
||||
<script type="text/javascript" src="https://assets.pyecharts.org/assets/v5/maps/china.js"></script>
|
||||
<script type="text/javascript" src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
|
||||
<script type="text/javascript" src="https://memotrace.cn/static/js/fullpage.min.js"></script>
|
||||
<script type="text/javascript" src="https://davidshimjs.github.io/qrcodejs/qrcode.min.js"></script>
|
||||
<style>
|
||||
body {
|
||||
/* background-color: rgb(57,56,206); */
|
||||
background: linear-gradient(to right, #9ebdd8,#84aeea),
|
||||
url("critters.png");
|
||||
/* background-image: url('../img/背景.png'); */
|
||||
margin: 0;
|
||||
display: flex;
|
||||
color: #fcf5f5;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.section{
|
||||
height: 100vh;
|
||||
margin: 0px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.slide{
|
||||
margin: 0px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
#snow {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
z-index: 1000;
|
||||
}
|
||||
@keyframes snowfall {
|
||||
from {
|
||||
transform: translateY(-100vh);
|
||||
}
|
||||
to {
|
||||
transform: translateY(100vh);
|
||||
}
|
||||
}
|
||||
.snowflake {
|
||||
position: absolute;
|
||||
background-image: url('../img/snow2.png');
|
||||
background-size: contain; /* ä¿æŒé›ªèŠ±å›¾ç‰‡çš„åŽŸå§‹æ¯”ä¾‹ */
|
||||
animation: snowfall linear infinite;
|
||||
animation-duration: 15s; /* ä¿®æ”¹ä¸ºä½ å¸Œæœ›çš„åŠ¨ç”»æŒç»æ—¶é—´ */
|
||||
animation-delay: calc(-15s * var(--animation-order));
|
||||
}
|
||||
.snowflake0 {
|
||||
position: absolute;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
content: '';
|
||||
z-index: -1;
|
||||
}
|
||||
.Mountain-Image{
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
max-height: 20%;
|
||||
}
|
||||
/* home */
|
||||
|
||||
ul,li{
|
||||
list-style:none;
|
||||
}
|
||||
ul{
|
||||
overflow:hidden;
|
||||
padding:3em;
|
||||
}
|
||||
ul li a{
|
||||
text-decoration:none;
|
||||
color:#000 ;
|
||||
background:#ffc ;
|
||||
display:block;
|
||||
height:10em;
|
||||
width:10em;
|
||||
padding:1em;
|
||||
}
|
||||
ul li{
|
||||
margin:1em;
|
||||
float:left;
|
||||
}
|
||||
|
||||
ul li h2
|
||||
{
|
||||
margin: 0;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
ul li p
|
||||
{
|
||||
margin: 0;
|
||||
font-family: “Reenie Beanie” ,arial,sans-serif,微软雅黑;
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
ul li a
|
||||
{
|
||||
text-decoration: none;
|
||||
color: #000 ;
|
||||
background: #ffc ;
|
||||
display: block;
|
||||
height: 10em;
|
||||
width: 10em;
|
||||
padding: 1em; /* Firefox */
|
||||
-moz-box-shadow: 5px 5px 7px rgba(33,33,33,1) ; /* Safari+Chrome */
|
||||
-webkit-box-shadow: 5px 5px 7px rgba(33,33,33,.7) ; /* Opera */
|
||||
box-shadow: 5px 5px 7px rgba(33,33,33,.7) ;
|
||||
}
|
||||
ul li a{
|
||||
-webkit-transform:rotate(-6deg);
|
||||
-o-transform:rotate(-6deg);
|
||||
-moz-transform:rotate(-6deg);
|
||||
}
|
||||
|
||||
ul li:nth-child(even) a{
|
||||
-o-transform:rotate(4deg);
|
||||
-webkit-transform:rotate(4deg);
|
||||
-moz-transform:rotate(4deg);
|
||||
position:relative;
|
||||
top:5px;
|
||||
}
|
||||
ul li:nth-child(3n) a{
|
||||
-o-transform:rotate(-3deg);
|
||||
-webkit-transform:rotate(-3deg);
|
||||
-moz-transform:rotate(-3deg);
|
||||
position:relative;
|
||||
top:-5px;
|
||||
}
|
||||
ul li:nth-child(5n) a{
|
||||
-o-transform:rotate(5deg);
|
||||
-webkit-transform:rotate(5deg);
|
||||
-moz-transform:rotate(5deg);
|
||||
position:relative;
|
||||
top:-10px;
|
||||
}
|
||||
|
||||
ul li a:hover,ul li a:focus{
|
||||
-moz-box-shadow:10px 10px 7px rgba(0,0,0,.7) ;
|
||||
-webkit-box-shadow: 10px 10px 7px rgba(0,0,0,.7) ;
|
||||
box-shadow:10px 10px 7px rgba(0,0,0,.7) ;
|
||||
-webkit-transform: scale(1.25);
|
||||
-moz-transform: scale(1.25);
|
||||
-o-transform: scale(1.25);
|
||||
position:relative;
|
||||
z-index:5;
|
||||
}
|
||||
|
||||
ul li:nth-child(even) a{
|
||||
-o-transform:rotate(4deg);
|
||||
-webkit-transform:rotate(4deg);
|
||||
-moz-transform:rotate(4deg);
|
||||
position:relative;
|
||||
top:5px;
|
||||
background:#cfc ;
|
||||
}
|
||||
ul li:nth-child(3n) a{
|
||||
-o-transform:rotate(-3deg);
|
||||
-webkit-transform:rotate(-3deg);
|
||||
-moz-transform:rotate(-3deg);
|
||||
position:relative;
|
||||
top:-5px;
|
||||
background:#ccf ;
|
||||
}
|
||||
a{
|
||||
padding: 0px;
|
||||
}
|
||||
.contact-container{
|
||||
padding-bottom: 5px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.avatar{
|
||||
height: 45px;
|
||||
width: 45px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.nickname{
|
||||
font: 1.1em sans-serif;
|
||||
font-weight: bold;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
text-overflow: ellipsis; /* 显示省略号 */
|
||||
max-width: 200px; /* 设置最大宽度,可以根据需要调整 */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* CSS代码 */
|
||||
.number {
|
||||
font: 1.1em sans-serif;
|
||||
color: #af27ca;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
|
||||
#cover {
|
||||
text-align: center;
|
||||
animation: fadeIn 3s ease-out;
|
||||
}
|
||||
|
||||
.cover {
|
||||
text-align: center;
|
||||
animation: fadeIn 3s ease-out;
|
||||
}
|
||||
h1 {
|
||||
color: #003366;
|
||||
font-size: 3em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #0066cc;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
#enterButton {
|
||||
cursor: pointer;
|
||||
padding: 10px 20px;
|
||||
background-color: #003366;
|
||||
color: #fff;
|
||||
border: none;
|
||||
font-size: 1em;
|
||||
margin-top: 20px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
#enterButton:hover {
|
||||
background-color: #001a33;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.chart{
|
||||
width: 800px;
|
||||
height: 500px;
|
||||
}
|
||||
.chart-container{
|
||||
display: flex;
|
||||
}
|
||||
#word_cloud{
|
||||
width: 700px;
|
||||
height: 600px;
|
||||
}
|
||||
@media screen and (max-width:480px){
|
||||
.chart{
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
}
|
||||
.chart-container{
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
#word_cloud{
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
#keywords {
|
||||
font-size: 2.5em;
|
||||
color: #003366;
|
||||
animation: slideIn 1.5s ease-out;
|
||||
transform: skew(-15deg);
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-50px) skew(-15deg);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0) skew(-15deg);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="snow"></div>
|
||||
<!-- Your content goes here -->
|
||||
<div id="fullpage">
|
||||
<div class="section">
|
||||
<div id="cover">
|
||||
<h1>年度聊天报告</h1>
|
||||
<p>可掌控的才真正属于你</p>
|
||||
<button id="enterButton" onclick="navigateToNextPage()">进入报告</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section cover">
|
||||
<h1>2023年</h1>
|
||||
<p>你一共给<span class="number">{{contact_num}}</span>个联系人<br>发送了<span class="number">{{send_msg_num}}</span>条消息<br>收到了<span class="number">{{receive_msg_num}}</span>条消息<br>总计<span class="number">{{total_text_num}}</span>字</p>
|
||||
<p>男<span class="number">{{man_contact_num}}</span>人 女<span class="number">{{woman_contact_num}}</span>人 </p>
|
||||
<div class="slide" data-anchor="slide1">
|
||||
<div id="contact_region_map" class="chart" ></div>
|
||||
</div>
|
||||
<div class="slide" data-anchor="slide1">
|
||||
<div id="types-chart" class="chart"></div>
|
||||
</div>
|
||||
<div class="slide" data-anchor="slide1">
|
||||
<div id="sender-chart" class="chart" ></div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="section cover">
|
||||
<h1>年度关键词</h1>
|
||||
<div id="keywords">“{{keyword}}”<span class="number">{{keyword_max_num}}</span>次</div>
|
||||
<div id="word_cloud"></div>
|
||||
</div>
|
||||
<div class="section cover">
|
||||
<h1>年度聊天好友</h1>
|
||||
<h2>聊天榜单</h2>
|
||||
<ul>
|
||||
{% for contact,msg_num,text_length in contact_topN:%}
|
||||
<li>
|
||||
<a href="/charts/{{contact.wxid}}" target="_blank">
|
||||
<div class="contact-container">
|
||||
<p class="nickname">{{contact.remark}}</p>
|
||||
<img class="avatar" src="{{contact.smallHeadImgUrl}}">
|
||||
</div>
|
||||
<div style="color: blueviolet;"><span class="number">{{msg_num}}</span>条消息<br><span class="number">{{text_length}}</span>字</div>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" style="text-align: center;display:flex;justify-content: center;align-items: center;">
|
||||
<h1>敬请期待</h1>
|
||||
<div>
|
||||
<img src="https://memotrace.cn/img/logo3.0.png" alt="Logo">
|
||||
<p class="text-larger mb-2">Copyrights © 2022-2024 <a href="https://memotrace.cn/">SiYuan</a> 版权所有. Inc.</p>
|
||||
<!-- <span class="op-07">请遵守所在国家的相关法律法规</span> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// JavaScript 代码用于生成聊天内容和雪花动画
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const snowContainer = document.getElementById('snow');
|
||||
// 生成雪花动画
|
||||
for (let i = 0; i < 50; i++) {
|
||||
const snowflake = document.createElement('div');
|
||||
snowflake.className = 'snowflake';
|
||||
var ran = Math.random();
|
||||
var ran0 = 1-ran;
|
||||
snowflake.style.left = `${Math.random() * 150}vw`;
|
||||
snowflake.style.animationDuration = `${ran0 * 20 + 7}s`;
|
||||
snowflake.style.setProperty('--animation-order', i);
|
||||
|
||||
// 设置雪花的随机大小
|
||||
const size = ran * 20 + 10; // 随机大小在 10 到 30 之间
|
||||
snowflake.style.width = `${size}px`;
|
||||
snowflake.style.height = `${size}px`;
|
||||
|
||||
snowContainer.appendChild(snowflake);
|
||||
}
|
||||
});
|
||||
function createSnowflake(top, left) {
|
||||
const snowflake = document.createElement('div');
|
||||
snowflake.className = 'snowflake0';
|
||||
snowflake.style.top = `${top}vh`;
|
||||
snowflake.style.left = `${left}vw`;
|
||||
// 设置雪花的随机大小
|
||||
const size = Math.random() * 20 + 10; // 随机大小在 10 到 30 之间
|
||||
snowflake.style.width = `${size}px`;
|
||||
snowflake.style.height = `${size}px`;
|
||||
document.body.appendChild(snowflake);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#fullpage').fullpage();
|
||||
});
|
||||
// 获取按钮元素
|
||||
var scrollToNextButton = document.getElementById('scrollToNext');
|
||||
function navigateToNextPage(){
|
||||
fullpage_api.moveSectionDown();
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
var chart_51ebd4312946429e9c32b2b55b96a479 = echarts.init(
|
||||
document.getElementById('types-chart'), 'white', {renderer: 'canvas'});
|
||||
var result = {{chart_data_types|safe}};
|
||||
chart_51ebd4312946429e9c32b2b55b96a479.setOption(result);
|
||||
|
||||
var chart_51ebd4312946429e9c32b2b55b96a479 = echarts.init(
|
||||
document.getElementById('contact_region_map'), 'white', {renderer: 'canvas'});
|
||||
var result = {{contact_region_map|safe}};
|
||||
chart_51ebd4312946429e9c32b2b55b96a479.setOption(result);
|
||||
|
||||
var chart_51ebd4312946429e9c32b2b55b96a4 = echarts.init(
|
||||
document.getElementById('sender-chart'), 'white', {renderer: 'canvas'});
|
||||
var result = {{chart_data_sender|safe}};
|
||||
chart_51ebd4312946429e9c32b2b55b96a4.setOption(result);
|
||||
|
||||
var chart_51ebd4312946429e9c32b2b55b96 = echarts.init(
|
||||
document.getElementById('word_cloud'), 'white', {renderer: 'canvas'});
|
||||
var result = {{chart_data_wordcloud|safe}};
|
||||
// 获取屏幕宽度
|
||||
const screenWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||
// 根据屏幕宽度设置字体范围
|
||||
let fontSizeRange;
|
||||
if (screenWidth < 768) { // 手机屏幕
|
||||
fontSizeRange = [5, 40];
|
||||
} else { // 电脑屏幕
|
||||
fontSizeRange = [10, 100];
|
||||
}
|
||||
result.series[0].sizeRange = fontSizeRange;
|
||||
chart_51ebd4312946429e9c32b2b55b96.setOption(result);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
297
app/web_ui/web.py
Normal file
297
app/web_ui/web.py
Normal file
@@ -0,0 +1,297 @@
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import requests
|
||||
from flask import Flask, render_template, send_file, jsonify, make_response, request
|
||||
from pyecharts.charts import Bar
|
||||
|
||||
from app.DataBase import msg_db, micro_msg_db
|
||||
from app.DataBase.hard_link import decodeExtraBuf
|
||||
from app.analysis import analysis
|
||||
from app.config import SERVER_API_URL
|
||||
from app.person import Contact, Me, ContactDefault
|
||||
from app.util.emoji import get_most_emoji
|
||||
from app.util.region_conversion import conversion_region_to_chinese
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
run_flag = False
|
||||
wxid = ''
|
||||
contact: Contact = None
|
||||
start_time = '2023-1-01 00:00:00'
|
||||
end_time = '2023-12-31 23:59:59'
|
||||
time_range = (start_time, end_time)
|
||||
html: str = ''
|
||||
|
||||
api_url = urljoin(SERVER_API_URL,'upload')
|
||||
|
||||
|
||||
|
||||
def get_contact(wxid) -> ContactDefault | Contact:
|
||||
contact_info_list = micro_msg_db.get_contact_by_username(wxid)
|
||||
if not contact_info_list:
|
||||
return ContactDefault('')
|
||||
detail = decodeExtraBuf(contact_info_list[9])
|
||||
# detail = {}
|
||||
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],
|
||||
'label_name': contact_info_list[10],
|
||||
'detail': detail,
|
||||
}
|
||||
contact =Contact(contact_info)
|
||||
print(detail)
|
||||
# region = contact.detail.get('region')
|
||||
# area = conversion_region_to_chinese(region)
|
||||
# print(area)
|
||||
return contact
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
contact_topN_num = msg_db.get_chatted_top_contacts(time_range=time_range, top_n=9999999, contain_chatroom=True)
|
||||
total_msg_num = sum(list(map(lambda x: x[1], contact_topN_num)))
|
||||
contact_topN = []
|
||||
for wxid, num in contact_topN_num:
|
||||
contact = get_contact(wxid)
|
||||
text_length = 0
|
||||
contact_topN.append([contact, num, text_length])
|
||||
contacts_data = analysis.contacts_analysis(contact_topN)
|
||||
contact_topN = []
|
||||
send_msg_num = msg_db.get_send_messages_number_sum(time_range)
|
||||
contact_topN_num = msg_db.get_chatted_top_contacts(time_range=time_range, top_n=9999999, contain_chatroom=False)
|
||||
|
||||
for wxid, num in contact_topN_num[:6]:
|
||||
contact = get_contact(wxid)
|
||||
text_length = msg_db.get_message_length(wxid, time_range)
|
||||
contact_topN.append([contact, num, text_length])
|
||||
|
||||
my_message_counter_data = analysis.my_message_counter(time_range=time_range)
|
||||
data = {
|
||||
'avatar': Me().smallHeadImgUrl,
|
||||
'contact_topN': contact_topN,
|
||||
'contact_num': len(contact_topN_num),
|
||||
'send_msg_num': send_msg_num,
|
||||
'receive_msg_num': total_msg_num - send_msg_num,
|
||||
}
|
||||
return render_template('index.html', **data,**contacts_data, **my_message_counter_data)
|
||||
|
||||
|
||||
@app.route("/christmas/<wxid>")
|
||||
def christmas(wxid):
|
||||
contact = get_contact(wxid)
|
||||
# 渲染模板,并传递图表的 HTML 到模板中
|
||||
try:
|
||||
first_message, first_time = msg_db.get_first_time_of_message(contact.wxid)
|
||||
except TypeError:
|
||||
first_time = '2023-01-01 00:00:00'
|
||||
data = {
|
||||
'ta_avatar_path': contact.smallHeadImgUrl,
|
||||
'my_avatar_path': Me().smallHeadImgUrl,
|
||||
'ta_nickname': contact.remark,
|
||||
'my_nickname': Me().name,
|
||||
'first_time': first_time,
|
||||
}
|
||||
wordcloud_cloud_data = analysis.wordcloud_christmas(contact.wxid,time_range=time_range)
|
||||
msg_data = msg_db.get_messages_by_hour(contact.wxid, time_range=time_range)
|
||||
msg_data.sort(key=lambda x: x[1], reverse=True)
|
||||
desc = {
|
||||
'夜猫子': {'22:00', '23:00', '00:00', '01:00', '02:00', '03:00', '04:00', '05:00'},
|
||||
'正常作息': {'06:00', "07:00", "08:00", "09:00", "10:00", "11:00", "12:00", "13:00", "14:00", "15:00", "16:00",
|
||||
"17:00", "18:00", "19:00", "20:00", "21:00"},
|
||||
}
|
||||
time_, num = msg_data[0] if msg_data else ('', 0)
|
||||
chat_time = f"凌晨{time_}" if time_ in {'00:00', '01:00', '02:00', '03:00', '04:00', '05:00'} else time_
|
||||
label = '夜猫子'
|
||||
for key, item in desc.items():
|
||||
if time_ in item:
|
||||
label = key
|
||||
latest_dialog = msg_db.get_latest_time_of_message(contact.wxid, time_range=time_range)
|
||||
latest_time = latest_dialog[0][2] if latest_dialog else ''
|
||||
time_data = {
|
||||
'latest_time': latest_time,
|
||||
'latest_time_dialog': latest_dialog,
|
||||
'chat_time_label': label,
|
||||
'chat_time': chat_time,
|
||||
'chat_time_num': num,
|
||||
}
|
||||
month_data = msg_db.get_messages_by_month(contact.wxid, time_range=time_range)
|
||||
|
||||
if month_data:
|
||||
month_data.sort(key=lambda x: x[1])
|
||||
max_month, max_num = month_data[-1]
|
||||
min_month, min_num = month_data[0]
|
||||
min_month = min_month[-2:].lstrip('0') + '月'
|
||||
max_month = max_month[-2:].lstrip('0') + '月'
|
||||
else:
|
||||
max_month, max_num = '月份', 0
|
||||
min_month, min_num = '月份', 0
|
||||
|
||||
month_data = {
|
||||
'year': '2023',
|
||||
'total_msg_num': msg_db.get_messages_number(contact.wxid, time_range=time_range),
|
||||
'max_month': max_month,
|
||||
'min_month': min_month,
|
||||
'max_month_num': max_num,
|
||||
'min_month_num': min_num,
|
||||
}
|
||||
|
||||
calendar_data = analysis.calendar_chart(contact.wxid, time_range)
|
||||
emoji_msgs = msg_db.get_messages_by_type(contact.wxid, 47, time_range=time_range)
|
||||
url, num = get_most_emoji(emoji_msgs)
|
||||
emoji_data = {
|
||||
'emoji_total_num': len(emoji_msgs),
|
||||
'emoji_url': url,
|
||||
'emoji_num': num,
|
||||
}
|
||||
global html
|
||||
html = render_template("christmas.html", **data, **wordcloud_cloud_data, **time_data, **month_data, **calendar_data,
|
||||
**emoji_data)
|
||||
return html
|
||||
|
||||
|
||||
@app.route('/upload')
|
||||
def upload():
|
||||
global html
|
||||
data = {
|
||||
'html_content': html,
|
||||
'wxid': contact.wxid,
|
||||
'username': Me().wxid,
|
||||
'token':Me().token,
|
||||
'type': 'contact'
|
||||
}
|
||||
response = requests.post(api_url, data=data)
|
||||
print(response)
|
||||
print(response.json())
|
||||
response = make_response(response.json())
|
||||
response.headers.add('Access-Control-Allow-Origin', '*') # Replace '*' with specific origins if needed
|
||||
response.headers.add('Content-Type', 'application/json')
|
||||
return response
|
||||
|
||||
|
||||
def set_text(text):
|
||||
html = '''
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Centered Text</title>
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.centered-text {
|
||||
font-size: 2em;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="centered-text">
|
||||
<!-- 这里是要显示的四个大字 -->
|
||||
%s
|
||||
<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Yellowdog.png" id="旺柴" class="emoji_img">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
''' % (text)
|
||||
return html
|
||||
|
||||
|
||||
@app.route('/test')
|
||||
def test():
|
||||
return set_text('以下内容仅对VIP开放')
|
||||
|
||||
|
||||
def run(port=21314):
|
||||
global run_flag
|
||||
if not run_flag:
|
||||
try:
|
||||
app.run(debug=True, host='0.0.0.0', port=port, use_reloader=False)
|
||||
run_flag = True
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
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')
|
||||
|
||||
|
||||
@app.route('/month_count', methods=['POST'])
|
||||
def get_chart_options():
|
||||
wxid = request.json.get('wxid')
|
||||
time_range = request.json.get('time_range', [])
|
||||
data = analysis.month_count(wxid, time_range=time_range)
|
||||
return jsonify(data)
|
||||
|
||||
|
||||
@app.route('/wordcloud', methods=['POST'])
|
||||
def get_wordcloud():
|
||||
wxid = request.json.get('wxid')
|
||||
time_range = request.json.get('time_range', [])
|
||||
|
||||
world_cloud_data = analysis.wordcloud_(wxid, time_range=time_range)
|
||||
return jsonify(world_cloud_data)
|
||||
|
||||
|
||||
@app.route('/charts/<wxid>')
|
||||
def charts(wxid):
|
||||
# 渲染模板,并传递图表的 HTML 到模板中
|
||||
contact = get_contact(wxid)
|
||||
try:
|
||||
first_message, first_time = msg_db.get_first_time_of_message(wxid)
|
||||
except TypeError:
|
||||
first_time = '2023-01-01 00:00:00'
|
||||
data = {
|
||||
'wxid': wxid,
|
||||
'my_nickname': Me().name,
|
||||
'ta_nickname': contact.remark,
|
||||
'first_time': first_time
|
||||
}
|
||||
return render_template('charts.html', **data)
|
||||
|
||||
|
||||
@app.route('/calendar', methods=['POST'])
|
||||
def get_calendar():
|
||||
wxid = request.json.get('wxid')
|
||||
time_range = request.json.get('time_range', [])
|
||||
world_cloud_data = analysis.calendar_chart(wxid, time_range=time_range)
|
||||
return jsonify(world_cloud_data)
|
||||
|
||||
|
||||
@app.route('/message_counter', methods=['POST'])
|
||||
def get_counter():
|
||||
wxid = request.json.get('wxid')
|
||||
time_range = request.json.get('time_range', [])
|
||||
contact = get_contact(wxid)
|
||||
data = analysis.sender(wxid, time_range=time_range, my_name=Me().name, ta_name=contact.remark)
|
||||
return jsonify(data)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=True, host='0.0.0.0')
|
||||
Reference in New Issue
Block a user