mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-17 13:57:10 +00:00
fix: 修复一些功能易用性
This commit is contained in:
parent
be7ceafb4b
commit
599f37e627
8 changed files with 249 additions and 61 deletions
17
apps/chat.js
17
apps/chat.js
|
|
@ -51,6 +51,9 @@ import { KickOutTool } from '../utils/tools/KickOutTool.js'
|
|||
import { SendAvatarTool } from '../utils/tools/SendAvatarTool.js'
|
||||
import { SendDiceTool } from '../utils/tools/SendDiceTool.js'
|
||||
import { EditCardTool } from '../utils/tools/EditCardTool.js'
|
||||
import {SearchVideoTool} from "../utils/tools/SearchBilibiliTool.js";
|
||||
import {SearchMusicTool} from "../utils/tools/SearchMusicTool.js";
|
||||
import {QueryStarRailTool} from "../utils/tools/QueryStarRailTool.js";
|
||||
try {
|
||||
await import('emoji-strip')
|
||||
} catch (err) {
|
||||
|
|
@ -1809,7 +1812,7 @@ export class chatgpt extends plugin {
|
|||
let promptPrefix = `You are ${Config.assistantLabel} ${useCast?.api || Config.promptPrefixOverride || defaultPropmtPrefix}
|
||||
Knowledge cutoff: 2021-09. Current date: ${currentDate}`
|
||||
let maxModelTokens = getMaxModelTokens(completionParams.model)
|
||||
let system = Config.promptPrefixOverride
|
||||
let system = promptPrefix
|
||||
if (maxModelTokens >= 16000 && Config.enableGroupContext) {
|
||||
try {
|
||||
let opt = {}
|
||||
|
|
@ -1917,22 +1920,22 @@ export class chatgpt extends plugin {
|
|||
timeoutMs: 120000
|
||||
// systemMessage: promptPrefix
|
||||
}
|
||||
if (Math.floor(Math.random() * 100) < 5) {
|
||||
// 小概率再次发送系统消息
|
||||
option.systemMessage = promptPrefix
|
||||
}
|
||||
option.systemMessage = system
|
||||
if (conversation) {
|
||||
option = Object.assign(option, conversation)
|
||||
}
|
||||
let tools = [
|
||||
new JinyanTool(),
|
||||
new SearchVideoTool(),
|
||||
new SendVideoTool(),
|
||||
new SearchMusicTool(),
|
||||
new SendMusicTool(),
|
||||
new KickOutTool(),
|
||||
new SendAvatarTool(),
|
||||
new SendDiceTool(),
|
||||
// new SendDiceTool(),
|
||||
new KickOutTool(),
|
||||
new EditCardTool()
|
||||
new EditCardTool(),
|
||||
new QueryStarRailTool()
|
||||
]
|
||||
let funcMap = {}
|
||||
tools.forEach(tool => {
|
||||
|
|
|
|||
|
|
@ -23,17 +23,22 @@ export class JinyanTool extends AbstractTool {
|
|||
|
||||
func = async function (opts) {
|
||||
let { qq, groupId, time = '600' } = opts
|
||||
let group = await Bot.pickGroup(groupId)
|
||||
time = parseInt(time.trim())
|
||||
if (time < 60) {
|
||||
time = 60
|
||||
}
|
||||
if (time > 86400 * 30) {
|
||||
time = 86400 * 30
|
||||
}
|
||||
let group = await Bot.pickGroup(groupId)
|
||||
time = parseInt(time.trim())
|
||||
if (qq.trim() === 'all') {
|
||||
await group.sendMsg('[日志]试图开启全员禁言')
|
||||
// await group.muteAll(time > 0)
|
||||
if (time > 0) {
|
||||
await group.sendMsg('[日志]试图开启全员禁言,但被系统阻止了')
|
||||
return 'error: you are not allowed to mute all in this group'
|
||||
} else {
|
||||
await group.muteAll(false)
|
||||
return '该群的全体禁言已经被解除'
|
||||
}
|
||||
} else {
|
||||
qq = parseInt(qq.trim())
|
||||
await group.muteMember(qq, time)
|
||||
|
|
@ -41,5 +46,5 @@ export class JinyanTool extends AbstractTool {
|
|||
return `the user ${qq} has been muted for ${time} seconds`
|
||||
}
|
||||
|
||||
description = 'Useful when you want to ban someone. The input to this tool should be the group number, the qq number of the one who should be banned and the mute duration in seconds(at least 60, at most 180, the number should be an integer multiple of 60), these three number should be concated with a space. If you want to mute all, just replace the qq number with \'all\''
|
||||
description = 'Useful when you want to ban someone. If you want to mute all, just replace the qq number with \'all\''
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {AbstractTool} from "./AbstractTool.js";
|
||||
import { AbstractTool } from './AbstractTool.js'
|
||||
|
||||
export class KickOutTool extends AbstractTool {
|
||||
name = 'kickOut'
|
||||
|
|
|
|||
76
utils/tools/QueryStarRailTool.js
Normal file
76
utils/tools/QueryStarRailTool.js
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import { AbstractTool } from './AbstractTool.js'
|
||||
|
||||
export class QueryStarRailTool extends AbstractTool {
|
||||
name = 'queryStarRail'
|
||||
|
||||
parameters = {
|
||||
properties: {
|
||||
qq: {
|
||||
type: 'string',
|
||||
description: '要查询的用户的qq号,将使用该qq号绑定的uid进行查询'
|
||||
},
|
||||
groupId: {
|
||||
type: 'string',
|
||||
description: '群号'
|
||||
},
|
||||
uid: {
|
||||
type: 'string',
|
||||
description: '游戏的uid,如果用户提供了则传入并优先使用'
|
||||
}
|
||||
},
|
||||
required: ['qq', 'groupId']
|
||||
}
|
||||
|
||||
func = async function (opts) {
|
||||
let { qq, groupId, uid } = opts
|
||||
if (!uid) {
|
||||
try {
|
||||
let { Panel } = await import('../../../StarRail-plugin/apps/panel.js')
|
||||
uid = await redis.get(`STAR_RAILWAY:UID:${qq}`)
|
||||
if (!uid) {
|
||||
return '用户没有绑定uid,无法查询。可以让用户主动提供uid进行查询'
|
||||
}
|
||||
} catch (e) {
|
||||
return '未安装StarRail-Plugin,无法查询'
|
||||
}
|
||||
}
|
||||
try {
|
||||
let uidRes = await fetch('https://avocado.wiki/v1/info/' + uid)
|
||||
uidRes = await uidRes.json()
|
||||
let { assistAvatar, displayAvatars } = uidRes.playerDetailInfo
|
||||
function dealAvatar (avatar) {
|
||||
delete avatar.position
|
||||
delete avatar.vo_tag
|
||||
delete avatar.desc
|
||||
delete avatar.promption
|
||||
delete avatar.relics
|
||||
delete avatar.behaviorList
|
||||
delete avatar.images
|
||||
delete avatar.ranks
|
||||
if (avatar.equipment) {
|
||||
avatar.equipment = {
|
||||
level: avatar.equipment.level,
|
||||
rank: avatar.equipment.rank,
|
||||
name: avatar.equipment.name,
|
||||
skill_desc: avatar.equipment.skill_desc
|
||||
}
|
||||
}
|
||||
}
|
||||
dealAvatar(assistAvatar)
|
||||
if (displayAvatars) {
|
||||
displayAvatars.forEach(avatar => {
|
||||
dealAvatar(avatar)
|
||||
})
|
||||
}
|
||||
uidRes.playerDetailInfo.assistAvatar = assistAvatar
|
||||
uidRes.playerDetailInfo.displayAvatars = displayAvatars
|
||||
delete uidRes.repository
|
||||
delete uidRes.version
|
||||
return `the player info in json format is: \n${JSON.stringify(uidRes)}`
|
||||
} catch (err) {
|
||||
return `failed to query, error: ${err.toString()}`
|
||||
}
|
||||
}
|
||||
|
||||
description = 'Useful when you want to query player information of Honkai Star Rail(崩坏:星穹铁道). '
|
||||
}
|
||||
76
utils/tools/SearchBilibiliTool.js
Normal file
76
utils/tools/SearchBilibiliTool.js
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import fetch from 'node-fetch'
|
||||
|
||||
import { formatDate, mkdirs } from '../common.js'
|
||||
import fs from 'fs'
|
||||
import { AbstractTool } from './AbstractTool.js'
|
||||
export class SearchVideoTool extends AbstractTool {
|
||||
name = 'searchVideo'
|
||||
|
||||
parameters = {
|
||||
properties: {
|
||||
keyword: {
|
||||
type: 'string',
|
||||
description: '要搜索的视频的标题或关键词'
|
||||
}
|
||||
},
|
||||
required: ['keyword']
|
||||
}
|
||||
|
||||
func = async function (opts) {
|
||||
let { keyword } = opts
|
||||
try {
|
||||
return await searchBilibili(keyword)
|
||||
} catch (err) {
|
||||
logger.error(err)
|
||||
return `fail to search video, error: ${err.toString()}`
|
||||
}
|
||||
}
|
||||
|
||||
description = 'Useful when you want to search a video by keywords. you should remember the id of the video if you want to share it'
|
||||
}
|
||||
|
||||
export async function searchBilibili (name) {
|
||||
let biliRes = await fetch('https://www.bilibili.com',
|
||||
{
|
||||
// headers: {
|
||||
// accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
||||
// Accept: '*/*',
|
||||
// 'Accept-Encoding': 'gzip, deflate, br',
|
||||
// 'accept-language': 'en-US,en;q=0.9',
|
||||
// Connection: 'keep-alive',
|
||||
// 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
|
||||
// }
|
||||
})
|
||||
const headers = biliRes.headers.raw()
|
||||
const setCookieHeaders = headers['set-cookie']
|
||||
if (setCookieHeaders) {
|
||||
const cookies = []
|
||||
setCookieHeaders.forEach(header => {
|
||||
const cookie = header.split(';')[0]
|
||||
cookies.push(cookie)
|
||||
})
|
||||
const cookieHeader = cookies.join('; ')
|
||||
let headers = {
|
||||
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
||||
'accept-language': 'en-US,en;q=0.9',
|
||||
Referer: 'https://www.bilibili.com',
|
||||
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36',
|
||||
cookie: cookieHeader
|
||||
}
|
||||
let response = await fetch(`https://api.bilibili.com/x/web-interface/search/type?keyword=${name}&search_type=video`,
|
||||
{
|
||||
headers
|
||||
})
|
||||
let json = await response.json()
|
||||
if (json.data?.numResults > 0) {
|
||||
let result = json.data.result.map(r => {
|
||||
return `id: ${r.bvid},标题:${r.title},作者:${r.author},播放量:${r.play},发布日期:${formatDate(new Date(r.pubdate * 1000))}`
|
||||
}).slice(0, Math.min(json.data?.numResults, 5)).join('\n')
|
||||
return `这些是关键词“${name}”的搜索结果:\n${result}`
|
||||
} else {
|
||||
return `没有找到关键词“${name}”的搜索结果`
|
||||
}
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
39
utils/tools/SearchMusicTool.js
Normal file
39
utils/tools/SearchMusicTool.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import fetch from 'node-fetch'
|
||||
import { AbstractTool } from './AbstractTool.js'
|
||||
|
||||
export class SearchMusicTool extends AbstractTool {
|
||||
name = 'searchMusic'
|
||||
|
||||
parameters = {
|
||||
properties: {
|
||||
keyword: {
|
||||
type: 'string',
|
||||
description: '音乐的标题或关键词'
|
||||
}
|
||||
},
|
||||
required: ['keyword']
|
||||
}
|
||||
|
||||
func = async function (opts) {
|
||||
let { keyword } = opts
|
||||
try {
|
||||
let result = await searchMusic163(keyword)
|
||||
return `search result: ${result}`
|
||||
} catch (e) {
|
||||
return `music search failed: ${e}`
|
||||
}
|
||||
}
|
||||
|
||||
description = 'Useful when you want to search music by keyword.'
|
||||
}
|
||||
|
||||
export async function searchMusic163 (name) {
|
||||
let response = await fetch(`http://music.163.com/api/search/get/web?s=${name}&type=1&offset=0&total=true&limit=6`)
|
||||
let json = await response.json()
|
||||
if (json.result?.songCount > 0) {
|
||||
return json.result.songs.map(song => {
|
||||
return `id: ${song.id}, name: ${song.name}, artists: ${song.artists.map(a => a.name).join('&')}, alias: ${song.alias || 'none'}`
|
||||
}).join('\n')
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
|
@ -8,31 +8,33 @@ export class SendVideoTool extends AbstractTool {
|
|||
|
||||
parameters = {
|
||||
properties: {
|
||||
keyword: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: '要发的视频的标题或关键词,用于搜索'
|
||||
description: '要发的视频的id'
|
||||
},
|
||||
groupId: {
|
||||
type: 'string',
|
||||
description: '群号或qq号,发送目标'
|
||||
}
|
||||
},
|
||||
required: ['keyword', 'groupId']
|
||||
required: ['id', 'groupId']
|
||||
}
|
||||
|
||||
func = async function (opts) {
|
||||
let { keyword, groupId } = opts
|
||||
let { id, groupId } = opts
|
||||
groupId = parseInt(groupId.trim())
|
||||
let msg = []
|
||||
try {
|
||||
let { arcurl, title, pic, description, videoUrl, headers, bvid, author, play, pubdate, like } = await searchBilibili(keyword)
|
||||
let { arcurl, title, pic, description, videoUrl, headers, bvid, author, play, pubdate, like, honor } = await getBilibili(id)
|
||||
let group = await Bot.pickGroup(groupId)
|
||||
console.log({ arcurl, title, pic, description, videoUrl })
|
||||
msg.push(title.replace(/(<([^>]+)>)/ig, '') + '\n')
|
||||
msg.push(`UP主:${author} 发布日期:${formatDate(new Date(pubdate * 1000))} 播放量:${play} 点赞:${like}\n`)
|
||||
msg.push(arcurl + '\n')
|
||||
msg.push(segment.image('https:' + pic))
|
||||
msg.push('\n' + description)
|
||||
if (honor) {
|
||||
msg.push(`本视频曾获得过${honor}称号`)
|
||||
}
|
||||
msg.push('\n视频在路上啦!')
|
||||
await group.sendMsg(msg)
|
||||
const videoResponse = await fetch(videoUrl, { headers })
|
||||
|
|
@ -45,7 +47,7 @@ export class SendVideoTool extends AbstractTool {
|
|||
await fs.writeFileSync(fileLoc, buffer)
|
||||
await group.sendMsg(segment.video(fileLoc))
|
||||
})
|
||||
return `the video ${title.replace(/(<([^>]+)>)/ig, '')} will be shared to ${groupId} after a while, please wait`
|
||||
return `the video ${title.replace(/(<([^>]+)>)/ig, '')} was shared to ${groupId}. the video information: ${msg}`
|
||||
} catch (err) {
|
||||
logger.error(err)
|
||||
if (msg.length > 0) {
|
||||
|
|
@ -56,10 +58,10 @@ export class SendVideoTool extends AbstractTool {
|
|||
}
|
||||
}
|
||||
|
||||
description = 'Useful when you want to share a video. The input should be the group number and the keywords that can find the video, connected with a space. If you want to send a specific video, you can give more detailed keywords'
|
||||
description = 'Useful when you want to share a video. You must use searchVideo to get search result and choose one video and get its id'
|
||||
}
|
||||
|
||||
export async function searchBilibili (name) {
|
||||
export async function getBilibili (bvid) {
|
||||
let biliRes = await fetch('https://www.bilibili.com',
|
||||
{
|
||||
// headers: {
|
||||
|
|
@ -87,28 +89,28 @@ export async function searchBilibili (name) {
|
|||
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36',
|
||||
cookie: cookieHeader
|
||||
}
|
||||
let response = await fetch(`https://api.bilibili.com/x/web-interface/search/type?keyword=${name}&search_type=video`,
|
||||
{
|
||||
headers
|
||||
})
|
||||
let json = await response.json()
|
||||
if (json.data?.numResults > 0) {
|
||||
let index = randomIndex()
|
||||
let { arcurl, title, pic, description, bvid, author, play, pubdate, like } = json.data.result[Math.min(index, json.data.numResults)]
|
||||
let videoInfo = await fetch(`https://api.bilibili.com/x/web-interface/view?bvid=${bvid}`, {
|
||||
headers
|
||||
})
|
||||
videoInfo = await videoInfo.json()
|
||||
let cid = videoInfo.data.cid
|
||||
let downloadInfo = await fetch(`https://api.bilibili.com/x/player/playurl?bvid=${bvid}&cid=${cid}`, { headers })
|
||||
let videoUrl = (await downloadInfo.json()).data.durl[0].url
|
||||
return {
|
||||
arcurl, title, pic, description, videoUrl, headers, bvid, author, play, pubdate, like
|
||||
}
|
||||
let videoInfo = await fetch(`https://api.bilibili.com/x/web-interface/view?bvid=${bvid}`, {
|
||||
headers
|
||||
})
|
||||
videoInfo = await videoInfo.json()
|
||||
let cid = videoInfo.data.cid
|
||||
let arcurl = `http://www.bilibili.com/video/av${videoInfo.data.aid}`
|
||||
let title = videoInfo.data.title
|
||||
let pic = videoInfo.data.pic
|
||||
let description = videoInfo.data.desc
|
||||
let author = videoInfo.data.owner.name
|
||||
let play = videoInfo.data.stat.view
|
||||
let pubdate = videoInfo.data.pubdate
|
||||
let like = videoInfo.data.stat.like
|
||||
let honor = videoInfo.data.honor_reply?.honor?.map(h => h.desc)?.join('、')
|
||||
let downloadInfo = await fetch(`https://api.bilibili.com/x/player/playurl?bvid=${bvid}&cid=${cid}`, {headers})
|
||||
let videoUrl = (await downloadInfo.json()).data.durl[0].url
|
||||
return {
|
||||
arcurl, title, pic, description, videoUrl, headers, bvid, author, play, pubdate, like, honor
|
||||
}
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
function randomIndex () {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
import fetch from 'node-fetch'
|
||||
import {AbstractTool} from "./AbstractTool.js";
|
||||
import { AbstractTool } from './AbstractTool.js'
|
||||
|
||||
export class SendMusicTool extends AbstractTool {
|
||||
name = 'sendMusic'
|
||||
|
||||
parameters = {
|
||||
properties: {
|
||||
keyword: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: '音乐的标题或关键词'
|
||||
description: '音乐的id'
|
||||
},
|
||||
groupId: {
|
||||
type: 'string',
|
||||
|
|
@ -19,28 +18,16 @@ export class SendMusicTool extends AbstractTool {
|
|||
}
|
||||
|
||||
func = async function (opts) {
|
||||
let { keyword, groupId } = opts
|
||||
let { id, groupId } = opts
|
||||
groupId = parseInt(groupId.trim())
|
||||
try {
|
||||
let { id, name } = await searchMusic163(keyword)
|
||||
let group = await Bot.pickGroup(groupId)
|
||||
await group.shareMusic('163', id)
|
||||
return `the music ${name} has been shared to ${groupId}`
|
||||
return `the music has been shared to ${groupId}`
|
||||
} catch (e) {
|
||||
return `music share failed: ${e}`
|
||||
}
|
||||
}
|
||||
|
||||
description = 'Useful when you want to share music. The input should be the group number and the name of the music to be sent or the keywords that can find the music, connected with a space'
|
||||
}
|
||||
|
||||
export async function searchMusic163 (name) {
|
||||
let response = await fetch(`http://music.163.com/api/search/get/web?s=${name}&type=1&offset=0&total=true&limit=20`)
|
||||
let json = await response.json()
|
||||
if (json.result?.songCount > 0) {
|
||||
let id = json.result.songs[0].id
|
||||
let name = json.result.songs[0].name
|
||||
return { id, name }
|
||||
}
|
||||
return null
|
||||
description = 'Useful when you want to share music. You must use searchMusic first to get the music id'
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue