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 = /