fix: 很多功能

This commit is contained in:
ikechan8370 2025-03-20 22:43:39 +08:00
parent a711ec13d7
commit 66905640e4
15 changed files with 242 additions and 29 deletions

View file

@ -53,17 +53,18 @@ export class bym extends plugin {
logger.debug('未找到预设,请检查配置文件')
return false
}
const sendMessageOption = JSON.parse(JSON.stringify(preset.sendMessageOption))
if (ChatGPTConfig.bym.presetPrefix) {
if (!preset.sendMessageOption.systemOverride) {
preset.sendMessageOption.systemOverride = ''
if (!sendMessageOption.systemOverride) {
sendMessageOption.systemOverride = ''
}
preset.sendMessageOption.systemOverride = ChatGPTConfig.bym.presetPrefix + preset.sendMessageOption.systemOverride
sendMessageOption.systemOverride = ChatGPTConfig.bym.presetPrefix + sendMessageOption.systemOverride
}
if (ChatGPTConfig.bym.temperature >= 0) {
preset.sendMessageOption.temperature = ChatGPTConfig.bym.temperature
sendMessageOption.temperature = ChatGPTConfig.bym.temperature
}
if (ChatGPTConfig.bym.maxTokens > 0) {
preset.sendMessageOption.maxTokens = ChatGPTConfig.bym.maxTokens
sendMessageOption.maxToken = ChatGPTConfig.bym.maxTokens
}
const userMessage = await intoUserMessage(e, {
handleReplyText: true,
@ -75,10 +76,10 @@ export class bym extends plugin {
togglePrefix: ChatGPTConfig.basic.togglePrefix
})
// 伪人不记录历史
preset.sendMessageOption.disableHistoryRead = true
preset.sendMessageOption.disableHistorySave = true
sendMessageOption.disableHistoryRead = true
sendMessageOption.disableHistorySave = true
// 设置多轮调用回掉
preset.sendMessageOption.onMessageWithToolCall = async content => {
sendMessageOption.onMessageWithToolCall = async content => {
const { msgs, forward } = await toYunzai(e, [content])
if (msgs.length > 0) {
await e.reply(msgs)
@ -89,11 +90,11 @@ export class bym extends plugin {
}
if (ChatGPTConfig.llm.enableGroupContext && e.isGroup) {
const contextPrompt = await getGroupContextPrompt(e, ChatGPTConfig.llm.groupContextLength)
preset.sendMessageOption.systemOverride = preset.sendMessageOption.systemOverride ? preset.sendMessageOption.systemOverride + '\n' + contextPrompt : contextPrompt
sendMessageOption.systemOverride = sendMessageOption.systemOverride ? sendMessageOption.systemOverride + '\n' + contextPrompt : contextPrompt
}
// 发送
const response = await Chaite.getInstance().sendMessage(userMessage, e, {
...preset.sendMessageOption,
...sendMessageOption,
chatPreset: preset
})
const { msgs, forward } = await toYunzai(e, response.contents)

View file

@ -85,6 +85,7 @@ export class ChatGPTManagement extends plugin {
if (e.msg.includes('全部')) {
if (!e.isMaster) {
this.reply('仅限主人使用')
return false
}
const userStates = await Chaite.getInstance().getUserStateStorage().listItems()
let num = 0
@ -99,7 +100,7 @@ export class ChatGPTManagement extends plugin {
this.reply(`已结束${num}个用户的对话`)
} else {
const state = await Chaite.getInstance().getUserStateStorage().getItem(e.sender.user_id + '')
if (!state) {
if (!state || !state.current.conversationId || !state.current.messageId) {
this.reply('当前未开启对话')
return false
}

View file

@ -117,7 +117,7 @@ class ChatGPTConfig {
groupContextLength: 20,
// 用于组装群聊上下文提示词的模板前缀
groupContextTemplatePrefix: 'Latest several messages in the group chat:\n' +
'| sender.card | sender.nickname | sender.user_id | sender.role | sender.title | time | messageId | raw_message |\n' +
' 群名片 | 昵称 | qq号 | 群角色 | 群头衔 | 时间 | messageId | 消息内容 |\n' +
'|---|---|---|---|---|---|---|---|',
// 用于组装群聊上下文提示词的模板内容部分每一条消息作为message仿照示例填写
// eslint-disable-next-line no-template-curly-in-string

View file

@ -22,7 +22,10 @@ export class LowDBChannelStorage extends ChaiteStorage {
*/
async getItem (key) {
const obj = await this.collection.findOne({ id: key })
return new Channel({}).fromString(JSON.stringify(obj))
if (!obj) {
return null
}
return new Channel(obj)
}
/**
@ -32,7 +35,7 @@ export class LowDBChannelStorage extends ChaiteStorage {
* @returns {Promise<string>}
*/
async setItem (id, channel) {
if (id) {
if (id && await this.getItem(id)) {
await this.collection.updateById(id, channel)
return id
}

View file

@ -28,7 +28,7 @@ export class LowDBChatPresetsStorage extends ChaiteStorage {
if (!obj) {
return null
}
return new ChatPreset({}).fromString(JSON.stringify(obj))
return new ChatPreset(obj)
}
/**
@ -38,7 +38,7 @@ export class LowDBChatPresetsStorage extends ChaiteStorage {
* @returns {Promise<string>}
*/
async setItem (id, preset) {
if (id) {
if (id && await this.getItem(id)) {
await this.collection.updateById(id, preset)
return id
}

View file

@ -1,4 +1,15 @@
import { Chaite, ChannelsManager, ChatPresetManager, DefaultChannelLoadBalancer, GeminiClient, OpenAIClient, ProcessorsManager, RAGManager, ToolManager } from 'chaite'
import {
Chaite,
ChannelsManager,
ChatPresetManager,
DefaultChannelLoadBalancer,
GeminiClient,
OpenAIClient,
ProcessorsManager,
RAGManager,
ToolManager,
ToolsGroupManager
} from 'chaite'
import ChatGPTConfig from '../../config/config.js'
import { LowDBChannelStorage } from './channel_storage.js'
import { LowDBChatPresetsStorage } from './chat_preset_storage.js'
@ -11,6 +22,8 @@ import { VectraVectorDatabase } from './vector_database.js'
import ChatGPTStorage from '../storage.js'
import path from 'path'
import fs from 'fs'
import { migrateDatabase } from '../../utils/initDB.js'
import { LowDBToolsGroupDTOsStorage } from './tool_groups_storage.js'
/**
* 认证以便共享上传
@ -117,14 +130,16 @@ export async function initChaite () {
}
const processorsManager = await ProcessorsManager.init(processorsDir, new LowDBProcessorsStorage(ChatGPTStorage))
const chatPresetManager = await ChatPresetManager.init(new LowDBChatPresetsStorage(ChatGPTStorage))
const toolsGroupManager = await ToolsGroupManager.init(new LowDBToolsGroupDTOsStorage(ChatGPTStorage))
const userModeSelector = new ChatGPTUserModeSelector()
const userStateStorage = new LowDBUserStateStorage(ChatGPTStorage)
const historyManager = new LowDBHistoryManager(ChatGPTStorage)
let chaite = Chaite.init(channelsManager, toolsManager, processorsManager, chatPresetManager,
let chaite = Chaite.init(channelsManager, toolsManager, processorsManager, chatPresetManager, toolsGroupManager,
userModeSelector, userStateStorage, historyManager, logger)
logger.info('Chaite 初始化完成')
chaite.setCloudService(ChatGPTConfig.chaite.cloudBaseUrl)
logger.info('Chaite.Cloud 初始化完成')
await migrateDatabase()
ChatGPTConfig.chaite.cloudApiKey && await chaite.auth(ChatGPTConfig.chaite.cloudApiKey)
await initRagManager(ChatGPTConfig.llm.embeddingModel, ChatGPTConfig.llm.dimensions)
if (!ChatGPTConfig.chaite.authKey) {

View file

@ -25,7 +25,10 @@ export class LowDBProcessorsStorage extends ChaiteStorage {
*/
async getItem (key) {
const obj = await this.collection.findOne({ id: key })
return new ProcessorDTO({}).fromString(JSON.stringify(obj))
if (!obj) {
return null
}
return new ProcessorDTO(obj)
}
/**
@ -35,7 +38,7 @@ export class LowDBProcessorsStorage extends ChaiteStorage {
* @returns {Promise<string>}
*/
async setItem (id, processor) {
if (id) {
if (id && await this.getItem(id)) {
await this.collection.updateById(id, processor)
return id
}

View file

@ -0,0 +1,70 @@
import { ChaiteStorage, ToolsGroupDTO } from 'chaite'
/**
* @extends {ChaiteStorage<import('chaite').ToolsGroupDTO>}
*/
export class LowDBToolsGroupDTOsStorage extends ChaiteStorage {
/**
*
* @param { LowDBStorage } storage
*/
constructor (storage) {
super()
this.storage = storage
/**
* 集合
* @type {LowDBCollection}
*/
this.collection = this.storage.collection('tool_groups')
}
/**
*
* @param key
* @returns {Promise<import('chaite').ToolsGroupDTO>}
*/
async getItem (key) {
const obj = await this.collection.findOne({ id: key })
if (!obj) {
return null
}
return new ToolsGroupDTO(obj)
}
/**
*
* @param {string} id
* @param {import('chaite').ToolsGroupDTO} preset
* @returns {Promise<string>}
*/
async setItem (id, preset) {
if (id && await this.getItem(id)) {
await this.collection.updateById(id, preset)
return id
}
const result = await this.collection.insert(preset)
return result.id
}
/**
*
* @param {string} key
* @returns {Promise<void>}
*/
async removeItem (key) {
await this.collection.deleteById(key)
}
/**
*
* @returns {Promise<import('chaite').ToolsGroupDTO[]>}
*/
async listItems () {
const list = await this.collection.findAll()
return list.map(item => new ToolsGroupDTO({}).fromString(JSON.stringify(item)))
}
async clear () {
await this.collection.deleteAll()
}
}

View file

@ -25,7 +25,10 @@ export class LowDBToolsStorage extends ChaiteStorage {
*/
async getItem (key) {
const obj = await this.collection.findOne({ id: key })
return new ToolDTO({}).fromString(JSON.stringify(obj))
if (!obj) {
return null
}
return new ToolDTO(obj)
}
/**
@ -35,7 +38,7 @@ export class LowDBToolsStorage extends ChaiteStorage {
* @returns {Promise<string>}
*/
async setItem (id, tools) {
if (id) {
if (id && await this.getItem(id)) {
await this.collection.updateById(id, tools)
return id
}

View file

@ -52,11 +52,9 @@ export class LowDBUserStateStorage extends ChaiteStorage {
* @returns {Promise<string>}
*/
async setItem (id, state) {
if (id) {
if (await this.getItem(id)) {
await this.collection.updateById(id, state)
return id
}
if (id && await this.getItem(id)) {
await this.collection.updateById(id, state)
return id
}
state.id = id
const result = await this.collection.insert(state)

View file

@ -348,7 +348,7 @@ export class LowDBCollection {
}
}
const dataDir = path.resolve('./plugins/chatgpt-plugin', ChatGPTConfig.chaite.dataDir)
export const dataDir = path.resolve('./plugins/chatgpt-plugin', ChatGPTConfig.chaite.dataDir)
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true })
}

View file

@ -4,7 +4,7 @@
"type": "module",
"author": "ikechan8370",
"dependencies": {
"chaite": "^1.2.6",
"chaite": "^1.3.0",
"js-yaml": "^4.1.0",
"keyv": "^5.3.1",
"keyv-file": "^5.1.2",

View file

@ -0,0 +1 @@
aW1wb3J0IHsgUG9zdFByb2Nlc3NvciB9IGZyb20gJ2NoYWl0ZScKaW1wb3J0IENoYXRHUFRDb25maWcgZnJvbSAnLi4vLi4vY29uZmlnL2NvbmZpZy5qcycKCmV4cG9ydCBjbGFzcyBCbGFja1Bvc3RQcm9jZXNzb3IgZXh0ZW5kcyBQb3N0UHJvY2Vzc29yIHsKICBuYW1lID0gJ0JsYWNrUG9zdFByb2Nlc3NvcicKCiAgLyoqCiAgICog5aSE55CG6YC76L6RCiAgICog5Y+v5Lul6YCa6L+HYGFzeW5jTG9jYWxTdG9yYWdlLmdldFN0b3JlKCkuZ2V0RXZlbnQoKWDojrflj5Zl5a6e5L6LCiAgICogQHBhcmFtIHtpbXBvcnQoJ2NoYWl0ZScpLkFzc2lzdGFudE1lc3NhZ2V9IG1lc3NhZ2UKICAgKiBAcmV0dXJucyB7UHJvbWlzZTxpbXBvcnQoJ2NoYWl0ZScpLkFzc2lzdGFudE1lc3NhZ2U+fQogICAqLwogIGFzeW5jIHByb2Nlc3MgKG1lc3NhZ2UpIHsKICAgIHN3aXRjaCAoQ2hhdEdQVENvbmZpZy5sbG0uYmxvY2tTdHJhdGVneSkgewogICAgICBjYXNlICdmdWxsJzogewogICAgICAgIGZvciAobGV0IGNvbnRlbnQgb2YgbWVzc2FnZS5jb250ZW50KSB7CiAgICAgICAgICBmb3IgKGNvbnN0IGJsb2NrV29yZCBvZiBDaGF0R1BUQ29uZmlnLmxsbS5yZXNwb25zZUJsb2NrV29yZHMpIHsKICAgICAgICAgICAgaWYgKGNvbnRlbnQudHlwZSA9PT0gJ3RleHQnICYmIGNvbnRlbnQudGV4dD8uaW5jbHVkZXMoYmxvY2tXb3JkKSkgewogICAgICAgICAgICAgIGNvbnRlbnQudGV4dCA9ICflm57lpI3lt7LlsY/olL0nCiAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBicmVhawogICAgICB9CiAgICAgIGNhc2UgJ21hc2snOiB7CiAgICAgICAgZm9yIChsZXQgY29udGVudCBvZiBtZXNzYWdlLmNvbnRlbnQpIHsKICAgICAgICAgIGZvciAoY29uc3QgYmxvY2tXb3JkIG9mIENoYXRHUFRDb25maWcubGxtLnJlc3BvbnNlQmxvY2tXb3JkcykgewogICAgICAgICAgICBpZiAoY29udGVudC50eXBlID09PSAndGV4dCcgJiYgY29udGVudC50ZXh0Py5pbmNsdWRlcyhibG9ja1dvcmQpKSB7CiAgICAgICAgICAgICAgY29udGVudC50ZXh0ID0gY29udGVudC50ZXh0LnJlcGxhY2VBbGwoYmxvY2tXb3JkLCBDaGF0R1BUQ29uZmlnLmxsbS5ibG9ja1dvcmRNYXNrIHx8ICcqKionKQogICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBtZXNzYWdlCiAgfQp9Cg==

View file

@ -0,0 +1 @@
aW1wb3J0IHsgUHJlUHJvY2Vzc29yIH0gZnJvbSAnY2hhaXRlJwppbXBvcnQgQ2hhdEdQVENvbmZpZyBmcm9tICcuLi8uLi9jb25maWcvY29uZmlnLmpzJwoKZXhwb3J0IGNsYXNzIEJsYWNrUHJlUHJvY2Vzc29yIGV4dGVuZHMgUHJlUHJvY2Vzc29yIHsKICBuYW1lID0gJ0JsYWNrUHJlUHJvY2Vzc29yJwoKICAvKioKICAgKiDlpITnkIbpgLvovpEKICAgKiDlj6/ku6XpgJrov4dgYXN5bmNMb2NhbFN0b3JhZ2UuZ2V0U3RvcmUoKS5nZXRFdmVudCgpYOiOt+WPlmXlrp7kvosKICAgKiBAcGFyYW0ge2ltcG9ydCgnY2hhaXRlJykuVXNlck1lc3NhZ2V9IG1lc3NhZ2UKICAgKiBAcmV0dXJucyB7UHJvbWlzZTxpbXBvcnQoJ2NoYWl0ZScpLlVzZXJNZXNzYWdlPn0KICAgKi8KICBhc3luYyBwcm9jZXNzIChtZXNzYWdlKSB7CiAgICBzd2l0Y2ggKENoYXRHUFRDb25maWcubGxtLmJsb2NrU3RyYXRlZ3kpIHsKICAgICAgY2FzZSAnZnVsbCc6IHsKICAgICAgICBmb3IgKGxldCBjb250ZW50IG9mIG1lc3NhZ2UuY29udGVudCkgewogICAgICAgICAgZm9yIChjb25zdCBibG9ja1dvcmQgb2YgQ2hhdEdQVENvbmZpZy5sbG0ucmVzcG9uc2VCbG9ja1dvcmRzKSB7CiAgICAgICAgICAgIGlmIChjb250ZW50LnR5cGUgPT09ICd0ZXh0JyAmJiBjb250ZW50LnRleHQ/LmluY2x1ZGVzKGJsb2NrV29yZCkpIHsKICAgICAgICAgICAgICBjb250ZW50LnRleHQgPSAn6K+35rGC5raI5oGv5Zug5YyF5ZCr5bGP6JS96K+N6KKr5bGP6JS9JwogICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgYnJlYWsKICAgICAgfQogICAgICBjYXNlICdtYXNrJzogewogICAgICAgIGZvciAobGV0IGNvbnRlbnQgb2YgbWVzc2FnZS5jb250ZW50KSB7CiAgICAgICAgICBmb3IgKGNvbnN0IGJsb2NrV29yZCBvZiBDaGF0R1BUQ29uZmlnLmxsbS5yZXNwb25zZUJsb2NrV29yZHMpIHsKICAgICAgICAgICAgaWYgKGNvbnRlbnQudHlwZSA9PT0gJ3RleHQnICYmIGNvbnRlbnQudGV4dD8uaW5jbHVkZXMoYmxvY2tXb3JkKSkgewogICAgICAgICAgICAgIGNvbnRlbnQudGV4dCA9IGNvbnRlbnQudGV4dC5yZXBsYWNlQWxsKGJsb2NrV29yZCwgQ2hhdEdQVENvbmZpZy5sbG0uYmxvY2tXb3JkTWFzayB8fCAnKioqJykKICAgICAgICAgICAgICBicmVhawogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICByZXR1cm4gbWVzc2FnZQogIH0KfQo=

117
utils/initDB.js Normal file
View file

@ -0,0 +1,117 @@
// initDB.js
// 插件初始化的基本数据库内容
import { BaseClientOptions, Chaite, Channel, ProcessorDTO, SendMessageOption } from 'chaite'
import fs from 'fs'
import path from 'path'
import { md5 } from './common.js'
/**
* 默认系统用户
* @type {import('chaite').User}
*/
const systemUser = {
username: 'system',
user_id: '00000'
}
/**
* 注入内置的处理器
* @param {string} resourcesDir
* @param {import('chaite').ProcessorsManager} processorsManager
* @param {'pre' | 'post'} type
* @param {string} name
* @param {string} description
* @returns {Promise<void>}
*/
async function addEmbeddedProcessor (resourcesDir, processorsManager, type, name, description) {
const codeBuf = fs.readFileSync(path.resolve(resourcesDir, name))
let code = Buffer.from(codeBuf.toString(), 'base64').toString()
await processorsManager.addInstance(new ProcessorDTO({
id: md5(name),
type,
name,
uploader: systemUser,
description,
code
}))
}
export async function migrateDatabase () {
logger.debug('检查数据库初始化...')
const resourcesDir = path.resolve('./plugins/chatgpt-plugin', 'resources/embedded')
// 1. 设置初始化的预处理器
const processorsManager = Chaite.getInstance().getProcessorsManager()
if (!await processorsManager.getInstance('BlackPostProcessor')) {
logger.info('初始化内置的屏蔽词前置处理器')
await addEmbeddedProcessor(resourcesDir, processorsManager, 'pre', 'BlackPostProcessor', '内置的屏蔽词前置处理器')
}
if (!await processorsManager.getInstance('BlackPreProcessor')) {
logger.info('初始化内置的屏蔽词后置处理器')
await addEmbeddedProcessor(resourcesDir, processorsManager, 'post', 'BlackPreProcessor', '内置的屏蔽词前置处理器')
}
// 2. 设置默认渠道
const channelsManager = Chaite.getInstance().getChannelsManager()
try {
await channelsManager.getChannelByModel('Qwen/Qwen2.5-7B-Instruct')
} catch (err) {
if (err.message === 'No available channels') {
await channelsManager.addInstance(new Channel({
id: 'free',
name: 'free',
models: ['Qwen/Qwen2.5-7B-Instruct'],
adapterType: 'openai',
type: 'openai',
weight: 1,
priority: 0,
status: 'enabled',
options: new BaseClientOptions({
features: ['tool', 'chat'],
baseUrl: 'https://oneapi.ikechan8370.com/v1',
apiKey: 'sk-uIzofH2TIMVu6giK56BeCeD5E98b42EbBe695597B5FeAc68',
postProcessorIds: [md5('BlackPreProcessor'), md5('BlackPostProcessor')]
}),
uploader: systemUser
}))
logger.info('初始化内置的免费渠道')
}
}
// 3. 设置默认预设
let chatPresetManager = Chaite.getInstance().getChatPresetManager()
if (!await chatPresetManager.getInstance('default_local')) {
await chatPresetManager.addInstance({
id: 'default_local',
local: true,
name: '默认预设',
prefix: 'chaite',
sendMessageOption: new SendMessageOption({
model: 'Qwen/Qwen2.5-7B-Instruct',
temperature: 0.8,
maxToken: 4096,
systemOverride: '你是Chaite一个在QQ群聊中活跃的AI助手。你可以与群友进行聊天提供帮助和解答问题。'
}),
uploader: systemUser
})
logger.info('初始化内置的默认预设')
}
// 4. 设置默认工具组
let toolGroupsManager = Chaite.getInstance().getToolsGroupManager()
if (!await toolGroupsManager.getInstance('default_local')) {
await toolGroupsManager.addInstance({
id: 'default_local',
name: '默认工具组',
description: '默认工具组仅用于占位,包括全部非禁用的工具',
toolIds: [],
status: 'enabled',
isDefault: true,
uploader: systemUser
})
}
// 5. 扫描同步工具
const toolManager = Chaite.getInstance().getToolsManager()
logger.info('初始化内置的工具组')
logger.debug('数据库初始化完成')
}