Merge branch 'ikechan8370:v2' into v2

This commit is contained in:
ifeif 2023-09-11 22:57:24 +08:00 committed by GitHub
commit 97fd363a4a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
185 changed files with 1543 additions and 7750 deletions

198
utils/claude.ai/index.js Normal file
View file

@ -0,0 +1,198 @@
import { File, FormData, Headers } from 'node-fetch'
import fs from 'fs'
import crypto from 'crypto'
import { Config } from '../config.js'
// 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', Config.claudeAIUA || '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 = Config.claudeAIJA3 || '772,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,27-5-65281-13-35-0-51-18-16-43-10-45-11-17513-23,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()

View file

@ -23,8 +23,6 @@ const defaultConfig = {
groupMerge: false,
quoteReply: true,
showQRCode: true,
cacheUrl: 'https://content.alcedogroup.com',
cacheEntry: false,
apiKey: '',
openAiBaseUrl: defaultOpenAIReverseProxy,
OpenAiPlatformRefreshToken: '',
@ -59,6 +57,7 @@ const defaultConfig = {
xhMaxTokens: 1024,
xhPromptSerialize: false,
xhPrompt: '',
xhPromptEval: false,
xhRetRegExp: '',
xhRetReplace: '',
promptPrefixOverride: 'Your answer shouldn\'t be too verbose. Prefer to answer in Chinese.',
@ -97,8 +96,6 @@ const defaultConfig = {
maxNumUserMessagesInConversation: 20,
sydneyApologyIgnored: true,
enforceMaster: false,
oldview: false,
newhelp: false,
serverPort: 3321,
serverHost: '',
viewHost: '',
@ -148,7 +145,12 @@ const defaultConfig = {
extraUrl: 'https://cpe.ikechan8370.com',
smartMode: false,
bingCaptchaOneShotUrl: 'http://bingcaptcha.ikechan8370.com/bing',
version: 'v2.7.3'
// claude2
claudeAIOrganizationId: '',
claudeAISessionKey: '',
claudeAIJA3: '772,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,27-5-65281-13-35-0-51-18-16-43-10-45-11-17513-23,29-23-24,0',
claudeAIUA: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36',
version: 'v2.7.4'
}
const _path = process.cwd()
let config = {}

View file

@ -3,7 +3,6 @@ import { Config } from '../config.js'
import { createParser } from 'eventsource-parser'
import https from 'https'
import WebSocket from 'ws'
import { config } from 'process'
const referer = atob('aHR0cHM6Ly94aW5naHVvLnhmeXVuLmNuL2NoYXQ/aWQ9')
const origin = atob('aHR0cHM6Ly94aW5naHVvLnhmeXVuLmNu')
@ -75,17 +74,6 @@ export default class XinghuoClient {
}
}
promptBypassPreset(prompt) {
switch (prompt) {
case '你是谁':
return '你是谁,叫什么'
case '你是谁啊':
return '你是谁啊,叫什么'
default:
return prompt
}
}
async initCache() {
if (!this.conversationsCache) {
const cacheOptions = this.cache || {}
@ -203,7 +191,8 @@ export default class XinghuoClient {
domain: Config.xhmode == 'api' ? "general" : "generalv2",
temperature: Config.xhTemperature, // 核采样阈值
max_tokens: Config.xhMaxTokens, // tokens最大长度
chat_id: chatId
chat_id: chatId,
top_k: Math.floor(Math.random() * 6) + 1 // 随机候选,避免重复回复
}
},
payload: {
@ -230,7 +219,17 @@ export default class XinghuoClient {
try {
const messageData = JSON.parse(message)
if (messageData.header.code != 0) {
reject(`接口发生错误Error Code ${messageData.header.code} ,${this.apiErrorInfo(messageData.header.code)}`)
if (messageData.header.code == 10907) {
const half = Math.floor(conversation.messages.length / 2)
conversation.messages.splice(0, half)
await this.conversationsCache.set(conversationKey, conversation)
resolve({
id: (Math.floor(Math.random() * 1000000) + 100000).toString() ,
response: '对话以达到上限,已自动清理对话,请重试'
})
} else {
reject(`接口发生错误Error Code ${messageData.header.code} ,${this.apiErrorInfo(messageData.header.code)}`)
}
}
if (messageData.header.status == 0 || messageData.header.status == 1) {
resMessage += messageData.payload.choices.text[0].content
@ -251,7 +250,10 @@ export default class XinghuoClient {
conversation.messages.splice(0, half)
}
await this.conversationsCache.set(conversationKey, conversation)
resolve(resMessage)
resolve({
id: chatId ,
response: resMessage
})
}
} catch (error) {
reject(new Error(error))
@ -372,9 +374,10 @@ export default class XinghuoClient {
})
}
async sendMessage(prompt, chatId, image) {
// 对星火预设的问题进行重写,避免收到预设回答
prompt = this.promptBypassPreset(prompt)
async sendMessage(prompt, option) {
let chatId = option?.chatId
let image = option?.image
if (Config.xhmode == 'api' || Config.xhmode == 'apiv2' || Config.xhmode == 'assistants') {
if (!Config.xhAppId || !Config.xhAPISecret || !Config.xhAPIKey) throw new Error('未配置api')
let Prompt = []
@ -389,12 +392,24 @@ export default class XinghuoClient {
} else {
Prompt = Config.xhPrompt ? [{ "role": "user", "content": Config.xhPrompt }] : []
}
let response = await this.apiMessage(prompt, chatId, Prompt)
if(Config.xhPromptEval) {
Prompt.forEach(obj => {
try {
obj.content = obj.content.replace(/{{(.*?)}}/g, (match, variable) => {
return Function(`"use strict";return ((e)=>{return ${variable} })`)()(option.e)
})
} catch (error) {
logger.error(error)
}
})
}
let { response, id } = await this.apiMessage(prompt, chatId, Prompt)
if (Config.xhRetRegExp) {
response = response.replace(new RegExp(Config.xhRetRegExp, 'g'), Config.xhRetReplace)
}
return {
conversationId: chatId,
conversationId: id,
text: response
}
} else if (Config.xhmode == 'web') {