From e192e51ef216d910d8e52a460b7e4f5b420a7c7a Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Fri, 23 Jun 2023 22:50:21 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=8A=A0=E4=B8=AA=E5=A4=A9=E6=B0=94?= =?UTF-8?q?=E5=B0=8F=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 4 ++- apps/entertainment.js | 39 ++++++++++++++--------------- guoba.support.js | 6 +++++ utils/config.js | 1 + utils/tools/JinyanTool.js | 2 +- utils/tools/WeatherTool.js | 32 ++++++++++++++++++++++++ utils/tools/WebsiteTool.js | 50 +++++++++++++++++++++++++++++++------- 7 files changed, 104 insertions(+), 30 deletions(-) create mode 100644 utils/tools/WeatherTool.js diff --git a/apps/chat.js b/apps/chat.js index 7abb07b..5417fad 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -55,6 +55,7 @@ import { SearchVideoTool } from '../utils/tools/SearchBilibiliTool.js' import { SearchMusicTool } from '../utils/tools/SearchMusicTool.js' import { QueryStarRailTool } from '../utils/tools/QueryStarRailTool.js' import { WebsiteTool } from '../utils/tools/WebsiteTool.js' +import {WeatherTool} from "../utils/tools/WeatherTool.js"; try { await import('emoji-strip') } catch (err) { @@ -1938,7 +1939,8 @@ export class chatgpt extends plugin { new QueryStarRailTool(), new WebsiteTool(), new JinyanTool(), - new KickOutTool() + new KickOutTool(), + new WeatherTool() ] // if (e.sender.role === 'admin' || e.sender.role === 'owner') { // tools.push(...[new JinyanTool(), new KickOutTool()]) diff --git a/apps/entertainment.js b/apps/entertainment.js index 3d767b0..bae4a62 100644 --- a/apps/entertainment.js +++ b/apps/entertainment.js @@ -203,7 +203,8 @@ ${translateLangLabels} await e.reply('请在群里发送此命令') } } - async wordcloud_latest(e) { + + async wordcloud_latest (e) { if (e.isGroup) { let groupId = e.group_id let lock = await redis.get(`CHATGPT:WORDCLOUD:${groupId}`) @@ -214,15 +215,15 @@ ${translateLangLabels} const regExp = /词云(\d{0,2})(|h)/ const match = e.msg.trim().match(regExp) - const duration = !match[1] ? 12 : parseInt(match[1]) // default 12h - - if(duration > 24) { + const duration = !match[1] ? 12 : parseInt(match[1]) // default 12h + + if (duration > 24) { await e.reply('最多只能统计24小时内的记录哦') return false } await e.reply('在统计啦,请稍等...') - - await redis.set(`CHATGPT:WORDCLOUD:${groupId}`, '1', {EX: 600}) + + await redis.set(`CHATGPT:WORDCLOUD:${groupId}`, '1', { EX: 600 }) try { await makeWordcloud(e, e.group_id, duration) } catch (err) { @@ -471,28 +472,28 @@ ${translateLangLabels} await this.reply(replyMsg) return false } - + async screenshotUrl (e) { let url = e.msg.replace(/^#url(:|:)/, '') if (url.length === 0) { return false } try { - if (!url.startsWith("http://") && !url.startsWith("https://")) { - url = "http://" + url + if (!url.startsWith('http://') && !url.startsWith('https://')) { + url = 'http://' + url } let urlLink = new URL(url) await e.reply( await renderUrl( - e, urlLink.href, - { - retType: 'base64', - Viewport: { - width: Config.chatViewWidth, - height: parseInt(Config.chatViewWidth * 0.56) - }, - deviceScaleFactor: Config.cloudDPR - } + e, urlLink.href, + { + retType: 'base64', + Viewport: { + width: Config.chatViewWidth, + height: parseInt(Config.chatViewWidth * 0.56) + }, + deviceScaleFactor: Config.cloudDPR + } ), - e.isGroup && Config.quoteReply) + e.isGroup && Config.quoteReply) } catch (err) { this.reply('无效url:' + url) } diff --git a/guoba.support.js b/guoba.support.js index 85e2fe1..68c2d20 100644 --- a/guoba.support.js +++ b/guoba.support.js @@ -788,6 +788,12 @@ export function supportGuoba () { label: 'Live2D模型', bottomHelpMessage: '选择Live2D使用的模型', component: 'Input' + }, + { + field: 'amapKey', + label: '高德APIKey', + bottomHelpMessage: '用于查询天气', + component: 'Input' } ], // 获取配置数据方法(用于前端填充显示数据) diff --git a/utils/config.js b/utils/config.js index 31a48e1..9f9b3bc 100644 --- a/utils/config.js +++ b/utils/config.js @@ -125,6 +125,7 @@ const defaultConfig = { enhanceAzureTTSEmotion: false, autoJapanese: false, enableGenerateContents: false, + amapKey: '', version: 'v2.6.2' } const _path = process.cwd() diff --git a/utils/tools/JinyanTool.js b/utils/tools/JinyanTool.js index 44ff35a..cf736b7 100644 --- a/utils/tools/JinyanTool.js +++ b/utils/tools/JinyanTool.js @@ -15,7 +15,7 @@ export class JinyanTool extends AbstractTool { }, time: { type: 'string', - description: '禁言时长,单位为秒' + description: '禁言时长,单位为秒,默认为600' }, isPunish: { type: 'string', diff --git a/utils/tools/WeatherTool.js b/utils/tools/WeatherTool.js new file mode 100644 index 0000000..c095137 --- /dev/null +++ b/utils/tools/WeatherTool.js @@ -0,0 +1,32 @@ +import { AbstractTool } from './AbstractTool.js' +import {Config} from "../config.js"; + +export class WeatherTool extends AbstractTool { + name = 'weather' + + parameters = { + properties: { + city: { + type: 'string', + description: '要查询的地点,细化到县/区级' + } + }, + required: ['city'] + } + + func = async function (opts) { + let { city } = opts + let key = Config.amapKey + + let adcodeRes = await fetch(`https://restapi.amap.com/v3/config/district?keywords=${city}&subdistrict=1&key=${key}`) + adcodeRes = await adcodeRes.json() + let adcode = adcodeRes.districts[0].adcode + let cityName = adcodeRes.districts[0].name + let res = await fetch(`https://restapi.amap.com/v3/weather/weatherInfo?city=${adcode}&key=${key}`) + res = await res.json() + let result = res.lives[0] + return `the weather information of area ${cityName} in json format is:\n${JSON.stringify(result)}` + } + + description = 'Useful when you want to query weather ' +} diff --git a/utils/tools/WebsiteTool.js b/utils/tools/WebsiteTool.js index 84b4bbc..67bd830 100644 --- a/utils/tools/WebsiteTool.js +++ b/utils/tools/WebsiteTool.js @@ -1,5 +1,9 @@ import { AbstractTool } from './AbstractTool.js' - +import { ChatGPTAPI } from '../openai/chatgpt-api.js' +import { Config } from '../config.js' +import fetch from 'node-fetch' +import proxy from 'https-proxy-agent' +import { getMaxModelTokens } from '../common.js' export class WebsiteTool extends AbstractTool { name = 'website' @@ -15,14 +19,42 @@ export class WebsiteTool extends AbstractTool { func = async function (opts) { let { url } = opts - let res = await fetch(url, { - headers: { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' - } - }) - let text = await res.text() - text = text.slice(0, Math.min(text.length, 4000)) - return `this is part of the content of website:\n ${text}` + try { + let res = await fetch(url, { + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' + } + }) + let text = await res.text() + let maxModelTokens = getMaxModelTokens(Config.model) + text = text.slice(0, Math.min(text.length, maxModelTokens - 1600)) + let api = new ChatGPTAPI({ + apiBaseUrl: Config.openAiBaseUrl, + apiKey: Config.apiKey, + debug: false, + completionParams: { + model: Config.model + }, + fetch: (url, options = {}) => { + const defaultOptions = Config.proxy + ? { + agent: proxy(Config.proxy) + } + : {} + const mergedOptions = { + ...defaultOptions, + ...options + } + return fetch(url, mergedOptions) + }, + maxModelTokens + }) + const htmlContentSummaryRes = await api.sendMessage(`这是一个网页html的内容,请你从中提取出其中的主体内容告诉我。${text}`) + let htmlContentSummary = htmlContentSummaryRes.text + return `this is the main content of website:\n ${htmlContentSummary}` + } catch (err) { + return `failed to visit the website, error: ${err.toString()}` + } } description = 'Useful when you want to browse a website by url'