Files
daily-paper/app/templates/trends.html
T
Rain-Bus 0d293422ac feat: enhance UI, refactor services, improve templates and tests
- 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
2026-06-07 19:38:58 +08:00

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 %}