fix: 黄历查询格式化优化 - 农历日期动态计算,宜忌数据清理

master
Eason (陈医生) 1 month ago
parent 9307770d6a
commit 51bc1a141e
  1. 132
      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<Object>} 黄历信息
*/
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));

Loading…
Cancel
Save