fix: 对接

This commit is contained in:
ikechan8370 2025-03-16 22:13:52 +08:00
parent 89ab58b3d7
commit eee1285e2f
11 changed files with 221 additions and 26 deletions

View file

@ -21,8 +21,8 @@ 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)
const preset = await getPreset(e, state.settings.preset, Config.basic.toggleMode, Config.basic.togglePrefix)
const sendMessageOptions = SendMessageOption.create(state?.settings)
const preset = await getPreset(e, state?.settings.preset || Config.llm.defaultChatPresetId, Config.basic.toggleMode, Config.basic.togglePrefix)
if (!preset) {
logger.debug('未找到预设,不进入对话')
return false

View file

@ -1,6 +1,7 @@
import ChatGPTConfig from '../config/config.js'
import { createCRUDCommandRules, createSwitchCommandRules } from '../utils/command.js'
import { Chaite } from '../../../../../../WebstormProjects/node-chaite/src/index.js'
import { Chaite } from 'chaite'
import { resolve } from 'eslint-plugin-promise/rules/lib/promise-statics.js'
export class ChatGPTManagement extends plugin {
constructor () {
@ -22,7 +23,19 @@ export class ChatGPTManagement extends plugin {
}
]
})
this.rules.push(...[
this.initCommand(cmdPrefix)
}
async initCommand (cmdPrefix) {
const waitForChaite = async () => {
while (!Chaite.getInstance()) {
await new Promise(resolve => setTimeout(resolve, 1000))
}
return Chaite.getInstance()
}
await waitForChaite()
this.rule.push(...[
...createCRUDCommandRules.bind(this)(cmdPrefix, '渠道', 'channels'),
...createCRUDCommandRules.bind(this)(cmdPrefix, '预设', 'presets'),
...createCRUDCommandRules.bind(this)(cmdPrefix, '工具', 'tools'),

View file

@ -1,3 +1,7 @@
import fs from 'fs'
import path from 'path'
import yaml from 'js-yaml'
class ChatGPTConfig {
/**
* 版本号
@ -105,13 +109,159 @@ class ChatGPTConfig {
cloudBaseUrl: '',
// 云端API Key
cloudApiKey: '',
// jwt key非必要勿修改
// jwt key非必要勿修改,修改需重启
authKey: '',
// 管理面板监听地址
host: '',
// 管理面板监听端口
port: 48370
}
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 = ''
}
/**
* Start config file sync
* call once!
* @param {string} configDir Directory containing config files
*/
startSync (configDir) {
const jsonPath = path.join(configDir, 'config.json')
const yamlPath = path.join(configDir, 'config.yaml')
// Determine which config file to use
if (fs.existsSync(jsonPath)) {
this.configPath = jsonPath
} else if (fs.existsSync(yamlPath)) {
this.configPath = yamlPath
} else {
this.configPath = jsonPath
this.saveToFile()
}
// Load initial config
this.loadFromFile()
// Watch for file changes
this.watcher = fs.watchFile(this.configPath, (curr, prev) => {
if (curr.mtime !== prev.mtime) {
this.loadFromFile()
}
})
const createDeepProxy = (obj, handler) => {
if (obj === null || typeof obj !== 'object') return obj
for (let key of Object.keys(obj)) {
if (typeof obj[key] === 'object' && obj[key] !== null) {
obj[key] = createDeepProxy(obj[key], handler)
}
}
return new Proxy(obj, handler)
}
// 创建处理器
const handler = {
set: (target, prop, value) => {
if (prop !== 'watcher' && prop !== 'configPath') {
target[prop] = typeof value === 'object' && value !== null
? createDeepProxy(value, handler)
: value
this.saveToFile()
}
return true
}
}
// 为所有嵌套对象创建Proxy
this.basic = createDeepProxy(this.basic, handler)
this.llm = createDeepProxy(this.llm, handler)
this.management = createDeepProxy(this.management, handler)
this.chaite = createDeepProxy(this.chaite, handler)
// 返回最外层的Proxy
return new Proxy(this, handler)
}
/**
* Load config from file
*/
loadFromFile () {
try {
const content = fs.readFileSync(this.configPath, 'utf8')
const config = this.configPath.endsWith('.json')
? JSON.parse(content)
: yaml.load(content)
Object.assign(this, config)
} catch (error) {
console.error('Failed to load config:', error)
}
}
/**
* Save config to file
*/
saveToFile () {
try {
const config = {
version: this.version,
basic: this.basic,
llm: this.llm,
management: this.management,
chaite: this.chaite
}
const content = this.configPath.endsWith('.json')
? JSON.stringify(config, null, 2)
: yaml.dump(config)
fs.writeFileSync(this.configPath, content, 'utf8')
} catch (error) {
console.error('Failed to save config:', error)
}
}
}
export default new ChatGPTConfig()

View file

@ -35,6 +35,8 @@ for (let i in files) {
global.chatgpt = {
}
ChatGPTConfig.startSync('./plugins/chatgpt-plugin/data')
initChaite()
logger.info('chatgpt-plugin加载成功')
logger.info(`当前版本${ChatGPTConfig.version}`)

View file

@ -1,4 +1,4 @@
import { ChaiteStorage } from 'chaite'
import { ChaiteStorage, Channel } from 'chaite'
export class LowDBChannelStorage extends ChaiteStorage {
/**
@ -21,7 +21,8 @@ export class LowDBChannelStorage extends ChaiteStorage {
* @returns {Promise<import('chaite').Channel>}
*/
async getItem (key) {
return this.collection.findOne({ id: key })
const obj = await this.collection.findOne({ id: key })
return new Channel({}).fromString(JSON.stringify(obj))
}
/**
@ -53,7 +54,8 @@ export class LowDBChannelStorage extends ChaiteStorage {
* @returns {Promise<import('chaite').Channel[]>}
*/
async listItems () {
return this.collection.findAll()
const list = await this.collection.findAll()
return list.map(item => new Channel({}).fromString(JSON.stringify(item)))
}
async clear () {

View file

@ -1,4 +1,4 @@
import { ChaiteStorage } from 'chaite'
import { ChaiteStorage, ChatPreset } from 'chaite'
/**
* @extends {ChaiteStorage<import('chaite').ChatPreset>}
@ -24,7 +24,11 @@ export class LowDBChatPresetsStorage extends ChaiteStorage {
* @returns {Promise<import('chaite').ChatPreset>}
*/
async getItem (key) {
return this.collection.findOne({ id: key })
const obj = await this.collection.findOne({ id: key })
if (!obj) {
return null
}
return new ChatPreset({}).fromString(JSON.stringify(obj))
}
/**
@ -56,7 +60,8 @@ export class LowDBChatPresetsStorage extends ChaiteStorage {
* @returns {Promise<import('chaite').ChatPreset[]>}
*/
async listItems () {
return this.collection.findAll()
const list = await this.collection.findAll()
return list.map(item => new ChatPreset({}).fromString(JSON.stringify(item)))
}
async clear () {

View file

@ -126,7 +126,11 @@ export async function initChaite () {
chaite.setCloudService(ChatGPTConfig.chaite.cloudBaseUrl)
logger.info('Chaite.Cloud 初始化完成')
ChatGPTConfig.chaite.cloudApiKey && await chaite.auth(ChatGPTConfig.chaite.cloudApiKey)
await initRagManager(ChatGPTConfig.llm.embeddingModel, ChatGPTConfig.dimensions)
await initRagManager(ChatGPTConfig.llm.embeddingModel, ChatGPTConfig.llm.dimensions)
if (!ChatGPTConfig.chaite.authKey) {
ChatGPTConfig.chaite.authKey = Chaite.getInstance().getFrontendAuthHandler().generateToken(0, true)
}
chaite.getGlobalConfig().setAuthKey(ChatGPTConfig.chaite.authKey)
// 监听Chaite配置变化同步需要同步的配置
chaite.on('config-change', obj => {
const { key, newVal, oldVal } = obj
@ -139,19 +143,33 @@ export async function initChaite () {
chaite.setUpdateConfigCallback(config => {
logger.debug('chatgpt-plugin config updated')
Object.keys(config).forEach(key => {
ChatGPTConfig[key] = config[key]
// 回传部分需要同步的配置,以防不一致
if (key === 'serverAuthKey') {
chaite.getGlobalConfig().setAuthKey(config[key])
if (typeof config[key] === 'object' && config[key] !== null && ChatGPTConfig[key]) {
deepMerge(ChatGPTConfig[key], config[key])
} else {
ChatGPTConfig[key] = config[key]
}
})
// 回传部分需要同步的配置,以防不一致
chaite.getGlobalConfig().setAuthKey(ChatGPTConfig.chaite.authKey)
})
// 授予Chaite获取插件配置的能力以便通过api放出
chaite.setGetConfig(async () => {
return ChatGPTConfig
})
logger.info('Chaite.RAGManager 初始化完成')
const token = chaite.getFrontendAuthHandler().generateToken()
logger.info(token)
chaite.runApiServer()
}
function deepMerge (target, source) {
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (typeof source[key] === 'object' && source[key] !== null && target[key]) {
// 如果是对象且目标属性存在,递归合并
deepMerge(target[key], source[key])
} else {
// 否则直接赋值
target[key] = source[key]
}
}
}
}

View file

@ -1,4 +1,4 @@
import { ChaiteStorage } from 'chaite'
import { ChaiteStorage, ProcessorDTO } from 'chaite'
/**
* @extends {ChaiteStorage<import('chaite').Processor>}
@ -24,7 +24,8 @@ export class LowDBProcessorsStorage extends ChaiteStorage {
* @returns {Promise<import('chaite').Processor>}
*/
async getItem (key) {
return this.collection.findOne({ id: key })
const obj = await this.collection.findOne({ id: key })
return new ProcessorDTO({}).fromString(JSON.stringify(obj))
}
/**
@ -56,7 +57,8 @@ export class LowDBProcessorsStorage extends ChaiteStorage {
* @returns {Promise<import('chaite').Processor[]>}
*/
async listItems () {
return this.collection.findAll()
const list = await this.collection.findAll()
return list.map(item => new ProcessorDTO({}).fromString(JSON.stringify(item)))
}
async clear () {

View file

@ -1,4 +1,4 @@
import { ChaiteStorage } from 'chaite'
import { ChaiteStorage, ToolDTO } from 'chaite'
/**
* @extends {ChaiteStorage<import('chaite').ToolDTO>}
@ -24,7 +24,8 @@ export class LowDBToolsStorage extends ChaiteStorage {
* @returns {Promise<import('chaite').ToolDTO>}
*/
async getItem (key) {
return this.collection.findOne({ id: key })
const obj = await this.collection.findOne({ id: key })
return new ToolDTO({}).fromString(JSON.stringify(obj))
}
/**
@ -56,7 +57,8 @@ export class LowDBToolsStorage extends ChaiteStorage {
* @returns {Promise<import('chaite').ToolDTO[]>}
*/
async listItems () {
return this.collection.findAll()
const list = await this.collection.findAll()
return list.map(item => new ToolDTO({}).fromString(JSON.stringify(item)))
}
async clear () {

View file

@ -5,6 +5,7 @@
"author": "ikechan8370",
"dependencies": {
"chaite": "/Users/geyinchi/WebstormProjects/node-chaite",
"js-yaml": "^4.1.0",
"keyv": "^5.3.1",
"keyv-file": "^5.1.2",
"lowdb": "^7.0.1",

View file

@ -81,7 +81,7 @@ export async function intoUserMessage (e, options = {}) {
if (text) {
contents.push({
type: 'text',
content: text
text
})
}
return {
@ -134,7 +134,7 @@ export async function getPreset (e, presetId, toggleMode, togglePrefix) {
* @returns {boolean}
*/
export function checkChatMsg (e, toggleMode, togglePrefix) {
if (toggleMode === 'at' && e.atBot) {
if (toggleMode === 'at' && (e.atBot || e.isPrivate)) {
return true
}
const prefixReg = new RegExp(`^#?(图片)?${togglePrefix}[^gpt][sS]*`)