mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-17 22:07:10 +00:00
commit
e9217f5321
5 changed files with 153 additions and 43 deletions
51
apps/chat.js
51
apps/chat.js
|
|
@ -2,10 +2,8 @@ import plugin from '../../../lib/plugins/plugin.js'
|
||||||
import common from '../../../lib/common/common.js'
|
import common from '../../../lib/common/common.js'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { Config } from '../utils/config.js'
|
import { Config } from '../utils/config.js'
|
||||||
import { v4 as uuid } from 'uuid'
|
|
||||||
import AzureTTS from '../utils/tts/microsoft-azure.js'
|
import AzureTTS from '../utils/tts/microsoft-azure.js'
|
||||||
import VoiceVoxTTS from '../utils/tts/voicevox.js'
|
import VoiceVoxTTS from '../utils/tts/voicevox.js'
|
||||||
import BingSunoClient from '../utils/BingSuno.js'
|
|
||||||
import {
|
import {
|
||||||
completeJSON,
|
completeJSON,
|
||||||
formatDate,
|
formatDate,
|
||||||
|
|
@ -21,8 +19,7 @@ import {
|
||||||
makeForwardMsg,
|
makeForwardMsg,
|
||||||
randomString,
|
randomString,
|
||||||
render,
|
render,
|
||||||
renderUrl,
|
renderUrl
|
||||||
extractMarkdownJson
|
|
||||||
} from '../utils/common.js'
|
} from '../utils/common.js'
|
||||||
|
|
||||||
import fetch from 'node-fetch'
|
import fetch from 'node-fetch'
|
||||||
|
|
@ -34,6 +31,7 @@ import XinghuoClient from '../utils/xinghuo/xinghuo.js'
|
||||||
import { getProxy } from '../utils/proxy.js'
|
import { getProxy } from '../utils/proxy.js'
|
||||||
import { generateSuggestedResponse } from '../utils/chat.js'
|
import { generateSuggestedResponse } from '../utils/chat.js'
|
||||||
import Core from '../model/core.js'
|
import Core from '../model/core.js'
|
||||||
|
import { collectProcessors } from '../utils/postprocessors/BasicProcessor.js'
|
||||||
|
|
||||||
let version = Config.version
|
let version = Config.version
|
||||||
let proxy = getProxy()
|
let proxy = getProxy()
|
||||||
|
|
@ -785,45 +783,16 @@ export class chatgpt extends plugin {
|
||||||
await redis.set(key, JSON.stringify(previousConversation), Config.conversationPreserveTime > 0 ? { EX: Config.conversationPreserveTime } : {})
|
await redis.set(key, JSON.stringify(previousConversation), Config.conversationPreserveTime > 0 ? { EX: Config.conversationPreserveTime } : {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 处理suno生成
|
|
||||||
if (Config.enableChatSuno) {
|
|
||||||
let client = new BingSunoClient() // 此处使用了bing的suno客户端,后续和本地suno合并
|
|
||||||
const sunoList = extractMarkdownJson(chatMessage.text)
|
|
||||||
if (sunoList.length == 0) {
|
|
||||||
const lyrics = client.extractLyrics(chatMessage.text)
|
|
||||||
if (lyrics !== '') {
|
|
||||||
sunoList.push(
|
|
||||||
{
|
|
||||||
json: { option: 'Suno', tags: client.generateRandomStyle(), title: `${e.sender.nickname}之歌`, lyrics },
|
|
||||||
markdown: null,
|
|
||||||
origin: lyrics
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let suno of sunoList) {
|
|
||||||
if (suno.json.option == 'Suno') {
|
|
||||||
chatMessage.text = chatMessage.text.replace(suno.origin, `歌曲 《${suno.json.title}》`)
|
|
||||||
logger.info(`开始生成歌曲${suno.json.tags}`)
|
|
||||||
redis.set(`CHATGPT:SUNO:${e.sender.user_id}`, 'c', { EX: 30 }).then(() => {
|
|
||||||
try {
|
|
||||||
if (Config.SunoModel == 'local') {
|
|
||||||
// 调用本地Suno配置进行歌曲生成
|
|
||||||
client.getLocalSuno(suno.json, e)
|
|
||||||
} else if (Config.SunoModel == 'api') {
|
|
||||||
// 调用第三方Suno配置进行歌曲生成
|
|
||||||
client.getApiSuno(suno.json, e)
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
redis.del(`CHATGPT:SUNO:${e.sender.user_id}`)
|
|
||||||
this.reply('歌曲生成失败:' + err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let response = chatMessage?.text?.replace('\n\n\n', '\n')
|
let response = chatMessage?.text?.replace('\n\n\n', '\n')
|
||||||
|
let postProcessors = await collectProcessors('post')
|
||||||
let thinking = chatMessage.thinking_text
|
let thinking = chatMessage.thinking_text
|
||||||
|
for (let processor of postProcessors) {
|
||||||
|
let output = await processor.processInner({
|
||||||
|
text: response, thinking
|
||||||
|
})
|
||||||
|
response = output.text
|
||||||
|
thinking = output.thinking_text
|
||||||
|
}
|
||||||
if (handler.has('chatgpt.response.post')) {
|
if (handler.has('chatgpt.response.post')) {
|
||||||
logger.debug('调用后处理器: chatgpt.response.post')
|
logger.debug('调用后处理器: chatgpt.response.post')
|
||||||
handler.call('chatgpt.response.post', this.e, {
|
handler.call('chatgpt.response.post', this.e, {
|
||||||
|
|
|
||||||
72
utils/postprocessors/BasicProcessor.js
Normal file
72
utils/postprocessors/BasicProcessor.js
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
import fs from 'fs'
|
||||||
|
import path from 'path'
|
||||||
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
|
export class AbstractPostProcessor {
|
||||||
|
name = ''
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
* @type {'pre' | 'post'}
|
||||||
|
*/
|
||||||
|
type = 'post'
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {{
|
||||||
|
* text: string,
|
||||||
|
* thinking_text?: string
|
||||||
|
* }} input
|
||||||
|
* @returns {Promise<{
|
||||||
|
* text: string,
|
||||||
|
* thinking_text?: string
|
||||||
|
* }>}
|
||||||
|
*/
|
||||||
|
async processInner (input) {}
|
||||||
|
}
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* collect
|
||||||
|
* @param {'pre' | 'post' | undefined} type
|
||||||
|
* @return {Promise<AbstractPostProcessor[]>}
|
||||||
|
*/
|
||||||
|
export async function collectProcessors (type) {
|
||||||
|
const processors = []
|
||||||
|
const directoryPath = __dirname // 当前目录
|
||||||
|
|
||||||
|
// 读取目录中的所有文件
|
||||||
|
const files = fs.readdirSync(directoryPath)
|
||||||
|
|
||||||
|
// 遍历所有文件,筛选出.js文件
|
||||||
|
for (const file of files) {
|
||||||
|
if (file.endsWith('.js') && file !== 'BasicProcessor.js') { // 排除自己
|
||||||
|
const fullPath = path.join(directoryPath, file)
|
||||||
|
try {
|
||||||
|
// 动态导入模块
|
||||||
|
const module = await import(fullPath)
|
||||||
|
|
||||||
|
// 遍历模块的所有导出成员
|
||||||
|
for (const key of Object.keys(module)) {
|
||||||
|
const ExportedClass = module[key]
|
||||||
|
|
||||||
|
// 确保它是一个类,并且继承了 AbstractPostProcessor
|
||||||
|
if (typeof ExportedClass === 'function' &&
|
||||||
|
Object.getPrototypeOf(ExportedClass) !== null) {
|
||||||
|
const parent = Object.getPrototypeOf(ExportedClass)
|
||||||
|
if (parent.name === 'AbstractPostProcessor') {
|
||||||
|
let instance = new ExportedClass()
|
||||||
|
if (!type || instance.type === type) {
|
||||||
|
processors.push(instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// console.error(`Error processing file ${file}:`, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return processors
|
||||||
|
}
|
||||||
54
utils/postprocessors/ReasonerProcessor.js
Normal file
54
utils/postprocessors/ReasonerProcessor.js
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { AbstractPostProcessor } from './BasicProcessor.js'
|
||||||
|
|
||||||
|
export class ReasonerProcessor extends AbstractPostProcessor {
|
||||||
|
constructor () {
|
||||||
|
super()
|
||||||
|
this.name = 'ReasonerPostProcessor'
|
||||||
|
this.type = 'post'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {{
|
||||||
|
* text: string,
|
||||||
|
* thinking_text?: string
|
||||||
|
* }} input
|
||||||
|
* @returns {Promise<{
|
||||||
|
* text: string,
|
||||||
|
* thinking_text?: string
|
||||||
|
* }>}
|
||||||
|
*/
|
||||||
|
async processInner (input) {
|
||||||
|
logger.debug('Running into ReasonerPostProcessor')
|
||||||
|
const { text, thinkingText } = extractThinkingTextAndText(input.text)
|
||||||
|
return {
|
||||||
|
text,
|
||||||
|
thinking_text: (input.thinking_text ? input.thinking_text : '') + thinkingText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* written by gpt-4o
|
||||||
|
* @param str
|
||||||
|
* @returns {{thinkingText: string, text: *}|{thinkingText: *, text: *}}
|
||||||
|
*/
|
||||||
|
const extractThinkingTextAndText = (str) => {
|
||||||
|
// 使用正则表达式提取think标签内容
|
||||||
|
const thinkRegex = /<think>(.*?)<\/think>/s
|
||||||
|
const match = str.match(thinkRegex)
|
||||||
|
|
||||||
|
// 如果找到了<think>标签内容
|
||||||
|
if (match) {
|
||||||
|
// thinking_text就是<think>标签内的内容
|
||||||
|
const thinkingText = match[1].trim()
|
||||||
|
|
||||||
|
// text就是</think>标签后的部分
|
||||||
|
const text = str.slice(match.index + match[0].length).trim()
|
||||||
|
|
||||||
|
return { thinkingText, text }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有<think>标签内容,返回空或原始内容
|
||||||
|
return { thinkingText: '', text: str.trim() }
|
||||||
|
}
|
||||||
|
|
@ -43,7 +43,7 @@ export class QueryStarRailTool extends AbstractTool {
|
||||||
e.user_id = qq
|
e.user_id = qq
|
||||||
e.isSr = true
|
e.isSr = true
|
||||||
await ProfileList.render(e)
|
await ProfileList.render(e)
|
||||||
return 'the player panel of genshin impact has been sent to group. you don\'t need text version'
|
return 'the player panel of star rail has been sent to group. you don\'t need text version'
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return `failed to query, error: ${err.toString()}`
|
return `failed to query, error: ${err.toString()}`
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,22 @@ export class SendMusicTool extends AbstractTool {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let group = await e.bot.pickGroup(target)
|
let group = await e.bot.pickGroup(target)
|
||||||
await group.shareMusic('163', id)
|
|
||||||
|
// 检查是否支持 shareMusic 方法
|
||||||
|
if (typeof group.shareMusic === 'function') {
|
||||||
|
await group.shareMusic('163', id)
|
||||||
|
} else {
|
||||||
|
// 构建音乐分享消息
|
||||||
|
const musicMsg = {
|
||||||
|
type: 'music',
|
||||||
|
data: {
|
||||||
|
type: '163',
|
||||||
|
id: id,
|
||||||
|
jumpUrl: `https://music.163.com/#/song?id=${id}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await e.reply(musicMsg)
|
||||||
|
}
|
||||||
return `the music has been shared to ${target}`
|
return `the music has been shared to ${target}`
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return `music share failed: ${e}`
|
return `music share failed: ${e}`
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue