mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-16 13:27:08 +00:00
fix: 修复
This commit is contained in:
parent
9838459446
commit
f0b717bed8
23 changed files with 799 additions and 48 deletions
278
utils/poe/index 2.js
Normal file
278
utils/poe/index 2.js
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
import { readFileSync } from 'fs'
|
||||
import { scrape } from './credential.js'
|
||||
import fetch from 'node-fetch'
|
||||
import crypto from 'crypto'
|
||||
// used when test as a single file
|
||||
// const _path = process.cwd()
|
||||
const _path = process.cwd() + '/plugins/chatgpt-plugin/utils/poe'
|
||||
const gqlDir = `${_path}/graphql`
|
||||
const queries = {
|
||||
// chatViewQuery: readFileSync(gqlDir + '/ChatViewQuery.graphql', 'utf8'),
|
||||
addMessageBreakMutation: readFileSync(gqlDir + '/AddMessageBreakMutation.graphql', 'utf8'),
|
||||
chatPaginationQuery: readFileSync(gqlDir + '/ChatPaginationQuery.graphql', 'utf8'),
|
||||
addHumanMessageMutation: readFileSync(gqlDir + '/AddHumanMessageMutation.graphql', 'utf8'),
|
||||
loginMutation: readFileSync(gqlDir + '/LoginWithVerificationCodeMutation.graphql', 'utf8'),
|
||||
signUpWithVerificationCodeMutation: readFileSync(gqlDir + '/SignupWithVerificationCodeMutation.graphql', 'utf8'),
|
||||
sendVerificationCodeMutation: readFileSync(gqlDir + '/SendVerificationCodeForLoginMutation.graphql', 'utf8')
|
||||
}
|
||||
const optionMap = [
|
||||
{ title: 'Claude (Powered by Anthropic)', value: 'a2' },
|
||||
{ title: 'Sage (Powered by OpenAI - logical)', value: 'capybara' },
|
||||
{ title: 'Dragonfly (Powered by OpenAI - simpler)', value: 'nutria' },
|
||||
{ title: 'ChatGPT (Powered by OpenAI - current)', value: 'chinchilla' },
|
||||
{ title: 'Claude+', value: 'a2_2' },
|
||||
{ title: 'GPT-4', value: 'beaver' }
|
||||
]
|
||||
export class PoeClient {
|
||||
constructor (props) {
|
||||
this.config = props
|
||||
}
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
Referrer: 'https://poe.com/',
|
||||
Origin: 'https://poe.com',
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
|
||||
}
|
||||
|
||||
chatId = 0
|
||||
bot = ''
|
||||
|
||||
reConnectWs = false
|
||||
|
||||
async setCredentials () {
|
||||
let result = await scrape(this.config.quora_cookie)
|
||||
console.log(result)
|
||||
this.config.quora_formkey = result.appSettings.formkey
|
||||
this.config.channel_name = result.channelName
|
||||
this.config.app_settings = result.appSettings
|
||||
|
||||
// set value
|
||||
this.headers['poe-formkey'] = this.config.quora_formkey
|
||||
this.headers['poe-tchannel'] = this.config.channel_name
|
||||
this.headers.Cookie = this.config.quora_cookie
|
||||
console.log(this.headers)
|
||||
}
|
||||
|
||||
async subscribe () {
|
||||
const query = {
|
||||
queryName: 'subscriptionsMutation',
|
||||
variables: {
|
||||
subscriptions: [
|
||||
{
|
||||
subscriptionName: 'messageAdded',
|
||||
query: 'subscription subscriptions_messageAdded_Subscription(\n $chatId: BigInt!\n) {\n messageAdded(chatId: $chatId) {\n id\n messageId\n creationTime\n state\n ...ChatMessage_message\n ...chatHelpers_isBotMessage\n }\n}\n\nfragment ChatMessageDownvotedButton_message on Message {\n ...MessageFeedbackReasonModal_message\n ...MessageFeedbackOtherModal_message\n}\n\nfragment ChatMessageDropdownMenu_message on Message {\n id\n messageId\n vote\n text\n ...chatHelpers_isBotMessage\n}\n\nfragment ChatMessageFeedbackButtons_message on Message {\n id\n messageId\n vote\n voteReason\n ...ChatMessageDownvotedButton_message\n}\n\nfragment ChatMessageOverflowButton_message on Message {\n text\n ...ChatMessageDropdownMenu_message\n ...chatHelpers_isBotMessage\n}\n\nfragment ChatMessageSuggestedReplies_SuggestedReplyButton_message on Message {\n messageId\n}\n\nfragment ChatMessageSuggestedReplies_message on Message {\n suggestedReplies\n ...ChatMessageSuggestedReplies_SuggestedReplyButton_message\n}\n\nfragment ChatMessage_message on Message {\n id\n messageId\n text\n author\n linkifiedText\n state\n ...ChatMessageSuggestedReplies_message\n ...ChatMessageFeedbackButtons_message\n ...ChatMessageOverflowButton_message\n ...chatHelpers_isHumanMessage\n ...chatHelpers_isBotMessage\n ...chatHelpers_isChatBreak\n ...chatHelpers_useTimeoutLevel\n ...MarkdownLinkInner_message\n}\n\nfragment MarkdownLinkInner_message on Message {\n messageId\n}\n\nfragment MessageFeedbackOtherModal_message on Message {\n id\n messageId\n}\n\nfragment MessageFeedbackReasonModal_message on Message {\n id\n messageId\n}\n\nfragment chatHelpers_isBotMessage on Message {\n ...chatHelpers_isHumanMessage\n ...chatHelpers_isChatBreak\n}\n\nfragment chatHelpers_isChatBreak on Message {\n author\n}\n\nfragment chatHelpers_isHumanMessage on Message {\n author\n}\n\nfragment chatHelpers_useTimeoutLevel on Message {\n id\n state\n text\n messageId\n}\n'
|
||||
},
|
||||
{
|
||||
subscriptionName: 'viewerStateUpdated',
|
||||
query: 'subscription subscriptions_viewerStateUpdated_Subscription {\n viewerStateUpdated {\n id\n ...ChatPageBotSwitcher_viewer\n }\n}\n\nfragment BotHeader_bot on Bot {\n displayName\n ...BotImage_bot\n}\n\nfragment BotImage_bot on Bot {\n profilePicture\n displayName\n}\n\nfragment BotLink_bot on Bot {\n displayName\n}\n\nfragment ChatPageBotSwitcher_viewer on Viewer {\n availableBots {\n id\n ...BotLink_bot\n ...BotHeader_bot\n }\n}\n'
|
||||
}
|
||||
]
|
||||
},
|
||||
query: 'mutation subscriptionsMutation(\n $subscriptions: [AutoSubscriptionQuery!]!\n) {\n autoSubscribe(subscriptions: $subscriptions) {\n viewer {\n id\n }\n }\n}\n'
|
||||
}
|
||||
|
||||
await this.makeRequest(query)
|
||||
}
|
||||
|
||||
async makeRequest (request) {
|
||||
let payload = JSON.stringify(request)
|
||||
let baseString = payload + this.headers['poe-formkey'] + 'WpuLMiXEKKE98j56k'
|
||||
const md5 = crypto.createHash('md5').update(baseString).digest('hex')
|
||||
const response = await fetch('https://poe.com/api/gql_POST', {
|
||||
method: 'POST',
|
||||
headers: Object.assign(this.headers, {
|
||||
'poe-tag-id': md5,
|
||||
'content-type': 'application/json'
|
||||
}),
|
||||
body: payload
|
||||
})
|
||||
let text = await response.text()
|
||||
try {
|
||||
let result = JSON.parse(text)
|
||||
console.log({ result })
|
||||
return result
|
||||
} catch (e) {
|
||||
console.error(text)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
async getBot (displayName) {
|
||||
let r
|
||||
let retry = 10
|
||||
while (retry >= 0) {
|
||||
let url = `https://poe.com/_next/data/${this.nextData.buildId}/${displayName}.json`
|
||||
let r = await fetch(url, {
|
||||
headers: this.headers
|
||||
})
|
||||
let res = await r.text()
|
||||
try {
|
||||
let chatData = (JSON.parse(res)).pageProps.payload.chatOfBotDisplayName
|
||||
return chatData
|
||||
} catch (e) {
|
||||
r = res
|
||||
retry--
|
||||
}
|
||||
}
|
||||
throw new Error(r)
|
||||
}
|
||||
|
||||
async getChatId () {
|
||||
let r = await fetch('https://poe.com', {
|
||||
headers: this.headers
|
||||
})
|
||||
let text = await r.text()
|
||||
const jsonRegex = /<script id="__NEXT_DATA__" type="application\/json">(.+?)<\/script>/
|
||||
const jsonText = text.match(jsonRegex)[1]
|
||||
const nextData = JSON.parse(jsonText)
|
||||
this.nextData = nextData
|
||||
this.viewer = nextData.props.pageProps.payload.viewer
|
||||
this.formkey = nextData.props.formkey
|
||||
let bots = this.viewer.availableBots
|
||||
this.bots = {}
|
||||
for (let i = 0; i < bots.length; i++) {
|
||||
let bot = bots[i]
|
||||
let chatData = await this.getBot(bot.displayName)
|
||||
this.bots[chatData.defaultBotObject.nickname] = chatData
|
||||
}
|
||||
console.log(this.bots)
|
||||
}
|
||||
|
||||
async clearContext (bot) {
|
||||
try {
|
||||
const data = await this.makeRequest({
|
||||
query: `${queries.addMessageBreakMutation}`,
|
||||
variables: { chatId: this.config.chat_ids[bot] }
|
||||
})
|
||||
|
||||
if (!data.data) {
|
||||
this.reConnectWs = true // for websocket purpose
|
||||
console.log('ON TRY! Could not clear context! Trying to reLogin..')
|
||||
}
|
||||
return data
|
||||
} catch (e) {
|
||||
this.reConnectWs = true // for websocket purpose
|
||||
console.log('ON CATCH! Could not clear context! Trying to reLogin..')
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
async sendMsg (bot, query) {
|
||||
try {
|
||||
const data = await this.makeRequest({
|
||||
query: `${queries.addHumanMessageMutation}`,
|
||||
variables: {
|
||||
bot,
|
||||
chatId: this.bots[bot].chatId,
|
||||
query,
|
||||
source: null,
|
||||
withChatBreak: false
|
||||
}
|
||||
})
|
||||
console.log(data)
|
||||
if (!data.data) {
|
||||
this.reConnectWs = true // for cli websocket purpose
|
||||
console.log('Could not send message! Trying to reLogin..')
|
||||
}
|
||||
return data
|
||||
} catch (e) {
|
||||
this.reConnectWs = true // for cli websocket purpose
|
||||
console.error(e)
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
async getHistory (bot) {
|
||||
try {
|
||||
let response = await this.makeRequest({
|
||||
query: `${queries.chatPaginationQuery}`,
|
||||
variables: {
|
||||
before: null,
|
||||
bot,
|
||||
last: 25
|
||||
}
|
||||
})
|
||||
|
||||
return response.data.chatOfBot.messagesConnection.edges
|
||||
.map(({ node: { messageId, text, authorNickname } }) => ({
|
||||
messageId,
|
||||
text,
|
||||
authorNickname
|
||||
}))
|
||||
} catch (e) {
|
||||
console.log('There has been an error while fetching your history!')
|
||||
}
|
||||
}
|
||||
|
||||
async deleteMessages (msgIds) {
|
||||
await this.makeRequest({
|
||||
queryName: 'MessageDeleteConfirmationModal_deleteMessageMutation_Mutation',
|
||||
variables: {
|
||||
messageIds: msgIds
|
||||
},
|
||||
query: 'mutation MessageDeleteConfirmationModal_deleteMessageMutation_Mutation(\n $messageIds: [BigInt!]!\n){\n messagesDelete(messageIds: $messageIds) {\n edgeIds\n }\n}\n'
|
||||
})
|
||||
}
|
||||
|
||||
async getResponse (bot) {
|
||||
let text
|
||||
let state
|
||||
let authorNickname
|
||||
try {
|
||||
while (true) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000))
|
||||
let response = await this.makeRequest({
|
||||
query: `${queries.chatPaginationQuery}`,
|
||||
variables: {
|
||||
before: null,
|
||||
bot,
|
||||
last: 1
|
||||
}
|
||||
})
|
||||
let base = response.data.chatOfBot.messagesConnection.edges
|
||||
let lastEdgeIndex = base.length - 1
|
||||
text = base[lastEdgeIndex].node.text
|
||||
authorNickname = base[lastEdgeIndex].node.authorNickname
|
||||
state = base[lastEdgeIndex].node.state
|
||||
if (state === 'complete' && authorNickname === bot) {
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Could not get response!')
|
||||
return {
|
||||
status: false,
|
||||
message: 'failed',
|
||||
data: null
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
status: true,
|
||||
message: 'success',
|
||||
data: text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function testPoe () {
|
||||
// const key = 'deb04db9f2332a3287b7d2545061af62'
|
||||
// const channel = 'poe-chan55-8888-ujygckefewomybvkqfrp'
|
||||
const cookie = 'p-b=WSvmyvjHVJoMtQVkirtn-A%3D%3D'
|
||||
let client = new PoeClient({
|
||||
// quora_formkey: key,
|
||||
// channel_name: channel,
|
||||
quora_cookie: cookie
|
||||
})
|
||||
await client.setCredentials()
|
||||
await client.getChatId()
|
||||
let ai = 'a2'
|
||||
await client.sendMsg(ai, '你说话不是很通顺啊')
|
||||
const response = await client.getResponse(ai)
|
||||
return response
|
||||
}
|
||||
|
||||
// testPoe().then(res => {
|
||||
// console.log(res)
|
||||
// })
|
||||
65
utils/poe/websocket 2.js
Normal file
65
utils/poe/websocket 2.js
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import WebSocket from 'ws'
|
||||
import * as diff from 'diff'
|
||||
import { readFileSync } from 'fs'
|
||||
|
||||
const getSocketUrl = async () => {
|
||||
const tchRand = Math.floor(100000 + Math.random() * 900000) // They're surely using 6 digit random number for ws url.
|
||||
const socketUrl = `wss://tch${tchRand}.tch.quora.com`
|
||||
const credentials = JSON.parse(readFileSync('config.json', 'utf8'))
|
||||
const appSettings = credentials.app_settings.tchannelData
|
||||
const boxName = appSettings.boxName
|
||||
const minSeq = appSettings.minSeq
|
||||
const channel = appSettings.channel
|
||||
const hash = appSettings.channelHash
|
||||
return `${socketUrl}/up/${boxName}/updates?min_seq=${minSeq}&channel=${channel}&hash=${hash}`
|
||||
}
|
||||
|
||||
export const connectWs = async () => {
|
||||
const url = await getSocketUrl()
|
||||
const ws = new WebSocket(url)
|
||||
return new Promise((resolve, reject) => {
|
||||
ws.on('open', function open () {
|
||||
console.log('Connected to websocket')
|
||||
return resolve(ws)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const disconnectWs = async (ws) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
ws.on('close', function close () {
|
||||
return resolve(true)
|
||||
})
|
||||
ws.close()
|
||||
})
|
||||
}
|
||||
|
||||
export const listenWs = async (ws) => {
|
||||
let previousText = ''
|
||||
return new Promise((resolve, reject) => {
|
||||
const onMessage = function incoming (data) {
|
||||
let jsonData = JSON.parse(data)
|
||||
if (jsonData.messages && jsonData.messages.length > 0) {
|
||||
const messages = JSON.parse(jsonData.messages[0])
|
||||
const dataPayload = messages.payload.data
|
||||
const text = dataPayload.messageAdded.text
|
||||
const state = dataPayload.messageAdded.state
|
||||
if (state !== 'complete') {
|
||||
const differences = diff.diffChars(previousText, text)
|
||||
let result = ''
|
||||
differences.forEach((part) => {
|
||||
if (part.added) {
|
||||
result += part.value
|
||||
}
|
||||
})
|
||||
previousText = text
|
||||
process.stdout.write(result)
|
||||
} else {
|
||||
ws.removeListener('message', onMessage)
|
||||
return resolve(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
ws.on('message', onMessage)
|
||||
})
|
||||
}
|
||||
|
|
@ -11,20 +11,20 @@ export class EditCardTool extends AbstractTool {
|
|||
},
|
||||
card: {
|
||||
type: 'string',
|
||||
description: '你想给他改的新名片'
|
||||
description: 'the new card'
|
||||
},
|
||||
groupId: {
|
||||
type: 'string',
|
||||
description: '群号'
|
||||
description: 'group number'
|
||||
}
|
||||
},
|
||||
required: ['card', 'groupId']
|
||||
}
|
||||
|
||||
description = '当你想要修改某个群员的群名片时有用。输入应该是群号、qq号和群名片,用空格隔开。'
|
||||
description = 'Useful when you want to edit someone\'s card in the group(群名片)'
|
||||
|
||||
func = async function (opts) {
|
||||
let {qq, card, groupId} = opts
|
||||
let { qq, card, groupId } = opts
|
||||
groupId = parseInt(groupId.trim())
|
||||
qq = parseInt(qq.trim())
|
||||
logger.info('edit card: ', groupId, qq)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export class HandleMessageMsgTool extends AbstractTool {
|
|||
},
|
||||
messageId: {
|
||||
type: 'string',
|
||||
description: 'which message, current one by default'
|
||||
description: 'which message to handle, current one by default'
|
||||
}
|
||||
},
|
||||
required: ['type']
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { AbstractTool } from './AbstractTool.js'
|
|||
import { getMasterQQ } from '../common.js'
|
||||
|
||||
export class QueryUserinfoTool extends AbstractTool {
|
||||
name = 'sendDice'
|
||||
name = 'queryUser'
|
||||
|
||||
parameters = {
|
||||
properties: {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import {AbstractTool} from "./AbstractTool.js";
|
||||
|
||||
import { AbstractTool } from './AbstractTool.js'
|
||||
|
||||
export class SendDiceTool extends AbstractTool {
|
||||
name = 'sendDice'
|
||||
|
|
@ -19,7 +18,7 @@ export class SendDiceTool extends AbstractTool {
|
|||
}
|
||||
|
||||
func = async function (opts) {
|
||||
let {num, groupId} = opts
|
||||
let { num, groupId } = opts
|
||||
let groupList = await Bot.getGroupList()
|
||||
if (groupList.get(groupId)) {
|
||||
let group = await Bot.pickGroup(groupId, true)
|
||||
|
|
@ -28,7 +27,7 @@ export class SendDiceTool extends AbstractTool {
|
|||
let friend = await Bot.pickFriend(groupId)
|
||||
await friend.sendMsg(segment.dice(num))
|
||||
}
|
||||
return `the dice has been sent`
|
||||
return 'the dice has been sent'
|
||||
}
|
||||
|
||||
description = 'If you want to roll dice, use this tool. If you know the group number, use the group number instead of the qq number first. The input should be the number of dice to be cast (1-6) and the target group number or qq number,and they should be concat with a space'
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export class SendPictureTool extends AbstractTool {
|
|||
},
|
||||
groupId: {
|
||||
type: 'string',
|
||||
description: '群号或qq号,发送目标,为空则发送到当前聊天'
|
||||
description: 'the group number or qq number, will send to current conversation if leave blank'
|
||||
}
|
||||
},
|
||||
required: ['picture']
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { AbstractTool } from './AbstractTool.js'
|
||||
import {Config} from "../config.js";
|
||||
import {Config} from '../config.js';
|
||||
|
||||
export class WeatherTool extends AbstractTool {
|
||||
name = 'weather'
|
||||
|
|
@ -17,7 +17,9 @@ export class WeatherTool extends AbstractTool {
|
|||
func = async function (opts) {
|
||||
let { city } = opts
|
||||
let key = Config.amapKey
|
||||
|
||||
if (!key) {
|
||||
return 'query failed: you don\'t provide API key of 高德'
|
||||
}
|
||||
let adcodeRes = await fetch(`https://restapi.amap.com/v3/config/district?keywords=${city}&subdistrict=1&key=${key}`)
|
||||
adcodeRes = await adcodeRes.json()
|
||||
let adcode = adcodeRes.districts[0]?.adcode
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue