345 lines
13 KiB
HTML
345 lines
13 KiB
HTML
<!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 href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||
<style>
|
||
body {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
min-height: 100vh;
|
||
padding: 20px;
|
||
}
|
||
.dashboard-card {
|
||
background: white;
|
||
border-radius: 15px;
|
||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||
padding: 25px;
|
||
margin-bottom: 20px;
|
||
}
|
||
.metric-card {
|
||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||
border-radius: 10px;
|
||
padding: 20px;
|
||
text-align: center;
|
||
margin-bottom: 15px;
|
||
}
|
||
.metric-value {
|
||
font-size: 2rem;
|
||
font-weight: bold;
|
||
color: #667eea;
|
||
}
|
||
.metric-label {
|
||
color: #666;
|
||
font-size: 0.9rem;
|
||
}
|
||
.btn-primary {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
border: none;
|
||
}
|
||
.btn-primary:hover {
|
||
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
|
||
}
|
||
.stat-icon {
|
||
font-size: 1.5rem;
|
||
margin-bottom: 10px;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="row mb-4">
|
||
<div class="col-12">
|
||
<div class="dashboard-card">
|
||
<h1 class="text-center mb-0">🚀 爆款内容仪表板</h1>
|
||
<p class="text-center text-muted mb-0">基于实时热点数据的智能内容生成系统</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 数据概览 -->
|
||
<div class="row mb-4">
|
||
<div class="col-md-3">
|
||
<div class="metric-card">
|
||
<div class="stat-icon">📊</div>
|
||
<div class="metric-value" id="topics-count">-</div>
|
||
<div class="metric-label">热门话题</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-3">
|
||
<div class="metric-card">
|
||
<div class="stat-icon">📈</div>
|
||
<div class="metric-value" id="analysis-status">-</div>
|
||
<div class="metric-label">分析状态</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-3">
|
||
<div class="metric-card">
|
||
<div class="stat-icon">✍️</div>
|
||
<div class="metric-value" id="generated-count">-</div>
|
||
<div class="metric-label">已生成内容</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-3">
|
||
<div class="metric-card">
|
||
<div class="stat-icon">🔄</div>
|
||
<div class="metric-value" id="last-update">-</div>
|
||
<div class="metric-label">最后更新</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 功能区 -->
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="dashboard-card">
|
||
<h3>📊 热点追踪</h3>
|
||
<div class="mb-3">
|
||
<label class="form-label">搜索关键词</label>
|
||
<input type="text" class="form-control" id="search-keyword" placeholder="输入关键词,如:AI工具">
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">数量</label>
|
||
<input type="number" class="form-control" id="search-count" value="10" min="5" max="50">
|
||
</div>
|
||
<button class="btn btn-primary w-100" onclick="searchNotes()">
|
||
🔍 搜索爆款笔记
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-md-6">
|
||
<div class="dashboard-card">
|
||
<h3>📝 内容生成</h3>
|
||
<div class="mb-3">
|
||
<label class="form-label">赛道</label>
|
||
<input type="text" class="form-control" id="niche-keyword" placeholder="如:AI工具、省钱攻略">
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">生成数量</label>
|
||
<input type="number" class="form-control" id="generate-count" value="3" min="1" max="10">
|
||
</div>
|
||
<div class="mb-3">
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="checkbox" id="use-trends" checked>
|
||
<label class="form-check-label" for="use-trends">
|
||
使用热点数据优化
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">API密钥</label>
|
||
<input type="password" class="form-control" id="api-key" placeholder="智谱AI API密钥">
|
||
</div>
|
||
<button class="btn btn-primary w-100" onclick="generateContent()">
|
||
✨ 生成爆款内容
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 分析结果 -->
|
||
<div class="row mt-4" id="results-section" style="display:none;">
|
||
<div class="col-12">
|
||
<div class="dashboard-card">
|
||
<h3>📈 分析结果</h3>
|
||
<div id="analysis-content"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 生成的内容 -->
|
||
<div class="row mt-4" id="generated-section" style="display:none;">
|
||
<div class="col-12">
|
||
<div class="dashboard-card">
|
||
<h3>✍️ 生成的内容</h3>
|
||
<div id="generated-content"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||
<script>
|
||
// 页面加载时更新数据
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
updateDashboard();
|
||
});
|
||
|
||
// 更新仪表板数据
|
||
async function updateDashboard() {
|
||
try {
|
||
const response = await fetch('/api/dashboard-data');
|
||
const data = await response.json();
|
||
|
||
document.getElementById('topics-count').textContent = data.latest_topics_count;
|
||
document.getElementById('analysis-status').textContent = data.has_analysis ? '已完成' : '未分析';
|
||
document.getElementById('generated-count').textContent = data.generated_content_count;
|
||
document.getElementById('last-update').textContent = data.last_update?.split(' ')[1] || '-';
|
||
} catch (error) {
|
||
console.error('更新失败:', error);
|
||
}
|
||
}
|
||
|
||
// 搜索笔记
|
||
async function searchNotes() {
|
||
const keyword = document.getElementById('search-keyword').value;
|
||
const count = document.getElementById('search-count').value;
|
||
|
||
if (!keyword) {
|
||
alert('请输入搜索关键词');
|
||
return;
|
||
}
|
||
|
||
const button = event.target;
|
||
button.disabled = true;
|
||
button.textContent = '🔍 搜索中...';
|
||
|
||
try {
|
||
const response = await fetch('/api/search-notes', {
|
||
method: 'POST',
|
||
headers: {'Content-Type': 'application/json'},
|
||
body: JSON.stringify({keyword, count: parseInt(count)})
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
alert(`找到 ${data.count} 篇笔记!`);
|
||
|
||
// 自动分析
|
||
if (data.notes.length > 0) {
|
||
await analyzeNotes(data.notes.map(n => n.url).slice(0, 5));
|
||
}
|
||
} else {
|
||
alert('搜索失败: ' + data.error);
|
||
}
|
||
} catch (error) {
|
||
alert('搜索出错: ' + error);
|
||
} finally {
|
||
button.disabled = false;
|
||
button.textContent = '🔍 搜索爆款笔记';
|
||
updateDashboard();
|
||
}
|
||
}
|
||
|
||
// 分析笔记
|
||
async function analyzeNotes(urls) {
|
||
try {
|
||
const response = await fetch('/api/analyze-notes', {
|
||
method: 'POST',
|
||
headers: {'Content-Type': 'application/json'},
|
||
body: JSON.stringify({urls})
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
displayAnalysis(data.report_summary);
|
||
}
|
||
} catch (error) {
|
||
console.error('分析失败:', error);
|
||
}
|
||
}
|
||
|
||
// 显示分析结果
|
||
function displayAnalysis(summary) {
|
||
const section = document.getElementById('results-section');
|
||
const content = document.getElementById('analysis-content');
|
||
|
||
section.style.display = 'block';
|
||
|
||
content.innerHTML = `
|
||
<div class="row">
|
||
<div class="col-md-4">
|
||
<h5>📊 样本数量</h5>
|
||
<p class="lead">${summary.sample_size}篇</p>
|
||
</div>
|
||
<div class="col-md-4">
|
||
<h5>🏆 最常见标题类型</h5>
|
||
<p class="lead">${summary.top_title_type || '未知'}</p>
|
||
</div>
|
||
<div class="col-md-4">
|
||
<h5>💭 最强情绪触发</h5>
|
||
<p class="lead">${summary.top_emotion || '未知'}</p>
|
||
</div>
|
||
</div>
|
||
<hr>
|
||
<h5>💡 优化建议</h5>
|
||
<ul>
|
||
${summary.recommendations.map(r => `<li>${r}</li>`).join('')}
|
||
</ul>
|
||
`;
|
||
}
|
||
|
||
// 生成内容
|
||
async function generateContent() {
|
||
const niche = document.getElementById('niche-keyword').value;
|
||
const count = document.getElementById('generate-count').value;
|
||
const useTrends = document.getElementById('use-trends').checked;
|
||
const apiKey = document.getElementById('api-key').value;
|
||
|
||
if (!niche || !apiKey) {
|
||
alert('请填写赛道和API密钥');
|
||
return;
|
||
}
|
||
|
||
const button = event.target;
|
||
button.disabled = true;
|
||
button.textContent = '✨ 生成中...';
|
||
|
||
try {
|
||
const response = await fetch('/api/generate-content', {
|
||
method: 'POST',
|
||
headers: {'Content-Type': 'application/json'},
|
||
body: JSON.stringify({
|
||
niche,
|
||
count: parseInt(count),
|
||
use_trends: useTrends,
|
||
api_key: apiKey
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
displayGenerated(data.contents);
|
||
alert(`成功生成 ${data.generated_count} 篇内容!`);
|
||
} else {
|
||
alert('生成失败: ' + data.error);
|
||
}
|
||
} catch (error) {
|
||
alert('生成出错: ' + error);
|
||
} finally {
|
||
button.disabled = false;
|
||
button.textContent = '✨ 生成爆款内容';
|
||
updateDashboard();
|
||
}
|
||
}
|
||
|
||
// 显示生成的内容
|
||
function displayGenerated(contents) {
|
||
const section = document.getElementById('generated-section');
|
||
const content = document.getElementById('generated-content');
|
||
|
||
section.style.display = 'block';
|
||
|
||
content.innerHTML = contents.map((item, index) => `
|
||
<div class="card mb-3">
|
||
<div class="card-body">
|
||
<h5 class="card-title">${item.emoji} ${item.title}</h5>
|
||
<p class="card-text">${item.content}</p>
|
||
<p class="mb-0"><strong>标签:</strong> ${item.tags.join(', ')}</p>
|
||
<small class="text-muted">优化策略: ${item.optimization.title_strategy || '默认'}</small>
|
||
</div>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
// 定时刷新
|
||
setInterval(updateDashboard, 30000);
|
||
</script>
|
||
</body>
|
||
</html>
|