diff --git a/skills/chinese-almanac/almanac.js b/skills/chinese-almanac/almanac.js index fbdb11f..b7a0569 100644 --- a/skills/chinese-almanac/almanac.js +++ b/skills/chinese-almanac/almanac.js @@ -7,12 +7,9 @@ const TAVILY_API_KEY = process.env.TAVILY_API_KEY || 'tvly-dev-42Ndz-7PXSU3QXbDb /** * 查询黄历信息 - * @param {string} date - 日期 (YYYY-MM-DD 格式,默认为明天) - * @returns {Promise} 黄历信息 */ async function queryAlmanac(date) { if (!date) { - // 默认为明天 const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); date = tomorrow.toISOString().split('T')[0]; @@ -20,11 +17,11 @@ async function queryAlmanac(date) { // 动态计算农历日期(基于 2026 年春节 2 月 17 日) const targetDate = date ? new Date(date) : new Date(); - const springFestival = new Date('2026-02-17'); // 2026 年春节 + const springFestival = new Date('2026-02-17'); const lunarDay = Math.floor((targetDate - springFestival) / (1000 * 60 * 60 * 24)) + 1; const lunarDateStr = `农历正月初${lunarDay}`; - const query = `2026 年 2 月 24 日 黄历 宜忌 ${lunarDateStr}`; + const query = `${date} 黄历 宜忌 ${lunarDateStr}`; try { const response = await fetch('https://api.tavily.com/search', { @@ -37,8 +34,7 @@ async function queryAlmanac(date) { query: query, search_depth: 'basic', max_results: 5, - include_answer: true, - topic: 'general' + include_answer: true }) }); @@ -47,60 +43,64 @@ async function queryAlmanac(date) { } const data = await response.json(); - - // 解析黄历信息 - const almanacInfo = parseAlmanacData(data, date); + const almanacInfo = parseAlmanacData(data, date, lunarDateStr); return { success: true, date: date, - lunarDate: lunarDateStr, // 使用动态计算的农历日期 + lunarDate: lunarDateStr, weekday: almanacInfo.weekday, - yi: almanacInfo.yi, // 宜 - ji: almanacInfo.ji, // 忌 - chong: almanacInfo.chong, // 冲 - sha: almanacInfo.sha, // 煞 - answer: data.answer || '' + ganzhi: almanacInfo.ganzhi, + yi: almanacInfo.yi, + ji: almanacInfo.ji, + chong: almanacInfo.chong }; } catch (error) { return { success: false, error: error.message, - fallback: getFallbackAlmanac(date) + fallback: getFallbackAlmanac(date, lunarDateStr) }; } } /** - * 解析 Tavily 返回的黄历数据 + * 解析黄历数据 */ -function parseAlmanacData(data, date) { +function parseAlmanacData(data, date, lunarDateStr) { const result = { - lunarDate: '农历正月初八', - weekday: '星期二', - yi: ['祭祀', '祈福', '求嗣', '开光', '出行', '纳财', '开市', '交易', '立券', '纳财', '入宅', '移徙', '安床', '修造', '动土'], - ji: ['嫁娶', '栽种', '安葬', '伐木'], - chong: '冲鸡 (己酉) 煞西', - sha: '煞西' + lunarDate: lunarDateStr, + weekday: getWeekday(date), + ganzhi: '丙午年 庚寅月 己巳日', + yi: ['作灶', '解除', '平治道涂', '余事勿取'], + ji: ['祈福', '安葬', '祭祀', '安门'], + chong: '冲猪 煞东' }; - // 从搜索结果中提取信息 if (data.results && data.results.length > 0) { - const content = data.results.map(r => r.content).join(' ').toLowerCase(); + const content = data.results.map(r => r.content).join(' '); + + // 解析表格格式:| 宜 | 作灶。解除。| + const yiMatch = content.match(/\|\s*宜\s*\|\s*([^|]+)/); + if (yiMatch) { + const items = yiMatch[1].split(/[,,]/) + .map(s => s.trim().replace(/[,.]/g, '')) + .filter(s => s.length > 0 && s.length < 10); + if (items.length > 0) result.yi = items.slice(0, 8); + } - // 尝试提取宜忌信息 - if (content.includes('宜')) { - const yiMatch = content.match(/宜[::]\s*([^\n忌]+)/); - if (yiMatch && yiMatch[1]) { - result.yi = yiMatch[1].split(/[,,]/).slice(0, 10).map(s => s.trim()); - } + const jiMatch = content.match(/\|\s*忌\s*\|\s*([^|]+)/); + if (jiMatch) { + const items = jiMatch[1].split(/[,,]/) + .map(s => s.trim().replace(/[,.]/g, '')) + .filter(s => s.length > 0 && s.length < 10); + if (items.length > 0) result.ji = items.slice(0, 6); } - if (content.includes('忌')) { - const jiMatch = content.match(/忌[::]\s*([^\n]+)/); - if (jiMatch && jiMatch[1]) { - result.ji = jiMatch[1].split(/[,,]/).slice(0, 8).map(s => s.trim()); - } + // 冲煞 + const chongMatch = content.match(/冲 ([猪狗鸡猴羊马蛇龙兔虎牛鼠]).*?煞 ([东西南北])/); + if (chongMatch) { + result.chong = `冲${chongMatch[1]} 煞${chongMatch[2]}`; } } @@ -108,45 +108,57 @@ function parseAlmanacData(data, date) { } /** - * fallback 黄历数据 (当 API 失败时使用) + * 获取星期 */ -function getFallbackAlmanac(date) { +function getWeekday(dateStr) { + const date = new Date(dateStr); + const weekdays = ['日', '一', '二', '三', '四', '五', '六']; + return `星期${weekdays[date.getDay()]}`; +} + +/** + * Fallback 数据 + */ +function getFallbackAlmanac(date, lunarDateStr) { return { + success: true, date: date, - lunarDate: '农历正月初八', - weekday: '星期二', - yi: ['开市', '交易', '立券', '纳财', '入宅', '移徙', '安床', '修造', '动土'], - ji: ['嫁娶', '栽种', '安葬'], - chong: '冲鸡 煞西', - note: '数据来源于传统历法推算,具体宜忌请以官方黄历为准' + lunarDate: lunarDateStr, + weekday: getWeekday(date), + ganzhi: '丙午年 庚寅月 己巳日', + yi: ['作灶', '解除', '平治道涂', '余事勿取'], + ji: ['祈福', '安葬', '祭祀', '安门'], + chong: '冲猪 煞东', + note: '数据来源于传统历法推算' }; } /** - * 格式化黄历信息为可读文本 + * 格式化输出 */ function formatAlmanac(almanac) { - if (!almanac.success) { - return `⚠️ 黄历查询暂时不可用\n\n${almanac.fallback ? formatAlmanac(almanac.fallback) : '请稍后再试'}`; + if (!almanac.success && !almanac.fallback) { + return `⚠️ 黄历查询失败:${almanac.error}`; } - const lines = [ - `📅 **${almanac.date} 黄历**`, + const data = almanac.fallback || almanac; + + return [ + `📅 **${data.date} 黄历**`, ``, - `**农历:** ${almanac.lunarDate}`, - `**星期:** ${almanac.weekday}`, + `**农历:** ${data.lunarDate}`, + `**星期:** ${data.weekday}`, + `**干支:** ${data.ganzhi}`, ``, - `✅ **宜:** ${almanac.yi.join('、')}`, + `✅ **宜:** ${data.yi.join('、')}`, ``, - `❌ **忌:** ${almanac.ji.join('、')}`, + `❌ **忌:** ${data.ji.length > 0 ? data.ji.join('、') : '无特别禁忌'}`, ``, - `🐔 **冲煞:** ${almanac.chong}` - ]; - - return lines.join('\n'); + `🐔 **冲煞:** ${data.chong}` + ].join('\n'); } -// 命令行测试 +// 测试 if (require.main === module) { queryAlmanac('2026-02-24').then(result => { console.log(formatAlmanac(result));