feat: init v3

This commit is contained in:
ikechan8370 2025-03-05 23:56:41 +08:00
parent d6cb085c40
commit 531986b2dc
284 changed files with 618 additions and 405179 deletions

View file

@ -1,207 +0,0 @@
import { v4 as uuidv4 } from 'uuid'
import { Config, officialChatGPTAPI } from './config.js'
import https from 'https'
import http from 'http'
import { createParser } from 'eventsource-parser'
// API3
export class OfficialChatGPTClient {
constructor (opts = {}) {
const {
accessToken,
apiReverseUrl
} = opts
this._accessToken = accessToken
this._apiReverseUrl = apiReverseUrl
}
async sendMessage (prompt, opts = {}, retry = 3, errorMsg) {
if (retry < 0) {
throw new Error(errorMsg || 'retry limit exceeded')
}
let {
conversationId,
parentMessageId = uuidv4(),
messageId = uuidv4(),
action = 'next',
model = ''
} = opts
let url = this._apiReverseUrl || officialChatGPTAPI
if (this._apiReverseUrl && Config.proxy && !Config.apiForceUseReverse) {
// 如果配了proxy而且有反代但是没开启强制反代
url = officialChatGPTAPI
}
const body = {
action,
messages: [
{
id: messageId,
role: 'user',
content: {
content_type: 'text',
parts: [prompt]
},
metadata: {}
}
],
model: model || (Config.useGPT4 ? 'gpt-4o' : 'auto'),
parent_message_id: parentMessageId,
timezone_offset_min: -480,
history_and_training_disabled: false
}
if (conversationId) {
body.conversation_id = conversationId
}
let conversationResponse
let statusCode
let requestP = new Promise((resolve, reject) => {
let option = {
method: 'POST',
headers: {
accept: 'text/event-stream',
'x-openai-assistant-app-id': '',
authorization: this._accessToken ? `Bearer ${this._accessToken}` : '',
'content-type': 'application/json',
referer: 'https://chat.openai.com/chat',
library: 'chatgpt-plugin'
},
referrer: 'https://chat.openai.com/chat',
timeout: 10000
}
logger.info('using api3 reverse proxy: ' + url)
let requestLib = url.startsWith('https') ? https : http
const req = requestLib.request(url, option, (res) => {
statusCode = res.statusCode
let response
function onMessage (data) {
if (data === '[DONE]') {
return resolve({
error: null,
response,
conversationId,
messageId,
conversationResponse
})
}
try {
const _checkJson = JSON.parse(data)
} catch (error) {
// console.log('warning: parse error.')
return
}
try {
const convoResponseEvent = JSON.parse(data)
conversationResponse = convoResponseEvent
if (convoResponseEvent.conversation_id) {
conversationId = convoResponseEvent.conversation_id
}
if (convoResponseEvent.message?.id) {
messageId = convoResponseEvent.message.id
}
const partialResponse =
convoResponseEvent.message?.content?.parts?.[0]
if (partialResponse) {
if (Config.debug) {
logger.info(JSON.stringify(convoResponseEvent))
}
response = partialResponse
}
} catch (err) {
console.warn('fetchSSE onMessage unexpected error', err)
reject(err)
}
}
const parser = createParser((event) => {
if (event.type === 'event') {
onMessage(event.data)
}
})
const errBody = []
res.on('data', (chunk) => {
// logger.mark('成功连接到chat.openai.com准备读取数据流')
if (statusCode === 200) {
let str = chunk.toString()
parser.feed(str)
}
errBody.push(chunk)
})
// const body = []
// res.on('data', (chunk) => body.push(chunk))
res.on('end', () => {
const resString = Buffer.concat(errBody).toString()
reject(resString)
})
})
req.on('error', (err) => {
reject(err)
})
req.on('timeout', () => {
req.destroy()
reject(new Error('Request time out'))
})
req.write(JSON.stringify(body))
req.end()
})
try {
const response = await requestP
if (statusCode === 200) {
return {
text: response.response,
conversationId: response.conversationId,
id: response.messageId,
parentMessageId
}
} else {
console.log(response)
throw new Error(JSON.stringify(response))
}
} catch (err) {
logger.warn(err)
if (typeof err === 'string') {
if (err.includes('You have sent too many messages to the model. Please try again later.')) {
logger.warn('账户的gpt-o额度不足将降级为auto重试')
opts.model = 'auto'
}
}
return await this.sendMessage(prompt, opts, retry - 1, err.message)
}
}
voices = ['ember', 'cove',
'juniper', 'sky', 'breeze'
// '__internal_only_shimmer',
// '__internal_only_santa'
]
async synthesis (opts = {}) {
const { id, conversationId } = opts
let url = this._apiReverseUrl.replace('/conversation', '/synthesize')
let randomVoice = this.voices[Math.floor(Math.random() * this.voices.length)]
url = `${url}?message_id=${id}&conversation_id=${conversationId}&voice=${randomVoice}&format=mp3`
let res = await fetch(url, {
method: 'GET',
headers: {
accept: 'audio/mpeg',
'x-openai-assistant-app-id': '',
authorization: this._accessToken ? `Bearer ${this._accessToken}` : '',
referer: 'https://chat.openai.com/chat',
library: 'chatgpt-plugin'
}
})
if (res.status !== 200) {
throw new Error(await res.text())
}
if (res.headers.get('content-type') !== 'audio/mpeg') {
throw new Error('invalid content type')
}
let buffer = await res.arrayBuffer()
return Buffer.from(buffer)
}
}