From f8f5f8f83a690e11c1faec848da2713739070878 Mon Sep 17 00:00:00 2001 From: zyc404 Date: Tue, 7 May 2024 14:33:52 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0bing=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E6=96=B9suno=E7=94=9F=E6=88=90=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- model/core.js | 7 +++- resources/view/setting_view.json | 6 +++ utils/BingSuno.js | 70 ++++++++++++++++++++++++++++++++ utils/config.js | 1 + 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/model/core.js b/model/core.js index 6360f72..c9db5df 100644 --- a/model/core.js +++ b/model/core.js @@ -259,7 +259,12 @@ class Core { }) redis.set(`CHATGPT:SUNO:${e.sender.user_id}`, 'c', { EX: 30 }).then(() => { try { - client.getSuno(prompt, e) + if (Config.bingLocalSuno) { + // 调用本地Suno配置进行歌曲生成 + client.getLocalSuno(prompt, e) + } else { + client.getSuno(prompt, e) + } } catch (err) { redis.del(`CHATGPT:SUNO:${e.sender.user_id}`) this.reply('歌曲生成失败:' + err) diff --git a/resources/view/setting_view.json b/resources/view/setting_view.json index 5eaf4e7..653c093 100644 --- a/resources/view/setting_view.json +++ b/resources/view/setting_view.json @@ -587,6 +587,12 @@ "placeholder": "使用AP插件代替Bing进行绘图", "data": "bingAPDraw" }, + { + "type": "check", + "label": "第三方歌曲生成", + "placeholder": "使用AP插件代替Bing进行绘图", + "data": "bingLocalSuno" + }, { "type": "textarea", "label": "前置对话第一轮(用户)", diff --git a/utils/BingSuno.js b/utils/BingSuno.js index b348f0c..8ccccde 100644 --- a/utils/BingSuno.js +++ b/utils/BingSuno.js @@ -1,8 +1,11 @@ import { downloadFile } from '../utils/common.js' +import { SunoClient } from '../client/SunoClient.js' +import { Config } from '../utils/config.js' import common from '../../../lib/common/common.js' import fs from 'fs' import crypto from 'crypto' import fetch from 'node-fetch' +import lodash from 'lodash' export default class BingSunoClient { constructor(opts) { @@ -76,6 +79,73 @@ export default class BingSunoClient { } } + async getLocalSuno(prompt, e) { + if (!Config.sunoClientToken || !Config.sunoSessToken) { + await e.reply('未配置Suno Token') + return true + } + let description = prompt.songPrompt + await e.reply('正在生成,请稍后') + try { + let sessTokens = Config.sunoSessToken.split(',') + let clientTokens = Config.sunoClientToken.split(',') + let tried = 0 + while (tried < sessTokens.length) { + let index = tried + let sess = sessTokens[index] + let clientToken = clientTokens[index] + let client = new SunoClient({ sessToken: sess, clientToken }) + let { credit, email } = await client.queryCredit() + logger.info({ credit, email }) + if (credit < 10) { + tried++ + logger.info(`账户${email}余额不足,尝试下一个账户`) + continue + } + + let songs = await client.createSong(description) + if (!songs || songs.length === 0) { + e.reply('生成失败,可能是提示词太长或者违规,请检查日志') + return + } + let messages = ['提示词:' + description] + for (let song of songs) { + messages.push(`歌名:${song.title}\n风格: ${song.metadata.tags}\n长度: ${lodash.round(song.metadata.duration, 0)}秒\n歌词:\n${song.metadata.prompt}\n`) + messages.push(`音频链接:${song.audio_url}\n视频链接:${song.video_url}\n封面链接:${song.image_url}\n`) + messages.push(segment.image(song.image_url)) + let retry = 3 + let videoPath + while (!videoPath && retry >= 0) { + try { + videoPath = await downloadFile(song.video_url, `suno/${song.title}.mp4`, false, false, { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36' + }) + } catch (err) { + retry-- + await common.sleep(1000) + } + } + if (videoPath) { + const data = fs.readFileSync(videoPath) + messages.push(segment.video(`base64://${data.toString('base64')}`)) + // 60秒后删除文件避免占用体积 + setTimeout(() => { + fs.unlinkSync(videoPath) + }, 60000) + } else { + logger.warn(`${song.title}下载视频失败,仅发送视频链接`) + } + } + await e.reply(await common.makeForwardMsg(e, messages, '音乐合成结果')) + return true + } + await e.reply('所有账户余额不足') + } catch (err) { + console.error(err) + await e.reply('生成失败,请查看日志') + } + } + async getSunoResult(requestId) { const skey = await this.#getSunoMetadata(requestId) if (skey) { diff --git a/utils/config.js b/utils/config.js index 54dfa8a..830dbf5 100644 --- a/utils/config.js +++ b/utils/config.js @@ -104,6 +104,7 @@ const defaultConfig = { sydneyApologyIgnored: true, enforceMaster: false, bingAPDraw: false, + bingLocalSuno: false, serverPort: 3321, serverHost: '', viewHost: '', From 991c63bb26c657a49b4607a8b066ac2e3a5036ac Mon Sep 17 00:00:00 2001 From: zyc404 Date: Tue, 7 May 2024 14:41:05 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86?= =?UTF-8?q?=E9=80=82=E9=85=8D=E5=99=A8=E4=B8=8D=E6=94=AF=E6=8C=81pickMembe?= =?UTF-8?q?r=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server/index.js b/server/index.js index 3ff5901..443ec1b 100644 --- a/server/index.js +++ b/server/index.js @@ -445,7 +445,13 @@ export async function createServer () { Bot.on('message', e => { e.message = e.message.map(item => { if (item.type === 'at') { - return { ...item, text: e.group.pickMember(parseInt(item.qq)).card || e.group.pickMember(parseInt(item.qq)).nickname } + let user + try { + user = e.group.pickMember(parseInt(item.qq)).card || e.group.pickMember(parseInt(item.qq)).nickname + } catch (error) { + user = item.qq + } + return { ...item, text: user } } return item })