Merge branch 'v2' of github.com:ikechan8370/chatgpt-plugin into v2

This commit is contained in:
ikechan8370 2023-07-09 21:58:55 +08:00
commit b35a2a9999
14 changed files with 77 additions and 61 deletions

View file

@ -39,7 +39,7 @@
* 2023-04-15 支持[Claude by Slack](https://www.anthropic.com/claude-in-slack )和PoeWIP。Claude配置参考[这里](https://ikechan8370.com/archives/chatgpt-plugin-for-yunzaipei-zhi-slack-claude)
* 2023-05-12 支持星火大模型
* 2023-05-29 支持gpt-4 API.必应无需cookie即可对话Sydney和自定义模式
* 2023-07 支持智能模式,机器人可以实现禁言、群名片/头衔(需给机器人管理员/群主、分享音乐视频、主动发音频、对接ap,sr和喵喵等插件、联网搜索等需api模式0613系列模型。
* 2023-07 支持智能模式,机器人可以实现禁言、群名片/头衔(需给机器人管理员/群主、分享音乐视频、主动发音频、对接ap,sr和喵喵等插件、联网搜索等需api模式0613系列模型。智能模式所需的额外api和搜索api分别可以参考[chatgpt-plugin-extras](https://github.com/ikechan8370/chatgpt-plugin-extras) 和 [search-api](https://github.com/ikechan8370/search-api) 自行搭建,其中后者提供了一个公益版本,前者可使用[huggingface](https://huggingface.co/spaces/ikechan8370/cp-extra)部署
### 如果觉得这个插件有趣或者对你有帮助请点一个star吧

View file

@ -2009,8 +2009,7 @@ export class chatgpt extends plugin {
} else {
tools.push(new SerpImageTool())
tools.push(...[new SearchVideoTool(),
new SendVideoTool(),
new EliMusicTool()])
new SendVideoTool()])
}
let funcMap = {}
let fullFuncMap = {}

View file

@ -30,7 +30,10 @@
"random": "^4.1.0",
"undici": "^5.21.0",
"uuid": "^9.0.0",
"ws": "^8.13.0"
"ws": "^8.13.0",
"js-tiktoken": "^1.0.5",
"quick-lru": "6.1.1"
},
"optionalDependencies": {
"@node-rs/jieba": "^1.6.2",

View file

@ -27,15 +27,14 @@ export class EliMovieTool extends AbstractTool {
let avocado
try {
// eslint-disable-next-line camelcase
let { AvocadoRuleALL } = await import('../../../avocado-plugin/apps/avocado.js')
avocado = new AvocadoRuleALL(e)
let { AvocadoMovie } = await import('../../../avocado-plugin/apps/avocadoMovie.js')
avocado = new AvocadoMovie(e)
} catch (err1) {
return 'the user didn\'t install avocado-plugin. suggest him to install'
}
try {
// eslint-disable-next-line new-cap
e.senderFromChatGpt = e.sender.user_id
await avocado.avocadoMovie(e)
await avocado.getHotMovies(e)
return 'notify the user that the movie has been sent to them and they can obtain more information by sending commands displayed in the picture. you dont need to search for additional information to reply! just simply inform them that you have completed your task!!!'
} catch (err) {
logger.warn(err)

View file

@ -5,75 +5,82 @@ export class EliMusicTool extends AbstractTool {
parameters = {
properties: {
keyword: {
keywordOrSongName: {
type: 'string',
description: 'Not necessarily a songName, it can be some descriptive words, but does not include the singer\'s name! can be left blank!'
description: 'Not necessarily a songName, it can be some descriptive words.'
},
singer: {
type: 'string',
description: 'Singer name, multiple singers are separated by \',\'! can be left blank!'
description: 'Singer name, multiple singers are separated by \',\'!'
},
isRandom: {
type: 'boolean',
description: 'Whether to randomly select songs, default is false'
},
isRandom2: {
type: 'boolean',
description: 'when isRandom is true and neither singer nor songName is specified!!!, this value is true; otherwise, it is false. The default value is false.'
description: 'true when randomly select songs'
},
isHot: {
type: 'boolean',
description: 'Whether it\'s related to \'hot\', consider filling in this item when there is no song name, can be left blank'
description: 'true when user\'s needs related to \'hot\''
},
singerRegion: {
singerTypeOrRegion: {
type: 'string',
description: 'Whether it\'s related to \'hot\', consider filling in this item when there is no song name, can be left blank'
description: 'Choose from [华语|中国|欧美|韩国|日本] when seeking the latest ranking of popular vocalists.'
},
isRelax: {
type: 'boolean',
description: 'Fill in when the user wants to sleep or rest, leave others blank when filling in this item, default is false'
description: 'Complete whenever you wish to discover the renowned vocalist in a particular locale.'
}
},
required: ['keyword', 'singer', 'isRandom', 'singerRegion, isRelax', 'isRandom2']
required: ['keywordOrSongName', 'singer', 'isRandom', 'singerTypeOrRegion, isRelax']
}
description = 'It is very useful when you want to meet the music needs or of users or when users want to sleep or unwind., so you should use this tool as much as possible, regardless of whether I asked you before!'
description = 'It is very useful when you want to meet the music needs of user or when user want to sleep or unwind(give him a relax music).'
func = async function (opts, e) {
let { keyword, singer, isRandom, isHot, singerRegion, isRelax, isRandom2 } = opts
let avocado
let { keywordOrSongName, singer, isRandom, isHot, singerTypeOrRegion, isRelax } = opts
let avocado, songDetail, musicUtils
try {
let { AvocadoMusic } = await import('../../../avocado-plugin/apps/avocadoMusic.js')
musicUtils = await import('../../../avocado-plugin/utils/music.js')
avocado = new AvocadoMusic(e)
} catch (err) {
return 'the user didn\'t install avocado-plugin. suggest him to install'
}
try {
// 不听话的gpt
isRandom2 = !keyword && isRandom && !isRandom2 && !singer
if (isRandom2) {
// 条件成立则随机播放最爱歌手的音乐
const orderFavSinger = !keywordOrSongName && isRandom && !singer
if (orderFavSinger) { // 随机播放最爱歌手的音乐, 需要通过指令设置
try {
singer = await redis.get(`AVOCADO:MUSIC_${e.sender.user_id}_FAVSINGER`)
if (!singer) throw new Error('no favorite singer')
singer = JSON.parse(singer).singer
logger.warn(singer)
singer = JSON.parse(singer).singerName
} catch (err) {
return 'the user didn\'t set a favorite singer. Suggest setting it through the command \'#设置歌手+歌手名称\'!'
}
e.msg = '#鳄梨酱#随机' + singer
} else if (isRelax) {
e.msg = '#鳄梨酱#随机放松'
} else if (singerRegion) {
e.msg = '#鳄梨酱#' + (isRandom ? '随机' : '') + (isHot ? '热门' : '') + singerRegion + '歌手'
} else {
e.msg = '#鳄梨酱#' + (isRandom ? '随机' : '') + (isHot ? '热门' : '') + (singer ? singer + (keyword ? ',' + keyword : '') : keyword)
e.msg = '#鳄梨酱音乐#随机' + singer
} else if (isRelax) { // 随机发送放松音乐
const arr = ['安静', '放松', '宁静', '白噪音']
e.msg = `#鳄梨酱音乐#随机${arr[Math.floor(Math.random() * arr.length)]}`
} else if (singerTypeOrRegion) { // 查看热门歌手榜单
if (['华语', '中国', '欧美', '韩国', '日本'].includes(singerTypeOrRegion)) {
e.msg = '#鳄梨酱音乐#' + (isRandom ? '随机' : '') + (!keywordOrSongName && isHot ? '热门' : '') + singerTypeOrRegion + '歌手'
}
} else { // 正常点歌
if (singer && keywordOrSongName) {
isRandom = false // 有时候ai会随意设置这个参数,降低权重
songDetail = await musicUtils.getOrderSongList(e.sender.user_id, singer + ',' + keywordOrSongName, 1)
}
e.msg = '#鳄梨酱音乐#' + (isRandom ? '随机' : '') + (!keywordOrSongName && isHot ? '热门' : '') + (singer ? singer + (keywordOrSongName ? ',' + keywordOrSongName : '') : keywordOrSongName)
}
e.senderFromChatGpt = e.sender.user_id
await avocado.pickMusic(e)
if (isRandom2) {
return 'tell the user that a random song by his favorite artist has been sent to him! you don\'t need to find other info!'
if (orderFavSinger) {
return 'tell the user that a random song by his favorite artist has been sent to him!'
} else {
return 'tell user that the response of his request has been sent to the user! you don\'t need to find other info!'
return 'tell user that the response of his request has been sent to the him!' +
(songDetail
? 'song detail is: ' + JSON.stringify(songDetail) + ' and send album picture to user'
: ''
)
}
} catch (e) {
return `music share failed: ${e}`

View file

@ -67,9 +67,10 @@ export class SendAudioMessageTool extends AbstractTool {
let { pendingText, ttsMode, vitsModeRole, azureModeRole, voxModeRole, speakingEmotion, speakingEmotionDegree, targetGroupIdOrQQNumber } = opts
let sendable
ttsMode = isNaN(ttsMode) || !ttsMode ? 1 : ttsMode
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? e.isGroup ? e.group_id : e.sender.user_id
: parseInt(targetGroupIdOrQQNumber.trim())
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
try {
switch (ttsMode) {
case 1:

View file

@ -23,9 +23,10 @@ export class SendAvatarTool extends AbstractTool {
if (!pictures.length) {
return 'there is no valid qq'
}
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? e.isGroup ? e.group_id : e.sender.user_id
: parseInt(targetGroupIdOrQQNumber.trim())
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
let groupList = await Bot.getGroupList()
console.log('sendAvatar', target, pictures)

View file

@ -23,9 +23,11 @@ export class SendVideoTool extends AbstractTool {
func = async function (opts, e) {
let { id, targetGroupIdOrQQNumber } = opts
// 非法值则发送到当前群聊或私聊
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? e.isGroup ? e.group_id : e.sender.user_id
: parseInt(targetGroupIdOrQQNumber.trim())
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
let msg = []
try {
let { arcurl, title, pic, description, videoUrl, headers, bvid, author, play, pubdate, like, honor } = await getBilibili(id)

View file

@ -20,9 +20,10 @@ export class SendDiceTool extends AbstractTool {
func = async function (opts, e) {
let { num, targetGroupIdOrQQNumber } = opts
// 非法值则发送到当前群聊或私聊
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? e.isGroup ? e.group_id : e.sender.user_id
: parseInt(targetGroupIdOrQQNumber.trim())
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
let groupList = await Bot.getGroupList()
num = isNaN(num) || !num ? 1 : num > 5 ? 5 : num
if (groupList.get(target)) {

View file

@ -10,7 +10,7 @@ export class SendMessageToSpecificGroupOrUserTool extends AbstractTool {
type: 'string',
description: 'text to be sent'
},
target: {
targetGroupIdOrQQNumber: {
type: 'string',
description: 'target qq or group number'
}
@ -19,10 +19,11 @@ export class SendMessageToSpecificGroupOrUserTool extends AbstractTool {
}
func = async function (opt, e) {
let { msg, target } = opt
target = isNaN(target) || !target
? e.isGroup ? e.group_id : e.sender.user_id
: parseInt(target.trim())
let { msg, targetGroupIdOrQQNumber } = opt
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
let groupList = await Bot.getGroupList()
try {

View file

@ -20,9 +20,10 @@ export class SendMusicTool extends AbstractTool {
func = async function (opts, e) {
let { id, targetGroupIdOrQQNumber } = opts
// 非法值则发送到当前群聊
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? e.group_id
: parseInt(targetGroupIdOrQQNumber.trim())
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
try {
let group = await Bot.pickGroup(target)

View file

@ -19,9 +19,10 @@ export class SendPictureTool extends AbstractTool {
func = async function (opt, e) {
let { urlOfPicture, targetGroupIdOrQQNumber } = opt
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? e.isGroup ? e.group_id : e.sender.user_id
: parseInt(targetGroupIdOrQQNumber.trim())
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
// 处理错误url和picture留空的情况
const urlRegex = /(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?@)?(?:((?:(?:[a-z0-9\u00a1-\u4dff\u9fd0-\uffff][a-z0-9\u00a1-\u4dff\u9fd0-\uffff_-]{0,62})?[a-z0-9\u00a1-\u4dff\u9fd0-\uffff]\.)+(?:[a-z\u00a1-\u4dff\u9fd0-\uffff]{2,}\.?))(?::\d{2,5})?)(?:\/[\w\u00a1-\u4dff\u9fd0-\uffff$-_.+!*'(),%]+)*(?:\?(?:[\w\u00a1-\u4dff\u9fd0-\uffff$-_.+!*(),%:@&=]|(?:[\[\]])|(?:[\u00a1-\u4dff\u9fd0-\uffff]))*)?(?:#(?:[\w\u00a1-\u4dff\u9fd0-\uffff$-_.+!*'(),;:@&=]|(?:[\[\]]))*)?\/?/i
if (/https:\/\/example.com/.test(urlOfPicture) || !urlOfPicture || !urlRegex.test(urlOfPicture)) urlOfPicture = ''

View file

@ -16,10 +16,10 @@ export class SendRPSTool extends AbstractTool {
}
func = async function (num, targetGroupIdOrQQNumber, e) {
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? e.isGroup ? e.group_id : e.sender.user_id
: parseInt(targetGroupIdOrQQNumber.trim())
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
let groupList = await Bot.getGroupList()
if (groupList.get(target)) {
let group = await Bot.pickGroup(target, true)

View file

@ -20,7 +20,7 @@ export class SerpIkechan8370Tool extends AbstractTool {
func = async function (opts) {
let { q, source } = opts
if (!source) {
source = 'google'
source = 'baidu'
}
let serpRes = await fetch(`https://serp.ikechan8370.com/${source}?q=${encodeURIComponent(q)}&lang=zh-CN&limit=10`, {
headers: {