diff --git a/.github/workflows/tagged-release.yml b/.github/workflows/tagged-release.yml index b8c7eb4..04308f0 100644 --- a/.github/workflows/tagged-release.yml +++ b/.github/workflows/tagged-release.yml @@ -62,3 +62,5 @@ jobs: build/safari.dmg build/chromium-without-katex.zip build/firefox-without-katex.zip + build/chromium-without-katex-and-tiktoken.zip + build/firefox-without-katex-and-tiktoken.zip diff --git a/build.mjs b/build.mjs index c379790..ca2667c 100644 --- a/build.mjs +++ b/build.mjs @@ -18,7 +18,7 @@ async function deleteOldDir() { await fs.rm(outdir, { recursive: true, force: true }) } -async function runWebpack(isWithoutKatex, callback) { +async function runWebpack(isWithoutKatex, isWithoutTiktoken, callback) { const compiler = webpack({ entry: { 'content-script': { @@ -37,6 +37,7 @@ async function runWebpack(isWithoutKatex, callback) { 'webextension-polyfill', '@primer/octicons-react', 'react-bootstrap-icons', + 'countries-list', './src/utils', ], }, @@ -169,9 +170,27 @@ async function runWebpack(isWithoutKatex, callback) { type: 'asset/inline', }, { - test: /\.(jpg|svg)$/, + test: /\.(jpg|png|svg)$/, type: 'asset/inline', }, + isWithoutTiktoken + ? { + test: /crop-text\.mjs$/, + loader: 'string-replace-loader', + options: { + multiple: [ + { + search: "import { encode } from '@nem035/gpt-3-encoder'", + replace: '', + }, + { + search: 'encode(', + replace: 'String(', + }, + ], + }, + } + : {}, ], }, }) @@ -244,11 +263,19 @@ async function build() { if (isProduction && !isAnalyzing) { await runWebpack( true, + false, generateWebpackCallback(() => finishOutput('-without-katex')), ) - await new Promise((r) => setTimeout(r, 2000)) + await new Promise((r) => setTimeout(r, 5000)) + await runWebpack( + true, + true, + generateWebpackCallback(() => finishOutput('-without-katex-and-tiktoken')), + ) + await new Promise((r) => setTimeout(r, 5000)) } await runWebpack( + false, false, generateWebpackCallback(() => finishOutput('')), ) diff --git a/package-lock.json b/package-lock.json index 0409fa0..6cb6ec7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,6 +60,7 @@ "run-script-os": "^1.1.6", "sass": "^1.59.3", "sass-loader": "^13.2.1", + "string-replace-loader": "^3.1.0", "terser-webpack-plugin": "^5.3.7", "webpack": "^5.76.2", "webpack-bundle-analyzer": "^4.8.0" @@ -2834,6 +2835,15 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmmirror.com/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -3667,6 +3677,15 @@ "integrity": "sha512-YyE8+GKyGtPEP1/kpvqsdhD6rA/TP1DUFDN4uiU/YI52NzDxmwHkEb3qjId8hLBa5siJvG0sfC3O66501jMruQ==", "dev": true }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -5582,6 +5601,20 @@ "node": ">=6.11.5" } }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz", @@ -8193,6 +8226,33 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-replace-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/string-replace-loader/-/string-replace-loader-3.1.0.tgz", + "integrity": "sha512-5AOMUZeX5HE/ylKDnEa/KKBqvlnFmRZudSOjVJHxhoJg9QYTwl1rECx7SLR8BBH7tfxb4Rp7EM2XVfQFxIhsbQ==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "peerDependencies": { + "webpack": "^5" + } + }, + "node_modules/string-replace-loader/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/string.prototype.matchall": { "version": "4.0.8", "resolved": "https://registry.npmmirror.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", diff --git a/package.json b/package.json index 14b49b1..fddfb44 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "run-script-os": "^1.1.6", "sass": "^1.59.3", "sass-loader": "^13.2.1", + "string-replace-loader": "^3.1.0", "terser-webpack-plugin": "^5.3.7", "webpack": "^5.76.2", "webpack-bundle-analyzer": "^4.8.0" diff --git a/src/background/apis/chatgpt-web.mjs b/src/background/apis/chatgpt-web.mjs index 178cf01..7f47e23 100644 --- a/src/background/apis/chatgpt-web.mjs +++ b/src/background/apis/chatgpt-web.mjs @@ -2,7 +2,7 @@ import { fetchSSE } from '../../utils/fetch-sse' import { isEmpty } from 'lodash-es' -import { chatgptWebModelKeys, getUserConfig, Models } from '../../config' +import { chatgptWebModelKeys, getUserConfig, Models } from '../../config/index.mjs' async function request(token, method, path, data) { const apiUrl = (await getUserConfig()).customChatGptWebApiUrl diff --git a/src/background/apis/openai-api.mjs b/src/background/apis/openai-api.mjs index 409cb52..b459a55 100644 --- a/src/background/apis/openai-api.mjs +++ b/src/background/apis/openai-api.mjs @@ -1,6 +1,6 @@ // api version -import { maxResponseTokenLength, Models, getUserConfig } from '../../config' +import { maxResponseTokenLength, Models, getUserConfig } from '../../config/index.mjs' import { fetchSSE } from '../../utils/fetch-sse' import { getConversationPairs } from '../../utils/get-conversation-pairs' import { isEmpty } from 'lodash-es' diff --git a/src/background/index.mjs b/src/background/index.mjs index bcc8c9d..d887be2 100644 --- a/src/background/index.mjs +++ b/src/background/index.mjs @@ -9,12 +9,12 @@ import { import { chatgptApiModelKeys, chatgptWebModelKeys, + defaultConfig, getUserConfig, gptApiModelKeys, isUsingApiKey, -} from '../config' +} from '../config/index.mjs' import { isSafari } from '../utils/is-safari' -import { config as toolsConfig } from '../content-script/selection-tools' const KEY_ACCESS_TOKEN = 'accessToken' const cache = new ExpiryMap(10 * 1000) @@ -114,12 +114,13 @@ Browser.contextMenus.removeAll().then(() => { title: 'New Chat', contexts: ['selection'], }) - for (const key in toolsConfig) { - const toolConfig = toolsConfig[key] + 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: toolConfig.label, + title: desc, contexts: ['selection'], }) } diff --git a/src/components/ConversationCard/index.jsx b/src/components/ConversationCard/index.jsx index 3007886..577fabd 100644 --- a/src/components/ConversationCard/index.jsx +++ b/src/components/ConversationCard/index.jsx @@ -10,7 +10,7 @@ import FileSaver from 'file-saver' import { render } from 'preact' import FloatingToolbar from '../FloatingToolbar' import { useClampWindowSize } from '../../hooks/use-clamp-window-size' -import { defaultConfig, getUserConfig } from '../../config' +import { defaultConfig, getUserConfig } from '../../config/index.mjs' const logo = Browser.runtime.getURL('logo.png') diff --git a/src/components/DecisionCard/index.jsx b/src/components/DecisionCard/index.jsx index 665d650..cd2dd46 100644 --- a/src/components/DecisionCard/index.jsx +++ b/src/components/DecisionCard/index.jsx @@ -2,7 +2,7 @@ import { LightBulbIcon, SearchIcon } from '@primer/octicons-react' import { useState, useEffect } from 'react' import PropTypes from 'prop-types' import ConversationCard from '../ConversationCard' -import { defaultConfig, getUserConfig } from '../../config' +import { defaultConfig, getUserConfig } from '../../config/index.mjs' import Browser from 'webextension-polyfill' import { getPossibleElementByQuerySelector, endsWithQuestionMark } from '../../utils' diff --git a/src/components/FloatingToolbar/index.jsx b/src/components/FloatingToolbar/index.jsx index 43a817c..897ed2d 100644 --- a/src/components/FloatingToolbar/index.jsx +++ b/src/components/FloatingToolbar/index.jsx @@ -2,7 +2,7 @@ import Browser from 'webextension-polyfill' import { cloneElement, useEffect, useState } from 'react' import ConversationCard from '../ConversationCard' import PropTypes from 'prop-types' -import { defaultConfig, getUserConfig } from '../../config.mjs' +import { defaultConfig, getUserConfig } from '../../config/index.mjs' import { config as toolsConfig } from '../../content-script/selection-tools' import { isMobile, setElementPositionInViewport } from '../../utils' import Draggable from 'react-draggable' diff --git a/src/config.mjs b/src/config/index.mjs similarity index 77% rename from src/config.mjs rename to src/config/index.mjs index f3a3b67..0c53bb0 100644 --- a/src/config.mjs +++ b/src/config/index.mjs @@ -1,8 +1,6 @@ import { defaults } from 'lodash-es' import Browser from 'webextension-polyfill' -import { isMobile } from './utils/is-mobile' -import { config as toolsConfig } from './content-script/selection-tools' -import { languages } from 'countries-list' +import { isMobile } from '../utils/is-mobile.mjs' /** * @typedef {object} Model @@ -37,8 +35,6 @@ export const ThemeMode = { auto: 'Auto', } -export const languageList = { auto: { name: 'Auto', native: 'Auto' }, ...languages } - export const maxResponseTokenLength = 1000 /** @@ -71,7 +67,7 @@ export const defaultConfig = { // others - activeSelectionTools: Object.keys(toolsConfig).filter((i) => i !== 'translateBidi'), + activeSelectionTools: ['translate', 'summary', 'polish', 'sentiment', 'divide', 'code', 'ask'], activeSiteAdapters: [ 'bilibili', 'github', @@ -88,7 +84,26 @@ export const defaultConfig = { // unchangeable userLanguage: navigator.language.substring(0, 2), - selectionTools: Object.keys(toolsConfig), + selectionTools: [ + 'translate', + 'translateBidi', + 'summary', + 'polish', + 'sentiment', + 'divide', + 'code', + 'ask', + ], + selectionToolsDesc: [ + 'Translate', + 'Translate (Bidirectional)', + 'Summary', + 'Polish', + 'Sentiment Analysis', + 'Divide Paragraphs', + 'Code Explain', + 'Ask', + ], // importing configuration will result in gpt-3-encoder being packaged into the output file siteAdapters: [ 'bilibili', @@ -102,26 +117,6 @@ export const defaultConfig = { ], } -export async function getUserLanguage() { - return languageList[defaultConfig.userLanguage].name -} - -export async function getUserLanguageNative() { - return languageList[defaultConfig.userLanguage].native -} - -export async function getPreferredLanguage() { - const config = await getUserConfig() - if (config.preferredLanguage === 'auto') return await getUserLanguage() - return languageList[config.preferredLanguage].name -} - -export async function getPreferredLanguageNative() { - const config = await getUserConfig() - if (config.preferredLanguage === 'auto') return await getUserLanguageNative() - return languageList[config.preferredLanguage].native -} - export function isUsingApiKey(config) { return ( gptApiModelKeys.includes(config.modelName) || chatgptApiModelKeys.includes(config.modelName) diff --git a/src/config/language.mjs b/src/config/language.mjs new file mode 100644 index 0000000..8e9d03c --- /dev/null +++ b/src/config/language.mjs @@ -0,0 +1,24 @@ +import { languages } from 'countries-list' +import { defaultConfig, getUserConfig } from './index.mjs' + +export const languageList = { auto: { name: 'Auto', native: 'Auto' }, ...languages } + +export async function getUserLanguage() { + return languageList[defaultConfig.userLanguage].name +} + +export async function getUserLanguageNative() { + return languageList[defaultConfig.userLanguage].native +} + +export async function getPreferredLanguage() { + const config = await getUserConfig() + if (config.preferredLanguage === 'auto') return await getUserLanguage() + return languageList[config.preferredLanguage].name +} + +export async function getPreferredLanguageNative() { + const config = await getUserConfig() + if (config.preferredLanguage === 'auto') return await getUserLanguageNative() + return languageList[config.preferredLanguage].native +} diff --git a/src/content-script/index.jsx b/src/content-script/index.jsx index 0dd8ba0..cd985e3 100644 --- a/src/content-script/index.jsx +++ b/src/content-script/index.jsx @@ -4,7 +4,7 @@ import { render } from 'preact' import DecisionCard from '../components/DecisionCard' import { config as siteConfig } from './site-adapters' import { config as toolsConfig } from './selection-tools' -import { clearOldAccessToken, getUserConfig, setAccessToken, getPreferredLanguage } from '../config' +import { clearOldAccessToken, getUserConfig, setAccessToken } from '../config/index.mjs' import { createElementAtPosition, getPossibleElementByQuerySelector, @@ -13,6 +13,7 @@ import { } from '../utils' import FloatingToolbar from '../components/FloatingToolbar' import Browser from 'webextension-polyfill' +import { getPreferredLanguage } from '../config/language.mjs' /** * @param {SiteConfig} siteConfig diff --git a/src/content-script/selection-tools/index.mjs b/src/content-script/selection-tools/index.mjs index 3b7fa07..4e50010 100644 --- a/src/content-script/selection-tools/index.mjs +++ b/src/content-script/selection-tools/index.mjs @@ -8,7 +8,7 @@ import { Braces, Globe, } from 'react-bootstrap-icons' -import { getPreferredLanguage } from '../../config.mjs' +import { getPreferredLanguage } from '../../config/language.mjs' export const config = { translate: { diff --git a/src/popup/Popup.jsx b/src/popup/Popup.jsx index 2b4eced..2f3b995 100644 --- a/src/popup/Popup.jsx +++ b/src/popup/Popup.jsx @@ -8,8 +8,7 @@ import { defaultConfig, Models, isUsingApiKey, - languageList, -} from '../config' +} from '../config/index.mjs' import { Tab, Tabs, TabList, TabPanel } from 'react-tabs' import 'react-tabs/style/react-tabs.css' import './styles.scss' @@ -18,8 +17,9 @@ import Browser from 'webextension-polyfill' import PropTypes from 'prop-types' import { config as toolsConfig } from '../content-script/selection-tools' import wechatpay from './donation/wechatpay.jpg' -import bugmeacoffee from './donation/bugmeacoffee.svg' +import bugmeacoffee from './donation/bugmeacoffee.png' import { useWindowTheme } from '../hooks/use-window-theme.mjs' +import { languageList } from '../config/language.mjs' function GeneralPart({ config, updateConfig }) { const [balance, setBalance] = useState(null) diff --git a/src/popup/donation/bugmeacoffee.png b/src/popup/donation/bugmeacoffee.png new file mode 100644 index 0000000..748ed25 Binary files /dev/null and b/src/popup/donation/bugmeacoffee.png differ diff --git a/src/popup/donation/bugmeacoffee.svg b/src/popup/donation/bugmeacoffee.svg deleted file mode 100644 index ef9943e..0000000 --- a/src/popup/donation/bugmeacoffee.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/utils/crop-text.mjs b/src/utils/crop-text.mjs index a507d69..cb0ad82 100644 --- a/src/utils/crop-text.mjs +++ b/src/utils/crop-text.mjs @@ -20,7 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { maxResponseTokenLength } from '../config.mjs' +import { maxResponseTokenLength } from '../config/index.mjs' import { encode } from '@nem035/gpt-3-encoder' // TODO add model support