feat: add poe AI (Sage, GPT4, ClaudePlus, Claude, ChatGPT, Dragonfly)

This commit is contained in:
josc146
2023-04-17 20:54:16 +08:00
parent 85265131e4
commit 0479ef260d
40 changed files with 691 additions and 7 deletions
+4
View File
@@ -184,6 +184,10 @@ async function runWebpack(isWithoutKatex, isWithoutTiktoken, callback) {
test: /\.(jpg|png|svg)$/,
type: 'asset/inline',
},
{
test: /\.(graphql|gql)$/,
loader: 'graphql-tag/loader',
},
isWithoutTiktoken
? {
test: /crop-text\.mjs$/,
+60 -2
View File
@@ -10,6 +10,7 @@
"@picocss/pico": "^1.5.7",
"@primer/octicons-react": "^18.2.0",
"countries-list": "^2.6.1",
"diff": "^5.1.0",
"eventsource-parser": "^0.1.0",
"file-saver": "^2.0.5",
"github-markdown-css": "^5.2.0",
@@ -17,6 +18,7 @@
"i18next": "^22.4.13",
"katex": "^0.16.4",
"lodash-es": "^4.17.21",
"md5": "^2.3.0",
"parse5": "^6.0.1",
"preact": "^10.13.1",
"prop-types": "^15.8.1",
@@ -51,6 +53,7 @@
"eslint": "^8.36.0",
"eslint-plugin-react": "^7.32.2",
"fs-extra": "^11.1.0",
"graphql-tag": "^2.12.6",
"jsdom": "^21.1.1",
"less-loader": "^11.1.0",
"mini-css-extract-plugin": "^2.7.5",
@@ -2996,6 +2999,14 @@
"resolved": "https://registry.npmmirror.com/character-entities/-/character-entities-2.0.2.tgz",
"integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="
},
"node_modules/charenc": {
"version": "0.0.2",
"resolved": "https://registry.npmmirror.com/charenc/-/charenc-0.0.2.tgz",
"integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
"engines": {
"node": "*"
}
},
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz",
@@ -3248,6 +3259,14 @@
"node": ">= 8"
}
},
"node_modules/crypt": {
"version": "0.0.2",
"resolved": "https://registry.npmmirror.com/crypt/-/crypt-0.0.2.tgz",
"integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
"engines": {
"node": "*"
}
},
"node_modules/css-declaration-sorter": {
"version": "6.3.1",
"resolved": "https://registry.npmmirror.com/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz",
@@ -4567,6 +4586,31 @@
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
"dev": true
},
"node_modules/graphql": {
"version": "16.6.0",
"resolved": "https://registry.npmmirror.com/graphql/-/graphql-16.6.0.tgz",
"integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==",
"dev": true,
"peer": true,
"engines": {
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
}
},
"node_modules/graphql-tag": {
"version": "2.12.6",
"resolved": "https://registry.npmmirror.com/graphql-tag/-/graphql-tag-2.12.6.tgz",
"integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==",
"dev": true,
"dependencies": {
"tslib": "^2.1.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
}
},
"node_modules/gzip-size": {
"version": "6.0.0",
"resolved": "https://registry.npmmirror.com/gzip-size/-/gzip-size-6.0.0.tgz",
@@ -5749,6 +5793,21 @@
"resolved": "https://registry.npmmirror.com/markdown-table/-/markdown-table-3.0.3.tgz",
"integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw=="
},
"node_modules/md5": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/md5/-/md5-2.3.0.tgz",
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
"dependencies": {
"charenc": "0.0.2",
"crypt": "0.0.2",
"is-buffer": "~1.1.6"
}
},
"node_modules/md5/node_modules/is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmmirror.com/is-buffer/-/is-buffer-1.1.6.tgz",
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
},
"node_modules/mdast-util-definitions": {
"version": "5.1.2",
"resolved": "https://registry.npmmirror.com/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz",
@@ -8637,8 +8696,7 @@
"version": "2.5.0",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.5.0.tgz",
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
"dev": true,
"peer": true
"dev": true
},
"node_modules/type-check": {
"version": "0.4.0",
+3
View File
@@ -23,6 +23,7 @@
"@picocss/pico": "^1.5.7",
"@primer/octicons-react": "^18.2.0",
"countries-list": "^2.6.1",
"diff": "^5.1.0",
"eventsource-parser": "^0.1.0",
"file-saver": "^2.0.5",
"github-markdown-css": "^5.2.0",
@@ -30,6 +31,7 @@
"i18next": "^22.4.13",
"katex": "^0.16.4",
"lodash-es": "^4.17.21",
"md5": "^2.3.0",
"parse5": "^6.0.1",
"preact": "^10.13.1",
"prop-types": "^15.8.1",
@@ -64,6 +66,7 @@
"eslint": "^8.36.0",
"eslint-plugin-react": "^7.32.2",
"fs-extra": "^11.1.0",
"graphql-tag": "^2.12.6",
"jsdom": "^21.1.1",
"less-loader": "^11.1.0",
"mini-css-extract-plugin": "^2.7.5",
+1 -1
View File
@@ -1,4 +1,4 @@
import BingAIClient from '../clients/BingAIClient'
import BingAIClient from '../clients/bing'
import { getUserConfig } from '../../config/index.mjs'
import { pushRecord, setAbortController } from './shared.mjs'
+41
View File
@@ -0,0 +1,41 @@
import { pushRecord, setAbortController } from './shared.mjs'
import PoeAiClient from '../clients/poe'
/**
* @param {Runtime.Port} port
* @param {string} question
* @param {Session} session
* @param {string} modelName
*/
export async function generateAnswersWithPoeWebApi(port, question, session, modelName) {
const bot = new PoeAiClient(session.poe_chatId)
const { messageListener } = setAbortController(port, () => {
bot.breakMsg()
bot.close()
})
let answer = ''
await bot
.ask(
question,
modelName,
(msg) => {
answer += msg
port.postMessage({ answer: answer, done: false, session: null })
},
() => {
if (bot.chatId) session.poe_chatId = bot.chatId
pushRecord(session, question, answer)
console.debug('conversation history', { content: session.conversationRecords })
port.onMessage.removeListener(messageListener)
port.postMessage({ answer: answer, done: true, session: session })
bot.close()
},
)
.catch((err) => {
port.onMessage.removeListener(messageListener)
bot.close()
throw err
})
}
@@ -0,0 +1,52 @@
mutation AddHumanMessageMutation(
$chatId: BigInt!
$bot: String!
$query: String!
$source: MessageSource
$withChatBreak: Boolean! = false
) {
messageCreateWithStatus(
chatId: $chatId
bot: $bot
query: $query
source: $source
withChatBreak: $withChatBreak
) {
message {
id
__typename
messageId
text
linkifiedText
authorNickname
state
vote
voteReason
creationTime
suggestedReplies
chat {
id
shouldShowDisclaimer
}
}
messageLimit{
canSend
numMessagesRemaining
resetTime
shouldShowReminder
}
chatBreak {
id
__typename
messageId
text
linkifiedText
authorNickname
state
vote
voteReason
creationTime
suggestedReplies
}
}
}
@@ -0,0 +1,17 @@
mutation AddMessageBreakMutation($chatId: BigInt!) {
messageBreakCreate(chatId: $chatId) {
message {
id
__typename
messageId
text
linkifiedText
authorNickname
state
vote
voteReason
creationTime
suggestedReplies
}
}
}
@@ -0,0 +1,7 @@
mutation AutoSubscriptionMutation($subscriptions: [AutoSubscriptionQuery!]!) {
autoSubscribe(subscriptions: $subscriptions) {
viewer {
id
}
}
}
@@ -0,0 +1,8 @@
fragment BioFragment on Viewer {
id
poeUser {
id
uid
bio
}
}
@@ -0,0 +1,5 @@
subscription ChatAddedSubscription {
chatAdded {
...ChatFragment
}
}
@@ -0,0 +1,6 @@
fragment ChatFragment on Chat {
id
chatId
defaultBotNickname
shouldShowDisclaimer
}
@@ -0,0 +1,26 @@
query ChatPaginationQuery($bot: String!, $before: String, $last: Int! = 10) {
chatOfBot(bot: $bot) {
id
__typename
messagesConnection(before: $before, last: $last) {
pageInfo {
hasPreviousPage
}
edges {
node {
id
__typename
messageId
text
linkifiedText
authorNickname
state
vote
voteReason
creationTime
suggestedReplies
}
}
}
}
}
@@ -0,0 +1,8 @@
query ChatViewQuery($bot: String!) {
chatOfBot(bot: $bot) {
id
chatId
defaultBotNickname
shouldShowDisclaimer
}
}
@@ -0,0 +1,7 @@
mutation DeleteHumanMessagesMutation($messageIds: [BigInt!]!) {
messagesDelete(messageIds: $messageIds) {
viewer {
id
}
}
}
@@ -0,0 +1,8 @@
fragment HandleFragment on Viewer {
id
poeUser {
id
uid
handle
}
}
@@ -0,0 +1,13 @@
mutation LoginWithVerificationCodeMutation(
$verificationCode: String!
$emailAddress: String
$phoneNumber: String
) {
loginWithVerificationCode(
verificationCode: $verificationCode
emailAddress: $emailAddress
phoneNumber: $phoneNumber
) {
status
}
}
@@ -0,0 +1,5 @@
subscription MessageAddedSubscription($chatId: BigInt!) {
messageAdded(chatId: $chatId) {
...MessageFragment
}
}
@@ -0,0 +1,6 @@
subscription MessageDeletedSubscription($chatId: BigInt!) {
messageDeleted(chatId: $chatId) {
id
messageId
}
}
@@ -0,0 +1,13 @@
fragment MessageFragment on Message {
id
__typename
messageId
text
linkifiedText
authorNickname
state
vote
voteReason
creationTime
suggestedReplies
}
@@ -0,0 +1,7 @@
mutation MessageRemoveVoteMutation($messageId: BigInt!) {
messageRemoveVote(messageId: $messageId) {
message {
...MessageFragment
}
}
}
@@ -0,0 +1,7 @@
mutation MessageSetVoteMutation($messageId: BigInt!, $voteType: VoteType!, $reason: String) {
messageSetVote(messageId: $messageId, voteType: $voteType, reason: $reason) {
message {
...MessageFragment
}
}
}
@@ -0,0 +1,12 @@
mutation SendVerificationCodeForLoginMutation(
$emailAddress: String
$phoneNumber: String
) {
sendVerificationCode(
verificationReason: login
emailAddress: $emailAddress
phoneNumber: $phoneNumber
) {
status
}
}
@@ -0,0 +1,9 @@
mutation ShareMessagesMutation(
$chatId: BigInt!
$messageIds: [BigInt!]!
$comment: String
) {
messagesShare(chatId: $chatId, messageIds: $messageIds, comment: $comment) {
shareCode
}
}
@@ -0,0 +1,13 @@
mutation SignupWithVerificationCodeMutation(
$verificationCode: String!
$emailAddress: String
$phoneNumber: String
) {
signupWithVerificationCode(
verificationCode: $verificationCode
emailAddress: $emailAddress
phoneNumber: $phoneNumber
) {
status
}
}
@@ -0,0 +1,7 @@
mutation StaleChatUpdateMutation($chatId: BigInt!) {
staleChatUpdate(chatId: $chatId) {
message {
...MessageFragment
}
}
}
@@ -0,0 +1,3 @@
query SummarizePlainPostQuery($comment: String!) {
summarizePlainPost(comment: $comment)
}
@@ -0,0 +1,3 @@
query SummarizeQuotePostQuery($comment: String, $quotedPostId: BigInt!) {
summarizeQuotePost(comment: $comment, quotedPostId: $quotedPostId)
}
@@ -0,0 +1,3 @@
query SummarizeSharePostQuery($comment: String!, $chatId: BigInt!, $messageIds: [BigInt!]!) {
summarizeSharePost(comment: $comment, chatId: $chatId, messageIds: $messageIds)
}
@@ -0,0 +1,14 @@
fragment UserSnippetFragment on PoeUser {
id
uid
bio
handle
fullName
viewerIsFollowing
isPoeOnlyUser
profilePhotoURLTiny: profilePhotoUrl(size: tiny)
profilePhotoURLSmall: profilePhotoUrl(size: small)
profilePhotoURLMedium: profilePhotoUrl(size: medium)
profilePhotoURLLarge: profilePhotoUrl(size: large)
isFollowable
}
@@ -0,0 +1,21 @@
query ViewerInfoQuery {
viewer {
id
uid
...ViewerStateFragment
...BioFragment
...HandleFragment
hasCompletedMultiplayerNux
poeUser {
id
...UserSnippetFragment
}
messageLimit{
canSend
numMessagesRemaining
resetTime
shouldShowReminder
}
}
}
@@ -0,0 +1,30 @@
fragment ViewerStateFragment on Viewer {
id
__typename
iosMinSupportedVersion: integerGate(gateName: "poe_ios_min_supported_version")
iosMinEncouragedVersion: integerGate(
gateName: "poe_ios_min_encouraged_version"
)
macosMinSupportedVersion: integerGate(
gateName: "poe_macos_min_supported_version"
)
macosMinEncouragedVersion: integerGate(
gateName: "poe_macos_min_encouraged_version"
)
showPoeDebugPanel: booleanGate(gateName: "poe_show_debug_panel")
enableCommunityFeed: booleanGate(gateName: "enable_poe_shares_feed")
linkifyText: booleanGate(gateName: "poe_linkify_response")
enableSuggestedReplies: booleanGate(gateName: "poe_suggested_replies")
removeInviteLimit: booleanGate(gateName: "poe_remove_invite_limit")
enableInAppPurchases: booleanGate(gateName: "poe_enable_in_app_purchases")
availableBots {
nickname
displayName
profilePicture
isDown
disclaimer
subtitle
poweredBy
}
}
@@ -0,0 +1,5 @@
subscription ViewerStateUpdatedSubscription {
viewerStateUpdated {
...ViewerStateFragment
}
}
+170
View File
@@ -0,0 +1,170 @@
// reference: https://github.com/muharamdani/poe
import { connectWs, disconnectWs, listenWs } from './websocket.js'
import chatViewQuery from './graphql/ChatViewQuery.graphql'
import addMessageBreakMutation from './graphql/AddMessageBreakMutation.graphql'
import addHumanMessageMutation from './graphql/AddHumanMessageMutation.graphql'
import Browser from 'webextension-polyfill'
import md5 from 'md5'
const queries = {
chatViewQuery: chatViewQuery.loc.source.body,
addMessageBreakMutation: addMessageBreakMutation.loc.source.body,
addHumanMessageMutation: addHumanMessageMutation.loc.source.body,
}
export default class PoeAiClient {
constructor(chatId = null) {
this.headers = {
'Content-Type': 'application/json',
Accept: 'application/json',
Origin: 'https://poe.com',
}
this.settings = null
this.ws = null
this.chatId = chatId
this.bot = null
}
async ask(message, model, onMessage, onComplete) {
if (!this.settings) {
await this.getCredentials()
}
if (!this.bot) {
await this.initBot(model || 'sage')
}
if (!this.chatId) {
await this.getChatId(this.bot)
}
if (!this.ws) {
this.ws = await connectWs(this.settings)
await this.subscribe()
listenWs(this.ws, onMessage, onComplete)
}
await this.sendMsg(message)
}
async close() {
if (this.ws) {
await disconnectWs(this.ws)
this.ws = null
}
}
async getFormkey() {
const encoded = (await (await fetch('https://poe.com')).text()).match(
/<script>if\(.+\)throw new Error;(.+)<\/script>/,
)[1]
const codebook = encoded.match(/var .="([0-9a-f]+)"/)[1]
const dict = Array.from(encoded.matchAll(/\[(\d+)\]=.\[(\d+)\]/g))
let result = new Array(dict.length)
dict.forEach(([, k, v]) => {
result[k] = codebook[v]
})
return result.join('')
}
async getCredentials() {
this.headers['Cookie'] = (await Browser.cookies.getAll({ url: 'https://poe.com/' }))
.map((cookie) => {
return `${cookie.name}=${cookie.value}`
})
.join('; ')
this.settings = await (
await fetch('https://poe.com/api/settings', { headers: this.headers })
).json()
console.debug('poe settings', this.settings)
if (this.settings.tchannelData.channel)
this.headers['poe-tchannel'] = this.settings.tchannelData.channel
this.headers['poe-formkey'] = await this.getFormkey()
console.debug('poe formkey', this.headers['poe-formkey'])
}
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) {
request = JSON.stringify(request)
this.headers['poe-tag-id'] = md5(request + this.headers['poe-formkey'] + 'WpuLMiXEKKE98j56k')
const response = await fetch('https://poe.com/api/gql_POST', {
method: 'POST',
headers: this.headers,
body: request,
})
return await response.json()
}
async getChatId(bot) {
const {
data: {
chatOfBot: { chatId },
},
} = await this.makeRequest({
query: queries.chatViewQuery,
variables: {
bot,
},
})
this.chatId = chatId
return chatId
}
async initBot(bot) {
if (bot === 'sage') {
bot = 'capybara'
} else if (bot === 'gpt-4') {
bot = 'beaver'
} else if (bot === 'claude+') {
bot = 'a2_2'
} else if (bot === 'claude') {
bot = 'a2'
} else if (bot === 'chatgpt') {
bot = 'chinchilla'
} else if (bot === 'dragonfly') {
bot = 'nutria'
}
this.bot = bot
}
async breakMsg() {
await this.makeRequest({
query: queries.addMessageBreakMutation,
variables: { chatId: this.chatId },
})
}
async sendMsg(query) {
await this.makeRequest({
query: queries.addHumanMessageMutation,
variables: {
bot: this.bot,
chatId: this.chatId,
query: query,
source: null,
withChatBreak: false,
},
})
}
}
+63
View File
@@ -0,0 +1,63 @@
import * as diff from 'diff'
const getSocketUrl = async (settings) => {
settings = settings.tchannelData
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 boxName = settings.boxName
const minSeq = settings.minSeq
const channel = settings.channel
const hash = settings.channelHash
return `${socketUrl}/up/${boxName}/updates?min_seq=${minSeq}&channel=${channel}&hash=${hash}`
}
export const connectWs = async (settings) => {
const url = await getSocketUrl(settings)
const ws = new WebSocket(url)
return new Promise((resolve) => {
ws.onopen = () => {
console.log('Connected to websocket')
return resolve(ws)
}
})
}
export const disconnectWs = async (ws) => {
return new Promise((resolve) => {
ws.onclose = () => {
return resolve(true)
}
ws.close()
})
}
export const listenWs = async (ws, onMessage, onComplete) => {
let previousText = ''
return new Promise((resolve) => {
let complete = false
ws.onmessage = (e) => {
let jsonData = JSON.parse(e.data)
console.log(jsonData)
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
if (onMessage) onMessage(result)
} else if (dataPayload.messageAdded.author !== 'human') {
if (!complete) {
complete = true
if (onComplete) onComplete(text)
return resolve(text)
}
}
}
}
})
}
+9
View File
@@ -12,6 +12,7 @@ import {
import { generateAnswersWithCustomApi } from './apis/custom-api.mjs'
import { generateAnswersWithAzureOpenaiApi } from './apis/azure-openai-api.mjs'
import { generateAnswersWithWaylaidwandererApi } from './apis/waylaidwanderer-api.mjs'
import { generateAnswersWithPoeWebApi } from './apis/poe-web.mjs'
import {
azureOpenAiApiModelKeys,
bingWebModelKeys,
@@ -25,6 +26,7 @@ import {
githubThirdPartyApiModelKeys,
gptApiModelKeys,
Models,
poeWebModelKeys,
setAccessToken,
} from '../config/index.mjs'
import { config as menuConfig } from '../content-script/menu-tools'
@@ -105,6 +107,13 @@ Browser.runtime.onConnect.addListener((port) => {
await generateAnswersWithAzureOpenaiApi(port, session.question, session)
} else if (githubThirdPartyApiModelKeys.includes(session.modelName)) {
await generateAnswersWithWaylaidwandererApi(port, session.question, session)
} else if (poeWebModelKeys.includes(session.modelName)) {
await generateAnswersWithPoeWebApi(
port,
session.question,
session,
Models[session.modelName].value,
)
}
} catch (err) {
console.error(err)
+17 -2
View File
@@ -13,7 +13,12 @@ import { isMobile } from '../utils/is-mobile.mjs'
export const Models = {
chatgptFree35: { value: 'text-davinci-002-render-sha', desc: 'ChatGPT (Web)' },
chatgptPlus4: { value: 'gpt-4', desc: 'ChatGPT (Web, GPT-4)' },
bingFree4: { value: 'gpt-4', desc: 'Bing (Web, GPT-4)' },
bingFree4: { value: '', desc: 'Bing (Web, GPT-4)' },
bingFreeSydney: { value: '', desc: 'Bing (Web, GPT-4, Sydney)' },
poeAiWebSage: { value: 'sage', desc: 'Poe AI (Web, Sage)' },
poeAiWebGPT4: { value: 'gpt-4', desc: 'Poe AI (Web, GPT-4)' },
poeAiWebClaudePlus: { value: 'claude+', desc: 'Poe AI (Web, Claude+)' },
poeAiWebClaude: { value: 'claude', desc: 'Poe AI (Web, Claude)' },
chatgptApi35: { value: 'gpt-3.5-turbo', desc: 'ChatGPT (GPT-3.5-turbo)' },
chatgptApi4_8k: { value: 'gpt-4', desc: 'ChatGPT (GPT-4-8k)' },
chatgptApi4_32k: { value: 'gpt-4-32k', desc: 'ChatGPT (GPT-4-32k)' },
@@ -21,15 +26,25 @@ export const Models = {
customModel: { value: '', desc: 'Custom Model' },
azureOpenAi: { value: '', desc: 'ChatGPT (Azure)' },
waylaidwandererApi: { value: '', desc: 'Waylaidwanderer API (Github)' },
poeAiWebChatGpt: { value: 'chatgpt', desc: 'Poe AI (Web, ChatGPT)' },
poeAiWebDragonfly: { value: 'dragonfly', desc: 'Poe AI (Web, Dragonfly)' },
}
export const chatgptWebModelKeys = ['chatgptFree35', 'chatgptPlus4']
export const bingWebModelKeys = ['bingFree4']
export const bingWebModelKeys = ['bingFree4', 'bingFreeSydney']
export const gptApiModelKeys = ['gptApiDavinci']
export const chatgptApiModelKeys = ['chatgptApi35', 'chatgptApi4_8k', 'chatgptApi4_32k']
export const customApiModelKeys = ['customModel']
export const azureOpenAiApiModelKeys = ['azureOpenAi']
export const githubThirdPartyApiModelKeys = ['waylaidwandererApi']
export const poeWebModelKeys = [
'poeAiWebSage',
'poeAiWebGPT4',
'poeAiWebClaudePlus',
'poeAiWebClaude',
'poeAiWebChatGpt',
'poeAiWebDragonfly',
]
export const TriggerMode = {
always: 'Always',
+2 -1
View File
@@ -11,7 +11,8 @@
},
"host_permissions": [
"https://*.openai.com/",
"https://*.bing.com/"
"https://*.bing.com/",
"https://*.poe.com/"
],
"permissions": [
"commands",
+2 -1
View File
@@ -17,7 +17,8 @@
"unlimitedStorage",
"tabs",
"https://*.openai.com/",
"https://*.bing.com/"
"https://*.bing.com/",
"https://*.poe.com/"
],
"optional_permissions": [
"background"
+4
View File
@@ -17,6 +17,7 @@ import { Models } from '../config/index.mjs'
* @property {string|null} bingWeb_conversationId
* @property {string|null} bingWeb_clientId
* @property {string|null} bingWeb_invocationId
* @property {number|null} poe_chatId
*/
/**
* @param {string|null} question
@@ -57,5 +58,8 @@ export function initSession({
bingWeb_conversationId: null,
bingWeb_clientId: null,
bingWeb_invocationId: null,
// poe
poe_chatId: null,
}
}