mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-16 13:27:08 +00:00
添加对bing suno插件的支持
This commit is contained in:
parent
33e04c1c24
commit
ec47a4d9b0
3 changed files with 236 additions and 4 deletions
|
|
@ -15,6 +15,7 @@ import _ from 'lodash'
|
|||
import { getChatHistoryGroup } from '../utils/chat.js'
|
||||
import { APTool } from '../utils/tools/APTool.js'
|
||||
import BingDrawClient from '../utils/BingDraw.js'
|
||||
import BingSunoClient from '../utils/BingSuno.js'
|
||||
import { solveCaptchaOneShot } from '../utils/bingCaptcha.js'
|
||||
import { OfficialChatGPTClient } from '../utils/message.js'
|
||||
import ChatGLMClient from '../utils/chatglm.js'
|
||||
|
|
@ -251,6 +252,20 @@ class Core {
|
|||
})
|
||||
}
|
||||
}
|
||||
opt.onSunoCreateRequest = prompt => {
|
||||
logger.mark(`开始生成内容:Suno ${prompt.songtId}`)
|
||||
let client = new BingSunoClient({
|
||||
cookies: cookies
|
||||
})
|
||||
redis.set(`CHATGPT:SUNO:${e.sender.user_id}`, 'c', { EX: 30 }).then(() => {
|
||||
try {
|
||||
client.getSuno(prompt, e)
|
||||
} catch (err) {
|
||||
redis.del(`CHATGPT:SUNO:${e.sender.user_id}`)
|
||||
this.reply('歌曲生成失败:' + err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
response = await bingAIClient.sendMessage(prompt, opt, (token) => {
|
||||
reply += token
|
||||
|
|
|
|||
192
utils/BingSuno.js
Normal file
192
utils/BingSuno.js
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
import { downloadFile } from '../utils/common.js'
|
||||
import common from '../../../lib/common/common.js'
|
||||
import fs from 'fs'
|
||||
import crypto from 'crypto'
|
||||
import fetch from 'node-fetch'
|
||||
|
||||
export default class BingSunoClient {
|
||||
constructor(opts) {
|
||||
this.opts = opts
|
||||
}
|
||||
|
||||
async replyMsg(song, e) {
|
||||
let messages = []
|
||||
messages.push(`歌名:${song.title}\n风格: ${song.musicalStyle}\n长度: ${song.duration}秒\n歌词:\n${song.prompt}\n`)
|
||||
messages.push(`音频链接:${song.audioURL}\n视频链接:${song.videoURL}\n封面链接:${song.imageURL}\n`)
|
||||
messages.push(segment.image(song.imageURL))
|
||||
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, '音乐合成结果'))
|
||||
}
|
||||
|
||||
async getSuno(prompt, e) {
|
||||
if (prompt.cookie) {
|
||||
this.opts.cookies = prompt.cookie
|
||||
}
|
||||
|
||||
const sunoResult = await this.getSunoResult(prompt.songtId)
|
||||
if (sunoResult) {
|
||||
const {
|
||||
duration,
|
||||
title,
|
||||
musicalStyle,
|
||||
requestId,
|
||||
} = sunoResult
|
||||
const generateURL = id => `https://th.bing.com/th?&id=${id}`
|
||||
const audioURL = generateURL(`OIG.a_${requestId}`)
|
||||
const imageURL = generateURL(`OIG.i_${requestId}`)
|
||||
const videoURL = generateURL(`OIG.v_${requestId}`)
|
||||
const sunoURL = `https://cdn1.suno.ai/${requestId}.mp4`
|
||||
const sunoDisplayResult = {
|
||||
title,
|
||||
duration,
|
||||
musicalStyle,
|
||||
audioURL,
|
||||
imageURL,
|
||||
videoURL,
|
||||
sunoURL,
|
||||
prompt: prompt.songPrompt
|
||||
}
|
||||
await e.reply('Bing Suno 生成中,请稍后')
|
||||
replyMsg(sunoDisplayResult, e)
|
||||
} else {
|
||||
await e.reply('Bing Suno 数据获取失败')
|
||||
redis.del(`CHATGPT:SUNO:${e.sender.user_id}`)
|
||||
}
|
||||
}
|
||||
|
||||
async getSunoResult(requestId) {
|
||||
const skey = await this.#getSunoMetadata(requestId)
|
||||
if (skey) {
|
||||
const sunoMedia = await this.#getSunoMedia(requestId, skey)
|
||||
return sunoMedia
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
async #getSunoMetadata(requestId) {
|
||||
const fetchURL = new URL('https://www.bing.com/videos/music')
|
||||
const searchParams = new URLSearchParams({
|
||||
vdpp: 'suno',
|
||||
kseed: '7500',
|
||||
SFX: '2',
|
||||
q: '',
|
||||
iframeid: crypto.randomUUID(),
|
||||
requestId,
|
||||
})
|
||||
fetchURL.search = searchParams.toString()
|
||||
const response = await fetch(fetchURL, {
|
||||
headers: {
|
||||
accept: 'text/html',
|
||||
cookie: this.opts.cookies,
|
||||
},
|
||||
method: 'GET',
|
||||
})
|
||||
if (response.status === 200) {
|
||||
const document = await response.text()
|
||||
|
||||
const patternSkey = /(?<=skey=)[^&]+/
|
||||
const matchSkey = document.match(patternSkey)
|
||||
const skey = matchSkey ? matchSkey[0] : null
|
||||
|
||||
const patternIG = /(?<=IG:"|IG:\s")[0-9A-F]{32}(?=")/
|
||||
const matchIG = document.match(patternIG)
|
||||
const ig = matchIG ? matchIG[0] : null
|
||||
|
||||
return { skey, ig }
|
||||
} else {
|
||||
console.error(`HTTP error! Error: ${response.error}, Status: ${response.status}`)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async #getSunoMedia(requestId, sunoMetadata) {
|
||||
let sfx = 1
|
||||
const maxTries = 30
|
||||
const { skey, ig } = sunoMetadata
|
||||
|
||||
let rawResponse
|
||||
const result = await new Promise((resolve, reject) => {
|
||||
const intervalId = setInterval(async () => {
|
||||
const fetchURL = new URL('https://www.bing.com/videos/api/custom/music')
|
||||
const searchParams = new URLSearchParams({
|
||||
skey,
|
||||
safesearch: 'Moderate',
|
||||
vdpp: 'suno',
|
||||
requestId,
|
||||
ig,
|
||||
iid: 'vsn',
|
||||
sfx: sfx.toString(),
|
||||
})
|
||||
fetchURL.search = searchParams.toString()
|
||||
|
||||
const response = await fetch(fetchURL, {
|
||||
headers: {
|
||||
accept: '*/*',
|
||||
cookie: this.opts.cookies,
|
||||
},
|
||||
method: 'GET',
|
||||
})
|
||||
try {
|
||||
const body = await response.json()
|
||||
rawResponse = JSON.parse(body.RawResponse)
|
||||
const { status } = rawResponse
|
||||
const done = status === 'complete'
|
||||
|
||||
if (done) {
|
||||
clearInterval(intervalId)
|
||||
resolve()
|
||||
} else {
|
||||
sfx++
|
||||
if (sfx === maxTries) {
|
||||
reject(new Error('Maximum number of tries exceeded'))
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`获取音乐失败 ${response.status}`)
|
||||
reject(new Error(error))
|
||||
}
|
||||
|
||||
}, 2000)
|
||||
})
|
||||
.then(() => {
|
||||
if (rawResponse?.status === 'complete') {
|
||||
return {
|
||||
duration: rawResponse.duration,
|
||||
title: rawResponse.gptPrompt,
|
||||
musicalStyle: rawResponse.musicalStyle,
|
||||
requestId: rawResponse.id,
|
||||
}
|
||||
} else {
|
||||
throw Error('Suno response could not be completed.')
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
return null
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -257,6 +257,7 @@ export default class SydneyAIClient {
|
|||
messageType = 'Chat',
|
||||
toSummaryFileContent,
|
||||
onImageCreateRequest = prompt => {},
|
||||
onSunoCreateRequest = prompt => {},
|
||||
isPro = this.pro
|
||||
} = opts
|
||||
// if (messageType === 'Chat') {
|
||||
|
|
@ -503,7 +504,12 @@ export default class SydneyAIClient {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.enableGenerateContents){
|
||||
argument0.plugins.push({
|
||||
"id": "22b7f79d-8ea4-437e-b5fd-3e21f09f7bc1",
|
||||
"category": 1
|
||||
})
|
||||
}
|
||||
if (encryptedconversationsignature) {
|
||||
delete argument0.conversationSignature
|
||||
}
|
||||
|
|
@ -707,6 +713,14 @@ export default class SydneyAIClient {
|
|||
adaptiveCardsSoFar = message.adaptiveCards
|
||||
suggestedResponsesSoFar = message.suggestedResponses
|
||||
}
|
||||
if (messages[0].contentType === 'SUNO') {
|
||||
console.log()
|
||||
onSunoCreateRequest({
|
||||
songtId: messages[0]?.hiddenText.split('=')[1],
|
||||
songPrompt: messages[0]?.text,
|
||||
cookie: this.opts.cookies
|
||||
})
|
||||
}
|
||||
const updatedText = messages[0].text
|
||||
if (!updatedText || updatedText === replySoFar[cursor]) {
|
||||
return
|
||||
|
|
@ -889,6 +903,9 @@ export default class SydneyAIClient {
|
|||
let imgBase64
|
||||
try {
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) {
|
||||
throw new Error(`图片${url}获取失败:${response.status}`)
|
||||
}
|
||||
const arrayBuffer = await response.arrayBuffer()
|
||||
const buffer = Buffer.from(arrayBuffer)
|
||||
imgBase64 = buffer.toString('base64')
|
||||
|
|
@ -975,6 +992,11 @@ function getOptionSet (tone, generateContent = false) {
|
|||
'responsible_ai_policy_235',
|
||||
'enablemm',
|
||||
'dv3sugg',
|
||||
'uquopt',
|
||||
'bicfluxv2',
|
||||
'langdtwb',
|
||||
'fluxprod',
|
||||
'eredirecturl',
|
||||
'autosave',
|
||||
'iyxapbing',
|
||||
'iycapbing',
|
||||
|
|
@ -992,7 +1014,6 @@ function getOptionSet (tone, generateContent = false) {
|
|||
'elec2t',
|
||||
'elecgnd',
|
||||
'gndlogcf',
|
||||
'eredirecturl',
|
||||
'clgalileo',
|
||||
'gencontentv3'
|
||||
])
|
||||
|
|
@ -1008,7 +1029,6 @@ function getOptionSet (tone, generateContent = false) {
|
|||
'elec2t',
|
||||
'elecgnd',
|
||||
'gndlogcf',
|
||||
'eredirecturl'
|
||||
])
|
||||
break
|
||||
case 'Creative':
|
||||
|
|
@ -1021,11 +1041,16 @@ function getOptionSet (tone, generateContent = false) {
|
|||
'elec2t',
|
||||
'elecgnd',
|
||||
'gndlogcf',
|
||||
'eredirecturl',
|
||||
'clgalileo',
|
||||
'gencontentv3'
|
||||
])
|
||||
break
|
||||
}
|
||||
if (Config.enableGenerateContents){
|
||||
optionset.push(...[
|
||||
'014CB21D',
|
||||
'B3FF9F21'
|
||||
])
|
||||
}
|
||||
return optionset
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue