refactor: services

This commit is contained in:
josc146
2023-04-27 20:31:53 +08:00
parent 9b157ff01e
commit 17778f5a14
48 changed files with 272 additions and 269 deletions
+27
View File
@@ -0,0 +1,27 @@
import Browser from 'webextension-polyfill'
import { config as menuConfig } from '../content-script/menu-tools/index.mjs'
export function registerCommands() {
Browser.commands.onCommand.addListener(async (command) => {
const message = {
itemId: command,
selectionText: '',
useMenuPosition: false,
}
console.debug('command triggered', message)
if (command in menuConfig) {
if (menuConfig[command].action) {
menuConfig[command].action()
}
if (menuConfig[command].genPrompt) {
const currentTab = (await Browser.tabs.query({ active: true, currentWindow: true }))[0]
Browser.tabs.sendMessage(currentTab.id, {
type: 'CREATE_CHAT',
data: message,
})
}
}
})
}
+61 -231
View File
@@ -4,161 +4,85 @@ import {
deleteConversation,
generateAnswersWithChatgptWebApi,
sendMessageFeedback,
} from './apis/chatgpt-web'
import { generateAnswersWithBingWebApi } from './apis/bing-web.mjs'
} from '../services/apis/chatgpt-web'
import { generateAnswersWithBingWebApi } from '../services/apis/bing-web.mjs'
import {
generateAnswersWithChatgptApi,
generateAnswersWithGptCompletionApi,
} from './apis/openai-api'
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'
} from '../services/apis/openai-api'
import { generateAnswersWithCustomApi } from '../services/apis/custom-api.mjs'
import { generateAnswersWithAzureOpenaiApi } from '../services/apis/azure-openai-api.mjs'
import { generateAnswersWithWaylaidwandererApi } from '../services/apis/waylaidwanderer-api.mjs'
import { generateAnswersWithPoeWebApi } from '../services/apis/poe-web.mjs'
import {
azureOpenAiApiModelKeys,
bingWebModelKeys,
chatgptApiModelKeys,
chatgptWebModelKeys,
clearOldAccessToken,
customApiModelKeys,
defaultConfig,
getPreferredLanguageKey,
getUserConfig,
githubThirdPartyApiModelKeys,
gptApiModelKeys,
Models,
poeWebModelKeys,
setAccessToken,
} from '../config/index.mjs'
import { config as menuConfig } from '../content-script/menu-tools'
import { t, changeLanguage } from 'i18next'
import '../_locales/i18n'
import { openUrl } from '../utils/open-url'
import {
getBingAccessToken,
getChatGptAccessToken,
registerPortListener,
} from '../services/wrappers.mjs'
import { refreshMenu } from './menus.mjs'
import { registerCommands } from './commands.mjs'
async function getChatGptAccessToken() {
await clearOldAccessToken()
const userConfig = await getUserConfig()
if (userConfig.accessToken) {
return userConfig.accessToken
} else {
const cookie = (await Browser.cookies.getAll({ url: 'https://chat.openai.com/' }))
.map((cookie) => {
return `${cookie.name}=${cookie.value}`
})
.join('; ')
const resp = await fetch('https://chat.openai.com/api/auth/session', {
headers: {
Cookie: cookie,
},
})
if (resp.status === 403) {
throw new Error('CLOUDFLARE')
async function executeApi(session, port, config) {
if (chatgptWebModelKeys.includes(session.modelName)) {
const accessToken = await getChatGptAccessToken()
session.messageId = uuidv4()
if (session.parentMessageId == null) {
session.parentMessageId = uuidv4()
}
const data = await resp.json().catch(() => ({}))
if (!data.accessToken) {
throw new Error('UNAUTHORIZED')
}
await setAccessToken(data.accessToken)
return data.accessToken
await generateAnswersWithChatgptWebApi(port, session.question, session, accessToken)
} else if (bingWebModelKeys.includes(session.modelName)) {
const accessToken = await getBingAccessToken()
if (session.modelName === 'bingFreeSydney')
await generateAnswersWithBingWebApi(port, session.question, session, accessToken, true)
else await generateAnswersWithBingWebApi(port, session.question, session, accessToken)
} else if (gptApiModelKeys.includes(session.modelName)) {
await generateAnswersWithGptCompletionApi(
port,
session.question,
session,
config.apiKey,
session.modelName,
)
} else if (chatgptApiModelKeys.includes(session.modelName)) {
await generateAnswersWithChatgptApi(
port,
session.question,
session,
config.apiKey,
session.modelName,
)
} else if (customApiModelKeys.includes(session.modelName)) {
await generateAnswersWithCustomApi(port, session.question, session, '', config.customModelName)
} else if (azureOpenAiApiModelKeys.includes(session.modelName)) {
await generateAnswersWithAzureOpenaiApi(port, session.question, session)
} else if (githubThirdPartyApiModelKeys.includes(session.modelName)) {
await generateAnswersWithWaylaidwandererApi(port, session.question, session)
} else if (poeWebModelKeys.includes(session.modelName)) {
if (session.modelName === 'poeAiWebCustom')
await generateAnswersWithPoeWebApi(port, session.question, session, config.poeCustomBotName)
else
await generateAnswersWithPoeWebApi(
port,
session.question,
session,
Models[session.modelName].value,
)
}
}
async function getBingAccessToken() {
return (await Browser.cookies.get({ url: 'https://bing.com/', name: '_U' }))?.value
}
Browser.runtime.onConnect.addListener((port) => {
console.debug('connected')
const onMessage = async (msg) => {
console.debug('received msg', msg)
const session = msg.session
if (!session) return
const config = await getUserConfig()
if (!session.modelName) session.modelName = config.modelName
if (!session.aiName) session.aiName = Models[session.modelName].desc
port.postMessage({ session })
try {
if (chatgptWebModelKeys.includes(session.modelName)) {
const accessToken = await getChatGptAccessToken()
session.messageId = uuidv4()
if (session.parentMessageId == null) {
session.parentMessageId = uuidv4()
}
await generateAnswersWithChatgptWebApi(port, session.question, session, accessToken)
} else if (bingWebModelKeys.includes(session.modelName)) {
const accessToken = await getBingAccessToken()
if (session.modelName === 'bingFreeSydney')
await generateAnswersWithBingWebApi(port, session.question, session, accessToken, true)
else await generateAnswersWithBingWebApi(port, session.question, session, accessToken)
} else if (gptApiModelKeys.includes(session.modelName)) {
await generateAnswersWithGptCompletionApi(
port,
session.question,
session,
config.apiKey,
session.modelName,
)
} else if (chatgptApiModelKeys.includes(session.modelName)) {
await generateAnswersWithChatgptApi(
port,
session.question,
session,
config.apiKey,
session.modelName,
)
} else if (customApiModelKeys.includes(session.modelName)) {
await generateAnswersWithCustomApi(
port,
session.question,
session,
'',
config.customModelName,
)
} else if (azureOpenAiApiModelKeys.includes(session.modelName)) {
await generateAnswersWithAzureOpenaiApi(port, session.question, session)
} else if (githubThirdPartyApiModelKeys.includes(session.modelName)) {
await generateAnswersWithWaylaidwandererApi(port, session.question, session)
} else if (poeWebModelKeys.includes(session.modelName)) {
if (session.modelName === 'poeAiWebCustom')
await generateAnswersWithPoeWebApi(
port,
session.question,
session,
config.poeCustomBotName,
)
else
await generateAnswersWithPoeWebApi(
port,
session.question,
session,
Models[session.modelName].value,
)
}
} catch (err) {
console.error(err)
if (!err.message.includes('aborted')) {
if (
['message you submitted was too long', 'maximum context length'].some((m) =>
err.message.includes(m),
)
)
port.postMessage({ error: t('Exceeded maximum context length') + '\n' + err.message })
else port.postMessage({ error: err.message })
}
}
}
const onDisconnect = () => {
console.debug('port disconnected, remove listener')
port.onMessage.removeListener(onMessage)
port.onDisconnect.removeListener(onDisconnect)
}
port.onMessage.addListener(onMessage)
port.onDisconnect.addListener(onDisconnect)
})
Browser.runtime.onMessage.addListener(async (message) => {
if (message.type === 'FEEDBACK') {
const token = await getChatGptAccessToken()
@@ -170,105 +94,11 @@ Browser.runtime.onMessage.addListener(async (message) => {
} else if (message.type === 'OPEN_URL') {
const data = message.data
openUrl(data.url)
}
})
Browser.commands.onCommand.addListener(async (command) => {
const message = {
itemId: command,
selectionText: '',
useMenuPosition: false,
}
console.debug('command triggered', message)
if (command in menuConfig) {
if (menuConfig[command].action) {
menuConfig[command].action()
}
if (menuConfig[command].genPrompt) {
const currentTab = (await Browser.tabs.query({ active: true, currentWindow: true }))[0]
Browser.tabs.sendMessage(currentTab.id, {
type: 'CREATE_CHAT',
data: message,
})
}
}
})
function refreshMenu() {
Browser.contextMenus.removeAll().then(async () => {
await getPreferredLanguageKey().then((lang) => {
changeLanguage(lang)
})
const menuId = 'ChatGPTBox-Menu'
Browser.contextMenus.create({
id: menuId,
title: 'ChatGPTBox',
contexts: ['all'],
})
for (const [k, v] of Object.entries(menuConfig)) {
Browser.contextMenus.create({
id: menuId + k,
parentId: menuId,
title: t(v.label),
contexts: ['all'],
})
}
Browser.contextMenus.create({
id: menuId + 'separator1',
parentId: menuId,
contexts: ['selection'],
type: 'separator',
})
for (const index in defaultConfig.selectionTools) {
const key = defaultConfig.selectionTools[index]
const desc = defaultConfig.selectionToolsDesc[index]
Browser.contextMenus.create({
id: menuId + key,
parentId: menuId,
title: t(desc),
contexts: ['selection'],
})
}
Browser.contextMenus.onClicked.addListener((info, tab) => {
Browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => {
const currentTab = tabs[0]
const message = {
itemId: info.menuItemId.replace(menuId, ''),
selectionText: info.selectionText,
useMenuPosition: tab.id === currentTab.id,
}
console.debug('menu clicked', message)
if (defaultConfig.selectionTools.includes(message.itemId)) {
Browser.tabs.sendMessage(currentTab.id, {
type: 'CREATE_CHAT',
data: message,
})
} else if (message.itemId in menuConfig) {
if (menuConfig[message.itemId].action) {
menuConfig[message.itemId].action()
}
if (menuConfig[message.itemId].genPrompt) {
Browser.tabs.sendMessage(currentTab.id, {
type: 'CREATE_CHAT',
data: message,
})
}
}
})
})
})
}
Browser.runtime.onMessage.addListener(async (message) => {
if (message.type === 'REFRESH_MENU') {
} else if (message.type === 'REFRESH_MENU') {
refreshMenu()
}
})
registerPortListener(async (session, port, config) => await executeApi(session, port, config))
registerCommands()
refreshMenu()
+73
View File
@@ -0,0 +1,73 @@
import Browser from 'webextension-polyfill'
import { defaultConfig, getPreferredLanguageKey } from '../config/index.mjs'
import { changeLanguage, t } from 'i18next'
import { config as menuConfig } from '../content-script/menu-tools/index.mjs'
export function refreshMenu() {
Browser.contextMenus.removeAll().then(async () => {
await getPreferredLanguageKey().then((lang) => {
changeLanguage(lang)
})
const menuId = 'ChatGPTBox-Menu'
Browser.contextMenus.create({
id: menuId,
title: 'ChatGPTBox',
contexts: ['all'],
})
for (const [k, v] of Object.entries(menuConfig)) {
Browser.contextMenus.create({
id: menuId + k,
parentId: menuId,
title: t(v.label),
contexts: ['all'],
})
}
Browser.contextMenus.create({
id: menuId + 'separator1',
parentId: menuId,
contexts: ['selection'],
type: 'separator',
})
for (const index in defaultConfig.selectionTools) {
const key = defaultConfig.selectionTools[index]
const desc = defaultConfig.selectionToolsDesc[index]
Browser.contextMenus.create({
id: menuId + key,
parentId: menuId,
title: t(desc),
contexts: ['selection'],
})
}
Browser.contextMenus.onClicked.addListener((info, tab) => {
Browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => {
const currentTab = tabs[0]
const message = {
itemId: info.menuItemId.replace(menuId, ''),
selectionText: info.selectionText,
useMenuPosition: tab.id === currentTab.id,
}
console.debug('menu clicked', message)
if (defaultConfig.selectionTools.includes(message.itemId)) {
Browser.tabs.sendMessage(currentTab.id, {
type: 'CREATE_CHAT',
data: message,
})
} else if (message.itemId in menuConfig) {
if (menuConfig[message.itemId].action) {
menuConfig[message.itemId].action()
}
if (menuConfig[message.itemId].genPrompt) {
Browser.tabs.sendMessage(currentTab.id, {
type: 'CREATE_CHAT',
data: message,
})
}
}
})
})
})
}
+3 -2
View File
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import Browser from 'webextension-polyfill'
import InputBox from '../InputBox'
import ConversationItem from '../ConversationItem'
import { createElementAtPosition, initSession, isSafari } from '../../utils'
import { createElementAtPosition, isSafari } from '../../utils'
import { DownloadIcon, LinkExternalIcon, ArchiveIcon } from '@primer/octicons-react'
import { WindowDesktop, XLg, Pin } from 'react-bootstrap-icons'
import FileSaver from 'file-saver'
@@ -14,8 +14,9 @@ import { Models } from '../../config/index.mjs'
import { useTranslation } from 'react-i18next'
import DeleteButton from '../DeleteButton'
import { useConfig } from '../../hooks/use-config.mjs'
import { createSession } from '../../config/localSession.mjs'
import { createSession } from '../../services/local-session.mjs'
import { v4 as uuidv4 } from 'uuid'
import { initSession } from '../../services/init-session.mjs'
const logo = Browser.runtime.getURL('logo.png')
+22 -22
View File
@@ -11,13 +11,13 @@ import {
cropText,
getClientPosition,
getPossibleElementByQuerySelector,
initSession,
} from '../utils'
import FloatingToolbar from '../components/FloatingToolbar'
import Browser from 'webextension-polyfill'
import { getPreferredLanguage } from '../config/language.mjs'
import '../_locales/i18n-react'
import { changeLanguage } from 'i18next'
import { initSession } from '../services/init-session.mjs'
/**
* @param {SiteConfig} siteConfig
@@ -99,27 +99,6 @@ async function getInput(inputQuery) {
}
}
async function overwriteAccessToken() {
if (location.hostname !== 'chat.openai.com') return
let data
if (location.pathname === '/api/auth/session') {
const response = document.querySelector('pre').textContent
try {
data = JSON.parse(response)
} catch (error) {
console.error('json error', error)
}
} else {
const resp = await fetch('https://chat.openai.com/api/auth/session')
data = await resp.json().catch(() => ({}))
}
if (data && data.accessToken) {
await setAccessToken(data.accessToken)
console.log(data.accessToken)
}
}
let toolbarContainer
const deleteToolbar = () => {
if (toolbarContainer && toolbarContainer.className === 'chatgptbox-toolbar-container')
@@ -293,6 +272,27 @@ async function prepareForStaticCard() {
}
}
async function overwriteAccessToken() {
if (location.hostname !== 'chat.openai.com') return
let data
if (location.pathname === '/api/auth/session') {
const response = document.querySelector('pre').textContent
try {
data = JSON.parse(response)
} catch (error) {
console.error('json error', error)
}
} else {
const resp = await fetch('https://chat.openai.com/api/auth/session')
data = await resp.json().catch(() => ({}))
}
if (data && data.accessToken) {
await setAccessToken(data.accessToken)
console.log(data.accessToken)
}
}
async function run() {
await getPreferredLanguageKey().then((lang) => {
changeLanguage(lang)
+1 -1
View File
@@ -5,7 +5,7 @@ import {
updateSession,
getSession,
deleteSession,
} from '../../config/localSession'
} from '../../services/local-session.mjs'
import { useEffect, useRef, useState } from 'react'
import './styles.scss'
import { useConfig } from '../../hooks/use-config.mjs'
@@ -1,7 +1,7 @@
import { getUserConfig } from '../../config/index.mjs'
import { getChatSystemPromptBase, pushRecord, setAbortController } from './shared.mjs'
import { getConversationPairs } from '../../utils/get-conversation-pairs'
import { fetchSSE } from '../../utils/fetch-sse'
import { getConversationPairs } from '../../utils/get-conversation-pairs.mjs'
import { fetchSSE } from '../../utils/fetch-sse.mjs'
import { isEmpty } from 'lodash-es'
/**
@@ -1,4 +1,4 @@
import BingAIClient from '../clients/bing'
import BingAIClient from '../clients/bing/index.mjs'
import { getUserConfig } from '../../config/index.mjs'
import { pushRecord, setAbortController } from './shared.mjs'
@@ -1,6 +1,6 @@
// web version
import { fetchSSE } from '../../utils/fetch-sse'
import { fetchSSE } from '../../utils/fetch-sse.mjs'
import { isEmpty } from 'lodash-es'
import { chatgptWebModelKeys, getUserConfig, Models } from '../../config/index.mjs'
import { pushRecord, setAbortController } from './shared.mjs'
@@ -6,8 +6,8 @@
// If necessary, I will refactor.
import { getUserConfig } from '../../config/index.mjs'
import { fetchSSE } from '../../utils/fetch-sse'
import { getConversationPairs } from '../../utils/get-conversation-pairs'
import { fetchSSE } from '../../utils/fetch-sse.mjs'
import { getConversationPairs } from '../../utils/get-conversation-pairs.mjs'
import { isEmpty } from 'lodash-es'
import { getCustomApiPromptBase, pushRecord, setAbortController } from './shared.mjs'
@@ -1,8 +1,8 @@
// api version
import { Models, getUserConfig } from '../../config/index.mjs'
import { fetchSSE } from '../../utils/fetch-sse'
import { getConversationPairs } from '../../utils/get-conversation-pairs'
import { fetchSSE } from '../../utils/fetch-sse.mjs'
import { getConversationPairs } from '../../utils/get-conversation-pairs.mjs'
import { isEmpty } from 'lodash-es'
import {
getChatSystemPromptBase,
@@ -1,5 +1,5 @@
import { pushRecord, setAbortController } from './shared.mjs'
import PoeAiClient from '../clients/poe'
import PoeAiClient from '../clients/poe/index.mjs'
/**
* @param {Runtime.Port} port
@@ -1,6 +1,6 @@
import { pushRecord, setAbortController } from './shared.mjs'
import { getUserConfig } from '../../config/index.mjs'
import { fetchSSE } from '../../utils/fetch-sse'
import { fetchSSE } from '../../utils/fetch-sse.mjs'
import { isEmpty } from 'lodash-es'
/**
@@ -1,6 +1,6 @@
import Browser from 'webextension-polyfill'
import { initSession } from '../utils/index.mjs'
import { getUserConfig } from './index.mjs'
import { initSession } from './init-session.mjs'
import { getUserConfig } from '../config/index.mjs'
export const initDefaultSession = async () => {
const config = await getUserConfig()
+73
View File
@@ -0,0 +1,73 @@
import { clearOldAccessToken, getUserConfig, Models, setAccessToken } from '../config/index.mjs'
import Browser from 'webextension-polyfill'
import { t } from 'i18next'
export async function getChatGptAccessToken() {
await clearOldAccessToken()
const userConfig = await getUserConfig()
if (userConfig.accessToken) {
return userConfig.accessToken
} else {
const cookie = (await Browser.cookies.getAll({ url: 'https://chat.openai.com/' }))
.map((cookie) => {
return `${cookie.name}=${cookie.value}`
})
.join('; ')
const resp = await fetch('https://chat.openai.com/api/auth/session', {
headers: {
Cookie: cookie,
},
})
if (resp.status === 403) {
throw new Error('CLOUDFLARE')
}
const data = await resp.json().catch(() => ({}))
if (!data.accessToken) {
throw new Error('UNAUTHORIZED')
}
await setAccessToken(data.accessToken)
return data.accessToken
}
}
export async function getBingAccessToken() {
return (await Browser.cookies.get({ url: 'https://bing.com/', name: '_U' }))?.value
}
export function registerPortListener(executor) {
Browser.runtime.onConnect.addListener((port) => {
console.debug('connected')
const onMessage = async (msg) => {
console.debug('received msg', msg)
const session = msg.session
if (!session) return
const config = await getUserConfig()
if (!session.modelName) session.modelName = config.modelName
if (!session.aiName) session.aiName = Models[session.modelName].desc
port.postMessage({ session })
try {
await executor(session, port, config)
} catch (err) {
console.error(err)
if (!err.message.includes('aborted')) {
if (
['message you submitted was too long', 'maximum context length'].some((m) =>
err.message.includes(m),
)
)
port.postMessage({ error: t('Exceeded maximum context length') + '\n' + err.message })
else port.postMessage({ error: err.message })
}
}
}
const onDisconnect = () => {
console.debug('port disconnected, remove listener')
port.onMessage.removeListener(onMessage)
port.onDisconnect.removeListener(onDisconnect)
}
port.onMessage.addListener(onMessage)
port.onDisconnect.addListener(onDisconnect)
})
}
-1
View File
@@ -7,7 +7,6 @@ export * from './get-client-position'
export * from './get-conversation-pairs'
export * from './get-core-content-text'
export * from './get-possible-element-by-query-selector'
export * from './init-session'
export * from './is-edge'
export * from './is-firefox'
export * from './is-mobile'