本项目旨在打造一个闭环的、高度自动化的个人数据处理系统。它始于你的日常记录,终于一份由 AI 生成的、发布在个人网站上的深度分析报告。整个系统由三大核心模块构成:Go Web 日记应用 (数据输入层)、n8n 自动化工作流 (数据处理与分析核心)、Hugo 静态网站 (数据展示层)。
系统架构总览
- 输入: 你通过浏览器访问 Go 日记应用,撰写每日任务、总结和心情。
- 存储: 数据被实时保存到 PostgreSQL 数据库。
- 触发: n8n 中的定时任务在每天深夜被激活。
- 提取: n8n 连接到数据库,抓取当天的日记数据。
- 分析: n8n 将数据发送给 Google Gemini,并根据预设指令生成一份包含 CSS 样式的精美 HTML 报告。
- 发布: n8n 将生成的 HTML 文件自动推送到托管在 GitHub 上的 Hugo 网站仓库。
- 部署: Netlify 或 Vercel 监测到 GitHub 仓库更新,自动重新构建并发布 Hugo 网站。
- 展示: 你可以在任何地方通过浏览器访问你的个人报告网站,回顾每一天的 AI 分析。
第一部分:Go Web 日记应用 (数据输入层)
核心目标: 提供一个稳定、高效、功能丰富的 Web 界面,用于日常记录。
所用工具 (Tools Used)
- 编程语言: Go
- Web 框架: Gin (
github.com/gin-gonic/gin) - 数据库驱动:
pqfor PostgreSQL (github.com/lib/pq) - 数据库服务: PostgreSQL (推荐使用 Supabase 或 AWS RDS 等云服务)
- 前端模板引擎: Go
html/template - 前端核心库:
- jQuery: 简化 DOM 操作和 AJAX。
- CKEditor 4: 提供富文本编辑体验。
- FullCalendar: 用于生成交互式日历。
- Prism.js: 提供代码高亮。
实现功能 (Features Implemented)
- 核心日记管理 (CRUD):
- 创建 (
Create):writeHandler确保每天只创建一篇日记,避免重复。 - 读取 (
Read):detailHandler负责读取并展示单篇日记的所有数据。 - 更新 (
Update):apiUpdateHandler提供核心 API,用于实时更新日记。 - 删除 (
Delete):deleteHandler允许用户删除指定的日记。
- 创建 (
- 极致用户体验:
- 无感自动保存: 通过 JavaScript 监听内容变化,延迟几百毫秒后自动向后端发送更新,无需手动保存。
- 富文本编辑: 集成 CKEditor,支持复杂格式、图片上传(需配置对象存储)和代码块。
- 动态任务列表: 可动态增删任务,备注后任务项自动划线,模拟“已完成”。
- 历史日记只读模式: 非当日记记自动锁定,所有输入框变为纯文本,防止误改。
- 智能化集成:
- 天气自动获取与更新: 加载日记时自动获取天气,并允许用户手动输入城市更新。
- 每日心情记录: 点击 Emoji 即可通过 API 快速保存当天心情。
- 便捷的回顾与导航:
- 日历视图: 侧边栏日历清晰标记有日记的日期、心情和任务量,点击即可跳转。
- “往年同期”功能: 页面底部自动异步加载并展示过去几年同一天的日记链接。
关键代码解析
1. 数据库连接与初始化 (main.go)
// main.go
func main() {
// ...
// DSN (数据源名称), 替换成你自己的
dsn := "postgres://postgres.vbvkjiywdbocjpcjmtjs:519yang982@aws-0-ap-southeast-1.pooler.supabase.com:6543/postgres?sslmode=require&statement_cache_mode=none"
db, err := sql.Open("postgres", dsn)
if err != nil {
log.Fatalf("打开数据库失败: %v", err)
}
defer db.Close()
// --- 数据库连接池配置 (非常重要!) ---
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(10)
db.SetConnMaxLifetime(5 * time.Minute)
if err = db.Ping(); err != nil {
log.Fatal("数据库 Ping 失败:", err)
}
// ... 自动建表和启动服务 ...
}
2. 自动保存API (main.go)
// main.go
func apiUpdateHandler(w http.ResponseWriter, r *http.Request) {
var payload struct {
ID int64 `json:"id"`
TopText string `json:"top_text"`
BottomText string `json:"bottom_text"`
Rows [][2]string `json:"rows"`
}
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
http.Error(w, "JSON错误", 400); return
}
contentBytes, err := json.Marshal(payload.Rows)
if err != nil {
http.Error(w, "内容编码失败", 500); return
}
_, err = db.Exec(`UPDATE yys_diary SET content=$1, top_text=$2, bottom_text=$3 WHERE id=$4`,
string(contentBytes), payload.TopText, payload.BottomText, payload.ID)
if err != nil {
http.Error(w, "数据库更新失败", 500); return
}
w.WriteHeader(200)
json.NewEncoder(w).Encode(map[string]string{"message": "更新成功"})
}
3. 前端自动保存逻辑 (templates/detail.html)
<!-- templates/detail.html -->
<script>
const diaryId = parseInt('{{.DiaryData.ID}}');
let saveTimer;
function scheduleSave() {
clearTimeout(saveTimer);
saveTimer = setTimeout(autoSave, 800);
}
function autoSave() {
const rows = Array.from(document.querySelectorAll('#tasks .task-row')).map(row => [
row.querySelector('.task-input')?.value || "",
row.querySelector('.note-input')?.value || ""
]);
const editorData = CKEDITOR.instances.bottomText.getData();
fetch('/api/update', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: diaryId,
top_text: document.getElementById('topTextDisplay')?.textContent.trim(),
bottom_text: editorData,
rows: rows
})
}).then(r => r.json()).then(data => console.log('[AUTO_SAVE]', data.message));
}
window.addEventListener('DOMContentLoaded', () => {
document.getElementById('tasks')?.addEventListener('input', scheduleSave);
if (CKEDITOR.instances.bottomText) {
CKEDITOR.instances.bottomText.on('change', scheduleSave);
}
});
</script>
第二部分:n8n 自动化工作流 (数据处理与分析核心)
核心目标: 作为系统的大脑,自动连接所有服务,完成数据提取、AI 分析和内容发布的完整流程。
docker compose安装
services:
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
ports:
- "8880:5678"
environment:
- N8N_HOST=0.0.0.0
- N8N_PORT=5678
- N8N_PROTOCOL=http
- N8N_SECURE_COOKIE=false
- GENERIC_TIMEZONE=Asia/Shanghai
- TZ=Asia/Shanghai
- DB_TYPE=sqlite
- DB_SQLITE_DATABASE=/home/node/.n8n/database.sqlite
- NODE_OPTIONS=--max-old-space-size=512
- EXECUTIONS_DATA_PRUNE=true
- EXECUTIONS_DATA_MAX_AGE=168
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=admin
- N8N_BASIC_AUTH_PASSWORD=ChangeThisPassword123!
- WEBHOOK_URL=http://你的ip:8880/
volumes:
- ./.n8n:/home/node/.n8n
mem_limit: 768m
mem_reservation: 512m
cpus: 0.5
sudo chown -R 1000:1000 .n8n
所用工具 (Tools Used)
- 自动化平台: n8n (云版或 Docker 自托管)
- 核心节点 (Nodes):
- Schedule Trigger: 定时触发器。
- Code Node: 执行 JavaScript 代码,处理数据。
- Postgres Node: 连接和查询 PostgreSQL。
- Google Gemini Node (或 Basic LLM Chain Node): 与大语言模型交互。
- GitHub Node: 执行 Git 操作,发布文件。
实现功能 (Features Implemented)
- 定时自动化执行: 使用
Schedule Trigger节点的 CRON 模式,实现每日定时启动,无需人工干预。 - 动态数据提取:
Code节点生成精确的当日时间范围,Postgres节点利用此范围,准确无误地抓取当天的日记。 - AI 驱动的报告生成:
Gemini节点接收日记数据,并结合一个精心设计的 Prompt,指导 AI 扮演分析师角色,从多维度进行解读,并最终输出一份包含 CSS 样式的、可以直接发布的 HTML 文件。 - 无人值守的内容发布:
GitHub节点链实现了 GitOps 流程,自动将 AI 生成的报告文件推送到 Hugo 网站仓库,触发后续的自动部署。
关键代码与配置
Node 1: Schedule Trigger
- Mode:
Cron - Cron Expression:
0 23 * * *(每天 23:00 执行)
Node 2: Code (准备查询参数)
- Language:
JavaScript - Code:
const today = new Date();
const startDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
const endDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1);
const formatForSQL = (date) => date.toISOString().slice(0, 19).replace('T', ' ');
return [{
json: {
startDate: formatForSQL(startDate),
endDate: formatForSQL(endDate),
reportDate: today.toISOString().slice(0, 10) // YYYY-MM-DD
}
}];
Node 3: Postgres (查询当日日记)
- Query:
SELECT title, mood, content, top_text, bottom_text
FROM yys_diary
WHERE created >= '{{ $json.startDate }}' AND created < '{{ $json.endDate }}'
ORDER BY created DESC
LIMIT 1;
Node 4: Gemini / Basic LLM Chain (AI 分析)
- Prompt (这是灵魂,请完整复制):
你是一位结合了敏锐数据分析师、深刻心理洞察者和创意生活顾问的顶尖 AI 助手。你的任务是分析我提供的 JSON 格式的日记数据,并生成一份完整、精美、可以直接在浏览器中打开的 HTML 格式分析报告(加个好看的css背景)。
**遵循以下指令:**
请确保输出包含 `<!DOCTYPE html>`, `<html>`, `<body>` 标签,并使用 UTF-8 编码。例如:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>分析结果</title>
</head>
<body>
<!-- 在这里生成您的分析内容,例如使用 <h1>, <p>, <strong> 等标签 -->
<h1>日记摘要分析</h1>
<p>这是对...的分析。</p>
</body>
</html>
现在,请根据以下数据生成报告:
标题: {{ $json.title }}
心情: {{ $json.mood }}
内容: {{ $json.content }}
天气: {{ $json.top_text }}
总结:{{ $json.bottom_text }}
最后给出建议(有创意的)。
Node 5: GitHub (发布报告)
- File Path:
content/reports/{{ $json.reportDate }}.html - Content:
{{ $('Google Gemini').first().json.output }} - Commit Message:
[Automated] Add daily report for {{ $json.reportDate }}

第三部分:Hugo 静态网站 (数据展示层)
核心目标: 提供一个极速、美观、免维护的网站来归档和展示所有 AI 生成的每日分析报告。
所用工具 (Tools Used)
- 静态网站生成器: Hugo
- 版本控制与托管: Git, GitHub
- CI/CD & 网站托管: Netlify / Vercel / GitHub Pages
实现功能 (Features Implemented)
- 报告自动聚合: 网站首页自动遍历
content/reports/目录下的所有报告文件并生成列表。 - 按日期智能排序: 利用文件名即日期的特性,将最新的报告自动展示在最顶部。
- 全自动化部署 (GitOps): n8n 推送更新到 GitHub 后,Netlify/Vercel 等平台会自动构建并发布新版本的网站。
- 极致的性能与安全性: 纯静态网站,访问速度快,无数据库,安全性高。
关键代码解析 (layouts/index.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>{{ .Site.Title }} - 个人 AI 分析报告</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; max-width: 800px; margin: 40px auto; padding: 20px; background-color: #f5f7fa; }
h1 { text-align: center; }
ul { list-style-type: none; padding: 0; }
li { background-color: #fff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.05); margin: 12px 0; transition: all 0.2s; }
li:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.1); }
a { display: block; padding: 18px 22px; text-decoration: none; color: #3498db; font-size: 1.1em; }
</style>
</head>
<body>
<h1>{{ .Site.Title }}</h1>
<p style="text-align: center; color: #7f8c8d;">{{ .Site.Params.description }}</p>
<h2>所有报告</h2>
<ul>
{{/*
这是 Hugo 的核心循环逻辑:
1. where .Site.Pages "Section" "reports": 只筛选出放在 "content/reports" 文件夹下的页面。
2. .ByTitle.Reverse: 因为文件名是日期 (如 2025-11-02.html),按标题(文件名)倒序,就能实现按日期降序。
*/}}
{{ range (where .Site.Pages "Section" "reports").ByTitle.Reverse }}
<li>
<a href="{{ .RelPermalink }}">
报告日期:{{ .File.BaseFileName }}
</a>
</li>
{{ end }}
</ul>
</body>
</html>
评论区(0 条)
发表评论⏳ 加载编辑器…