mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-17 13:57:10 +00:00
feat: add support for chatglm
This commit is contained in:
parent
9929d55bea
commit
94d5691e8a
5 changed files with 164 additions and 15 deletions
46
apps/chat.js
46
apps/chat.js
|
|
@ -22,6 +22,7 @@ import fetch from 'node-fetch'
|
||||||
import { deleteConversation, getConversations, getLatestMessageIdByConversationId } from '../utils/conversation.js'
|
import { deleteConversation, getConversations, getLatestMessageIdByConversationId } from '../utils/conversation.js'
|
||||||
import { convertSpeaker, generateAudio, speakers } from '../utils/tts.js'
|
import { convertSpeaker, generateAudio, speakers } from '../utils/tts.js'
|
||||||
import { segment } from 'oicq'
|
import { segment } from 'oicq'
|
||||||
|
import ChatGLMClient from "../utils/chatglm.js";
|
||||||
try {
|
try {
|
||||||
await import('keyv')
|
await import('keyv')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -194,6 +195,21 @@ export class chatgpt extends plugin {
|
||||||
logger.info(`SydneyUser_${e.sender.user_id}`, await conversationsCache.get(`SydneyUser_${e.sender.user_id}`))
|
logger.info(`SydneyUser_${e.sender.user_id}`, await conversationsCache.get(`SydneyUser_${e.sender.user_id}`))
|
||||||
await conversationsCache.delete(`SydneyUser_${e.sender.user_id}`)
|
await conversationsCache.delete(`SydneyUser_${e.sender.user_id}`)
|
||||||
await this.reply('已退出当前对话,该对话仍然保留。请@我进行聊天以开启新的对话', true)
|
await this.reply('已退出当前对话,该对话仍然保留。请@我进行聊天以开启新的对话', true)
|
||||||
|
} else if (use === 'chatglm') {
|
||||||
|
const conversation = {
|
||||||
|
store: new KeyvFile({ filename: 'cache.json' }),
|
||||||
|
namespace: 'chatglm'
|
||||||
|
}
|
||||||
|
let Keyv
|
||||||
|
try {
|
||||||
|
Keyv = (await import('keyv')).default
|
||||||
|
} catch (err) {
|
||||||
|
await this.reply('依赖keyv未安装,请执行pnpm install keyv', true)
|
||||||
|
}
|
||||||
|
const conversationsCache = new Keyv(conversation)
|
||||||
|
logger.info(`ChatGLMUser_${e.sender.user_id}`, await conversationsCache.get(`SydneyUser_${e.sender.user_id}`))
|
||||||
|
await conversationsCache.delete(`SydneyUser_${e.sender.user_id}`)
|
||||||
|
await this.reply('已退出当前对话,该对话仍然保留。请@我进行聊天以开启新的对话', true)
|
||||||
} else {
|
} else {
|
||||||
let c = await redis.get(`CHATGPT:CONVERSATIONS:${e.sender.user_id}`)
|
let c = await redis.get(`CHATGPT:CONVERSATIONS:${e.sender.user_id}`)
|
||||||
if (!c) {
|
if (!c) {
|
||||||
|
|
@ -224,6 +240,21 @@ export class chatgpt extends plugin {
|
||||||
const conversationsCache = new Keyv(conversation)
|
const conversationsCache = new Keyv(conversation)
|
||||||
await conversationsCache.delete(`SydneyUser_${qq}`)
|
await conversationsCache.delete(`SydneyUser_${qq}`)
|
||||||
await this.reply('已退出当前对话,该对话仍然保留。请@我进行聊天以开启新的对话', true)
|
await this.reply('已退出当前对话,该对话仍然保留。请@我进行聊天以开启新的对话', true)
|
||||||
|
} else if (use === 'chatglm') {
|
||||||
|
const conversation = {
|
||||||
|
store: new KeyvFile({ filename: 'cache.json' }),
|
||||||
|
namespace: 'chatglm'
|
||||||
|
}
|
||||||
|
let Keyv
|
||||||
|
try {
|
||||||
|
Keyv = (await import('keyv')).default
|
||||||
|
} catch (err) {
|
||||||
|
await this.reply('依赖keyv未安装,请执行pnpm install keyv', true)
|
||||||
|
}
|
||||||
|
const conversationsCache = new Keyv(conversation)
|
||||||
|
logger.info(`SydneyUser_${e.sender.user_id}`, await conversationsCache.get(`SydneyUser_${e.sender.user_id}`))
|
||||||
|
await conversationsCache.delete(`ChatGLMUser_${qq}`)
|
||||||
|
await this.reply('已退出当前对话,该对话仍然保留。请@我进行聊天以开启新的对话', true)
|
||||||
} else {
|
} else {
|
||||||
let c = await redis.get(`CHATGPT:CONVERSATIONS:${qq}`)
|
let c = await redis.get(`CHATGPT:CONVERSATIONS:${qq}`)
|
||||||
if (!c) {
|
if (!c) {
|
||||||
|
|
@ -527,9 +558,6 @@ export class chatgpt extends plugin {
|
||||||
if (!lastMessageId) {
|
if (!lastMessageId) {
|
||||||
lastMessageId = await getLatestMessageIdByConversationId(conversationId, newFetch)
|
lastMessageId = await getLatestMessageIdByConversationId(conversationId, newFetch)
|
||||||
}
|
}
|
||||||
// let lastMessagePrompt = await redis.get(`CHATGPT:CONVERSATION_LAST_MESSAGE_PROMPT:${conversationId}`)
|
|
||||||
// let conversationCreateTime = await redis.get(`CHATGPT:CONVERSATION_CREATE_TIME:${conversationId}`)
|
|
||||||
// let conversationLength = await redis.get(`CHATGPT:CONVERSATION_LENGTH:${conversationId}`)
|
|
||||||
conversation = {
|
conversation = {
|
||||||
conversationId,
|
conversationId,
|
||||||
parentMessageId: lastMessageId
|
parentMessageId: lastMessageId
|
||||||
|
|
@ -855,6 +883,18 @@ export class chatgpt extends plugin {
|
||||||
}
|
}
|
||||||
return sendMessageResult
|
return sendMessageResult
|
||||||
}
|
}
|
||||||
|
case 'chatglm': {
|
||||||
|
const cacheOptions = {
|
||||||
|
namespace: 'chatglm_6b',
|
||||||
|
store: new KeyvFile({ filename: 'cache.json' })
|
||||||
|
}
|
||||||
|
this.chatGPTApi = new ChatGLMClient({
|
||||||
|
user: e.sender.user_id,
|
||||||
|
cache: cacheOptions
|
||||||
|
})
|
||||||
|
let sendMessageResult = await this.chatGPTApi.sendMessage(prompt, conversation)
|
||||||
|
return sendMessageResult
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
let completionParams = {}
|
let completionParams = {}
|
||||||
if (Config.model) {
|
if (Config.model) {
|
||||||
|
|
|
||||||
|
|
@ -128,8 +128,8 @@ let helpData = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'switch',
|
icon: 'switch',
|
||||||
title: '#chatgpt切换浏览器/API/API2/API3/Bing',
|
title: '#chatgpt切换浏览器/API/API3/Bing/ChatGLM',
|
||||||
desc: '切换使用的后端为浏览器或OpenAI API/第三方API/反代官网API/Bing'
|
desc: '切换使用的后端为浏览器或OpenAI API/反代官网API/Bing/自建ChatGLM'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'confirm',
|
icon: 'confirm',
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,8 @@ export class ChatgptManagement extends plugin {
|
||||||
permission: 'master'
|
permission: 'master'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
reg: '^#chatgpt切换API2$',
|
reg: '^#chatgpt切换(ChatGLM|chatglm)$',
|
||||||
fnc: 'useReversedAPIBasedSolution',
|
fnc: 'useChatGLMSolution',
|
||||||
permission: 'master'
|
permission: 'master'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -207,10 +207,9 @@ export class ChatgptManagement extends plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async useReversedAPIBasedSolution (e) {
|
async useChatGLMSolution (e) {
|
||||||
await this.reply('API2已废弃,处于不可用状态,不会为你切换')
|
await redis.set('CHATGPT:USE', 'chatglm')
|
||||||
// await redis.set('CHATGPT:USE', 'apiReverse')
|
await this.reply('已切换到ChatGLM-6B解决方案,如果已经对话过建议执行`#结束对话`避免引起404错误')
|
||||||
// await this.reply('【暂时不可用,请关注仓库更新和群公告】已切换到基于第三方Reversed CompletionAPI的解决方案,如果已经对话过建议执行`#结束对话`避免引起404错误')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async useReversedAPIBasedSolution2 (e) {
|
async useReversedAPIBasedSolution2 (e) {
|
||||||
|
|
@ -340,10 +339,11 @@ export class ChatgptManagement extends plugin {
|
||||||
let mode = await redis.get('CHATGPT:USE')
|
let mode = await redis.get('CHATGPT:USE')
|
||||||
const modeMap = {
|
const modeMap = {
|
||||||
browser: '浏览器',
|
browser: '浏览器',
|
||||||
apiReverse: 'API2',
|
// apiReverse: 'API2',
|
||||||
api: 'API',
|
api: 'API',
|
||||||
bing: '必应',
|
bing: '必应',
|
||||||
api3: 'API3'
|
api3: 'API3',
|
||||||
|
chatglm: 'ChatGLM-6B'
|
||||||
}
|
}
|
||||||
let modeText = modeMap[mode || 'api']
|
let modeText = modeMap[mode || 'api']
|
||||||
let message = ` API模式和浏览器模式如何选择?
|
let message = ` API模式和浏览器模式如何选择?
|
||||||
|
|
@ -357,7 +357,9 @@ export class ChatgptManagement extends plugin {
|
||||||
|
|
||||||
必应(Bing)将调用微软新必应接口进行对话。需要在必应网页能够正常使用新必应且设置有效的Bing 登录Cookie方可使用。#chatgpt设置必应token
|
必应(Bing)将调用微软新必应接口进行对话。需要在必应网页能够正常使用新必应且设置有效的Bing 登录Cookie方可使用。#chatgpt设置必应token
|
||||||
|
|
||||||
您可以使用‘#chatgpt切换浏览器/API/API2/API3/Bing’来切换到指定模式。
|
自建ChatGLM模式会调用自建的ChatGLM-6B服务器API进行对话,需要自建。参考https://github.com/ikechan8370/SimpleChatGLM6BAPI
|
||||||
|
|
||||||
|
您可以使用‘#chatgpt切换浏览器/API/API3/Bing/ChatGLM’来切换到指定模式。
|
||||||
|
|
||||||
当前为${modeText}模式。
|
当前为${modeText}模式。
|
||||||
`
|
`
|
||||||
|
|
|
||||||
106
utils/chatglm.js
Normal file
106
utils/chatglm.js
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
import { Config } from './config.js'
|
||||||
|
import fetch from 'node-fetch'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
async function getKeyv () {
|
||||||
|
let Keyv
|
||||||
|
try {
|
||||||
|
Keyv = (await import('keyv')).default
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error('keyv依赖未安装,请使用pnpm install keyv安装')
|
||||||
|
}
|
||||||
|
return Keyv
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class ChatGLMClient {
|
||||||
|
constructor (opts) {
|
||||||
|
// user: qq号
|
||||||
|
this.opts = opts
|
||||||
|
}
|
||||||
|
|
||||||
|
async initCache () {
|
||||||
|
if (!this.conversationsCache) {
|
||||||
|
const cacheOptions = this.opts.cache || {}
|
||||||
|
cacheOptions.namespace = cacheOptions.namespace || 'chatglm'
|
||||||
|
let Keyv = await getKeyv()
|
||||||
|
this.conversationsCache = new Keyv(cacheOptions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendMessage (prompt, opts) {
|
||||||
|
const {
|
||||||
|
conversationId = uuidv4(),
|
||||||
|
messageId = uuidv4(),
|
||||||
|
parentMessageId,
|
||||||
|
temperature = Config.temperature
|
||||||
|
} = opts
|
||||||
|
await this.initCache()
|
||||||
|
let url = Config.chatglmBaseUrl + '/api/chat'
|
||||||
|
if (Config.debug) {
|
||||||
|
logger.info('use chatglm api server endpoint: ' + url)
|
||||||
|
}
|
||||||
|
const conversationKey = `ChatGLMUser_${this.opts.user}`
|
||||||
|
const conversation = (await this.conversationsCache.get(conversationKey)) || {
|
||||||
|
messages: [],
|
||||||
|
createdAt: Date.now()
|
||||||
|
}
|
||||||
|
let history = getMessagesForConversation(conversation.messages, parentMessageId)
|
||||||
|
if (Config.debug) {
|
||||||
|
logger.info(history)
|
||||||
|
}
|
||||||
|
console.log(history)
|
||||||
|
let option = {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
prompt,
|
||||||
|
temperature,
|
||||||
|
history
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
library: 'chatgpt-plugin'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let response = await fetch(url, option)
|
||||||
|
let result = await response.text()
|
||||||
|
try {
|
||||||
|
result = JSON.parse(result)
|
||||||
|
conversation.messages.push({
|
||||||
|
id: messageId,
|
||||||
|
role: 'user',
|
||||||
|
content: prompt,
|
||||||
|
parentMessageId
|
||||||
|
})
|
||||||
|
let responseId = uuidv4()
|
||||||
|
conversation.messages.push({
|
||||||
|
id: responseId,
|
||||||
|
role: 'AI',
|
||||||
|
content: result.data,
|
||||||
|
parentMessageId: messageId
|
||||||
|
})
|
||||||
|
await this.conversationsCache.set(conversationKey, conversation)
|
||||||
|
return {
|
||||||
|
conversationId,
|
||||||
|
id: responseId,
|
||||||
|
text: result.data
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(result)
|
||||||
|
throw new Error(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMessagesForConversation (messages, parentMessageId) {
|
||||||
|
const orderedMessages = []
|
||||||
|
let currentMessageId = parentMessageId
|
||||||
|
while (currentMessageId) {
|
||||||
|
const message = messages.find((m) => m.id === currentMessageId)
|
||||||
|
if (!message) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
orderedMessages.unshift(message)
|
||||||
|
currentMessageId = message.parentMessageId
|
||||||
|
}
|
||||||
|
|
||||||
|
return orderedMessages
|
||||||
|
}
|
||||||
|
|
@ -66,7 +66,8 @@ const defaultConfig = {
|
||||||
initiativeChatGroups: [],
|
initiativeChatGroups: [],
|
||||||
enableDraw: true,
|
enableDraw: true,
|
||||||
helloPrompt: '写一段话让大家来找我聊天。类似于“有人找我聊天吗?"这种风格,轻松随意一点控制在20个字以内',
|
helloPrompt: '写一段话让大家来找我聊天。类似于“有人找我聊天吗?"这种风格,轻松随意一点控制在20个字以内',
|
||||||
version: 'v2.2.3'
|
chatglmBaseUrl: 'http://localhost:8080',
|
||||||
|
version: 'v2.2.4'
|
||||||
}
|
}
|
||||||
const _path = process.cwd()
|
const _path = process.cwd()
|
||||||
let config = {}
|
let config = {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue