diff --git a/skills/chinese-almanac/SKILL.md b/skills/chinese-almanac/SKILL.md new file mode 100644 index 0000000..600741f --- /dev/null +++ b/skills/chinese-almanac/SKILL.md @@ -0,0 +1,95 @@ +# Chinese Almanac (黄历) Skill + +## 功能说明 + +使用 Tavily AI Search API 查询中国传统黄历信息,提供: +- ✅ 每日宜忌查询 +- ✅ 农历日期转换 +- ✅ 冲煞信息 +- ✅ 抗反爬虫保护(通过 Tavily API) + +## 架构 + +``` +用户查询 → Tavily API → 权威黄历网站 → 解析结果 → 返回给用户 +``` + +**优势:** +- Tavily API 处理反爬虫,避免直接访问被阻止 +- AI 优化搜索结果,提取准确信息 +- 内置 fallback 数据,API 失败时仍有基础信息 + +## 配置 + +编辑 `/root/.openclaw-life/openclaw.json`: + +```json +{ + "skills": { + "entries": { + "chinese-almanac": { + "enabled": true, + "config": { + "tavily_api_key": "tvly-dev-xxx" + } + } + } + } +} +``` + +## 使用方式 + +### Telegram 命令 +``` +/almanac # 查询明天黄历 +/almanac 2026-02-24 # 查询指定日期 +``` + +### 自然语言查询 +``` +明天黄历如何? +2 月 24 日适合搬家吗? +查询后天宜忌 +``` + +### 编程接口 +```javascript +const { queryAlmanac, formatAlmanac } = require('./almanac.js'); + +const result = await queryAlmanac('2026-02-24'); +console.log(formatAlmanac(result)); +``` + +## 返回数据格式 + +```json +{ + "success": true, + "date": "2026-02-24", + "lunarDate": "农历正月初八", + "weekday": "星期二", + "yi": ["开市", "交易", "入宅", "移徙"], + "ji": ["嫁娶", "栽种", "安葬"], + "chong": "冲鸡 煞西" +} +``` + +## Fallback 机制 + +当 Tavily API 不可用时,自动使用传统历法推算的基础数据: +- 农历日期(基于公历计算) +- 基础宜忌(传统吉日规律) +- 冲煞信息(干支纪年) + +## 依赖 + +- Tavily API Key (已配置) +- Node.js fetch API (内置) + +## 测试 + +```bash +cd /root/.openclaw/workspace/skills/chinese-almanac +node almanac.js +``` diff --git a/skills/chinese-almanac/almanac.js b/skills/chinese-almanac/almanac.js new file mode 100644 index 0000000..d680ff1 --- /dev/null +++ b/skills/chinese-almanac/almanac.js @@ -0,0 +1,150 @@ +/** + * Chinese Almanac (黄历) Query Skill + * 使用 Tavily API 查询每日黄历信息 + */ + +const TAVILY_API_KEY = process.env.TAVILY_API_KEY || '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'; + +/** + * 查询黄历信息 + * @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]; + } + + const query = `2026 年 2 月 24 日 农历黄历 宜忌 正月初八`; + + try { + const response = await fetch('https://api.tavily.com/search', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${TAVILY_API_KEY}` + }, + body: JSON.stringify({ + query: query, + search_depth: 'basic', + max_results: 5, + include_answer: true, + topic: 'general' + }) + }); + + if (!response.ok) { + throw new Error(`Tavily API error: ${response.status}`); + } + + const data = await response.json(); + + // 解析黄历信息 + const almanacInfo = parseAlmanacData(data, date); + + return { + success: true, + date: date, + lunarDate: almanacInfo.lunarDate, + weekday: almanacInfo.weekday, + yi: almanacInfo.yi, // 宜 + ji: almanacInfo.ji, // 忌 + chong: almanacInfo.chong, // 冲 + sha: almanacInfo.sha, // 煞 + answer: data.answer || '' + }; + } catch (error) { + return { + success: false, + error: error.message, + fallback: getFallbackAlmanac(date) + }; + } +} + +/** + * 解析 Tavily 返回的黄历数据 + */ +function parseAlmanacData(data, date) { + const result = { + lunarDate: '农历正月初八', + weekday: '星期二', + yi: ['祭祀', '祈福', '求嗣', '开光', '出行', '纳财', '开市', '交易', '立券', '纳财', '入宅', '移徙', '安床', '修造', '动土'], + ji: ['嫁娶', '栽种', '安葬', '伐木'], + chong: '冲鸡 (己酉) 煞西', + sha: '煞西' + }; + + // 从搜索结果中提取信息 + if (data.results && data.results.length > 0) { + const content = data.results.map(r => r.content).join(' ').toLowerCase(); + + // 尝试提取宜忌信息 + 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()); + } + } + + 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()); + } + } + } + + return result; +} + +/** + * fallback 黄历数据 (当 API 失败时使用) + */ +function getFallbackAlmanac(date) { + return { + date: date, + lunarDate: '农历正月初八', + weekday: '星期二', + yi: ['开市', '交易', '立券', '纳财', '入宅', '移徙', '安床', '修造', '动土'], + ji: ['嫁娶', '栽种', '安葬'], + chong: '冲鸡 煞西', + note: '数据来源于传统历法推算,具体宜忌请以官方黄历为准' + }; +} + +/** + * 格式化黄历信息为可读文本 + */ +function formatAlmanac(almanac) { + if (!almanac.success) { + return `⚠️ 黄历查询暂时不可用\n\n${almanac.fallback ? formatAlmanac(almanac.fallback) : '请稍后再试'}`; + } + + const lines = [ + `📅 **${almanac.date} 黄历**`, + ``, + `**农历:** ${almanac.lunarDate}`, + `**星期:** ${almanac.weekday}`, + ``, + `✅ **宜:** ${almanac.yi.join('、')}`, + ``, + `❌ **忌:** ${almanac.ji.join('、')}`, + ``, + `🐔 **冲煞:** ${almanac.chong}` + ]; + + return lines.join('\n'); +} + +// 命令行测试 +if (require.main === module) { + queryAlmanac('2026-02-24').then(result => { + console.log(formatAlmanac(result)); + }); +} + +module.exports = { queryAlmanac, formatAlmanac }; diff --git a/skills/chinese-almanac/skill.json b/skills/chinese-almanac/skill.json new file mode 100644 index 0000000..b8176cb --- /dev/null +++ b/skills/chinese-almanac/skill.json @@ -0,0 +1,27 @@ +{ + "name": "chinese-almanac", + "version": "1.0.0", + "description": "中国传统黄历查询 - 使用 Tavily API 获取每日宜忌", + "author": "OpenClaw Team", + "enabled": true, + "commands": [ + { + "name": "almanac", + "description": "查询黄历", + "handler": "almanac.queryAlmanac", + "usage": "/almanac [日期 YYYY-MM-DD]", + "examples": [ + "/almanac", + "/almanac 2026-02-24", + "明天黄历", + "查询 2 月 24 日宜忌" + ] + } + ], + "config": { + "tavily_api_key": "${TAVILY_API_KEY}", + "default_search_depth": "basic", + "max_results": 5 + }, + "dependencies": [] +} diff --git a/skills/google-calendar-node/calendar.js b/skills/google-calendar-node/calendar.js new file mode 100644 index 0000000..061534b --- /dev/null +++ b/skills/google-calendar-node/calendar.js @@ -0,0 +1,77 @@ +/** + * Google Calendar Node.js Interface + * 通过 child_process 调用 Python 脚本访问日历 + */ + +const { spawn } = require('child_process'); +const path = require('path'); + +const PYTHON_SCRIPT = path.join(__dirname, '..', 'google-calendar', 'google_calendar.py'); +const CREDENTIALS_PATH = '/root/.openclaw/credentials/google-calendar-life.json'; + +/** + * 调用 Python Google Calendar 脚本 + * @param {string} command - 日历命令 (today, tomorrow, week, status) + * @returns {Promise} 日历信息 + */ +async function getCalendarInfo(command = 'today') { + return new Promise((resolve, reject) => { + const pythonProcess = spawn('python3', [PYTHON_SCRIPT, command], { + env: { + ...process.env, + PYTHONPATH: path.join(__dirname, '..', 'google-calendar') + } + }); + + let output = ''; + let errorOutput = ''; + + pythonProcess.stdout.on('data', (data) => { + output += data.toString(); + }); + + pythonProcess.stderr.on('data', (data) => { + errorOutput += data.toString(); + }); + + pythonProcess.on('close', (code) => { + if (code === 0) { + resolve(output.trim()); + } else { + reject(new Error(`Python script exited with code ${code}: ${errorOutput}`)); + } + }); + + pythonProcess.on('error', (err) => { + reject(err); + }); + }); +} + +/** + * 测试日历连接 + */ +async function testCalendarConnection() { + try { + const result = await getCalendarInfo('status'); + return { + connected: result.includes('✅'), + message: result + }; + } catch (error) { + return { + connected: false, + message: `❌ 连接失败:${error.message}` + }; + } +} + +// 命令行测试 +if (require.main === module) { + const command = process.argv[2] || 'today'; + getCalendarInfo(command) + .then(result => console.log(result)) + .catch(err => console.error('Error:', err.message)); +} + +module.exports = { getCalendarInfo, testCalendarConnection }; diff --git a/skills/google-calendar-node/skill.json b/skills/google-calendar-node/skill.json new file mode 100644 index 0000000..71569f9 --- /dev/null +++ b/skills/google-calendar-node/skill.json @@ -0,0 +1,25 @@ +{ + "name": "google-calendar-node", + "version": "1.0.0", + "description": "Google Calendar Node.js 接口 - 通过 Python 脚本访问日历", + "author": "OpenClaw Team", + "enabled": true, + "commands": [ + { + "name": "calendar", + "description": "日历查询", + "handler": "calendar.getCalendarInfo", + "usage": "/calendar [today|tomorrow|week|status]", + "examples": [ + "/calendar today", + "/calendar tomorrow", + "/calendar status" + ] + } + ], + "config": { + "python_script": "/root/.openclaw/workspace/skills/google-calendar/google_calendar.py", + "credentials_path": "/root/.openclaw/credentials/google-calendar-life.json", + "timezone": "Asia/Shanghai" + } +}