Skip to content

Commit

Permalink
feat: Claude2 from claude.ai (#561)
Browse files Browse the repository at this point in the history
* feat: claude2 test

* fix: node-fetch的bug,使用redirect暂时解决

* fix: field error

* fix: field error

* fix: 引用文件

* fix: filename error

* fix: ignore convert document error
  • Loading branch information
ikechan8370 authored Sep 8, 2023
1 parent bf761c2 commit 56d6b50
Show file tree
Hide file tree
Showing 5 changed files with 283 additions and 75 deletions.
161 changes: 88 additions & 73 deletions apps/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
getUserReplySetting,
getImageOcrText,
getImg,
getMaxModelTokens, formatDate, generateAudio, formatDate2
getMaxModelTokens, formatDate, generateAudio, formatDate2, mkdirs
} from '../utils/common.js'
import { ChatGPTPuppeteer } from '../utils/browser.js'
import { KeyvFile } from 'keyv-file'
Expand Down Expand Up @@ -68,6 +68,8 @@ import { SendAvatarTool } from '../utils/tools/SendAvatarTool.js'
import { SendMessageToSpecificGroupOrUserTool } from '../utils/tools/SendMessageToSpecificGroupOrUserTool.js'
import { SetTitleTool } from '../utils/tools/SetTitleTool.js'
import { createCaptcha, solveCaptcha, solveCaptchaOneShot } from '../utils/bingCaptcha.js'
import { ClaudeAIClient } from '../utils/claude.ai/index.js'
import fs from 'fs'

try {
await import('@azure/openai')
Expand Down Expand Up @@ -156,6 +158,12 @@ export class chatgpt extends plugin {
reg: '^#claude开启新对话',
fnc: 'newClaudeConversation'
},
{
/** 命令正则匹配 */
reg: '^#claude2[sS]*',
/** 执行方法 */
fnc: 'claude2'
},
{
/** 命令正则匹配 */
reg: '^#claude[sS]*',
Expand Down Expand Up @@ -249,43 +257,11 @@ export class chatgpt extends plugin {
fnc: 'deleteConversation',
permission: 'master'
}
// {
// reg: '^#chatgpt必应验证码',
// fnc: 'bingCaptcha'
// }
]
})
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当前对话列表
* @param e
Expand Down Expand Up @@ -328,6 +304,11 @@ export class chatgpt extends plugin {
await e.reply('claude对话已结束')
return
}
if (use === 'claude2') {
await redis.del(`CHATGPT:CLAUDE2_CONVERSATION:${e.sender.user_id}`)
await e.reply('claude2对话已结束')
return
}
if (use === 'xh') {
await redis.del(`CHATGPT:CONVERSATIONS_XH:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`)
await e.reply('星火对话已结束')
Expand Down Expand Up @@ -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}`
break
}
case 'claude2': {
key = `CHATGPT:CLAUDE2_CONVERSATION:${e.sender.user_id}`
break
}
case 'xh': {
key = `CHATGPT:CONVERSATIONS_XH:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`
break
Expand Down Expand Up @@ -1416,7 +1401,26 @@ export class chatgpt extends plugin {
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) {
return false
}
Expand Down Expand Up @@ -1858,6 +1862,56 @@ export class chatgpt extends plugin {
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': {
const cacheOptions = {
namespace: 'xh',
Expand Down Expand Up @@ -2544,45 +2598,6 @@ export class chatgpt extends plugin {
}
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 = []) {
Expand Down
17 changes: 16 additions & 1 deletion apps/management.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ export class ChatgptManagement extends plugin {
fnc: 'useSlackClaudeBasedSolution',
permission: 'master'
},
{
reg: '^#chatgpt切换(Claude2|claude2|claude.ai)$',
fnc: 'useClaudeAISolution',
permission: 'master'
},
{
reg: '^#chatgpt切换星火$',
fnc: 'useXinghuoBasedSolution',
Expand Down Expand Up @@ -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 () {
let use = await redis.get('CHATGPT:USE')
if (use !== 'xh') {
Expand Down Expand Up @@ -1404,4 +1419,4 @@ Poe 模式会调用 Poe 中的 Claude-instant 进行对话。需要提供 Cookie
await e.reply('好的,已经关闭智能模式')
}
}
}
}
16 changes: 16 additions & 0 deletions guoba.support.js
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,22 @@ export function supportGuoba () {
bottomHelpMessage: '若启用全局设定,每个人都会默认使用这里的设定。',
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方式的配置',
component: 'Divider'
Expand Down
Loading

0 comments on commit 56d6b50

Please sign in to comment.