0d293422ac
- Replace image_extractor with pdf_image_extractor service - Enhance pi_client with expanded API capabilities - Improve summarizer service with additional features - Update admin routes with more endpoints - Add login page template - Enhance detail page with comprehensive layout - Improve search and trends pages - Update base template with additional elements - Refactor tests for better coverage - Add validate_summary script - Update project configuration and dependencies
181 lines
4.9 KiB
HTML
181 lines
4.9 KiB
HTML
{% extends "base.html" %} {% block title %}{{ page_title }} — HF Daily Papers{%
|
|
endblock %} {% block content %}
|
|
<section class="trends-page">
|
|
<h1>趋势看板</h1>
|
|
|
|
<div class="charts-grid">
|
|
{# 按日论文数量折线图 #}
|
|
<div class="chart-card">
|
|
<h2>📅 每日论文数量(近 30 天)</h2>
|
|
<canvas id="dailyChart"></canvas>
|
|
</div>
|
|
|
|
{# 热门标签 Top 20 #}
|
|
<div class="chart-card">
|
|
<h2>🏷️ 热门标签 Top 20</h2>
|
|
<canvas id="tagsChart"></canvas>
|
|
</div>
|
|
|
|
{# Upvotes 分布 #}
|
|
<div class="chart-card">
|
|
<h2>👍 Upvotes 分布</h2>
|
|
<canvas id="upvotesChart"></canvas>
|
|
</div>
|
|
|
|
{# 总结完成率 #}
|
|
<div class="chart-card">
|
|
<h2>📝 总结完成率</h2>
|
|
<canvas id="summaryChart"></canvas>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
{% endblock %} {% block scripts %}
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
|
|
<script>
|
|
// 颜色配置(Kami ink-blue 暖调色系)
|
|
const COLORS = {
|
|
primary: '#1B365D',
|
|
primaryLight: 'rgba(27, 54, 93, 0.12)',
|
|
accent: '#2a4d7a',
|
|
success: '#3d6e3d',
|
|
warning: '#7a6430',
|
|
danger: '#8c2828',
|
|
muted: '#6b6a64',
|
|
palette: [
|
|
'#1B365D', '#2a4d7a', '#3d6e3d', '#7a6430', '#8c2828',
|
|
'#4a4070', '#2d6b6e', '#8a5a2a', '#504e49', '#5c6030',
|
|
'#2b4a80', '#70304a', '#2d5e56', '#7a4a10', '#353a60',
|
|
'#6a6a28', '#552a5a', '#2d6b6e', '#4a3828', '#3d4450',
|
|
],
|
|
};
|
|
|
|
const statsData = {{ stats | tojson }};
|
|
|
|
// 每日论文数量折线图
|
|
(function() {
|
|
const ctx = document.getElementById('dailyChart').getContext('2d');
|
|
const labels = statsData.daily_counts.map(d => d.date);
|
|
const data = statsData.daily_counts.map(d => d.count);
|
|
new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{
|
|
label: '论文数',
|
|
data: data,
|
|
borderColor: COLORS.primary,
|
|
backgroundColor: COLORS.primaryLight,
|
|
fill: true,
|
|
tension: 0.3,
|
|
pointRadius: 3,
|
|
pointHoverRadius: 6,
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
plugins: { legend: { display: false } },
|
|
scales: {
|
|
x: { ticks: { maxTicksLimit: 10, font: { size: 11 } } },
|
|
y: { beginAtZero: true, ticks: { stepSize: 1 } },
|
|
}
|
|
}
|
|
});
|
|
})();
|
|
|
|
// 热门标签柱状图
|
|
(function() {
|
|
const ctx = document.getElementById('tagsChart').getContext('2d');
|
|
const labels = statsData.top_tags.map(d => d.tag);
|
|
const data = statsData.top_tags.map(d => d.count);
|
|
new Chart(ctx, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{
|
|
label: '论文数',
|
|
data: data,
|
|
backgroundColor: COLORS.palette.slice(0, data.length),
|
|
borderRadius: 4,
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
indexAxis: 'y',
|
|
plugins: { legend: { display: false } },
|
|
scales: {
|
|
x: { beginAtZero: true, ticks: { stepSize: 1 } },
|
|
}
|
|
}
|
|
});
|
|
})();
|
|
|
|
// Upvotes 分布
|
|
(function() {
|
|
const ctx = document.getElementById('upvotesChart').getContext('2d');
|
|
const labels = statsData.upvotes_dist.map(d => d.range);
|
|
const data = statsData.upvotes_dist.map(d => d.count);
|
|
new Chart(ctx, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{
|
|
label: '论文数',
|
|
data: data,
|
|
backgroundColor: COLORS.accent,
|
|
borderRadius: 4,
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
plugins: { legend: { display: false } },
|
|
scales: {
|
|
y: { beginAtZero: true, ticks: { stepSize: 1 } },
|
|
}
|
|
}
|
|
});
|
|
})();
|
|
|
|
// 总结完成率环形图
|
|
(function() {
|
|
const ctx = document.getElementById('summaryChart').getContext('2d');
|
|
const statusLabels = {
|
|
'done': '已完成',
|
|
'pending': '待总结',
|
|
'processing': '总结中',
|
|
'failed': '失败',
|
|
'permanent_failure': '永久失败',
|
|
'none': '未开始',
|
|
};
|
|
const statusColors = {
|
|
'done': COLORS.success,
|
|
'pending': COLORS.warning,
|
|
'processing': COLORS.primary,
|
|
'failed': COLORS.danger,
|
|
'permanent_failure': '#b71c1c',
|
|
'none': '#bdbdbd',
|
|
};
|
|
const labels = statsData.summary_completion.map(d => statusLabels[d.status] || d.status);
|
|
const data = statsData.summary_completion.map(d => d.count);
|
|
const colors = statsData.summary_completion.map(d => statusColors[d.status] || COLORS.muted);
|
|
new Chart(ctx, {
|
|
type: 'doughnut',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{
|
|
data: data,
|
|
backgroundColor: colors,
|
|
borderWidth: 2,
|
|
borderColor: '#fff',
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
plugins: {
|
|
legend: { position: 'bottom', labels: { padding: 12 } },
|
|
}
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
{% endblock %}
|