mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-18 06:17:06 +00:00
Merge branch 'v2' of https://github.com/ikechan8370/chatgpt-plugin into v2
This commit is contained in:
commit
c2c3052df1
6 changed files with 323 additions and 76 deletions
161
apps/chat.js
161
apps/chat.js
|
|
@ -25,7 +25,7 @@ import {
|
||||||
getUserReplySetting,
|
getUserReplySetting,
|
||||||
getImageOcrText,
|
getImageOcrText,
|
||||||
getImg,
|
getImg,
|
||||||
getMaxModelTokens, formatDate, generateAudio, formatDate2
|
getMaxModelTokens, formatDate, generateAudio, formatDate2, mkdirs
|
||||||
} from '../utils/common.js'
|
} from '../utils/common.js'
|
||||||
import { ChatGPTPuppeteer } from '../utils/browser.js'
|
import { ChatGPTPuppeteer } from '../utils/browser.js'
|
||||||
import { KeyvFile } from 'keyv-file'
|
import { KeyvFile } from 'keyv-file'
|
||||||
|
|
@ -68,6 +68,8 @@ import { SendAvatarTool } from '../utils/tools/SendAvatarTool.js'
|
||||||
import { SendMessageToSpecificGroupOrUserTool } from '../utils/tools/SendMessageToSpecificGroupOrUserTool.js'
|
import { SendMessageToSpecificGroupOrUserTool } from '../utils/tools/SendMessageToSpecificGroupOrUserTool.js'
|
||||||
import { SetTitleTool } from '../utils/tools/SetTitleTool.js'
|
import { SetTitleTool } from '../utils/tools/SetTitleTool.js'
|
||||||
import { createCaptcha, solveCaptcha, solveCaptchaOneShot } from '../utils/bingCaptcha.js'
|
import { createCaptcha, solveCaptcha, solveCaptchaOneShot } from '../utils/bingCaptcha.js'
|
||||||
|
import { ClaudeAIClient } from '../utils/claude.ai/index.js'
|
||||||
|
import fs from 'fs'
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await import('@azure/openai')
|
await import('@azure/openai')
|
||||||
|
|
@ -156,6 +158,12 @@ export class chatgpt extends plugin {
|
||||||
reg: '^#claude开启新对话',
|
reg: '^#claude开启新对话',
|
||||||
fnc: 'newClaudeConversation'
|
fnc: 'newClaudeConversation'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
/** 命令正则匹配 */
|
||||||
|
reg: '^#claude2[sS]*',
|
||||||
|
/** 执行方法 */
|
||||||
|
fnc: 'claude2'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
/** 命令正则匹配 */
|
/** 命令正则匹配 */
|
||||||
reg: '^#claude[sS]*',
|
reg: '^#claude[sS]*',
|
||||||
|
|
@ -249,43 +257,11 @@ export class chatgpt extends plugin {
|
||||||
fnc: 'deleteConversation',
|
fnc: 'deleteConversation',
|
||||||
permission: 'master'
|
permission: 'master'
|
||||||
}
|
}
|
||||||
// {
|
|
||||||
// reg: '^#chatgpt必应验证码',
|
|
||||||
// fnc: 'bingCaptcha'
|
|
||||||
// }
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
this.toggleMode = toggleMode
|
this.toggleMode = toggleMode
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* deprecated
|
|
||||||
* @param e
|
|
||||||
* @returns {Promise<boolean>}
|
|
||||||
*/
|
|
||||||
async bingCaptcha(e) {
|
|
||||||
let bingTokens = JSON.parse(await redis.get('CHATGPT:BING_TOKENS'))
|
|
||||||
if (!bingTokens) {
|
|
||||||
await e.reply('尚未绑定必应token:必应过码必须绑定token')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
bingTokens = bingTokens.map(token => token.Token)
|
|
||||||
let index = e.msg.replace(/^#chatgpt必应验证码/, '')
|
|
||||||
if (!index) {
|
|
||||||
await e.reply('指令不完整:请输入#chatgpt必应验证码+token序号(从1开始),如#chatgpt必应验证码1')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
index = parseInt(index) - 1
|
|
||||||
let bingToken = bingTokens[index]
|
|
||||||
let { id, regionId, image } = await createCaptcha(e, bingToken)
|
|
||||||
e.bingCaptchaId = id
|
|
||||||
e.regionId = regionId
|
|
||||||
e.token = bingToken
|
|
||||||
await e.reply(['请崽60秒内输入下面图片以通过必应人机验证', segment.image(`base64://${image}`)])
|
|
||||||
this.setContext('solveBingCaptcha', false, 60)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取chatgpt当前对话列表
|
* 获取chatgpt当前对话列表
|
||||||
* @param e
|
* @param e
|
||||||
|
|
@ -328,6 +304,11 @@ export class chatgpt extends plugin {
|
||||||
await e.reply('claude对话已结束')
|
await e.reply('claude对话已结束')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (use === 'claude2') {
|
||||||
|
await redis.del(`CHATGPT:CLAUDE2_CONVERSATION:${e.sender.user_id}`)
|
||||||
|
await e.reply('claude2对话已结束')
|
||||||
|
return
|
||||||
|
}
|
||||||
if (use === 'xh') {
|
if (use === 'xh') {
|
||||||
await redis.del(`CHATGPT:CONVERSATIONS_XH:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`)
|
await redis.del(`CHATGPT:CONVERSATIONS_XH:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`)
|
||||||
await e.reply('星火对话已结束')
|
await e.reply('星火对话已结束')
|
||||||
|
|
@ -1032,6 +1013,10 @@ export class chatgpt extends plugin {
|
||||||
key = `CHATGPT:CONVERSATIONS_BROWSER:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`
|
key = `CHATGPT:CONVERSATIONS_BROWSER:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
case 'claude2': {
|
||||||
|
key = `CHATGPT:CLAUDE2_CONVERSATION:${e.sender.user_id}`
|
||||||
|
break
|
||||||
|
}
|
||||||
case 'xh': {
|
case 'xh': {
|
||||||
key = `CHATGPT:CONVERSATIONS_XH:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`
|
key = `CHATGPT:CONVERSATIONS_XH:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`
|
||||||
break
|
break
|
||||||
|
|
@ -1416,7 +1401,26 @@ export class chatgpt extends plugin {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
async claude(e) {
|
async claude2 (e) {
|
||||||
|
if (!Config.allowOtherMode) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let ats = e.message.filter(m => m.type === 'at')
|
||||||
|
if (!e.atme && ats.length > 0) {
|
||||||
|
if (Config.debug) {
|
||||||
|
logger.mark('艾特别人了,没艾特我,忽略#claude2')
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let prompt = _.replace(e.raw_message.trimStart(), '#claude2', '').trim()
|
||||||
|
if (prompt.length === 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
await this.abstractChat(e, prompt, 'claude2')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
async claude (e) {
|
||||||
if (!Config.allowOtherMode) {
|
if (!Config.allowOtherMode) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -1858,6 +1862,56 @@ export class chatgpt extends plugin {
|
||||||
text
|
text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case 'claude2': {
|
||||||
|
let { conversationId } = conversation
|
||||||
|
let client = new ClaudeAIClient({
|
||||||
|
organizationId: Config.claudeAIOrganizationId,
|
||||||
|
sessionKey: Config.claudeAISessionKey,
|
||||||
|
debug: Config.debug,
|
||||||
|
proxy: Config.proxy
|
||||||
|
})
|
||||||
|
let fileUrl, filename, attachments
|
||||||
|
if (e.source && e.source.message === '[文件]') {
|
||||||
|
if (e.isGroup) {
|
||||||
|
let source = (await e.group.getChatHistory(e.source.seq, 1))[0]
|
||||||
|
let file = source.message.find(m => m.type === 'file')
|
||||||
|
if (file) {
|
||||||
|
filename = file.name
|
||||||
|
fileUrl = await e.group.getFileUrl(file.fid)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let source = (await e.friend.getChatHistory(e.source.time, 1))[0]
|
||||||
|
let file = source.message.find(m => m.type === 'file')
|
||||||
|
if (file) {
|
||||||
|
filename = file.name
|
||||||
|
fileUrl = await e.group.getFileUrl(file.fid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fileUrl) {
|
||||||
|
logger.info('文件地址:' + fileUrl)
|
||||||
|
mkdirs('data/chatgpt/files')
|
||||||
|
let destinationPath = 'data/chatgpt/files/' + filename
|
||||||
|
const response = await fetch(fileUrl)
|
||||||
|
const fileStream = fs.createWriteStream(destinationPath)
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
response.body.pipe(fileStream)
|
||||||
|
response.body.on('error', (err) => {
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
fileStream.on('finish', () => {
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
attachments = [await client.convertDocument(destinationPath, filename)]
|
||||||
|
}
|
||||||
|
if (conversationId) {
|
||||||
|
return await client.sendMessage(prompt, conversationId, attachments)
|
||||||
|
} else {
|
||||||
|
let conv = await client.createConversation()
|
||||||
|
return await client.sendMessage(prompt, conv.uuid, attachments)
|
||||||
|
}
|
||||||
|
}
|
||||||
case 'xh': {
|
case 'xh': {
|
||||||
const cacheOptions = {
|
const cacheOptions = {
|
||||||
namespace: 'xh',
|
namespace: 'xh',
|
||||||
|
|
@ -2544,45 +2598,6 @@ export class chatgpt extends plugin {
|
||||||
}
|
}
|
||||||
return await this.chatGPTApi.sendMessage(prompt, sendMessageOption)
|
return await this.chatGPTApi.sendMessage(prompt, sendMessageOption)
|
||||||
}
|
}
|
||||||
|
|
||||||
async solveBingCaptcha(e) {
|
|
||||||
try {
|
|
||||||
let id = e.bingCaptchaId
|
|
||||||
let regionId = e.regionId
|
|
||||||
let text = this.e.msg
|
|
||||||
let solveResult = await solveCaptcha(id, regionId, text, e.token)
|
|
||||||
if (solveResult.result) {
|
|
||||||
logger.mark('验证码正确:' + JSON.stringify(solveResult.detail))
|
|
||||||
const cacheOptions = {
|
|
||||||
namespace: Config.toneStyle,
|
|
||||||
store: new KeyvFile({ filename: 'cache.json' })
|
|
||||||
}
|
|
||||||
const bingAIClient = new SydneyAIClient({
|
|
||||||
userToken: e.token, // "_U" cookie from bing.com
|
|
||||||
debug: Config.debug,
|
|
||||||
cache: cacheOptions,
|
|
||||||
user: e.sender.user_id,
|
|
||||||
proxy: Config.proxy
|
|
||||||
})
|
|
||||||
try {
|
|
||||||
let response = await bingAIClient.sendMessage('hello', Object.assign({ invocationId: '1' }, e.bingConversation))
|
|
||||||
if (response.response) {
|
|
||||||
await e.reply('验证码已通过')
|
|
||||||
} else {
|
|
||||||
await e.reply('验证码正确,但账户未解决验证码')
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
logger.error(err)
|
|
||||||
await e.reply('验证码正确,但账户未解决验证码')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await e.reply('验证码失败:' + JSON.stringify(solveResult.detail))
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
this.finish('solveBingCaptcha')
|
|
||||||
}
|
|
||||||
this.finish('solveBingCaptcha')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAvailableBingToken(conversation, throttled = []) {
|
async function getAvailableBingToken(conversation, throttled = []) {
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,11 @@ export class ChatgptManagement extends plugin {
|
||||||
fnc: 'useSlackClaudeBasedSolution',
|
fnc: 'useSlackClaudeBasedSolution',
|
||||||
permission: 'master'
|
permission: 'master'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
reg: '^#chatgpt切换(Claude2|claude2|claude.ai)$',
|
||||||
|
fnc: 'useClaudeAISolution',
|
||||||
|
permission: 'master'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
reg: '^#chatgpt切换星火$',
|
reg: '^#chatgpt切换星火$',
|
||||||
fnc: 'useXinghuoBasedSolution',
|
fnc: 'useXinghuoBasedSolution',
|
||||||
|
|
@ -840,6 +845,16 @@ azure语音:Azure 语音是微软 Azure 平台提供的一项语音服务,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async useClaudeAISolution () {
|
||||||
|
let use = await redis.get('CHATGPT:USE')
|
||||||
|
if (use !== 'claude2') {
|
||||||
|
await redis.set('CHATGPT:USE', 'claude2')
|
||||||
|
await this.reply('已切换到基于claude.ai的解决方案')
|
||||||
|
} else {
|
||||||
|
await this.reply('当前已经是claude2模式了')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async useXinghuoBasedSolution () {
|
async useXinghuoBasedSolution () {
|
||||||
let use = await redis.get('CHATGPT:USE')
|
let use = await redis.get('CHATGPT:USE')
|
||||||
if (use !== 'xh') {
|
if (use !== 'xh') {
|
||||||
|
|
@ -1404,4 +1419,4 @@ Poe 模式会调用 Poe 中的 Claude-instant 进行对话。需要提供 Cookie
|
||||||
await e.reply('好的,已经关闭智能模式')
|
await e.reply('好的,已经关闭智能模式')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -585,6 +585,22 @@ export function supportGuoba () {
|
||||||
bottomHelpMessage: '若启用全局设定,每个人都会默认使用这里的设定。',
|
bottomHelpMessage: '若启用全局设定,每个人都会默认使用这里的设定。',
|
||||||
component: 'Input'
|
component: 'Input'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '以下为Claude2方式的配置',
|
||||||
|
component: 'Divider'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'claudeAIOrganizationId',
|
||||||
|
label: 'claude2 OrganizationId',
|
||||||
|
bottomHelpMessage: 'claude.ai的OrganizationId',
|
||||||
|
component: 'Input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'claudeAISessionKey',
|
||||||
|
label: 'claude2 SessionKey',
|
||||||
|
bottomHelpMessage: 'claude.ai Cookie中的SessionKey',
|
||||||
|
component: 'Input'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '以下为ChatGLM方式的配置',
|
label: '以下为ChatGLM方式的配置',
|
||||||
component: 'Divider'
|
component: 'Divider'
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,8 @@
|
||||||
"puppeteer-extra": "^3.3.6",
|
"puppeteer-extra": "^3.3.6",
|
||||||
"puppeteer-extra-plugin-recaptcha": "^3.6.8",
|
"puppeteer-extra-plugin-recaptcha": "^3.6.8",
|
||||||
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
||||||
"sharp": "^0.32.3"
|
"sharp": "^0.32.3",
|
||||||
|
"cycletls": "^1.0.21"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
|
|
||||||
197
utils/claude.ai/index.js
Normal file
197
utils/claude.ai/index.js
Normal file
|
|
@ -0,0 +1,197 @@
|
||||||
|
import { File, FormData, Headers } from 'node-fetch'
|
||||||
|
import fs from 'fs'
|
||||||
|
import crypto from 'crypto'
|
||||||
|
// import initCycleTLS from 'cycletls'
|
||||||
|
let initCycleTLS
|
||||||
|
try {
|
||||||
|
initCycleTLS = (await import('cycletls')).default
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('未安装cycletls,无法使用claude2功能。')
|
||||||
|
}
|
||||||
|
export class ClaudeAIClient {
|
||||||
|
constructor (opts) {
|
||||||
|
if (!initCycleTLS) {
|
||||||
|
throw new Error('CycleTLS is not installed')
|
||||||
|
}
|
||||||
|
const { organizationId, sessionKey, proxy, debug = false } = opts
|
||||||
|
this.organizationId = organizationId
|
||||||
|
this.sessionKey = sessionKey
|
||||||
|
this.debug = debug
|
||||||
|
let headers = new Headers()
|
||||||
|
headers.append('Cookie', `sessionKey=${sessionKey}`)
|
||||||
|
headers.append('referrer', 'https://claude.ai/chat')
|
||||||
|
headers.append('origin', 'https://claude.ai')
|
||||||
|
headers.append('Content-Type', 'application/json')
|
||||||
|
headers.append('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36')
|
||||||
|
// headers.append('sec-ch-ua', '"Chromium";v="116", "Not)A;Brand";v="24", "Google Chrome";v="116"')
|
||||||
|
// headers.append('Sec-Ch-Ua-Mobile', '?0')
|
||||||
|
// headers.append('Sec-Ch-Ua-Platform', '"Windows"')
|
||||||
|
headers.append('Sec-Fetch-Dest', 'empty')
|
||||||
|
headers.append('Sec-Fetch-Mode', 'cors')
|
||||||
|
headers.append('Sec-Fetch-Site', 'same-origin')
|
||||||
|
headers.append('Connection', 'keep-alive')
|
||||||
|
headers.append('TE', 'trailers')
|
||||||
|
headers.append('Accept-Encoding', 'gzip, deflate, br')
|
||||||
|
headers.append('Accept-Language', 'en-US,en;q=0.5')
|
||||||
|
headers.append('Dnt', '1')
|
||||||
|
headers.append('Accept', '*/*')
|
||||||
|
// headers.append('sentry-trace', 'd1c13c8e760c4e9e969a5e1aed6a38cf-a854f94e3d1a4bc7-0')
|
||||||
|
// headers.append('anthropic-client-sha', 'cab849b55d41c73804c1b2b87a7a7fdb84263dc9')
|
||||||
|
// headers.append('anthropic-client-version', '1')
|
||||||
|
// headers.append('baggage', 'sentry-environment=production,sentry-release=cab849b55d41c73804c1b2b87a7a7fdb84263dc9,sentry-public_key=58e9b9d0fc244061a1b54fe288b0e483,sentry-trace_id=d1c13c8e760c4e9e969a5e1aed6a38cf')
|
||||||
|
this.JA3 = '772,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,5-27-45-35-65281-16-18-10-17513-43-13-23-51-0-11,29-23-24,0'
|
||||||
|
|
||||||
|
this.headers = headers
|
||||||
|
this.rawHeaders = {}
|
||||||
|
Array.from(this.headers.keys()).forEach(key => {
|
||||||
|
this.rawHeaders[key] = this.headers.get(key)
|
||||||
|
})
|
||||||
|
this.proxy = proxy
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抽取文件文本内容,https://claude.ai/api/convert_document
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @param filename
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async convertDocument (filePath, filename = 'file.pdf') {
|
||||||
|
let formData = new FormData()
|
||||||
|
formData.append('orgUuid', this.organizationId)
|
||||||
|
let buffer = fs.readFileSync(filePath)
|
||||||
|
formData.append('file', new File([buffer], filename))
|
||||||
|
// let result = await this.fetch('https://claude.ai/api/convert_document', {
|
||||||
|
// body: formData,
|
||||||
|
// headers: this.headers,
|
||||||
|
// method: 'POST',
|
||||||
|
// redirect: 'manual',
|
||||||
|
// referrer: 'https://claude.ai/chat/bba5a67d-ee59-4196-a371-ece8a35db1f2'
|
||||||
|
// })
|
||||||
|
// if (result.statusCode === 307) {
|
||||||
|
// throw new Error('claude.ai目前不支持你所在的地区')
|
||||||
|
// }
|
||||||
|
// if (result.statusCode !== 200) {
|
||||||
|
// console.warn('failed to parse document convert result: ' + result.statusCode + ' ' + result.statusText)
|
||||||
|
// return null
|
||||||
|
// }
|
||||||
|
// let raw = await result.text()
|
||||||
|
// try {
|
||||||
|
// return JSON.parse(raw)
|
||||||
|
// } catch (e) {
|
||||||
|
// console.warn('failed to parse document convert result: ' + raw)
|
||||||
|
// return null
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建新的对话
|
||||||
|
* @param uuid
|
||||||
|
* @param name
|
||||||
|
* @returns {Promise<unknown>}
|
||||||
|
*/
|
||||||
|
async createConversation (uuid = crypto.randomUUID(), name = '') {
|
||||||
|
let body = {
|
||||||
|
name,
|
||||||
|
uuid
|
||||||
|
}
|
||||||
|
body = JSON.stringify(body)
|
||||||
|
// let result = await this.fetch(`https://claude.ai/api/organizations/${this.organizationId}/chat_conversations`, {
|
||||||
|
// body,
|
||||||
|
// headers: this.headers,
|
||||||
|
// method: 'POST',
|
||||||
|
// redirect: 'manual'
|
||||||
|
// // referrer: 'https://claude.ai/chat/bba5a67d-ee59-4196-a371-ece8a35db1f2'
|
||||||
|
// })
|
||||||
|
const cycleTLS = await initCycleTLS()
|
||||||
|
let result = await cycleTLS(`https://claude.ai/api/organizations/${this.organizationId}/chat_conversations`, {
|
||||||
|
ja3: this.JA3,
|
||||||
|
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36',
|
||||||
|
proxy: this.proxy,
|
||||||
|
body,
|
||||||
|
headers: this.rawHeaders,
|
||||||
|
disableRedirect: true
|
||||||
|
}, 'post')
|
||||||
|
if (result.status === 307) {
|
||||||
|
throw new Error('claude.ai目前不支持你所在的地区')
|
||||||
|
}
|
||||||
|
let jsonRes = result.body
|
||||||
|
if (this.debug) {
|
||||||
|
console.log(jsonRes)
|
||||||
|
}
|
||||||
|
if (!jsonRes?.uuid) {
|
||||||
|
console.error(jsonRes)
|
||||||
|
// console.log(result.headers)
|
||||||
|
throw new Error('conversation create error')
|
||||||
|
}
|
||||||
|
return jsonRes
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendMessage (text, conversationId, attachments = []) {
|
||||||
|
let body = {
|
||||||
|
conversation_uuid: conversationId,
|
||||||
|
organization_uuid: this.organizationId,
|
||||||
|
text,
|
||||||
|
attachments,
|
||||||
|
completion: {
|
||||||
|
incremental: true,
|
||||||
|
model: 'claude-2',
|
||||||
|
prompt: text,
|
||||||
|
timezone: 'Asia/Hong_Kong'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let url = 'https://claude.ai/api/append_message'
|
||||||
|
const cycleTLS = await initCycleTLS()
|
||||||
|
let streamDataRes = await cycleTLS(url, {
|
||||||
|
ja3: this.JA3,
|
||||||
|
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36',
|
||||||
|
proxy: this.proxy,
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
headers: this.rawHeaders,
|
||||||
|
disableRedirect: true
|
||||||
|
}, 'post')
|
||||||
|
if (streamDataRes.status === 307) {
|
||||||
|
throw new Error('claude.ai目前不支持你所在的地区')
|
||||||
|
}
|
||||||
|
let streamData = streamDataRes.body
|
||||||
|
// console.log(streamData)
|
||||||
|
let responseText = ''
|
||||||
|
let streams = streamData.split('\n\n')
|
||||||
|
for (let s of streams) {
|
||||||
|
let jsonStr = s.replace('data: ', '').trim()
|
||||||
|
try {
|
||||||
|
let jsonObj = JSON.parse(jsonStr)
|
||||||
|
if (jsonObj && jsonObj.completion) {
|
||||||
|
responseText += jsonObj.completion
|
||||||
|
}
|
||||||
|
if (this.debug) {
|
||||||
|
console.log(jsonObj)
|
||||||
|
}
|
||||||
|
// console.log(responseText)
|
||||||
|
} catch (err) {
|
||||||
|
// ignore error
|
||||||
|
if (this.debug) {
|
||||||
|
console.log(jsonStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
text: responseText.trim(),
|
||||||
|
conversationId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testClaudeAI () {
|
||||||
|
let client = new ClaudeAIClient({
|
||||||
|
organizationId: '',
|
||||||
|
sessionKey: '',
|
||||||
|
debug: true,
|
||||||
|
proxy: 'http://127.0.0.1:7890'
|
||||||
|
})
|
||||||
|
let conv = await client.createConversation()
|
||||||
|
let result = await client.sendMessage('hello, who are you', conv.uuid)
|
||||||
|
console.log(result.text)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// testClaudeAI()
|
||||||
|
|
@ -144,7 +144,10 @@ const defaultConfig = {
|
||||||
extraUrl: 'https://cpe.ikechan8370.com',
|
extraUrl: 'https://cpe.ikechan8370.com',
|
||||||
smartMode: false,
|
smartMode: false,
|
||||||
bingCaptchaOneShotUrl: 'http://bingcaptcha.ikechan8370.com/bing',
|
bingCaptchaOneShotUrl: 'http://bingcaptcha.ikechan8370.com/bing',
|
||||||
version: 'v2.7.3'
|
// claude2
|
||||||
|
claudeAIOrganizationId: '',
|
||||||
|
claudeAISessionKey: '',
|
||||||
|
version: 'v2.7.4'
|
||||||
}
|
}
|
||||||
const _path = process.cwd()
|
const _path = process.cwd()
|
||||||
let config = {}
|
let config = {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue