feat: add daily tip & case auto-publish system

- GitHub Actions workflow: daily-content.yml (UTC 00:00 / 北京 08:00)
- Content generation script: .github/scripts/generate-daily.js (Claude API)
- Initial data: website/daily/data.json
- website/index.html: new 每日精选 section with bilingual support

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hfshfg
2026-04-02 20:06:49 +08:00
parent 5c7408495d
commit f3530888f3
4 changed files with 403 additions and 0 deletions

157
.github/scripts/generate-daily.js vendored Normal file
View File

@@ -0,0 +1,157 @@
#!/usr/bin/env node
/**
* 每日内容生成脚本
* 调用 Claude API 生成每日小技巧和每日最佳案例
* 写入 website/daily/data.json
*/
const https = require('https');
const fs = require('fs');
const path = require('path');
const DATA_FILE = path.join(__dirname, '../../website/daily/data.json');
const MAX_HISTORY = 30;
const TODAY = new Date().toLocaleDateString('zh-CN', {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: '2-digit',
day: '2-digit'
}).replace(/\//g, '-');
const SYSTEM_PROMPT = `你是 U-Claw 虾盘的内容助手。U-Claw 是一款专为中国用户打造的 OpenClaw AI 助手离线安装 U 盘,特点如下:
- 完全离线安装,无需翻墙
- 支持 macOS / Windows / Linux
- 内置 52 个预装技能Skills
- 支持 8 大国产模型DeepSeek、Kimi、通义千问、智谱GLM、MiniMax、豆包、千帆、Mimo
- 多平台接入QQ / 飞书 / 钉钉 / 企业微信 / Telegram / Discord
- 便携模式:插上 U 盘即用,配置跟着 U 盘走
- 安装到电脑:一键永久安装
- 支持远程控制Agent 模式)
- 基于 OpenClaw 开源项目
每日内容需要实用、具体、对真实用户有帮助。内容要中英双语json格式不要有多余的格式。`;
const USER_PROMPT = `请生成今天(${TODAY})的内容,包含两部分:
1. **每日小技巧**tip一个关于 U-Claw / OpenClaw 的具体使用技巧,可以是快捷操作、配置方法、隐藏功能等
2. **每日最佳案例**case一个真实使用场景的案例展示如何用 U-Claw 解决实际问题
要求:
- 每部分有标题title和正文content正文 80-150 字
- 中英双语zh中文和 en英文版本
- 实用、具体,避免空泛
请严格按以下 JSON 格式返回,不要有多余文字:
{
"tip": {
"title": { "zh": "中文标题", "en": "English Title" },
"content": { "zh": "中文内容", "en": "English content" },
"tag": { "zh": "技巧", "en": "Tip" }
},
"case": {
"title": { "zh": "中文标题", "en": "English Title" },
"content": { "zh": "中文内容", "en": "English content" },
"tag": { "zh": "案例", "en": "Case" }
}
}`;
function callClaude(apiKey) {
return new Promise((resolve, reject) => {
const body = JSON.stringify({
model: 'claude-sonnet-4-6',
max_tokens: 1024,
system: SYSTEM_PROMPT,
messages: [{ role: 'user', content: USER_PROMPT }]
});
const options = {
hostname: 'api.anthropic.com',
path: '/v1/messages',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': apiKey,
'anthropic-version': '2023-06-01',
'Content-Length': Buffer.byteLength(body)
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
if (res.statusCode !== 200) {
reject(new Error(`API error ${res.statusCode}: ${data}`));
return;
}
try {
const parsed = JSON.parse(data);
const text = parsed.content[0].text.trim();
// 提取 JSON防止模型输出额外文字
const jsonMatch = text.match(/\{[\s\S]*\}/);
if (!jsonMatch) throw new Error('No JSON found in response');
resolve(JSON.parse(jsonMatch[0]));
} catch (e) {
reject(new Error(`Parse error: ${e.message}\nRaw: ${data}`));
}
});
});
req.on('error', reject);
req.write(body);
req.end();
});
}
async function main() {
const apiKey = process.env.ANTHROPIC_API_KEY;
if (!apiKey) {
console.error('ANTHROPIC_API_KEY not set');
process.exit(1);
}
console.log(`Generating content for ${TODAY}...`);
let content;
try {
content = await callClaude(apiKey);
console.log('API call successful');
} catch (err) {
console.error('API call failed:', err.message);
process.exit(0); // 失败时退出但不破坏 CI
}
// 读取现有数据
let data = { latest: null, history: [] };
if (fs.existsSync(DATA_FILE)) {
try {
data = JSON.parse(fs.readFileSync(DATA_FILE, 'utf8'));
} catch (e) {
console.warn('Could not parse existing data, starting fresh');
}
}
// 构建今日条目
const entry = {
date: TODAY,
tip: content.tip,
case: content.case
};
// 如果今天已有记录,替换;否则追加到 history
if (data.latest && data.latest.date !== TODAY) {
data.history.unshift(data.latest);
// 保留最近 MAX_HISTORY 条
if (data.history.length > MAX_HISTORY) {
data.history = data.history.slice(0, MAX_HISTORY);
}
}
data.latest = entry;
fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2), 'utf8');
console.log(`Written to ${DATA_FILE}`);
}
main();

38
.github/workflows/daily-content.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: Daily Content Generator
on:
schedule:
- cron: '0 0 * * *' # UTC 00:00 = 北京时间 08:00
workflow_dispatch: # 支持手动触发测试
jobs:
generate:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Generate daily content
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: node .github/scripts/generate-daily.js
- name: Commit and push changes
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add website/daily/data.json
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "chore: update daily content $(date -u '+%Y-%m-%d')"
git push
fi