18 KiB
18 KiB
季度 AI 热点词云系统设计文档
创建日期: 2026-01-25 功能类型: 数据驱动可视化 技术栈: n8n + Next.js + PostgreSQL + Prisma
一、功能概述
季度 AI 热点词云是一个自动化数据驱动的可视化词云系统,通过 n8n 工作流从 Google Trends 采集 AI 相关热点词汇,经 AI 清洗和规则引擎处理后,自动入库并在前端展示。
核心目标
- 内容营销: 吸引访客回访查看每季度更新,提供社交分享素材
- 教育参考: 帮助新手理解 AI 技术演进历程
- 数据洞察: 展示 AI 领域热点变化趋势
用户旅程
- 用户访问
/keyword-cloud页面 - 看到当前季度的 AI 热点词云(如 2024-Q1)
- 鼠标悬停在词汇上,查看详细描述和要点
- 点击左右箭头切换不同季度,浏览历史热点
- 可视化展示:词汇大小代表搜索热度,颜色代表分类
二、系统架构
架构图
┌─────────────┐ ┌─────────────┐ ┌──────────────┐
│ Google │ │ n8n │ │ PostgreSQL │
│ Trends API │───▶│ Workflow │───▶│ Database │
└─────────────┘ └─────────────┘ └──────────────┘
│
▼
┌─────────────┐
│ Next.js │
│ Frontend │
└─────────────┘
数据流向
- 定时触发: n8n Schedule 每季度末自动执行
- 数据采集: Google Trends API 获取热门搜索词
- AI 清洗: 过滤无关词汇,生成描述和要点
- 规则匹配: 根据热度分数分配视觉样式
- 数据入库: 写入 PostgreSQL 数据库
- 前端展示: Next.js 从数据库读取并渲染词云
三、数据库模型
3.1 Quarter 表(季度元数据)
model Quarter {
id Int @id @default(autoincrement())
quarter String @unique // "2023-Q1", "2023-Q2"
title String @db.Text // "2023年第一季度"
titleEn String? @db.Text // "Q1 2023"
subtitle String? @db.Text // "聊天界面的黎明"
subtitleEn String? @db.Text // "The dawn of chat interface"
displayOrder Int @default(0) // 前端排序
isActive Boolean @default(true) // 是否显示
keywords Keyword[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([quarter])
@@index([displayOrder])
}
3.2 Keyword 表(关键词核心数据)
model Keyword {
id Int @id @default(autoincrement())
word String // "ChatGPT"
trendScore Int // 0-100, 从 Google Trends 获取
// 外键关联
quarterId Int
quarter Quarter @relation(fields: [quarterId], references: [id], onDelete: Cascade)
// 内容字段(支持中英双语)
description String @db.Text // AI 生成的一句话描述
descriptionEn String? @db.Text // 英文描述
detailPoints Json // JSON 数组: ["要点1", "要点2", "要点3"]
detailPointsEn Json? // 英文版要点
// 视觉样式配置
visualConfig Json // {color, size, rotation, border}
// 元数据
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([quarterId])
@@index([trendScore])
@@index([word])
}
visualConfig 字段结构示例:
{
"color": "secondary",
"size": "text-5xl",
"rotation": "rotate-1",
"border": "border-4"
}
3.3 VisualStyleRule 表(视觉样式规则配置)
model VisualStyleRule {
id Int @id @default(autoincrement())
name String @unique // "热门大词-金色"
// 分数区间
minScore Int // 90
maxScore Int // 100
// 视觉属性
color String // "primary", "secondary", "accent"
size String // "text-5xl", "text-3xl", "text-xl"
border String // "border-4", "border-2"
rotation String? // "rotate-1", "rotate-2", null
// 控制
priority Int @default(0) // 优先级,分数重叠时按优先级
enabled Boolean @default(true) // 是否启用
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([enabled])
@@index([minScore, maxScore])
}
3.4 KeywordCloudErrorLog 表(错误日志)
model KeywordCloudErrorLog {
id Int @id @default(autoincrement())
quarter String // "2023-Q1"
keyword String? // "ChatGPT"
errorType String // "INVALID_DATA", "API_ERROR", "DB_ERROR"
errorMessage String @db.Text // 详细错误信息
rawData Json? // 原始数据便于调试
createdAt DateTime @default(now())
@@index([quarter])
@@index([errorType])
}
四、n8n 工作流设计
4.1 工作流概览
5 个核心节点实现从数据采集到入库的完整流程。
4.2 节点详细配置
节点 1: Schedule Trigger(定时触发)
- 类型:
n8n-nodes-base.scheduleTrigger - Cron 表达式:
0 0 23 28-31 * *(每季度末最后一天的 23:00) - 月份判断: Function 节点检查当前月份(3/6/9/12),如果不是则跳过
- 输出: 当前季度的标识(如 "2024-Q1")
节点 2: Google Trends 采集
- 类型:
@gamal.dev/n8n-nodes-google-trends - 配置参数:
keywords: ["AI", "artificial intelligence", "machine learning", "GPT", "LLM"]timeRange: 当前季度的 3 个月(如 2024-01-01 to 2024-03-31)category: "Science > Computer Science > AI"geo: "GB"
- 输出示例:
{ "keyword": "ChatGPT", "trendScore": 95, "rising": true }
节点 3: AI 清洗和内容生成
- 类型:
@n8n/n8n-nodes-langchain.lmChatChain - Prompt 模板:
你是一个 AI 领域专家。以下是 Google Trends 采集的热门关键词列表: {{ $json.all() }} 任务: 1. 过滤掉与 AI/机器学习无关的关键词 2. 为每个关键词生成中文描述(10-50字) 3. 生成 3 条详细要点(每条 10-30 字,客观描述,避免营销用语) 输出格式(JSON 数组): [ { "word": "ChatGPT", "trendScore": 95, "description": "OpenAI 开发的对话式人工智能助手", "detailPoints": ["支持多轮对话", "基于 GPT-3.5 架构", "2023年用户突破1亿"] } ]
节点 4: 规则引擎匹配
- 类型:
n8n-nodes-base.code - 逻辑:
- HTTP Request 获取
VisualStyleRule表数据- 方法: GET
- URL:
{{ $env.API_URL }}/api/keyword-cloud/rules
- 按
priority排序规则 - 遍历每个关键词,匹配第一个符合的规则(
minScore <= trendScore <= maxScore) - 将视觉配置注入数据
- HTTP Request 获取
节点 5: 批量写入数据库
- 类型:
n8n-nodes-base.httpRequest - 方法: POST
- URL:
{{ $env.API_URL }}/api/keyword-cloud/keywords - 认证: Bearer Token(环境变量
API_KEY) - Body:
{ "quarter": "2024-Q1", "keywords": [ { "word": "ChatGPT", "trendScore": 95, "description": "...", "detailPoints": ["...", "...", "..."], "visualConfig": {...} } ] } - 批量处理: 超过 20 个关键词时分批提交
4.3 错误处理
- 每个节点设置
continueOnFail: true - 错误日志写入
KeywordCloudErrorLog表 - 关键错误发送通知(Email/Slack)
五、API 端点设计
5.1 GET /api/keyword-cloud/quarters
获取季度列表。
查询参数:
isActive(可选): 只返回激活的季度
响应示例:
{
"quarters": [
{
"id": 1,
"quarter": "2024-Q1",
"title": "2024年第一季度",
"titleEn": "Q1 2024",
"subtitle": "聊天界面的黎明",
"subtitleEn": "The dawn of chat interface",
"displayOrder": 0,
"keywordCount": 15
}
]
}
排序: 按 displayOrder ASC
5.2 GET /api/keyword-cloud/keywords/[quarter]
获取指定季度的关键词列表。
路径参数:
quarter: 季度标识(如 "2024-Q1")
响应示例:
{
"quarter": "2024-Q1",
"title": "2024年第一季度",
"keywords": [
{
"id": 1,
"word": "ChatGPT",
"trendScore": 95,
"description": "OpenAI 开发的对话式 AI 助手",
"detailPoints": ["支持多轮对话", "基于 GPT-3.5", "2023用户破亿"],
"visualConfig": {
"color": "secondary",
"size": "text-5xl",
"border": "border-4",
"rotation": "rotate-1"
}
}
]
}
排序: 按 trendScore DESC
5.3 POST /api/keyword-cloud/keywords
n8n 工作流写入关键词数据。
认证: Bearer Token (WEBHOOK_API_KEY)
请求体:
{
"quarter": "2024-Q1",
"keywords": [
{
"word": "ChatGPT",
"trendScore": 95,
"description": "...",
"detailPoints": ["...", "...", "..."],
"visualConfig": {...}
}
]
}
响应:
{
"success": true,
"created": 15,
"failed": 2,
"errors": [
{ "word": "Invalid", "error": "trendScore out of range" }
]
}
逻辑:
- 验证 API Key
- 查找或创建
Quarter记录 - 批量创建
Keyword记录(PrismacreateMany) - 失败记录写入
KeywordCloudErrorLog表 - 返回成功/失败统计
5.4 GET /api/keyword-cloud/rules
获取视觉样式规则配置(n8n 规则引擎使用)。
查询参数:
enabled(可选): 只返回启用的规则
响应示例:
{
"rules": [
{
"id": 1,
"name": "热门大词-金色",
"minScore": 90,
"maxScore": 100,
"visualConfig": {
"color": "primary",
"size": "text-5xl",
"border": "border-4",
"rotation": "rotate-1"
},
"priority": 0,
"enabled": true
}
]
}
排序: 按 priority ASC
5.5 POST /api/keyword-cloud/rules
创建新的视觉样式规则(管理员功能)。
请求体: 同单个规则对象
验证:
minScore < maxScore- 必填字段检查
- 颜色值必须是预定义的颜色类别
六、前端组件设计
6.1 路由结构
src/app/[locale]/keyword-cloud/
├── page.tsx # 主页面
└── components/
├── KeywordCloud.tsx # 词云容器组件
├── CloudWord.tsx # 单个词汇组件
├── QuarterNavigator.tsx # 季度切换导航
├── WordPopover.tsx # 弹出框详情
└── ProgressIndicator.tsx # 进度条
6.2 核心组件
KeywordCloud.tsx
词云容器组件,负责数据获取和布局。
interface KeywordCloudProps {
quarter: string;
}
function KeywordCloud({ quarter }: KeywordCloudProps) {
const { data, isLoading } = useKeywordData(quarter);
return (
<div className="bg-white/50 dark:bg-black/20 backdrop-blur-sm border-4 border-black p-8 md:p-12 shadow-hard">
<ProgressIndicator currentQuarter={quarter} totalQuarters={4} />
<QuarterNavigator current={quarter} />
<div className="word-cluster py-12">
{data?.keywords.map((keyword) => (
<CloudWord key={keyword.id} data={keyword} />
))}
</div>
<FunFactBubble fact={data.funFact} />
</div>
);
}
CloudWord.tsx
单个词汇组件,应用视觉样式和悬停交互。
interface CloudWordProps {
data: Keyword;
}
function CloudWord({ data }: CloudWordProps) {
const { word, visualConfig, description, detailPoints } = data;
const { color, size, border, rotation } = visualConfig;
const colorClass = colorMap[color];
return (
<span className={cn(
"cloud-word",
border,
"border-black",
colorClass,
"px-6 py-3",
"rounded-full",
size,
"font-black",
"shadow-hard",
rotation,
"transition-all",
"hover:scale-105",
"cursor-pointer"
)}>
{word}
<WordPopover title={word} description={description} points={detailPoints} />
</span>
);
}
WordPopover.tsx
弹出框组件,显示词汇的详细信息。
interface WordPopoverProps {
title: string;
description: string;
points: string[];
}
function WordPopover({ title, description, points }: WordPopoverProps) {
return (
<div className="popover">
<div className="bg-primary text-black font-display font-bold p-2 border-b-2 border-black text-sm uppercase">
{title}
</div>
<div className="p-3 space-y-2 text-xs font-medium dark:text-gray-100">
<div className="flex gap-2 items-start">
<span>•</span>
<span>{description}</span>
</div>
{points.map((point, i) => (
<div key={i} className="flex gap-2 items-start">
<span>•</span>
<span>{point}</span>
</div>
))}
</div>
</div>
);
}
QuarterNavigator.tsx
季度切换导航组件。
function QuarterNavigator({ current }: { current: string }) {
const quarters = ["2023-Q1", "2023-Q2", "2023-Q3", "2023-Q4"];
const currentIndex = quarters.indexOf(current);
return (
<div className="flex items-center justify-between gap-8">
<button
disabled={currentIndex === 0}
className="nav-button"
onClick={() => navigate(quarters[currentIndex - 1])}
>
<span className="material-symbols-outlined text-4xl">chevron_left</span>
</button>
<div className="text-center">
<div className="bg-primary border-4 border-black px-10 py-4 shadow-hard font-display font-bold text-5xl">
{current}
</div>
</div>
<button
disabled={currentIndex === quarters.length - 1}
className="nav-button"
onClick={() => navigate(quarters[currentIndex + 1])}
>
<span className="material-symbols-outlined text-4xl">chevron_right</span>
</button>
</div>
);
}
6.3 数据获取
// src/hooks/useKeywordCloud.ts
export async function getKeywordData(quarter: string) {
const response = await fetch(`${API_URL}/api/keyword-cloud/keywords/${quarter}`);
return response.json();
}
6.4 样式系统
复用项目现有的 Tailwind 配置和样式类:
.cloud-word: 词云词汇的基础样式.popover: 弹出框样式(包括箭头).word-cluster: 词汇容器布局.nav-button: 导航按钮样式
响应式断点:md:, lg:
七、错误处理和监控
7.1 分层错误处理
n8n 工作流层:
- 每个节点
continueOnFail: true - 失败记录写入
KeywordCloudErrorLog表 - 关键错误发送通知
API 层:
- Zod schema 验证
- 部分成功响应模式
- HTTP 状态码规范
前端层:
- 友好的错误提示
- Error Boundary
- 重试机制
7.2 监控策略
- n8n 执行日志监控
- 定期检查
KeywordCloudErrorLog表 - API 响应时间监控
- 前端错误追踪
八、测试策略
8.1 单元测试(Vitest)
- API 路由处理逻辑
- 规则引擎匹配算法
- 数据验证 schemas
8.2 E2E 测试
- 季度切换功能
- 弹出框交互
- 响应式布局
8.3 n8n 工作流测试
- 使用测试环境 API 手动触发
- 验证生成的数据质量
- 检查规则匹配结果
九、部署指南
9.1 环境变量
# .env.local
DATABASE_URL="..."
WEBHOOK_API_KEY="..."
N8N_WEBHOOK_URL="https://your-n8n-instance.com/..."
9.2 数据库迁移
pnpm prisma migrate dev --name add_keyword_cloud_tables
9.3 n8n 部署
- 使用自托管 n8n 或 n8n Cloud
- 配置环境变量(API_URL, API_KEY)
- 设置 Cron 定时任务
- 测试工作流执行
9.4 初始化数据
- 创建第一个
Quarter记录(2023-Q1) - 配置 3-5 条
VisualStyleRule:- 90-100: 热门大词(金色, text-5xl, border-4)
- 70-89: 中等词汇(蓝色, text-3xl, border-2)
- 50-69: 小词汇(紫色, text-xl, border-2)
- 0-49: 长尾词(灰色, text-base, border-2)
9.5 监控设置
- n8n 执行日志告警
- 错误日志定期检查
- API 性能监控
十、未来扩展
- 预测功能: 基于历史数据预测下一个热点词汇
- 趋势分析: 展示词汇热度的季度变化曲线
- 用户贡献: 允许用户提交词汇建议
- 多维度: 按技术栈、应用领域等维度分类
- 导出功能: 导出季度报告(PDF/图片)
附录
A. 颜色系统
const colorMap = {
primary: "bg-primary", // Gold (#FFD700)
secondary: "bg-secondary", // Blue (#7FB5FF)
accent: "bg-accent", // Purple (#C39BD3)
gray: "bg-gray-100", // Gray
};
B. 字体大小映射
const sizeMap = {
hot: "text-5xl", // 90-100 分
medium: "text-3xl", // 70-89 分
small: "text-xl", // 50-69 分
tiny: "text-base", // 0-49 分
};
C. 参考资源
- Google Trends API: https://trends.google.com/
- n8n 文档: https://docs.n8n.io/
- Tailwind CSS: https://tailwindcss.com/