使用飞书卡片格式推送AI新闻,支持可点击链接

This commit is contained in:
bojunc 2026-02-25 12:18:21 +08:00
parent 333788d43b
commit 797deb62f4

View File

@ -0,0 +1,174 @@
#!/usr/bin/env node
/**
* 飞书卡片消息格式化
* 生成可点击链接的富文本卡片
*/
const fs = require('fs');
const path = require('path');
const DAILY_DIR = path.join(__dirname, '../../daily');
function getYesterdayDate() {
const d = new Date();
d.setDate(d.getDate() - 1);
return d.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
timeZone: 'Asia/Shanghai'
}).replace(/\//g, '-');
}
function parseMarkdown(markdown) {
const lines = markdown.split('\n');
const items = [];
let currentTime = '';
let totalItems = 0;
// 解析元数据
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.startsWith('> 采集时间:')) {
currentTime = line.replace('> 采集时间:', '').trim();
}
if (line.startsWith('> 总条目:')) {
totalItems = parseInt(line.replace('> 总条目:', '').trim());
}
}
// 解析新闻条目
const itemRegex = /^(\d+)\.\s+\[([^\]]+)\]\(([^)]+)\)\s+-\s+\*\*([^*]+)\*\*/;
let currentItem = null;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const match = line.match(itemRegex);
if (match) {
if (currentItem) {
items.push(currentItem);
}
// 清理URL
let url = match[3];
let title = match[2];
if (url.includes('login?return_to=')) {
const realPath = decodeURIComponent(url.split('return_to=')[1]);
url = `https://github.com${realPath}`;
title = realPath.replace('/', '');
}
currentItem = {
number: match[1],
title: title,
url: url,
source: match[4],
description: ''
};
} else if (currentItem && line.trim().startsWith('>') && !line.includes('采集时间') && !line.includes('总条目')) {
currentItem.description = line.replace(/^\s*>\s*/, '').trim();
}
}
if (currentItem) {
items.push(currentItem);
}
return { currentTime, totalItems, items };
}
function createFeishuCard(data) {
const { currentTime, totalItems, items } = data;
const elements = [
{
tag: "div",
text: {
tag: "lark_md",
content: `**⏰ 采集时间**: ${currentTime}\n**📊 总条目**: ${totalItems}`
}
},
{
tag: "hr"
}
];
// 添加新闻条目
items.forEach((item, index) => {
const num = ['1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣', '🔟'][index] || `${index + 1}.`;
elements.push({
tag: "div",
text: {
tag: "lark_md",
content: `${num} **${item.title}**\n\`${item.source}\`\n> ${item.description}\n[🔗 点击查看详情](${item.url})`
}
});
// 每条之间加分隔线(除了最后一条)
if (index < items.length - 1) {
elements.push({
tag: "hr"
});
}
});
// 添加底部提示
elements.push({
tag: "hr"
});
elements.push({
tag: "note",
elements: [
{
tag: "plain_text",
content: "💡 点击链接跳转到GitHub查看详情\n*Generated by AINewsCollector*"
}
]
});
return {
msg_type: "interactive",
card: {
header: {
title: {
tag: "plain_text",
content: `📰 AI Daily Brief - ${getYesterdayDate()}`
},
template: "blue"
},
elements: elements
}
};
}
async function main() {
const yesterday = getYesterdayDate();
const reportPath = path.join(DAILY_DIR, `${yesterday}.md`);
if (!fs.existsSync(reportPath)) {
console.log(`❌ 未找到昨日简报: ${reportPath}`);
return { success: false, error: 'Report not found' };
}
const markdown = fs.readFileSync(reportPath, 'utf8');
const data = parseMarkdown(markdown);
const card = createFeishuCard(data);
console.log(JSON.stringify(card, null, 2));
return {
success: true,
date: yesterday,
card: card
};
}
if (require.main === module) {
main().catch(console.error);
}
module.exports = { main, createFeishuCard, parseMarkdown };