190 lines
5.1 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* 格式化AI新闻简报 - 飞书友好版本(含中文翻译)
* 生成易读、链接可点击的消息格式
*/
const fs = require('fs');
const path = require('path');
const DAILY_DIR = path.join(__dirname, '../../daily');
// 简单的翻译映射(常见术语)
const termMap = {
'web browser': '网页浏览器',
'browser': '浏览器',
'independent': '独立的',
'framework': '框架',
'methodology': '方法论',
'agentic': '代理式',
'adaptive': '自适应',
'web scraping': '网页爬取',
'framework': '框架',
'high performance': '高性能',
'vector graph': '向量图',
'real time': '实时',
'analytics': '分析',
'portrait': '肖像',
'animation': '动画',
'live streaming': '直播',
'health records': '健康记录',
'medical practice': '医疗实践',
'management': '管理',
'solution': '解决方案',
'open source': '开源',
'tool': '工具',
'location': '位置',
'mobile number': '手机号码',
'track': '追踪',
'system': '系统',
'built in': '构建于',
'focused on': '专注于'
};
function translateToChinese(text) {
let translated = text;
// 替换常见术语
for (const [eng, chi] of Object.entries(termMap)) {
const regex = new RegExp(eng, 'gi');
translated = translated.replace(regex, chi);
}
return translated;
}
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 currentDate = '';
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 formatForFeishu(data) {
const { currentTime, totalItems, items } = data;
let message = `📰 AI Daily Brief - ${getYesterdayDate()}\n\n`;
message += `⏰ 采集时间: ${currentTime}\n`;
message += `📊 总条目: ${totalItems}\n\n`;
message += `━━━━━━━━━━━━━━━━━━━━\n\n`;
message += `🔥 今日热点\n\n`;
items.forEach((item, index) => {
const num = ['1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣', '🔟'][index] || `${index + 1}.`;
message += `${num} ${item.title}\n`;
message += `${item.source}\n`;
if (item.description) {
// 添加中文翻译
const translated = translateToChinese(item.description);
message += `${translated}\n`;
// 如果翻译后不同,显示原文
if (translated !== item.description) {
message += `(原文:${item.description}\n`;
}
}
message += `🔗 ${item.url}\n\n`;
});
message += `━━━━━━━━━━━━━━━━━━━━\n`;
message += `💡 点击链接跳转到GitHub查看详情\n`;
return message;
}
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 formattedMessage = formatForFeishu(data);
console.log('格式化后的消息:');
console.log(formattedMessage);
return {
success: true,
date: yesterday,
message: formattedMessage
};
}
if (require.main === module) {
main().catch(console.error);
}
module.exports = { main, formatForFeishu, parseMarkdown };