diff --git a/apps/bym.js b/apps/bym.js index 92ec1eb..a52a549 100644 --- a/apps/bym.js +++ b/apps/bym.js @@ -18,6 +18,7 @@ import { KickOutTool } from '../utils/tools/KickOutTool.js' import { SetTitleTool } from '../utils/tools/SetTitleTool.js' import { SerpTool } from '../utils/tools/SerpTool.js' import { initializeImageTool } from '../utils/tools/ImageTool.js' +import { DailyNewsTool } from '../utils/tools/DailyNewsTool.js' const DefaultConfig = { returnQQ: [], @@ -303,7 +304,8 @@ export class bym extends plugin { new SendMusicTool(), new SendPictureTool(), new WebsiteTool(), - new WeatherTool() + new WeatherTool(), + new DailyNewsTool() ] if (Config.azSerpKey) { tools.push(new SerpTool()) diff --git a/guoba.support.js b/guoba.support.js index 5674d65..58df3be 100644 --- a/guoba.support.js +++ b/guoba.support.js @@ -1078,6 +1078,7 @@ export function supportGuoba () { required: true, } ], + }, field: 'bymFuckList', label: '伪人模式反击的触发词', bottomHelpMessage: '请输入用于伪人模式下骂人反击的触发词,每个词组将被单独处理', diff --git a/utils/tools/DailyNewsTool.js b/utils/tools/DailyNewsTool.js new file mode 100644 index 0000000..b280c71 --- /dev/null +++ b/utils/tools/DailyNewsTool.js @@ -0,0 +1,94 @@ +import { AbstractTool } from './AbstractTool.js' +import fetch from 'node-fetch' + +export class DailyNewsTool extends AbstractTool { + name = 'dailyNews' + parameters = { + properties: { + action: { + type: 'string', + enum: ['getNews'], + description: 'Get daily news summary' + } + }, + required: ['action'] + } + + description = 'Useful when you want to know today\'s news headlines and hot topics. Use keywords like "今日新闻", "每日新闻", "60秒新闻" to get news.' + + func = async function(opts) { + try { + // 添加请求头和超时设置 + const controller = new AbortController() + const timeout = setTimeout(() => controller.abort(), 10000) // 10秒超时 + + const response = await fetch('https://60s.viki.moe/?v2=1', { + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + 'Accept': 'application/json' + }, + signal: controller.signal + }) + + clearTimeout(timeout) + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + + const jsonData = await response.json() + + // 检查数据格式 + if (!jsonData?.data?.news || !Array.isArray(jsonData.data.news)) { + throw new Error('新闻数据格式无效') + } + + const { news, tip, updated } = jsonData.data + + // 格式化时间 + const updateTime = new Date(updated).toLocaleString('zh-CN', { + hour12: false, + timeZone: 'Asia/Shanghai' + }) + + // 构建返回消息 + let message = `今日要闻 (更新时间: ${updateTime}):\n\n` + message += news.map((item, index) => `${index + 1}. ${item}`).join('\n') + message += `\n\n${tip}` // 添加每日寄语 + + return message + } catch (error) { + logger.error(`[DailyNewsTool] 获取新闻失败: ${error.message}`, error) + + // 更友好的错误提示 + if (error.name === 'AbortError') { + return '获取新闻超时,请稍后再试' + } + if (error.name === 'FetchError') { + return '网络请求失败,请检查网络连接' + } + return '获取新闻失败,请稍后重试' + } + } + + // 添加缓存机制 + #cache = { + data: null, + timestamp: 0, + TTL: 5 * 60 * 1000 // 5分钟缓存 + } + + async getNewsWithCache() { + const now = Date.now() + if (this.#cache.data && (now - this.#cache.timestamp) < this.#cache.TTL) { + return this.#cache.data + } + + const result = await this.func({ action: 'getNews' }) + this.#cache = { + data: result, + timestamp: now + } + return result + } +} \ No newline at end of file