mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-16 05:17:10 +00:00
feat: bym
This commit is contained in:
parent
6997d1e024
commit
9fcc25a726
5 changed files with 219 additions and 46 deletions
93
apps/bym.js
Normal file
93
apps/bym.js
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import ChatGPTConfig from '../config/config.js'
|
||||
import { Chaite } from 'chaite'
|
||||
import { intoUserMessage, toYunzai } from '../utils/message.js'
|
||||
import common from '../../../lib/common/common.js'
|
||||
|
||||
export class bym extends plugin {
|
||||
constructor () {
|
||||
super({
|
||||
name: 'ChatGPT-Plugin伪人模式',
|
||||
dsc: 'ChatGPT-Plugin伪人模式',
|
||||
event: 'message',
|
||||
priority: -150,
|
||||
rule: [
|
||||
{
|
||||
reg: '^#chatgpt伪人模式$',
|
||||
fnc: 'bym'
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
async bym (e) {
|
||||
if (!ChatGPTConfig.bym.enable) {
|
||||
return false
|
||||
}
|
||||
let recall = false
|
||||
let presetId = ChatGPTConfig.bym.defaultPreset
|
||||
if (ChatGPTConfig.bym.presetMap && ChatGPTConfig.bym.presetMap.length > 0) {
|
||||
const option = ChatGPTConfig.bym.presetMap.sort((a, b) => a.priority - b.priority)
|
||||
.find(item => item.keywords.find(keyword => e.msg.includes(keyword)))
|
||||
if (option) {
|
||||
presetId = option.presetId
|
||||
}
|
||||
recall = !!option.recall
|
||||
}
|
||||
|
||||
const presetManager = Chaite.getInstance().getChatPresetManager()
|
||||
let preset = await presetManager.getInstance(presetId)
|
||||
if (!preset) {
|
||||
preset = await presetManager.getInstance(ChatGPTConfig.bym.defaultPreset)
|
||||
}
|
||||
if (!preset) {
|
||||
logger.debug('未找到预设,请检查配置文件')
|
||||
return false
|
||||
}
|
||||
if (ChatGPTConfig.bym.presetPrefix) {
|
||||
if (!preset.sendMessageOption.systemOverride) {
|
||||
preset.sendMessageOption.systemOverride = ''
|
||||
}
|
||||
preset.sendMessageOption.systemOverride = ChatGPTConfig.bym.presetPrefix + preset.sendMessageOption.systemOverride
|
||||
}
|
||||
const userMessage = await intoUserMessage(e, {
|
||||
handleReplyText: true,
|
||||
handleReplyImage: true,
|
||||
useRawMessage: true,
|
||||
handleAtMsg: true,
|
||||
excludeAtBot: false,
|
||||
toggleMode: ChatGPTConfig.basic.toggleMode,
|
||||
togglePrefix: ChatGPTConfig.basic.togglePrefix
|
||||
})
|
||||
// 伪人不记录历史
|
||||
preset.sendMessageOption.disableHistoryRead = true
|
||||
preset.sendMessageOption.disableHistorySave = true
|
||||
// 设置多轮调用回掉
|
||||
preset.sendMessageOption.onMessageWithToolCall = async content => {
|
||||
const { msgs, forward } = await toYunzai(e, [content])
|
||||
if (msgs.length > 0) {
|
||||
await e.reply(msgs)
|
||||
}
|
||||
for (let forwardElement of forward) {
|
||||
this.reply(forwardElement)
|
||||
}
|
||||
}
|
||||
// 发送
|
||||
const response = await Chaite.getInstance().sendMessage(userMessage, e, {
|
||||
...preset.sendMessageOption,
|
||||
chatPreset: preset
|
||||
})
|
||||
const { msgs, forward } = await toYunzai(e, response.contents)
|
||||
if (msgs.length > 0) {
|
||||
// await e.reply(msgs, false, { recallMsg: recall })
|
||||
for (let msg of msgs) {
|
||||
await e.reply(msg, false, { recallMsg: recall ? 10 : 0 })
|
||||
await common.sleep(Math.floor(Math.random() * 2000) + 1000)
|
||||
}
|
||||
}
|
||||
if (ChatGPTConfig.bym.sendReasoning) {
|
||||
for (let forwardElement of forward) {
|
||||
await e.reply(forwardElement, false, { recallMsg: recall ? 10 : 0 })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
apps/chat.js
25
apps/chat.js
|
|
@ -1,6 +1,6 @@
|
|||
import Config from '../config/config.js'
|
||||
import { Chaite, SendMessageOption } from 'chaite'
|
||||
import { getPreset, intoUserMessage } from '../utils/message.js'
|
||||
import { getPreset, intoUserMessage, toYunzai } from '../utils/message.js'
|
||||
|
||||
export class Chat extends plugin {
|
||||
constructor () {
|
||||
|
|
@ -22,9 +22,18 @@ export class Chat extends plugin {
|
|||
async chat (e) {
|
||||
const state = await Chaite.getInstance().getUserStateStorage().getItem(e.sender.user_id + '')
|
||||
const sendMessageOptions = SendMessageOption.create(state?.settings)
|
||||
sendMessageOptions.onMessageWithToolCall = async content => {
|
||||
const { msgs, forward } = await toYunzai(e, [content])
|
||||
if (msgs.length > 0) {
|
||||
await e.reply(msgs)
|
||||
}
|
||||
for (let forwardElement of forward) {
|
||||
this.reply(forwardElement)
|
||||
}
|
||||
}
|
||||
const preset = await getPreset(e, state?.settings.preset || Config.llm.defaultChatPresetId, Config.basic.toggleMode, Config.basic.togglePrefix)
|
||||
if (!preset) {
|
||||
logger.debug('未找到预设,不进入对话')
|
||||
logger.debug('不满足对话触发条件或未找到预设,不进入对话')
|
||||
return false
|
||||
}
|
||||
const userMessage = await intoUserMessage(e, {
|
||||
|
|
@ -40,10 +49,12 @@ export class Chat extends plugin {
|
|||
...sendMessageOptions,
|
||||
chatPreset: preset
|
||||
})
|
||||
const responseText = response.contents
|
||||
.filter(c => c.type === 'text')
|
||||
.map(c => (/** @type {import('chaite').TextContent} **/ c).text)
|
||||
.reduce((a, b) => a + b, '')
|
||||
await this.reply(responseText)
|
||||
const { msgs, forward } = await toYunzai(e, response.contents)
|
||||
if (msgs.length > 0) {
|
||||
await e.reply(msgs, true)
|
||||
}
|
||||
for (let forwardElement of forward) {
|
||||
this.reply(forwardElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import ChatGPTConfig from '../config/config.js'
|
||||
import { createCRUDCommandRules, createSwitchCommandRules } from '../utils/command.js'
|
||||
import { Chaite } from 'chaite'
|
||||
import { resolve } from 'eslint-plugin-promise/rules/lib/promise-statics.js'
|
||||
|
||||
export class ChatGPTManagement extends plugin {
|
||||
constructor () {
|
||||
|
|
@ -20,6 +19,11 @@ export class ChatGPTManagement extends plugin {
|
|||
{
|
||||
reg: `^${cmdPrefix}结束(全部)?对话$`,
|
||||
fnc: 'destroyConversation'
|
||||
},
|
||||
{
|
||||
reg: `^${cmdPrefix}(bym|伪人)设置默认预设`,
|
||||
fnc: 'setDefaultBymPreset',
|
||||
permission: 'master'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
|
@ -49,7 +53,8 @@ export class ChatGPTManagement extends plugin {
|
|||
...createCRUDCommandRules.bind(this)(cmdPrefix, '黑名单群', 'blackGroups', false),
|
||||
...createCRUDCommandRules.bind(this)(cmdPrefix, '白名单群', 'whiteGroups', false),
|
||||
...createCRUDCommandRules.bind(this)(cmdPrefix, '黑名单用户', 'blackUsers', false),
|
||||
...createCRUDCommandRules.bind(this)(cmdPrefix, '白名单用户', 'whiteUsers', false)
|
||||
...createCRUDCommandRules.bind(this)(cmdPrefix, '白名单用户', 'whiteUsers', false),
|
||||
createSwitchCommandRules(cmdPrefix, '(伪人|bym)', 'bym')
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -60,6 +65,17 @@ export class ChatGPTManagement extends plugin {
|
|||
this.reply(`token: ${token}, 有效期300秒`, true)
|
||||
}
|
||||
|
||||
async setDefaultBymPreset (e) {
|
||||
const presetId = e.msg.replace(`${ChatGPTConfig.basic.commandPrefix}伪人设置默认预设`, '')
|
||||
const preset = await Chaite.getInstance().getChatPresetManager().getInstance(presetId)
|
||||
if (preset) {
|
||||
ChatGPTConfig.bym.defaultPreset = presetId
|
||||
this.reply(`伪人模式默认预设已切换为${presetId}(${preset.name})`)
|
||||
} else {
|
||||
this.reply(`未找到预设${presetId}`)
|
||||
}
|
||||
}
|
||||
|
||||
async destroyConversation (e) {
|
||||
if (e.msg.includes('全部')) {
|
||||
if (!e.isMaster) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,47 @@ class ChatGPTConfig {
|
|||
commandPrefix: '^#chatgpt'
|
||||
}
|
||||
|
||||
/**
|
||||
* 伪人模式,基于框架实现,因此机器人开启前缀后依然需要带上前缀。
|
||||
* @type {{
|
||||
* enable: boolean,
|
||||
* hit: string[],
|
||||
* probability: number,
|
||||
* defaultPreset: string,
|
||||
* presetPrefix?: string,
|
||||
* presetMap: Array<{
|
||||
* keywords: string[],
|
||||
* presetId: string,
|
||||
* priority: number,
|
||||
* recall?: boolean
|
||||
* }>,
|
||||
* maxTokens: number,
|
||||
* temperature: number,
|
||||
* sendReasoning: boolean
|
||||
* }}
|
||||
* }}
|
||||
*/
|
||||
bym = {
|
||||
// 开关
|
||||
enable: false,
|
||||
// 伪人必定触发词
|
||||
hit: ['bym'],
|
||||
// 不包含伪人必定触发词时的概率
|
||||
probability: 0.02,
|
||||
// 伪人模式的默认预设
|
||||
defaultPreset: '',
|
||||
// 伪人模式的预设前缀,会加在在所有其他预设前。例如此处可以用于配置通用的伪人发言风格(随意、模仿群友等),presetMap中专心配置角色设定即可
|
||||
presetPrefix: '',
|
||||
// 包含关键词与预设的对应关系。包含特定触发词使用特定的预设,按照优先级排序
|
||||
presetMap: [],
|
||||
// 如果大于0,会覆盖preset中的maxToken,用于控制伪人模式发言长度
|
||||
maxTokens: 0,
|
||||
// 如果大于等于0,会覆盖preset中的temperature,用于控制伪人模式发言随机性
|
||||
temperature: -1,
|
||||
// 是否发送思考内容
|
||||
sendReasoning: false
|
||||
}
|
||||
|
||||
/**
|
||||
* 模型和对话相关配置
|
||||
* @type {{
|
||||
|
|
@ -119,43 +160,6 @@ class ChatGPTConfig {
|
|||
|
||||
constructor () {
|
||||
this.version = '3.0.0'
|
||||
this.basic = {
|
||||
toggleMode: 'at',
|
||||
togglePrefix: '#chat',
|
||||
debug: false,
|
||||
commandPrefix: '^#chatgpt'
|
||||
}
|
||||
this.llm = {
|
||||
defaultModel: '',
|
||||
embeddingModel: 'gemini-embedding-exp-03-07',
|
||||
dimensions: 0,
|
||||
defaultChatPresetId: '',
|
||||
enableCustomPreset: false,
|
||||
customPresetUserWhiteList: [],
|
||||
customPresetUserBlackList: [],
|
||||
promptBlockWords: [],
|
||||
responseBlockWords: [],
|
||||
blockStrategy: 'full',
|
||||
blockWordMask: '***'
|
||||
}
|
||||
this.management = {
|
||||
blackGroups: [],
|
||||
whiteGroups: [],
|
||||
blackUsers: [],
|
||||
whiteUsers: [],
|
||||
defaultRateLimit: 0
|
||||
}
|
||||
this.chaite = {
|
||||
dataDir: 'data',
|
||||
processorsDirPath: 'utils/processors',
|
||||
toolsDirPath: 'utils/tools',
|
||||
cloudBaseUrl: '',
|
||||
cloudApiKey: '',
|
||||
authKey: '',
|
||||
host: '',
|
||||
port: 48370
|
||||
}
|
||||
|
||||
this.watcher = null
|
||||
this.configPath = ''
|
||||
}
|
||||
|
|
@ -216,6 +220,7 @@ class ChatGPTConfig {
|
|||
|
||||
// 为所有嵌套对象创建Proxy
|
||||
this.basic = createDeepProxy(this.basic, handler)
|
||||
this.bym = createDeepProxy(this.bym, handler)
|
||||
this.llm = createDeepProxy(this.llm, handler)
|
||||
this.management = createDeepProxy(this.management, handler)
|
||||
this.chaite = createDeepProxy(this.chaite, handler)
|
||||
|
|
@ -248,6 +253,7 @@ class ChatGPTConfig {
|
|||
const config = {
|
||||
version: this.version,
|
||||
basic: this.basic,
|
||||
bym: this.bym,
|
||||
llm: this.llm,
|
||||
management: this.management,
|
||||
chaite: this.chaite
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { Chaite } from 'chaite'
|
||||
import common from '../../../lib/common/common.js'
|
||||
|
||||
/**
|
||||
* 将e中的消息转换为chaite的UserMessage
|
||||
|
|
@ -143,3 +144,49 @@ export function checkChatMsg (e, toggleMode, togglePrefix) {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 模型响应转为机器人格式
|
||||
* @param e
|
||||
* @param {import('chaite').MessageContent[]} contents
|
||||
* @returns {Promise<{ msgs: (import('icqq').TextElem | import('icqq').ImageElem | import('icqq').AtElem | import('icqq').PttElem | string)[], forward: *[]}>}
|
||||
*/
|
||||
export async function toYunzai (e, contents) {
|
||||
/**
|
||||
* 要发送的消息
|
||||
* @type {(import('icqq').TextElem | import('icqq').ImageElem | import('icqq').AtElem | import('icqq').PttElem | string)[]}
|
||||
*/
|
||||
const msgs = []
|
||||
/**
|
||||
* 要转发的
|
||||
* @type {*[]}
|
||||
*/
|
||||
const forward = []
|
||||
for (let content of contents) {
|
||||
switch (content.type) {
|
||||
case 'text': {
|
||||
msgs.push((/** @type {import('chaite').TextContent} **/ content).text)
|
||||
break
|
||||
}
|
||||
case 'image': {
|
||||
msgs.push(segment.image((/** @type {import('chaite').ImageContent} **/ content).image))
|
||||
break
|
||||
}
|
||||
case 'audio': {
|
||||
msgs.push(segment.record((/** @type {import('chaite').AudioContent} **/ content).data))
|
||||
break
|
||||
}
|
||||
case 'reasoning': {
|
||||
const reasoning = await common.makeForwardMsg(e, [(/** @type {import('chaite').ReasoningContent} **/ content).text], '思考过程')
|
||||
forward.push(reasoning)
|
||||
break
|
||||
}
|
||||
default: {
|
||||
logger.warn(`不支持的类型 ${content.type}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
msgs, forward
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue