Repository: ChatGPTBox-dev/chatGPTBox Branch: master Commit: c236a4b12818 Files: 227 Total size: 910.5 KB Directory structure: gitextract_4t6jkhck/ ├── .eslintrc.json ├── .gitattributes ├── .github/ │ ├── CONTRIBUTING.md │ ├── ISSUE_TEMPLATE/ │ │ ├── bug-report---问题报告.md │ │ └── feature-request---新功能请求.md │ ├── dependabot.yml │ └── workflows/ │ ├── pr-tests.yml │ ├── pre-release-build.yml │ ├── scripts/ │ │ ├── update-coverage-badge.mjs │ │ └── verify-search-engine-configs.mjs │ ├── tagged-release.yml │ └── verify-configs.yml ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── AGENTS.md ├── CURRENT_CHANGE.md ├── LICENSE ├── README.md ├── README_IN.md ├── README_JA.md ├── README_TR.md ├── README_ZH.md ├── badges/ │ └── coverage.json ├── build.mjs ├── package.json ├── safari/ │ ├── appdmg.json │ ├── build.sh │ ├── export-options.plist │ ├── project.patch │ ├── project.pre.patch │ └── project_developer.patch ├── src/ │ ├── _locales/ │ │ ├── de/ │ │ │ └── main.json │ │ ├── en/ │ │ │ └── main.json │ │ ├── es/ │ │ │ └── main.json │ │ ├── fr/ │ │ │ └── main.json │ │ ├── i18n-react.mjs │ │ ├── i18n.mjs │ │ ├── in/ │ │ │ └── main.json │ │ ├── it/ │ │ │ └── main.json │ │ ├── ja/ │ │ │ └── main.json │ │ ├── ko/ │ │ │ └── main.json │ │ ├── pt/ │ │ │ └── main.json │ │ ├── resources.mjs │ │ ├── ru/ │ │ │ └── main.json │ │ ├── tr/ │ │ │ └── main.json │ │ ├── zh-hans/ │ │ │ └── main.json │ │ └── zh-hant/ │ │ └── main.json │ ├── background/ │ │ ├── commands.mjs │ │ ├── index.mjs │ │ ├── menus.mjs │ │ └── redact.mjs │ ├── components/ │ │ ├── ConfirmButton/ │ │ │ └── index.jsx │ │ ├── ConversationCard/ │ │ │ └── index.jsx │ │ ├── ConversationItem/ │ │ │ └── index.jsx │ │ ├── CopyButton/ │ │ │ └── index.jsx │ │ ├── DecisionCard/ │ │ │ └── index.jsx │ │ ├── DeleteButton/ │ │ │ └── index.jsx │ │ ├── FeedbackForChatGPTWeb/ │ │ │ └── index.jsx │ │ ├── FloatingToolbar/ │ │ │ └── index.jsx │ │ ├── InputBox/ │ │ │ └── index.jsx │ │ ├── MarkdownRender/ │ │ │ ├── Hyperlink.jsx │ │ │ ├── Pre.jsx │ │ │ ├── markdown-without-katex.jsx │ │ │ └── markdown.jsx │ │ ├── ReadButton/ │ │ │ └── index.jsx │ │ ├── WebJumpBackNotification/ │ │ │ └── index.jsx │ │ └── index.mjs │ ├── config/ │ │ ├── index.mjs │ │ └── language.mjs │ ├── content-script/ │ │ ├── index.jsx │ │ ├── menu-tools/ │ │ │ └── index.mjs │ │ ├── selection-tools/ │ │ │ └── index.mjs │ │ ├── site-adapters/ │ │ │ ├── arxiv/ │ │ │ │ └── index.mjs │ │ │ ├── baidu/ │ │ │ │ └── index.mjs │ │ │ ├── bilibili/ │ │ │ │ └── index.mjs │ │ │ ├── brave/ │ │ │ │ └── index.mjs │ │ │ ├── duckduckgo/ │ │ │ │ └── index.mjs │ │ │ ├── followin/ │ │ │ │ └── index.mjs │ │ │ ├── github/ │ │ │ │ └── index.mjs │ │ │ ├── gitlab/ │ │ │ │ └── index.mjs │ │ │ ├── index.mjs │ │ │ ├── juejin/ │ │ │ │ └── index.mjs │ │ │ ├── quora/ │ │ │ │ └── index.mjs │ │ │ ├── reddit/ │ │ │ │ └── index.mjs │ │ │ ├── stackoverflow/ │ │ │ │ └── index.mjs │ │ │ ├── weixin/ │ │ │ │ └── index.mjs │ │ │ ├── youtube/ │ │ │ │ └── index.mjs │ │ │ └── zhihu/ │ │ │ └── index.mjs │ │ └── styles.scss │ ├── fonts/ │ │ └── styles.css │ ├── hooks/ │ │ ├── use-clamp-window-size.mjs │ │ ├── use-config.mjs │ │ ├── use-theme.mjs │ │ ├── use-window-size.mjs │ │ └── use-window-theme.mjs │ ├── manifest.json │ ├── manifest.v2.json │ ├── pages/ │ │ ├── IndependentPanel/ │ │ │ ├── App.jsx │ │ │ ├── index.html │ │ │ ├── index.jsx │ │ │ └── styles.scss │ │ └── styles.scss │ ├── popup/ │ │ ├── Popup.jsx │ │ ├── index.html │ │ ├── index.jsx │ │ ├── sections/ │ │ │ ├── AdvancedPart.jsx │ │ │ ├── ApiModes.jsx │ │ │ ├── FeaturePages.jsx │ │ │ ├── GeneralPart.jsx │ │ │ ├── ModulesPart.jsx │ │ │ ├── SelectionTools.jsx │ │ │ ├── SiteAdapters.jsx │ │ │ └── import-data-cleanup.mjs │ │ └── styles.scss │ ├── rules.json │ ├── services/ │ │ ├── apis/ │ │ │ ├── aiml-api.mjs │ │ │ ├── azure-openai-api.mjs │ │ │ ├── bard-web.mjs │ │ │ ├── bing-web.mjs │ │ │ ├── chatglm-api.mjs │ │ │ ├── chatgpt-web.mjs │ │ │ ├── claude-api.mjs │ │ │ ├── claude-web.mjs │ │ │ ├── custom-api.mjs │ │ │ ├── deepseek-api.mjs │ │ │ ├── moonshot-api.mjs │ │ │ ├── moonshot-web.mjs │ │ │ ├── ollama-api.mjs │ │ │ ├── openai-api.mjs │ │ │ ├── openai-token-params.mjs │ │ │ ├── openrouter-api.mjs │ │ │ ├── poe-web.mjs │ │ │ ├── shared.mjs │ │ │ └── waylaidwanderer-api.mjs │ │ ├── clients/ │ │ │ ├── bard/ │ │ │ │ └── index.mjs │ │ │ ├── bing/ │ │ │ │ ├── BingImageCreator.js │ │ │ │ └── index.mjs │ │ │ ├── claude/ │ │ │ │ └── index.mjs │ │ │ └── poe/ │ │ │ ├── graphql/ │ │ │ │ ├── AddHumanMessageMutation.graphql │ │ │ │ ├── AddMessageBreakMutation.graphql │ │ │ │ ├── AutoSubscriptionMutation.graphql │ │ │ │ ├── BioFragment.graphql │ │ │ │ ├── ChatAddedSubscription.graphql │ │ │ │ ├── ChatFragment.graphql │ │ │ │ ├── ChatPaginationQuery.graphql │ │ │ │ ├── ChatViewQuery.graphql │ │ │ │ ├── DeleteHumanMessagesMutation.graphql │ │ │ │ ├── HandleFragment.graphql │ │ │ │ ├── LoginWithVerificationCodeMutation.graphql │ │ │ │ ├── MessageAddedSubscription.graphql │ │ │ │ ├── MessageDeletedSubscription.graphql │ │ │ │ ├── MessageFragment.graphql │ │ │ │ ├── MessageRemoveVoteMutation.graphql │ │ │ │ ├── MessageSetVoteMutation.graphql │ │ │ │ ├── SendVerificationCodeForLoginMutation.graphql │ │ │ │ ├── ShareMessagesMutation.graphql │ │ │ │ ├── SignupWithVerificationCodeMutation.graphql │ │ │ │ ├── StaleChatUpdateMutation.graphql │ │ │ │ ├── SummarizePlainPostQuery.graphql │ │ │ │ ├── SummarizeQuotePostQuery.graphql │ │ │ │ ├── SummarizeSharePostQuery.graphql │ │ │ │ ├── UserSnippetFragment.graphql │ │ │ │ ├── ViewerInfoQuery.graphql │ │ │ │ ├── ViewerStateFragment.graphql │ │ │ │ └── ViewerStateUpdatedSubscription.graphql │ │ │ ├── index.mjs │ │ │ └── websocket.js │ │ ├── init-session.mjs │ │ ├── local-session.mjs │ │ └── wrappers.mjs │ └── utils/ │ ├── change-children-font-size.mjs │ ├── create-element-at-position.mjs │ ├── crop-text.mjs │ ├── ends-with-question-mark.mjs │ ├── eventsource-parser.mjs │ ├── fetch-bg.mjs │ ├── fetch-sse.mjs │ ├── get-client-position.mjs │ ├── get-conversation-pairs.mjs │ ├── get-core-content-text.mjs │ ├── get-possible-element-by-query-selector.mjs │ ├── index.mjs │ ├── is-edge.mjs │ ├── is-firefox.mjs │ ├── is-mobile.mjs │ ├── is-safari.mjs │ ├── jwt-token-generator.mjs │ ├── limited-fetch.mjs │ ├── model-name-convert.mjs │ ├── open-url.mjs │ ├── parse-float-with-clamp.mjs │ ├── parse-int-with-clamp.mjs │ ├── set-element-position-in-viewport.mjs │ ├── update-ref-height.mjs │ └── wait-for-element-to-exist-and-select.mjs └── tests/ ├── setup/ │ ├── browser-shim.mjs │ └── jsx-loader-hooks.mjs └── unit/ ├── background/ │ └── redact.test.mjs ├── config/ │ ├── config-predicates.test.mjs │ └── user-config.test.mjs ├── content-script/ │ └── selection-tools.test.mjs ├── helpers/ │ ├── port.mjs │ └── sse-response.mjs ├── popup/ │ └── import-data-cleanup.test.mjs ├── services/ │ ├── apis/ │ │ ├── azure-openai-api.test.mjs │ │ ├── claude-api.test.mjs │ │ ├── custom-api.test.mjs │ │ ├── openai-api-compat.test.mjs │ │ ├── openai-token-params.test.mjs │ │ ├── shared.test.mjs │ │ └── thin-adapters.test.mjs │ ├── handle-port-error.test.mjs │ ├── init-session.test.mjs │ ├── local-session.test.mjs │ └── wrappers-register.test.mjs ├── setup/ │ └── browser-shim.test.mjs └── utils/ ├── basic-guards.test.mjs ├── browser-detection.test.mjs ├── crop-text.test.mjs ├── eventsource-parser.test.mjs ├── fetch-sse.test.mjs ├── get-client-position.test.mjs ├── jwt-token-generator.test.mjs ├── model-name-convert.test.mjs └── set-element-position-in-viewport.test.mjs ================================================ FILE CONTENTS ================================================ ================================================ FILE: .eslintrc.json ================================================ { "env": { "browser": true, "es2021": true }, "extends": ["eslint:recommended", "plugin:react/recommended"], "overrides": [], "parserOptions": { "ecmaVersion": "latest", "sourceType": "module" }, "rules": { "react/react-in-jsx-scope": "off" }, "ignorePatterns": ["build/**", "build.mjs", "src/utils/is-mobile.mjs"], "settings": { "react": { "version": "detect" } } } ================================================ FILE: .gitattributes ================================================ src/services/clients/** linguist-vendored ================================================ FILE: .github/CONTRIBUTING.md ================================================ See https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Development&Contributing ================================================ FILE: .github/ISSUE_TEMPLATE/bug-report---问题报告.md ================================================ --- name: Bug report / 问题报告 about: Create a report to help us improve title: '' labels: '' assignees: '' --- **Describe the bug** **问题描述** A clear and concise description of what the bug is. **To Reproduce** **如何复现** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** **期望行为** A clear and concise description of what you expected to happen. **Screenshots** **截图说明** If applicable, add screenshots to help explain your problem. **Please complete the following information):** **请补全以下内容** - OS: [e.g. Windows] - Browser: [e.g. chrome, safari] - Extension Version: [e.g. v2.0.2] **Additional context** **其他** Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/feature-request---新功能请求.md ================================================ --- name: Feature request / 新功能请求 about: Suggest an idea for this project title: '' labels: '' assignees: '' --- **Is your feature request related to a problem? Please describe.** **新功能是否与解决某个问题相关, 请描述** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** **你期望的新功能实现方案** A clear and concise description of what you want to happen. **Additional context** **其他** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" commit-message: prefix: "chore" include: "scope" ================================================ FILE: .github/workflows/pr-tests.yml ================================================ name: pr-tests on: pull_request: types: - "opened" - "reopened" - "synchronize" paths: - "src/**" - "build.mjs" - "tests/**" - "package.json" - "package-lock.json" - ".github/workflows/scripts/**" - ".github/workflows/pr-tests.yml" push: branches: - "master" paths: - "src/**" - "build.mjs" - "tests/**" - "package.json" - "package-lock.json" - ".github/workflows/scripts/**" - ".github/workflows/pr-tests.yml" jobs: tests: runs-on: ubuntu-22.04 permissions: contents: read steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: node-version: 22 - run: npm ci - run: npm run test:coverage - run: npm run lint - run: npm run build update_coverage_badge: if: github.event_name == 'push' && github.ref == 'refs/heads/master' needs: tests runs-on: ubuntu-22.04 permissions: contents: write steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - uses: actions/setup-node@v6 with: node-version: 22 - run: npm ci - run: npm run test:coverage - run: node .github/workflows/scripts/update-coverage-badge.mjs - name: Commit coverage badge run: | branch="${GITHUB_REF#refs/heads/}" max_retries=3 if git diff --quiet -- badges/coverage.json; then echo "Coverage badge unchanged" exit 0 fi git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git add badges/coverage.json git commit -m "Update coverage badge [skip ci]" for attempt in $(seq 1 "${max_retries}"); do echo "Attempt ${attempt}/${max_retries}: pushing coverage badge update to ${branch}" if git push origin "HEAD:${branch}"; then echo "Coverage badge push succeeded" exit 0 fi if [ "${attempt}" -eq "${max_retries}" ]; then echo "::warning::Failed to push coverage badge after ${max_retries} attempts due to concurrent updates. Skipping without failing CI." exit 0 fi echo "Push rejected. Fetching latest origin/${branch} and retrying with rebase..." if ! git fetch origin "${branch}"; then echo "::warning::Failed to fetch origin/${branch} while retrying coverage badge push. Skipping without failing CI." exit 0 fi if ! git rebase "origin/${branch}"; then git rebase --abort || true echo "::warning::Rebase conflict while retrying coverage badge push. Skipping without failing CI." exit 0 fi sleep $((attempt * 2)) done ================================================ FILE: .github/workflows/pre-release-build.yml ================================================ name: pre-release on: workflow_dispatch: # push: # branches: # - master # paths: # - "src/**" # - "!src/**/*.json" # - "build.mjs" # tags-ignore: # - "v*" permissions: id-token: "write" contents: "write" jobs: build_and_release: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: node-version: 22 cache: 'npm' cache-dependency-path: '**/package-lock.json' - name: Detect Node version run: echo "NODE_VERSION=$(node -p 'process.versions.node')" >> $GITHUB_ENV - run: npm ci - name: Cache Webpack filesystem cache uses: actions/cache@v5 with: path: | .cache/webpack node_modules/.cache/webpack key: ${{ runner.os }}-node${{ env.NODE_VERSION }}-webpack-${{ hashFiles('**/package-lock.json', 'build.mjs') }} restore-keys: | ${{ runner.os }}-node${{ env.NODE_VERSION }}-webpack- - run: npm run build - uses: josStorer/get-current-time@v2 id: current-time with: format: YYYY_MMDD_HHmm - uses: actions/upload-artifact@v7 with: name: Chromium_Build_${{ steps.current-time.outputs.formattedTime }} path: build/chromium/* - uses: actions/upload-artifact@v7 with: name: Firefox_Build_${{ steps.current-time.outputs.formattedTime }} path: build/firefox/* - uses: actions/upload-artifact@v7 with: name: Chromium_Build_WithoutKatex_${{ steps.current-time.outputs.formattedTime }} path: build/chromium-without-katex-and-tiktoken/* - uses: actions/upload-artifact@v7 with: name: Firefox_Build_WithoutKatex_${{ steps.current-time.outputs.formattedTime }} path: build/firefox-without-katex-and-tiktoken/* - uses: marvinpinto/action-automatic-releases@v1.2.1 with: repo_token: "${{ secrets.GITHUB_TOKEN }}" automatic_release_tag: "latest" prerelease: true title: "Development Build" files: | build/chromium.zip build/firefox.zip build/chromium-without-katex-and-tiktoken.zip build/firefox-without-katex-and-tiktoken.zip ================================================ FILE: .github/workflows/scripts/update-coverage-badge.mjs ================================================ import fs from 'node:fs' import path from 'node:path' const coverageSummaryPath = 'coverage/coverage-summary.json' const badgePath = 'badges/coverage.json' function getBadgeColor(percentage) { if (percentage >= 90) return 'brightgreen' if (percentage >= 80) return 'green' if (percentage >= 70) return 'yellowgreen' if (percentage >= 60) return 'yellow' if (percentage >= 50) return 'orange' return 'red' } function main() { if (!fs.existsSync(coverageSummaryPath)) { throw new Error(`Coverage summary file not found: ${coverageSummaryPath}`) } const summary = JSON.parse(fs.readFileSync(coverageSummaryPath, 'utf8')) const linesPercentage = Number(summary?.total?.lines?.pct) if (!Number.isFinite(linesPercentage)) { throw new Error('Unable to read lines coverage percentage from coverage summary') } const roundedPercentage = Number(linesPercentage.toFixed(2)) const badge = { schemaVersion: 1, label: 'coverage', message: `${roundedPercentage}%`, color: getBadgeColor(roundedPercentage), } fs.mkdirSync(path.dirname(badgePath), { recursive: true }) fs.writeFileSync(badgePath, JSON.stringify(badge, null, 2) + '\n') console.log(`Updated ${badgePath} with lines coverage ${roundedPercentage}%`) } main() ================================================ FILE: .github/workflows/scripts/verify-search-engine-configs.mjs ================================================ import { JSDOM } from 'jsdom' import fetch, { Headers } from 'node-fetch' const config = { google: { inputQuery: ["input[name='q']", "textarea[name='q']"], sidebarContainerQuery: ['#rhs'], appendContainerQuery: ['#rcnt'], resultsContainerQuery: ['#rso'], }, bing: { inputQuery: ["[name='q']"], sidebarContainerQuery: ['#b_context'], appendContainerQuery: [], resultsContainerQuery: ['#b_results'], }, yahoo: { inputQuery: ["input[name='p']"], sidebarContainerQuery: ['#right', '.Contents__inner.Contents__inner--sub'], appendContainerQuery: ['#cols', '#contents__wrap'], resultsContainerQuery: [ '#main-algo', '.searchCenterMiddle', '.Contents__inner.Contents__inner--main', '#contentsInner', ], }, duckduckgo: { inputQuery: ["input[name='q']"], sidebarContainerQuery: ['.js-react-sidebar', '.react-results--sidebar'], appendContainerQuery: ['#links_wrapper'], resultsContainerQuery: ['.react-results--main'], }, startpage: { inputQuery: ["input[name='query']"], sidebarContainerQuery: ['#sidebar'], appendContainerQuery: [], resultsContainerQuery: ['#main'], }, baidu: { inputQuery: ["input[id='kw']"], sidebarContainerQuery: ['#content_right'], appendContainerQuery: ['#container'], resultsContainerQuery: ['#content_left', '#results'], }, kagi: { inputQuery: ["input[name='q']", "textarea[name='q']"], sidebarContainerQuery: ['.right-content-box'], appendContainerQuery: ['#_0_app_content'], resultsContainerQuery: ['#main', '#app'], }, yandex: { inputQuery: ["input[name='text']"], sidebarContainerQuery: ['#search-result-aside'], appendContainerQuery: [], resultsContainerQuery: ['#search-result'], }, naver: { inputQuery: ["input[name='query']"], sidebarContainerQuery: ['#main_pack'], appendContainerQuery: ['#content'], resultsContainerQuery: ['#main_pack', '#ct'], }, brave: { inputQuery: ["input[name='q']"], sidebarContainerQuery: ['.sidebar'], appendContainerQuery: [], resultsContainerQuery: ['#results'], }, searx: { inputQuery: ["input[name='q']"], sidebarContainerQuery: ['#sidebar_results', '#sidebar'], appendContainerQuery: [], resultsContainerQuery: ['#urls', '#main_results', '#results'], }, ecosia: { inputQuery: ["input[name='q']"], sidebarContainerQuery: ['.sidebar.web__sidebar'], appendContainerQuery: ['#main'], resultsContainerQuery: ['.mainline'], }, neeva: { inputQuery: ["input[name='q']"], sidebarContainerQuery: ['.result-group-layout__stickyContainer-iDIO8'], appendContainerQuery: ['.search-index__searchHeaderContainer-2JD6q'], resultsContainerQuery: ['.result-group-layout__component-1jzTe', '#search'], }, } const urls = { google: [ /*'https://www.google.com/search?q=hello'*/ ], bing: ['https://www.bing.com/search?q=hello'], yahoo: [ /*'https://search.yahoo.com/search?p=hello', */ 'https://search.yahoo.co.jp/search?p=hello', ], duckduckgo: [], startpage: [], // need redirect and post https://www.startpage.com/do/search?query=hello baidu: ['https://www.baidu.com/s?wd=hello'], kagi: [], // need login https://kagi.com/search?q=hello yandex: [], // need cookie https://yandex.com/search/?text=hello naver: ['https://search.naver.com/search.naver?query=hello'], brave: [], searx: [ /*'https://searx.tiekoetter.com/search?q=hello'*/ ], ecosia: [], // unknown verify method https://www.ecosia.org/search?q=hello neeva: [], // unknown verify method(FetchError: maximum redirect reached) https://neeva.com/search?q=hello presearch: [], } const commonHeaders = { Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', Connection: 'keep-alive', 'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7', // for baidu } const desktopHeaders = new Headers({ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/108.0.1462.76', ...commonHeaders, }) const mobileHeaders = { 'User-Agent': 'Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Mobile Safari/537.36 Edg/108.0.1462.76', ...commonHeaders, } const desktopQueryNames = [ 'inputQuery', 'sidebarContainerQuery', 'appendContainerQuery', 'resultsContainerQuery', ] const mobileQueryNames = ['inputQuery', 'resultsContainerQuery'] let errors = '' async function verify(errorTag, urls, headers, queryNames) { await Promise.all( Object.entries(urls).map(([siteName, urlArray]) => Promise.all( urlArray.map((url) => fetch(url, { method: 'GET', headers: headers, }) .then((response) => response.text()) .then((text) => { const dom = new JSDOM(text) for (const queryName of queryNames) { const queryArray = config[siteName][queryName] if (queryArray.length === 0) continue let foundQuery for (const query of queryArray) { const element = dom.window.document.querySelector(query) if (element) { foundQuery = query break } } if (foundQuery) { console.log(`${siteName} ${url} ${queryName}: ${foundQuery} passed`) } else { const error = `${siteName} ${url} ${queryName} failed` errors += errorTag + error + '\n' } } }) .catch((error) => { errors += errorTag + error + '\n' }), ), ), ), ) } async function main() { console.log('Verify desktop search engine configs:') await verify('desktop: ', urls, desktopHeaders, desktopQueryNames) console.log('\nVerify mobile search engine configs:') await verify('mobile: ', urls, mobileHeaders, mobileQueryNames) if (errors.length > 0) throw new Error('\n' + errors) else console.log('\nAll passed') } main() ================================================ FILE: .github/workflows/tagged-release.yml ================================================ name: tagged-release on: push: tags: - "v*" permissions: id-token: "write" contents: "write" env: GH_TOKEN: ${{ github.token }} jobs: build_and_release: runs-on: macos-14 steps: - run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV - uses: actions/checkout@v6 with: ref: master - name: Update manifest.json version uses: jossef/action-set-json-field@v2.2 with: file: src/manifest.json field: version value: ${{ env.VERSION }} - name: Update manifest.v2.json version uses: jossef/action-set-json-field@v2.2 with: file: src/manifest.v2.json field: version value: ${{ env.VERSION }} - name: Push files continue-on-error: true run: | git config --global user.email "github-actions[bot]@users.noreply.github.com" git config --global user.name "github-actions[bot]" git commit -am "release v${{ env.VERSION }}" git push - run: | gh release create ${{github.ref_name}} -d -F CURRENT_CHANGE.md -t ${{github.ref_name}} - uses: actions/setup-node@v6 with: node-version: 22 - run: npm ci - uses: actions/setup-python@v6 with: python-version: '3.10' # for appdmg - uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: 16.2 - run: sed -i '' "s/0.0.0/${{ env.VERSION }}/g" safari/project.pre.patch - run: sed -i '' "s/0.0.0/${{ env.VERSION }}/g" safari/project.patch - run: npm run build:safari - run: | gh release upload ${{github.ref_name}} build/chromium.zip gh release upload ${{github.ref_name}} build/firefox.zip gh release upload ${{github.ref_name}} build/safari.dmg gh release upload ${{github.ref_name}} build/chromium-without-katex-and-tiktoken.zip gh release upload ${{github.ref_name}} build/firefox-without-katex-and-tiktoken.zip - run: | gh release edit ${{github.ref_name}} --draft=false ================================================ FILE: .github/workflows/verify-configs.yml ================================================ name: verify-configs on: workflow_dispatch: schedule: - cron: "0 6 * * *" jobs: verify_configs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: node-version: 22 - run: npm ci - run: npm run verify ================================================ FILE: .gitignore ================================================ .idea/ .vscode/ node_modules/ build/ .coverage/ coverage/ .DS_Store *.zip ================================================ FILE: .nvmrc ================================================ 22 ================================================ FILE: .prettierignore ================================================ build/ src/manifest.json src/manifest.v2.json ================================================ FILE: .prettierrc ================================================ { "printWidth": 100, "semi": false, "tabWidth": 2, "singleQuote": true, "trailingComma": "all", "bracketSpacing": true, "overrides": [ { "files": ".prettierrc", "options": { "parser": "json" } } ] } ================================================ FILE: AGENTS.md ================================================ # ChatGPTBox - Browser Extension ChatGPTBox is a cross-platform browser extension that deeply integrates ChatGPT and other AI models into web browsing. The extension provides chat dialogs, selection tools, site-specific adapters, and AI-powered features across the web. Always reference these instructions first and fall back to search or bash commands only when you encounter unexpected information that does not match the info here. ## Working Effectively ### Bootstrap and Build - Install dependencies: `npm ci` -- npm audit warnings may appear; for development-only dependencies they generally do not affect the shipped extension. Review and address runtime-impacting advisories separately. - Development build: `npm run dev` -- runs webpack in watch mode. Do not kill mid-compilation, but stop gracefully when switching branches or after dependency/config changes, then restart to avoid stale watchers and inconsistent state. - Production build: `npm run build` -- Avoid force-killing mid-bundle; stop, fix, then rebuild. See "Time Expectations" and "Build Issues" for the hung-build policy and recovery steps. - Analyze bundle: `npm run analyze` -- Inspects the size of webpack output files. - Format code: `npm run pretty` -- uses Prettier to format all JS/JSX/CSS files. Run this before linting. - Lint code: `npm run lint` -- uses ESLint. - Safari build: `npm run build:safari` (see Platform-Specific Instructions for details) ### Build Performance Options - BUILD_PARALLEL: Toggle parallel build of production variants - Default: on (parallel). Set to `0` to run sequentially (lower CPU/IO spikes on low-core machines) - BUILD_THREAD / BUILD_THREAD_WORKERS: Control Babel parallelism via thread-loader - Default: threads enabled in dev/prod; workers = CPU cores - Set `BUILD_THREAD=0` to disable; set `BUILD_THREAD_WORKERS=` to override worker count - BUILD_CACHE_COMPRESSION: Webpack filesystem cache compression - Default: `0` (no compression) for faster warm builds on CPU-bound SSD machines - Options: `0|false|none`, `gzip` (or `brotli` if explicitly desired) - Affects only `.cache/webpack` size/speed; does not change final artifacts - Note: Babel loader cache uses its own compression setting (currently disabled for speed) and is independent of BUILD_CACHE_COMPRESSION - BUILD_WATCH_ONCE (dev): When set, `npm run dev` runs a single build and exits (useful for timing) - BUILD_POOL_TIMEOUT: Override thread-loader production pool timeout (ms) - Default: `2000`. Increase if workers recycle too aggressively on slow machines/CI - BUILD_RESOLVE_SYMLINKS: When set to `1`/`true`, re-enable Webpack symlink resolution for `npm link`/pnpm workspace development. Default is `false` to improve performance and ensure consistent module identity (avoids duplicate module instances) - Source maps (dev): Dev builds emit external `.map` files next to JS bundles for CSP-safe debugging; production builds disable source maps Performance defaults: esbuild handles JS/CSS minification. In development, CSS is injected via style-loader; in production, CSS is extracted via MiniCssExtractPlugin. Thread-loader is enabled by default in both dev and prod. ### Build Output Structure Production build creates multiple variants in `build/` directory: - `chromium/` - Chromium-based browsers (Chrome, Edge) with full features - `firefox/` - Firefox with manifest v2 - `chromium-without-katex-and-tiktoken/` - Minimal build without math rendering and token encoding - `firefox-without-katex-and-tiktoken/` - Minimal Firefox build without math rendering and token encoding - Distribution artifacts: - Chromium: `build/chromium.zip` - Firefox: `build/firefox.zip` - Safari: `Fission - ChatBox.app` and `safari.dmg` (see Safari Build section for details) ## Architecture Overview The project uses Preact (for React-like components), SCSS (for styling), and Webpack 5 (for bundling). ### Key Components - **Content Script** (`src/content-script/index.jsx`) - Injected into all web pages, provides main chat functionality - **Background Script** (`src/background/index.mjs`) - Handles browser APIs and cross-page communication - **Popup** (`src/popup/`) - Extension popup interface accessible via browser toolbar - **Independent Panel** (`src/pages/IndependentPanel/`) - Standalone chat page and side panel - **Site Adapters** (`src/content-script/site-adapters/`) - Custom integrations for specific websites (Reddit, GitHub, YouTube, etc.) - **Selection Tools** (`src/content-script/selection-tools/`) - Text selection features (translate, summarize, explain, etc.) ### Manifests - `src/manifest.json` - Manifest v3 for Chromium browsers (Chrome, Edge, Opera, etc.) - `src/manifest.v2.json` - Manifest v2 for Firefox (current status; future MV3 migration may change this) - Background runs as service worker (MV3) vs background page (MV2) - Different permission models between manifest versions ## Testing and Validation ### Manual Browser Extension Testing (CRITICAL) This browser extension includes automated unit tests, but manual browser extension testing is still essential: 1. **Load Extension in Browser:** - Chrome: Go to `chrome://extensions/`, enable Developer Mode, click "Load unpacked", then select the folder `build/chromium/` (the folder must contain `manifest.json`). - Firefox: Go to `about:debugging#/runtime/this-firefox`, click "Load Temporary Add-on", then select the `manifest.json` file inside `build/firefox/` (do not select the folder directly). Note: Temporary (unsigned) add-ons are removed on browser restart; reload them via the same "This Firefox" page after every restart, and some environments with enterprise policies may block loading from file. - **Important**: Extension files cannot be tested by serving them via HTTP server - they must be loaded as a proper browser extension. 2. **Core Functionality Tests:** - Press `Ctrl+B` (Windows/Linux) or `⌘+B` (macOS) to open the chat dialog on any webpage - Select text on a page, verify selection tools appear - Right-click and verify "Ask ChatGPT" context menu appears - Click extension icon to open popup - Press `Ctrl+Shift+H` (Windows/Linux) or `⌘+Shift+H` (macOS) to open the independent conversation page 3. **Site Integration Tests:** - Visit YouTube.com, verify video summary features work - Visit Reddit.com, verify ChatGPT integration appears in sidebar - Visit GitHub.com, verify code analysis features work - Visit Google.com search results, verify ChatGPT responses appear 4. **Configuration Tests:** - Open extension popup, navigate through tabs (General, Feature Pages, Modules > Selection Tools, Modules > Sites, Advanced) - Test API mode switching (Web API vs OpenAI API) under Modules > API Modes - If using Web APIs, ensure you are signed in to the provider in the same browser profile; if using API Keys, configure valid keys in settings - Verify language settings work Debugging tips: - Inspect background Service Worker, page DevTools for content scripts, and use "Inspect popup" for the popup UI - After rebuilds, reload the extension and refresh the page to re‑inject content scripts ### Build Validation Ensure these files exist in `build/chromium/` after successful build: - `manifest.json` (contains proper extension metadata) - `background.js` (service worker bundle) - `content-script.js` (main functionality) - `content-script.css` (styling) - `popup.html` and `popup.js` (popup interface) - `IndependentPanel.html` and `IndependentPanel.js` (standalone chat page) - `shared.js` (shared vendor/runtime; size varies by environment and dependencies) - `logo.png` (extension icon) - `rules.json` (declarative net request rules) Bundle sizes are approximate and not validation criteria. ### Verify Script Limitations - `npm run verify` tests search engine configurations by attempting to fetch search results from external search engines (Bing, Yahoo, Baidu, Naver) to validate that the site adapters can parse and handle real responses. - **Successful validation**: For each search engine, the script expects to receive a valid HTTP response (status 200) and to successfully extract and parse search results using the corresponding site adapter. If the adapter can parse the expected data structure from the response, the test is considered a pass. - **Expected failure modes**: In sandboxed or CI environments, the script may fail due to network restrictions (e.g., DNS errors, timeouts, connection refused), HTTP errors (e.g., 403, 429, 503), or changes in the search engine's response format. These failures are expected and do **not** indicate build problems. - If you see network or HTTP errors during `npm run verify`, you can safely ignore them unless you are specifically testing or updating site adapter logic. Usage notes: - Default checks target: `https://www.bing.com/search?q=hello`, `https://search.yahoo.co.jp/search?p=hello`, `https://www.baidu.com/s?wd=hello`, `https://search.naver.com/search.naver?query=hello` - Optional engines (may be blocked by region or anti-bot measures): Google, DuckDuckGo, Brave, Searx. - Troubleshooting: If a site fails, try adjusting `Accept-Language`/`User-Agent` headers in the script, update the site's selector arrays with ordered fallbacks, or temporarily reduce the test to a single URL while iterating. ## Development Workflow ### Code Style, Quality, and File Organization - ALWAYS run `npm run lint` before committing - CI will fail otherwise - ALWAYS run `npm run pretty` to format code consistently - ESLint configuration in `.eslintrc.json` enforces React/JSX standards - Prettier configuration in `.prettierrc` handles formatting (100 char width, no semicolons, single quotes, trailing commas) ✅ Good: `import Browser from 'webextension-polyfill'` (single quotes, no semicolon) ❌ Bad: `import Browser from "webextension-polyfill";` (double quotes, semicolon) - Naming conventions: component directories use PascalCase; feature folders use kebab-case; entry files are typically `index.jsx` or `index.mjs` - Avoid heavy dependencies; if necessary, justify and keep bundle size under control **Pre-commit hooks automatically:** 1. Run prettier formatting 2. Stage formatted files 3. Run lint checks **Key file locations:** - Configuration: `src/config/index.mjs` - API integrations: `src/services/apis/` - Localization: `src/_locales/` - UI components: `src/components/` - Utilities: `src/utils/` ### Commits & PRs - Keep changes minimal and focused. Avoid unrelated refactors in the same PR. - Commit subject: imperative, capitalize first word; separate subject/body with a blank line; wrap at ~72 characters; explain what and why. - PRs: link related issues, summarize scope/behavior changes; include screenshots for UI changes. - Note i18n updates in PR description when `src/_locales/` changes. - If any validation step is skipped, document the reason and the skipped check(s) in the PR description (see `Critical Validation Steps` below). ### Directory Structure ```text src/ ├── background/ # Background script/service worker ├── components/ # Reusable UI components ├── config/ # Configuration management ├── content-script/ # Main content script and features │ ├── site-adapters/ # Website-specific integrations │ ├── selection-tools/ # Text selection features │ └── menu-tools/ # Context menu features ├── pages/IndependentPanel/ # Standalone chat page ├── popup/ # Extension popup ├── services/ # API clients and wrappers └── utils/ # Helper functions ``` ## Platform-Specific Instructions ### Safari Build (macOS Only) - Run `npm run build:safari` (requires macOS with Xcode installed) - Creates `Fission - ChatBox.app` bundle and `safari.dmg` installer - Uses `safari/build.sh` script with platform-specific patches ### Cross-Browser Compatibility - Uses `webextension-polyfill` for API compatibility ## Security & Privacy - Do not commit secrets, API keys, or user data - Keep manifest permissions minimal and justify any additions - Centralize network/API logic under `src/services/apis/` and keep endpoints auditable ## Localization - Source of truth: `src/_locales/en/main.json`; do not change existing keys (only add new ones) - Add new strings to `en/main.json` first, then propagate to other locales - Register new locales in `src/_locales/resources.mjs` - Preserve placeholders and product names; keep punctuation/quotes intact - For Traditional Chinese (Taiwan), use `src/_locales/zh-hant/main.json` and avoid zh‑CN terms ## AI Model Support The extension supports multiple AI providers: - **Web (cookie-based)**: ChatGPT (Web), Claude (Web), Kimi.Moonshot (Web), Bing (Web), Bard (Web), Poe (Web) - **APIs (key-based)**: OpenAI (API), Azure OpenAI (API), Anthropic (Claude API), OpenRouter (API), AI/ML (API), DeepSeek (API), Ollama (local), ChatGLM (API), Waylaidwanderer (API), Kimi.Moonshot (API) - **Custom/self-hosted**: Alternative endpoints and self-hosted backends ## Troubleshooting ### Build Issues - Build failures: Check Node.js version (requires Node 22+), clear caches and rebuild. - macOS/Linux: `rm -rf node_modules && npm ci && rm -rf node_modules/.cache build/ dist/` - Windows (PowerShell): `Remove-Item -Recurse -Force node_modules, build, dist; if (Test-Path node_modules\.cache) { Remove-Item -Recurse -Force node_modules\.cache }; npm ci` - "Module not found" errors: Usually indicate missing `npm ci` ### Runtime Issues - Extension not loading: Check console for manifest errors - API not working: Verify browser has required permissions and cookies - Selection tools not appearing: Check if content script loaded correctly ### Common Development Tasks - Adding new site adapter: Create new file in `src/content-script/site-adapters/`, register it in `src/content-script/site-adapters/index.mjs`, keep selectors minimal with feature detection, and verify on Chromium/Firefox - Adding new selection tool: Modify `src/content-script/selection-tools/`, keep UI and logic separate, and reuse helpers in `src/utils/` - Updating API integration: Modify files in `src/services/apis/` - Adding new UI component: Create in `src/components/` **Note:** Ask before deleting/renaming files, modifying build config/manifests, or making changes that affect multiple site adapters. If the user explicitly requests one of these changes, proceed and document scope and risk in the current workflow handoff output, and in the PR summary when applicable. ## Time Expectations - Do not interrupt builds or long-running commands unless they appear hung or unresponsive. - `npm ci`: ~30 seconds - `npm run build`: ~35 seconds (measured). Set timeout to 5-10 minutes for system variations. - `npm run dev`: ~15 seconds initial build, then watches for changes; use Ctrl+C to stop when switching branches or after config/dependency changes. - `npm run lint`: ~5 seconds - Manual extension testing: 5-10 minutes for thorough validation - Safari build: 2-5 minutes (macOS only) ## Critical Validation Steps 1. General changes (any change not covered by Step 2 or Step 3): run `npm test` and `npm run build`, verify expected build artifacts, and run manual browser smoke tests. If changes include `safari/**`, also run `npm run build:safari` on macOS. If macOS is unavailable for those changes, document the skip reason in PR validation notes. 2. Behavior-adjacent localization changes (`src/_locales/**` only): run `npm run build` and manual browser smoke tests. Use this step only when all changed files are under `src/_locales/**`. 3. Docs-only changes (`*.md`, `screenshots/**`): build/manual browser tests may be skipped, but the PR description must include `Validation skipped: docs/screenshots-only change; no runtime files touched.` 4. If changes span multiple categories, apply the strictest applicable step (runtime > localization > docs/screenshots); when in doubt, treat the change as runtime-impacting and execute the full validation flow. --- Most of this document was generated by AI and reviewed under human supervision. If you find any clear errors while using it, please submit corrections with supporting evidence where possible. ================================================ FILE: CURRENT_CHANGE.md ================================================ Long time no see — ChatGPTBox is back! Nearly every feature that had broken due to page updates or API changes has been fixed, and we’ve also introduced some new features. Over the past year the LLM landscape has shifted dramatically, and the key players are now fairly clear. Regarding ChatGPTBox’s free web APIs, some providers are still actively trying to block reverse-engineering, while others remain open. At the moment, ChatGPT, Claude, and Kimi are still open, so we’ll keep maintaining the related web free APIs. The web APIs for Bing and Gemini, however, will no longer be supported; if you need some reverse-engineering web apis, please check out the work of this organization: https://github.com/LLM-Red-Team. As OpenRouter has consistently offered stable and affordable APIs, we’ve now added direct option support for it — no need to rely on custom mode and manually fill in the API URL. During this period, countless AI projects have exploded onto the scene and just as many have quietly disappeared. I’ve been tied up with various non-public projects and have neglected ChatGPTBox, while also pondering how to keep it vibrant. I have to admit that when ChatGPTBox was first created, many decisions and code designs were rather hasty and not very modern. Without much forethought, I made choices that now make it inconvenient to add new features. I’m currently rewriting ChatGPTBox from scratch using the WXT framework while ensuring full backward compatibility with old data. This will take a considerable amount of time, but I’ll keep pushing forward. I also have some commercialization ideas for ChatGPTBox; of course only server-related features would be charged, while all web APIs and user Api Key features will remain completely free, and the project will stay open-source under the MIT license. As I’m simultaneously in charge of several other non-public projects, I can’t promise when the rewrite will be finished, but I’ll keep making steady progress. In the meantime, I’ll continue to fix major issues in the current version of ChatGPTBox. ## Changes ### Features - add support for openRouter, AI/ML and DeepSeek api (previously required filling in the URL via the custom model option) - a new option has been added to the general settings to disable cropText, ensuring the full input tokens are always passed. This can improve summarization on sites like YouTube, but note that you should only disable cropText when using a model with a sufficiently long context. - - reasoning model renderer support - ### Improvements - add a range of new models recently made available by various AI providers - significantly improve the prompt templates for built-in tools. Great thanks to @PeterDaveHello - update and enhance API clients (including Claude, ChatGLM, and Kimi.Moonshot) that had become unavailable or unstable due to recent policy changes and adjustments by AI providers - increase the default input and response limits, as current LLMs generally support longer contexts - improve kimi.moonshot support and add more available models like k2, kimi-latest, k1.5, k1.5-thinking - improve google search sidebar ### Fixes - fix the issue where YouTube subtitles could not be fetched and the video summarization feature became unavailable due to the recent introduction of the "pot" parameter by YouTube - avoid crash when readability parser returns null (#865) @PeterDaveHello - fix the issue where kimi web functionality became unstable due to changes in the page and domain - fix an issue where the selected model might be not displayed correctly due to inconsistent key ordering in JSON.stringify - fix the issue of abnormal subtitle retrieval caused by changes to Bilibili API ### Chores - update adapters support for startpage, kagi, naver, wechat, juejin - update dependencies to mitigate security vulnerabilities @PeterDaveHello - update default configs - since ChatGPT has relaxed the web API request restrictions, it is no longer necessary to simulate input to retrieve data (#869) - update verify-search-engine-configs.mjs ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2022 josStorer Copyright (c) 2022 wong2 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================

ChatGPT Box

Deep ChatGPT integrations in your browser, completely for free. [![license][license-image]][license-url] [![release][release-image]][release-url] [![size](https://img.shields.io/badge/minified%20size-390%20kB-blue)][release-url] [![verfiy][verify-image]][verify-url] [![coverage][coverage-image]][coverage-url] English   |   [Indonesia](README_IN.md)   |   [简体中文](README_ZH.md)   |   [日本語](README_JA.md)   |   [Türkçe](README_TR.md) ### Install [![Chrome][Chrome-image]][Chrome-url] [![Edge][Edge-image]][Edge-url] [![Firefox][Firefox-image]][Firefox-url] [![Safari][Safari-image]][Safari-url] [![Android][Android-image]][Android-url] [![Github][Github-image]][Github-url] [Guide](https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Guide)   |   [Preview](#Preview)   |   [Development&Contributing][dev-url]   |   [Video Demonstration](https://www.youtube.com/watch?v=E1smDxJvTRs)   |   [Credit](#Credit) [dev-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Development&Contributing [license-image]: http://img.shields.io/badge/license-MIT-blue.svg [license-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/blob/master/LICENSE [release-image]: https://img.shields.io/github/release/ChatGPTBox-dev/chatGPTBox.svg [release-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/releases/latest [verify-image]: https://github.com/ChatGPTBox-dev/chatGPTBox/workflows/verify-configs/badge.svg [verify-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/actions/workflows/verify-configs.yml [coverage-image]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/ChatGPTBox-dev/chatGPTBox/master/badges/coverage.json [coverage-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/actions/workflows/pr-tests.yml [Chrome-image]: https://img.shields.io/badge/-Chrome-brightgreen?logo=google-chrome&logoColor=white [Chrome-url]: https://chrome.google.com/webstore/detail/chatgptbox/eobbhoofkanlmddnplfhnmkfbnlhpbbo [Edge-image]: https://img.shields.io/badge/-Edge-blue?logo=microsoft-edge&logoColor=white [Edge-url]: https://microsoftedge.microsoft.com/addons/detail/fission-chatbox-best/enjmfilpkbbabhgeoadmdpjjpnahkogf [Firefox-image]: https://img.shields.io/badge/-Firefox-orange?logo=firefox-browser&logoColor=white [Firefox-url]: https://addons.mozilla.org/firefox/addon/chatgptbox/ [Safari-image]: https://img.shields.io/badge/-Safari-blue?logo=safari&logoColor=white [Safari-url]: https://apps.apple.com/app/fission-chatbox/id6446611121 [Android-image]: https://img.shields.io/badge/-Android-brightgreen?logo=android&logoColor=white [Android-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Install#install-to-android [Github-image]: https://img.shields.io/badge/-Github-black?logo=github&logoColor=white [Github-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Install
## News - This extension does **not** collect your data. You can verify it by conducting a global search for `fetch(` and `XMLHttpRequest(` in the code to find all network request calls. The amount of code is not much, so it's easy to do that. - This tool will not transmit any data to ChatGPT unless you explicitly ask it to. By default, the extension must be activated manually. It will only send a request to ChatGPT if you specifically click "Ask ChatGPT" or trigger the selection floating tools — and this is applicable only when you're using GPT API modes. (issue #407) - You can use projects like https://github.com/BerriAI/litellm / https://github.com/songquanpeng/one-api to convert LLM APIs into OpenAI format and use them in conjunction with ChatGPTBox's `Custom Model` mode - You can also use [Ollama](https://github.com/ChatGPTBox-dev/chatGPTBox/issues/616#issuecomment-1975186467) / https://openrouter.ai/docs#models with ChatGPTBox's `Custom Model` mode ## ✨ Features - 🌈 Call up the chat dialog box on any page at any time. (Ctrl+B) - 📱 Support for mobile devices. - 📓 Summarize any page with right-click menu. (Alt+B) - 📖 Independent conversation page. (Ctrl+Shift+H) - 🔗 Multiple API support (Web API for Free and Plus users, GPT-3.5, GPT-4, Claude, New Bing, Moonshot, Self-Hosted, Azure etc.). - 📦 Integration for various commonly used websites (Reddit, Quora, YouTube, GitHub, GitLab, StackOverflow, Zhihu, Bilibili). (Inspired by [wimdenherder](https://github.com/wimdenherder)) - 🔍 Integration to all mainstream search engines, and custom queries to support additional sites. - 🧰 Selection tool and right-click menu to perform various tasks, such as translation, summarization, polishing, sentiment analysis, paragraph division, code explain and queries. - 🗂️ Static cards support floating chat boxes for multi-branch conversations. - 🖨️ Easily save your complete chat records or copy them partially. - 🎨 Powerful rendering support, whether for code highlighting or complex mathematical formulas. - 🌍 Language preference support. - 📝 Custom API address support. - ⚙️ All site adaptations and selection tools(bubble) can be freely switched on or off, disable modules you don't need. - 💡 Selection tools and site adaptation are easy to develop and extend, see the [Development&Contributing][dev-url] section. - 😉 Chat to improve the answer quality. ## Preview
**Search Engine Integration, Floating Windows, Conversation Branches** ![preview_google_floatingwindow_conversationbranch](screenshots/preview_google_floatingwindow_conversationbranch.jpg) **Integration with Commonly Used Websites, Selection Tools** ![preview_reddit_selectiontools](screenshots/preview_reddit_selectiontools.jpg) **Independent Conversation Page** ![preview_independentpanel](screenshots/preview_independentpanel.jpg) **Git Analysis, Right Click Menu** ![preview_github_rightclickmenu](screenshots/preview_github_rightclickmenu.jpg) **Video Summary** ![preview_youtube](screenshots/preview_youtube.jpg) **Mobile Support** ![image](https://user-images.githubusercontent.com/13366013/225529110-9221c8ce-ad41-423e-b6ec-097981e74b66.png) **Settings** ![preview_settings](screenshots/preview_settings.jpg)
## Credit This project is based on one of my other repositories, [josStorer/chatGPT-search-engine-extension](https://github.com/josStorer/chatGPT-search-engine-extension) [josStorer/chatGPT-search-engine-extension](https://github.com/josStorer/chatGPT-search-engine-extension) is forked from [wong2/chat-gpt-google-extension](https://github.com/wong2/chat-gpt-google-extension) (I learned a lot from that) and detached since 14 December of 2022 [wong2/chat-gpt-google-extension](https://github.com/wong2/chat-gpt-google-extension) is inspired by [ZohaibAhmed/ChatGPT-Google](https://github.com/ZohaibAhmed/ChatGPT-Google) ([upstream-c54528b](https://github.com/wong2/chatgpt-google-extension/commit/c54528b0e13058ab78bfb433c92603db017d1b6b)) ================================================ FILE: README_IN.md ================================================

ChatGPT Box

Integrasi Deep ChatGPT di browser Anda, sepenuhnya gratis. [![license][license-image]][license-url] [![release][release-image]][release-url] [![size](https://img.shields.io/badge/minified%20size-390%20kB-blue)][release-url] [![verfiy][verify-image]][verify-url] [Inggris](README.md)   |   Indonesia   |   [简体中文](README_ZH.md)   |   [日本語](README_JA.md)   |   [Türkçe](README_TR.md) ### Install [![Chrome][Chrome-image]][Chrome-url] [![Edge][Edge-image]][Edge-url] [![Firefox][Firefox-image]][Firefox-url] [![Safari][Safari-image]][Safari-url] [![Android][Android-image]][Android-url] [![Github][Github-image]][Github-url] [Panduan](https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Guide)   |   [Pratinjau](#Pratinjau)   |   [Pengembangan & Berkontribusi][dev-url]   |   [Demonstrasi Video](https://www.youtube.com/watch?v=E1smDxJvTRs)   |   [Kredit](#Kredit) [dev-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Development&Contributing [license-image]: http://img.shields.io/badge/license-MIT-blue.svg [license-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/blob/master/LICENSE [release-image]: https://img.shields.io/github/release/ChatGPTBox-dev/chatGPTBox.svg [release-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/releases/latest [verify-image]: https://github.com/ChatGPTBox-dev/chatGPTBox/workflows/verify-configs/badge.svg [verify-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/actions/workflows/verify-configs.yml [Chrome-image]: https://img.shields.io/badge/-Chrome-brightgreen?logo=google-chrome&logoColor=white [Chrome-url]: https://chrome.google.com/webstore/detail/chatgptbox/eobbhoofkanlmddnplfhnmkfbnlhpbbo [Edge-image]: https://img.shields.io/badge/-Edge-blue?logo=microsoft-edge&logoColor=white [Edge-url]: https://microsoftedge.microsoft.com/addons/detail/fission-chatbox-best/enjmfilpkbbabhgeoadmdpjjpnahkogf [Firefox-image]: https://img.shields.io/badge/-Firefox-orange?logo=firefox-browser&logoColor=white [Firefox-url]: https://addons.mozilla.org/firefox/addon/chatgptbox/ [Safari-image]: https://img.shields.io/badge/-Safari-blue?logo=safari&logoColor=white [Safari-url]: https://apps.apple.com/app/fission-chatbox/id6446611121 [Android-image]: https://img.shields.io/badge/-Android-brightgreen?logo=android&logoColor=white [Android-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Install#install-to-android [Github-image]: https://img.shields.io/badge/-Github-black?logo=github&logoColor=white [Github-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Install
## Berita - Ekstensi ini **tidak** mengumpulkan data Anda. Anda dapat memverifikasinya dengan melakukan pencarian global untuk `fetch(` dan `XMLHttpRequest(` dalam kode untuk menemukan semua panggilan permintaan jaringan. Jumlah kode tidak banyak, jadi mudah untuk melakukannya. - Anda dapat menggunakan proyek seperti https://github.com/BerriAI/litellm / https://github.com/songquanpeng/one-api untuk mengkonversi API LLM ke dalam format OpenAI dan menggunakannya bersama dengan mode `Custom Model` dari ChatGPTBox - Anda juga dapat menggunakan [Ollama](https://github.com/ChatGPTBox-dev/chatGPTBox/issues/616#issuecomment-1975186467) / https://openrouter.ai/docs#models dengan mode `Custom Model` dari ChatGPTBox ## ✨ Fitur - 🌈 Panggil kotak dialog percakapan di halaman apa pun kapan saja. (Ctrl+B) - 📱 Dukungan untuk perangkat seluler. - 📓 Ringkaskan halaman apa pun dengan menu klik kanan. (Alt+B) - 📖 Halaman percakapan independen. (Ctrl+Shift+H) - 🔗 Dukungan untuk beberapa API (Web API untuk pengguna Gratis dan Plus, GPT-3.5, GPT-4, Claude, New Bing, Moonshot, Self-Hosted, Azure, dll.). - 📦 Integrasi untuk berbagai situs web yang umum digunakan (Reddit, Quora, YouTube, GitHub, GitLab, StackOverflow, Zhihu, Bilibili). (Terinspirasi dari [wimdenherder](https://github.com/wimdenherder)) - 🔍 Integrasi dengan semua mesin pencari utama, dan permintaan kustom untuk mendukung situs tambahan. - 🧰 Alat pemilihan dan menu klik kanan untuk melakukan berbagai tugas, seperti terjemahan, ringkasan, penyempurnaan, analisis sentimen, pembagian paragraf, penjelasan kode, dan permintaan. - 🗂️ Dukungan kartu statis untuk kotak percakapan bercabang. - 🖨️ Mudah menyimpan catatan percakapan lengkap atau menyalinnya sebagian. - 🎨 Dukungan rendering yang kuat, baik untuk penyorotan kode maupun rumus matematika kompleks. - 🌍 Dukungan preferensi bahasa. - 📝 Dukungan alamat API kustom. - ⚙️ Semua adaptasi situs dan alat pemilihan (gelembung) dapat dinonaktifkan atau diaktifkan secara bebas, nonaktifkan modul yang tidak diperlukan. - 💡 Alat pemilihan dan adaptasi situs mudah untuk dikembangkan dan diperluas, lihat bagian [Pengembangan & Berkontribusi][dev-url]. - 😉 Berbicara untuk meningkatkan kualitas jawaban. ## Pratinjau
**Integrasi Mesin Pencari, Jendela Mengapung, Percakapan Cabang** ![preview_google_floatingwindow_conversationbranch](screenshots/preview_google_floatingwindow_conversationbranch.jpg) **Integrasi dengan Situs Web yang Umum Digunakan, Alat Pemilihan** ![preview_reddit_selectiontools](screenshots/preview_reddit_selectiontools.jpg) **Halaman Percakapan Independen** ![preview_independentpanel](screenshots/preview_independentpanel.jpg) **Analisis Git, Menu Klik Kanan** ![preview_github_rightclickmenu](screenshots/preview_github_rightclickmenu.jpg) **Ringkasan Video** ![preview_youtube](screenshots/preview_youtube.jpg) **Dukungan Perangkat Seluler** ![image](https://user-images.githubusercontent.com/13366013/225529110-9221c8ce-ad41-423e-b6ec-097981e74b66.png) **Pengaturan** ![preview_settings](screenshots/preview_settings.jpg)
## Kredit Proyek ini didasarkan pada salah satu repositori saya yang lain, [josStorer/chatGPT-search-engine-extension](https://github.com/josStorer/chatGPT-search-engine-extension) [josStorer/chatGPT-search-engine-extension](https://github.com/josStorer/chatGPT-search-engine-extension) bercabang dari [wong2/chat-gpt-google-extension](https://github.com/wong2/chat-gpt-google-extension) (Saya belajar banyak dari situ) dan terlepas sejak 14 Desember 2022 [wong2/chat-gpt-google-extension](https://github.com/wong2/chat-gpt-google-extension) terinspirasi oleh [ZohaibAhmed/ChatGPT-Google](https://github.com/ZohaibAhmed/ChatGPT-Google) ([upstream-c54528b](https://github.com/wong2/chatgpt-google-extension/commit/c54528b0e13058ab78bfb433c92603db017d1b6b)) ================================================ FILE: README_JA.md ================================================

ChatGPT Box

深い ChatGPT 統合をブラウザに、完全無料で。 [![license][license-image]][license-url] [![release][release-image]][release-url] [![size](https://img.shields.io/badge/minified%20size-390%20kB-blue)][release-url] [![verfiy][verify-image]][verify-url] [English](README.md)   |   [Indonesia](README_IN.md)   |   [简体中文](README_ZH.md)   |   日本語   |   [Türkçe](README_TR.md) ### インストール [![Chrome][Chrome-image]][Chrome-url] [![Edge][Edge-image]][Edge-url] [![Firefox][Firefox-image]][Firefox-url] [![Safari][Safari-image]][Safari-url] [![Android][Android-image]][Android-url] [![Github][Github-image]][Github-url] [ガイド](https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Guide)   |   [プレビュー](#プレビュー)   |   [開発 & コントリビュート][dev-url]   |   [ビデオデモ](https://www.youtube.com/watch?v=E1smDxJvTRs)   |   [クレジット](#クレジット) [dev-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Development&Contributing [license-image]: http://img.shields.io/badge/license-MIT-blue.svg [license-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/blob/master/LICENSE [release-image]: https://img.shields.io/github/release/ChatGPTBox-dev/chatGPTBox.svg [release-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/releases/latest [verify-image]: https://github.com/ChatGPTBox-dev/chatGPTBox/workflows/verify-configs/badge.svg [verify-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/actions/workflows/verify-configs.yml [Chrome-image]: https://img.shields.io/badge/-Chrome-brightgreen?logo=google-chrome&logoColor=white [Chrome-url]: https://chrome.google.com/webstore/detail/chatgptbox/eobbhoofkanlmddnplfhnmkfbnlhpbbo [Edge-image]: https://img.shields.io/badge/-Edge-blue?logo=microsoft-edge&logoColor=white [Edge-url]: https://microsoftedge.microsoft.com/addons/detail/fission-chatbox-best/enjmfilpkbbabhgeoadmdpjjpnahkogf [Firefox-image]: https://img.shields.io/badge/-Firefox-orange?logo=firefox-browser&logoColor=white [Firefox-url]: https://addons.mozilla.org/firefox/addon/chatgptbox/ [Safari-image]: https://img.shields.io/badge/-Safari-blue?logo=safari&logoColor=white [Safari-url]: https://apps.apple.com/app/fission-chatbox/id6446611121 [Android-image]: https://img.shields.io/badge/-Android-brightgreen?logo=android&logoColor=white [Android-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Install#install-to-android [Github-image]: https://img.shields.io/badge/-Github-black?logo=github&logoColor=white [Github-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Install
## ニュース - この拡張機能はあなたのデータを収集しません。コード内の `fetch(` と `XMLHttpRequest(` をグローバル検索して、すべてのネットワークリクエストの呼び出しを見つけることで確認できます。コードの量はそれほど多くないので、簡単にできます。 - このツールは、あなたが明示的に要求しない限り、ChatGPT にデータを送信しません。デフォルトでは、拡張機能は手動で有効にする必要があります ChatGPT へのリクエストは、"Ask ChatGPT" をクリックするか、選択フローティングツールをトリガーした場合にのみ送信されます。(issue #407) - https://github.com/BerriAI/litellm / https://github.com/songquanpeng/one-api のようなプロジェクトを使用して、LLM APIをOpenAI形式に変換し、それらをChatGPTBoxの `カスタムモデル` モードと組み合わせて使用することができます - もちろんです。ChatGPTBoxの `カスタムモデル` モードを使用する際には、[Ollama](https://github.com/ChatGPTBox-dev/chatGPTBox/issues/616#issuecomment-1975186467) / https://openrouter.ai/docs#models もご利用いただけます ## ✨ 機能 - 🌈 いつでもどのページでもチャットダイアログボックスを呼び出すことができます。 (Ctrl+B) - 📱 モバイル機器のサポート。 - 📓 右クリックメニューで任意のページを要約。 (Alt+B) - 📖 独立した会話ページ。 (Ctrl+Shift+H) - 🔗 複数の API をサポート(無料および Plus ユーザー向け Web API、GPT-3.5、GPT-4、Claude、New Bing、Moonshot、セルフホスト、Azure など)。 - 📦 よく使われる様々なウェブサイト(Reddit、Quora、YouTube、GitHub、GitLab、StackOverflow、Zhihu、Bilibili)の統合。 ([wimdenherder](https://github.com/wimdenherder) にインスパイアされました) - 🔍 すべての主要検索エンジンと統合し、追加のサイトをサポートするためのカスタムクエリ。 - 🧰 選択ツールと右クリックメニューで、翻訳、要約、推敲、感情分析、段落分割、コード説明、クエリーなど、さまざまなタスクを実行できます。 - 🗂️ 静的なカードは、複数の支店での会話のためのフローティングチャットボックスをサポートしています。 - 🖨️ チャット記録を完全に保存することも、部分的にコピーすることも簡単です。 - 🎨 コードのハイライトや複雑な数式など、強力なレンダリングをサポート。 - 🌍 言語設定のサポート。 - 📝 カスタム API アドレスのサポート - ⚙️ すべてのサイト適応と選択ツール(バブル)は、自由にオンまたはオフに切り替えることができ、不要なモジュールを無効にすることができます。 - 💡 セレクションツールやサイトへの適応は簡単に開発・拡張できます。[開発 & コントリビュート][dev-url]のセクションを参照。 - 😉 チャットして回答の質を高められます。 ## プレビュー
**検索エンジンの統合、フローティングウィンドウ、会話ブランチ** ![preview_google_floatingwindow_conversationbranch](screenshots/preview_google_floatingwindow_conversationbranch.jpg) **よく使われるウェブサイトや選択ツールとの統合** ![preview_reddit_selectiontools](screenshots/preview_reddit_selectiontools.jpg) **独立会話ページ** ![preview_independentpanel](screenshots/preview_independentpanel.jpg) **Git 分析、右クリックメニュー** ![preview_github_rightclickmenu](screenshots/preview_github_rightclickmenu.jpg) **ビデオ要約** ![preview_youtube](screenshots/preview_youtube.jpg) **モバイルサポート** ![image](https://user-images.githubusercontent.com/13366013/225529110-9221c8ce-ad41-423e-b6ec-097981e74b66.png) **設定** ![preview_settings](screenshots/preview_settings.jpg)
## クレジット このプロジェクトは、私の他のリポジトリ [josStorer/chatGPT-search-engine-extension](https://github.com/josStorer/chatGPT-search-engine-extension) に基づいています [josStorer/chatGPT-search-engine-extension](https://github.com/josStorer/chatGPT-search-engine-extension) は [wong2/chat-gpt-google-extension](https://github.com/wong2/chat-gpt-google-extension) (参考にしました)からフォークされ、2022年12月14日から切り離されています [wong2/chat-gpt-google-extension](https://github.com/wong2/chat-gpt-google-extension) は [ZohaibAhmed/ChatGPT-Google](https://github.com/ZohaibAhmed/ChatGPT-Google) にインスパイアされています([upstream-c54528b](https://github.com/wong2/chatgpt-google-extension/commit/c54528b0e13058ab78bfb433c92603db017d1b6b)) ================================================ FILE: README_TR.md ================================================

ChatGPT Box

Tarayıcınıza derin ChatGPT entegrasyonu, tamamen ücretsiz. [![license][license-image]][license-url] [![release][release-image]][release-url] [![size](https://img.shields.io/badge/minified%20size-390%20kB-blue)][release-url] [![verfiy][verify-image]][verify-url] [English](README.md)   |   [Indonesia](README_IN.md)   |   [简体中文](README_ZH.md)   |   [日本語](README_JA.md)   |   Türkçe ### Yükle [![Chrome][Chrome-image]][Chrome-url] [![Edge][Edge-image]][Edge-url] [![Firefox][Firefox-image]][Firefox-url] [![Safari][Safari-image]][Safari-url] [![Android][Android-image]][Android-url] [![Github][Github-image]][Github-url] [Rehber](https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Guide)   |   [Önizleme](#Preview)   |   [Gelişim ve Katkı Sağlama][dev-url]   |   [Video](https://www.youtube.com/watch?v=E1smDxJvTRs)   |   [Credit](#Credit) [dev-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Development&Contributing [license-image]: http://img.shields.io/badge/license-MIT-blue.svg [license-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/blob/master/LICENSE [release-image]: https://img.shields.io/github/release/ChatGPTBox-dev/chatGPTBox.svg [release-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/releases/latest [verify-image]: https://github.com/ChatGPTBox-dev/chatGPTBox/workflows/verify-configs/badge.svg [verify-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/actions/workflows/verify-configs.yml [Chrome-image]: https://img.shields.io/badge/-Chrome-brightgreen?logo=google-chrome&logoColor=white [Chrome-url]: https://chrome.google.com/webstore/detail/chatgptbox/eobbhoofkanlmddnplfhnmkfbnlhpbbo [Edge-image]: https://img.shields.io/badge/-Edge-blue?logo=microsoft-edge&logoColor=white [Edge-url]: https://microsoftedge.microsoft.com/addons/detail/fission-chatbox-best/enjmfilpkbbabhgeoadmdpjjpnahkogf [Firefox-image]: https://img.shields.io/badge/-Firefox-orange?logo=firefox-browser&logoColor=white [Firefox-url]: https://addons.mozilla.org/firefox/addon/chatgptbox/ [Safari-image]: https://img.shields.io/badge/-Safari-blue?logo=safari&logoColor=white [Safari-url]: https://apps.apple.com/app/fission-chatbox/id6446611121 [Android-image]: https://img.shields.io/badge/-Android-brightgreen?logo=android&logoColor=white [Android-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Install#install-to-android [Github-image]: https://img.shields.io/badge/-Github-black?logo=github&logoColor=white [Github-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Install
## Bilgilendirme - Bu eklenti hiçbir verinizi **toplamaz**. Kod içinde network isteği çağrılarını bulmak için `fetch(` ve `XMLHttpRequest(` için global bir arama yaparak bunu doğrulayabilirsiniz. Kod miktarı fazla değil, bu yüzden yapılması kolaydır. - Bu araç ChatGPT'ye siz açıkça belirtmediğiniz sürece hiçbir veri iletmez. Varsayılan olarak, eklentinin manuel olarak aktif hale getirilmesi gerekmektedir. Özellikle, sadece "ChatGPT'ye Sor" butonuna basarsanız ChatGPT'ye istek atar veya yüzen seçim araçlarını tetiklerseniz — Bu yalnızca GPT API modlarını kullandığınızda uygulanır (konu #407) - Proje olarak https://github.com/BerriAI/litellm / https://github.com/songquanpeng/one-api gibi şeyleri kullanarak LLM API'larını OpenAI formatına dönüştürebilir ve bunları ChatGPTBox'ın `Custom Model` modu ile birlikte kullanabilirsiniz - ChatGPTBox'un `Custom Model` modu ile [Ollama](https://github.com/ChatGPTBox-dev/chatGPTBox/issues/616#issuecomment-1975186467) / https://openrouter.ai/docs#models adresini de kullanabilirsiniz ## ✨ Özellikler - 🌈 Sohbet diyalog kutusunu istediğiniz zaman çağırma. (Ctrl+B) - 📱 Mobil cihaz desteği. - 📓 Herhangi bir sayfayı sağ tık menüsüyle özetleme (Alt+B) - 📖 Bağımsız konuşma sayfası. (Ctrl+Shift+H) - 🔗 Çoklu API desteği (Ücretsiz ve Plus kullanıcıları için Web API , GPT-3.5, GPT-4, Claude, New Bing, Moonshot, Self-Hosted, Azure vs.). - 📦 Çeşitli olarak yaygın kullanılan websiteler için entegrasyon (Reddit, Quora, YouTube, GitHub, GitLab, StackOverflow, Zhihu, Bilibili). ([wimdenherder](https://github.com/wimdenherder)'den esinlenilmiştir) - 🔍 Tüm popüler arama motorlarına entegrasyon ve ek siteleri desteklemek için özel sorgu desteği - 🧰 Çeşitli görevleri yerine getirmek için, seçim aracı ve sağ tık menüsü (Çeviri, Özetleme,Polishing, Duygu Analizi, Paragraf Bölme, Kod Açıklama ve Sorgular gibi.) - 🗂️ Çok dallı konuşmalar için statik yüzen kart kutuları desteği. - 🖨️ Kolaylıkla tam sohbet kayıtlarınızı kaydedin veya kısmi olarak kopyalayın. - 🎨 Güçlü render'lama desteği, ister kod için olsun ister karışık matematik formülleri için. - 🌍 Dil tercih desteği. - 📝 Özel API adres desteği. - ⚙️ Tüm site adaptasyonları ve seçim araçları(sohbet balonu) özgürce açıp kapatılabilir, ihtiyacınız olmayan modülleri kapatın. - 💡 Seçim araçları ve site adaptasyonunun geliştirilmesi kolay ve geniştir, [Development&Contributing][dev-url] bölümüne bakınız. - 😉 Yanıt kalitesini artırmak için sohbet edin. ## Önizleme
**Arama Motoru Entegrasyonu, Yüzen Pencereler, Konuşma Dalları** ![preview_google_floatingwindow_conversationbranch](screenshots/preview_google_floatingwindow_conversationbranch.jpg) **Yaygın Olarak Kullanılan Sitelerle Entegrasyon, Seçim Araçları** ![preview_reddit_selectiontools](screenshots/preview_reddit_selectiontools.jpg) **Bağımsız Konuşma Sayfası** ![preview_independentpanel](screenshots/preview_independentpanel.jpg) **Git Analizi, Sağ Tık Menüsü** ![preview_github_rightclickmenu](screenshots/preview_github_rightclickmenu.jpg) **Video Özeti** ![preview_youtube](screenshots/preview_youtube.jpg) **Mobil Desteği** ![image](https://user-images.githubusercontent.com/13366013/225529110-9221c8ce-ad41-423e-b6ec-097981e74b66.png) **Ayarlar** ![preview_settings](screenshots/preview_settings.jpg)
## Katkıda Bulunanlar Bu proje diğer repolarımın birisinden baz alınmıştır. [josStorer/chatGPT-search-engine-extension](https://github.com/josStorer/chatGPT-search-engine-extension) [josStorer/chatGPT-search-engine-extension](https://github.com/josStorer/chatGPT-search-engine-extension) projesi [wong2/chat-gpt-google-extension](https://github.com/wong2/chat-gpt-google-extension) projesinden "fork"lanmıştır (Ondan çok şey öğrendim) ve 14 Aralık 2022'den beri bağımsızım [wong2/chat-gpt-google-extension](https://github.com/wong2/chat-gpt-google-extension) projesi [ZohaibAhmed/ChatGPT-Google](https://github.com/ZohaibAhmed/ChatGPT-Google) ([upstream-c54528b](https://github.com/wong2/chatgpt-google-extension/commit/c54528b0e13058ab78bfb433c92603db017d1b6b)) projesinden esinlenilmiştir ================================================ FILE: README_ZH.md ================================================

ChatGPT Box

将ChatGPT深度集成到浏览器中, 你所需要的一切均在于此 [![license][license-image]][license-url] [![release][release-image]][release-url] [![size](https://img.shields.io/badge/minified%20size-390%20kB-blue)][release-url] [![verfiy][verify-image]][verify-url] [English](README.md)   |   [Indonesia](README_IN.md)   |   简体中文   |   [日本語](README_JA.md)   |   [Türkçe](README_TR.md) ### 安装链接 [![Chrome][Chrome-image]][Chrome-url] [![Edge][Edge-image]][Edge-url] [![Firefox][Firefox-image]][Firefox-url] [![Safari][Safari-image]][Safari-url] [![Android][Android-image]][Android-url] [![Github][Github-image]][Github-url] [使用指南](https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Guide)   |   [效果预览](#Preview)   |   [开发&贡献][dev-url]   |   [视频演示](https://www.bilibili.com/video/BV1524y1x7io)   |   [鸣谢](#Credit) [dev-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Development&Contributing [license-image]: http://img.shields.io/badge/license-MIT-blue.svg [license-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/blob/master/LICENSE [release-image]: https://img.shields.io/github/release/ChatGPTBox-dev/chatGPTBox.svg [release-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/releases/latest [verify-image]: https://github.com/ChatGPTBox-dev/chatGPTBox/workflows/verify-configs/badge.svg [verify-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/actions/workflows/verify-configs.yml [Chrome-image]: https://img.shields.io/badge/-Chrome-brightgreen?logo=google-chrome&logoColor=white [Chrome-url]: https://chrome.google.com/webstore/detail/chatgptbox/eobbhoofkanlmddnplfhnmkfbnlhpbbo [Edge-image]: https://img.shields.io/badge/-Edge-blue?logo=microsoft-edge&logoColor=white [Edge-url]: https://microsoftedge.microsoft.com/addons/detail/fission-chatbox-best/enjmfilpkbbabhgeoadmdpjjpnahkogf [Firefox-image]: https://img.shields.io/badge/-Firefox-orange?logo=firefox-browser&logoColor=white [Firefox-url]: https://addons.mozilla.org/firefox/addon/chatgptbox/ [Safari-image]: https://img.shields.io/badge/-Safari-blue?logo=safari&logoColor=white [Safari-url]: https://apps.apple.com/app/fission-chatbox/id6446611121 [Android-image]: https://img.shields.io/badge/-Android-brightgreen?logo=android&logoColor=white [Android-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Install#install-to-android [Github-image]: https://img.shields.io/badge/-Github-black?logo=github&logoColor=white [Github-url]: https://github.com/ChatGPTBox-dev/chatGPTBox/wiki/Install
## 新闻 - 这个扩展程序不收集你的数据, 你可以通过对代码全局搜索 `fetch(` 和 `XMLHttpRequest(` 找到所有的网络请求调用. 代码量不多, 所以很容易验证. - 你可以使用像 https://github.com/BerriAI/litellm / https://github.com/songquanpeng/one-api 这样的项目,将各种 大语言模型 API 转换为OpenAI格式,并与ChatGPTBox的`自定义模型`模式结合使用 - 对于国内用户, 有GPT, Midjourney, Netflix等账号需求的, 可以考虑此站点购买合租, 此链接购买的订单也会给我带来一定收益, 作为对本项目的支持: https://nf.video/yinhe/web?sharedId=84599 - 三方API服务兼容, 查看 https://api2d.com/r/193934 和 https://openrouter.ai/docs#models, 该服务并不是由我提供的, 但对于获取账号困难的用户可以考虑, 使用方法: [视频](https://www.bilibili.com/video/BV1bo4y1h7Hb/) [图文](https://github.com/ChatGPTBox-dev/chatGPTBox/issues/166#issuecomment-1504704489) - 离线/自托管模型 现已支持, 在`自定义模型`模式下使用, 具体查看 [Ollama](https://github.com/ChatGPTBox-dev/chatGPTBox/issues/616#issuecomment-1975186467) / [RWKV-Runner](https://github.com/josStorer/RWKV-Runner), 你还可以部署wenda (https://github.com/wenda-LLM/wenda), 配合自定义模型模式使用, 从而调用各类本地模型, 参考 [#397](https://github.com/ChatGPTBox-dev/chatGPTBox/issues/397) 修改API URL ## ✨ Features - 🌈 在任何页面随时呼出聊天对话框 (Ctrl+B) - 📱 支持手机等移动设备 - 📓 通过右键菜单总结任意页面 (Alt+B) - 📖 独立对话页面 (Ctrl+Shift+H) - 🔗 多种API支持 (免费用户和Plus用户可用Web API, 此外还有GPT-3.5, GPT-4, Claude, NewBing, Moonshot, 自托管支持, Azure等) - 📦 对各种常用网站的集成适配 (Reddit, Quora, YouTube, GitHub, GitLab, StackOverflow, Zhihu, Bilibili) (受到[wimdenherder](https://github.com/wimdenherder)启发) - 🔍 对所有主流搜索引擎的适配, 并支持自定义查询以支持额外的站点 - 🧰 框选工具与右键菜单, 执行各种你的需求, 如翻译, 总结, 润色, 情感分析, 段落划分, 代码解释, 问询 - 🗂️ 静态卡片支持浮出聊天框, 进行多分支对话 - 🖨️ 随意保存你的完整对话记录, 或进行局部复制 - 🎨 强大的渲染支持, 不论是代码高亮, 还是复杂数学公式 - 🌍 多语言偏好支持 - 📝 [自定义API地址](https://github.com/Ice-Hazymoon/openai-scf-proxy)支持 - ⚙️ 所有站点适配与工具均可自由开关, 随时停用你不需要的模块 - 💡 工具与站点适配开发易于扩展, 对于开发人员易于自定义, 请查看[开发&贡献][dev-url]部分 - 😉 此外, 如果回答有任何不足, 直接聊天解决! ## Preview
**搜索引擎适配, 浮动窗口, 对话分支** ![preview_google_floatingwindow_conversationbranch](screenshots/preview_google_floatingwindow_conversationbranch.jpg) **常用站点集成, 选择浮动工具** ![preview_reddit_selectiontools](screenshots/preview_reddit_selectiontools.jpg) **独立对话页面** ![preview_independentpanel](screenshots/preview_independentpanel.jpg) **Git分析, 右键菜单** ![preview_github_rightclickmenu](screenshots/preview_github_rightclickmenu.jpg) **视频总结** ![preview_youtube](screenshots/preview_youtube.jpg) **移动端效果** ![image](https://user-images.githubusercontent.com/13366013/225529110-9221c8ce-ad41-423e-b6ec-097981e74b66.png) **设置界面** ![preview_settings](screenshots/preview_settings.jpg)
## Credit 该项目基于我的另一个项目 [josStorer/chatGPT-search-engine-extension](https://github.com/josStorer/chatGPT-search-engine-extension) [josStorer/chatGPT-search-engine-extension](https://github.com/josStorer/chatGPT-search-engine-extension) fork自 [wong2/chat-gpt-google-extension](https://github.com/wong2/chat-gpt-google-extension)(我从中学到很多) 并在2022年12月14日与上游分离 [wong2/chat-gpt-google-extension](https://github.com/wong2/chat-gpt-google-extension) 的想法源于 [ZohaibAhmed/ChatGPT-Google](https://github.com/ZohaibAhmed/ChatGPT-Google) ([upstream-c54528b](https://github.com/wong2/chatgpt-google-extension/commit/c54528b0e13058ab78bfb433c92603db017d1b6b)) ================================================ FILE: badges/coverage.json ================================================ { "schemaVersion": 1, "label": "coverage", "message": "17.69%", "color": "red" } ================================================ FILE: build.mjs ================================================ import archiver from 'archiver' import fs from 'fs-extra' import path from 'path' import webpack from 'webpack' import os from 'os' import ProgressBarPlugin from 'progress-bar-webpack-plugin' import CssMinimizerPlugin from 'css-minimizer-webpack-plugin' import MiniCssExtractPlugin from 'mini-css-extract-plugin' import { EsbuildPlugin } from 'esbuild-loader' import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer' const outdir = 'build' const __dirname = path.resolve() const isProduction = process.argv[2] !== '--development' // --production and --analyze are both production const isAnalyzing = process.argv[2] === '--analyze' // Env helpers function getBooleanEnv(val, defaultValue) { if (val == null) return defaultValue const s = String(val).trim().toLowerCase() if (s === '' || s === '0' || s === 'false' || s === 'no' || s === 'off') { return false } if (s === '1' || s === 'true' || s === 'yes' || s === 'on') { return true } console.warn(`[build] Unknown boolean env value "${val}", defaulting to ${defaultValue}`) return defaultValue } // Default: parallel build ON unless explicitly disabled const parallelBuild = getBooleanEnv(process.env.BUILD_PARALLEL, true) const isWatchOnce = getBooleanEnv(process.env.BUILD_WATCH_ONCE, false) // Cache compression control: default none; allow override via env function parseCacheCompressionOption(envVal) { if (envVal == null) return false const v = String(envVal).trim().toLowerCase() if (v === '' || v === '0' || v === 'false' || v === 'none') return false if (v === 'gzip' || v === 'brotli') return v console.warn(`[build] Unknown BUILD_CACHE_COMPRESSION="${envVal}", defaulting to no compression`) return false } const cacheCompressionOption = parseCacheCompressionOption(process.env.BUILD_CACHE_COMPRESSION) let cpuCount = 1 try { // os.cpus() returns an array in Node.js; guard with try/catch for portability cpuCount = Math.max(1, os.cpus().length || 1) } catch { cpuCount = 1 } function parseThreadWorkerCount(envValue, cpuCount) { const maxWorkers = Math.max(1, cpuCount) if (envValue !== undefined && envValue !== null) { const rawStr = String(envValue).trim() if (/^[1-9]\d*$/.test(rawStr)) { const raw = Number(rawStr) if (raw > cpuCount) { console.warn( `[build] BUILD_THREAD_WORKERS=${raw} exceeds CPU count (${cpuCount}); capping to ${cpuCount}`, ) } return Math.min(raw, cpuCount) } console.warn(`[build] Invalid BUILD_THREAD_WORKERS="${envValue}", defaulting to ${maxWorkers}`) } return maxWorkers } const threadWorkers = parseThreadWorkerCount(process.env.BUILD_THREAD_WORKERS, cpuCount) // Thread-loader pool timeout constants (allow override via env) // Keep worker pool warm briefly to amortize repeated builds while still exiting quickly in CI let PRODUCTION_POOL_TIMEOUT_MS = 2000 if (process.env.BUILD_POOL_TIMEOUT) { const n = parseInt(process.env.BUILD_POOL_TIMEOUT, 10) if (Number.isFinite(n) && n > 0) { PRODUCTION_POOL_TIMEOUT_MS = n } else { console.warn( `[build] Invalid BUILD_POOL_TIMEOUT="${process.env.BUILD_POOL_TIMEOUT}", keep default ${PRODUCTION_POOL_TIMEOUT_MS}ms`, ) } } // Enable threads by default; allow disabling via BUILD_THREAD=0/false/no/off const enableThread = getBooleanEnv(process.env.BUILD_THREAD, true) // Allow opt-in symlink resolution for linked/workspace development when needed const resolveSymlinks = getBooleanEnv(process.env.BUILD_RESOLVE_SYMLINKS, false) // Cache and resolve Sass implementation once per process let sassImplPromise function resolveSassImplementation(mod) { if (mod && typeof mod.info === 'string') return mod if (mod?.default && typeof mod.default.info === 'string') return mod.default return mod } async function getSassImplementation() { if (!sassImplPromise) { sassImplPromise = (async () => { try { const mod = await import('sass-embedded') return resolveSassImplementation(mod) } catch (e1) { try { const mod = await import('sass') return resolveSassImplementation(mod) } catch (e2) { console.error('[build] Failed to load sass-embedded:', e1) console.error('[build] Failed to load sass:', e2) throw new Error("No Sass implementation available. Install 'sass-embedded' or 'sass'.") } } })() } return sassImplPromise } async function deleteOldDir() { await fs.rm(outdir, { recursive: true, force: true }) } async function runWebpack(isWithoutKatex, isWithoutTiktoken, minimal, sourceBuildDir, callback) { const shared = [ 'preact', 'webextension-polyfill', '@primer/octicons-react', 'react-bootstrap-icons', 'countries-list', 'i18next', 'react-i18next', 'react-tabs', './src/utils', './src/_locales/i18n-react', ] if (isWithoutKatex) shared.push('./src/components') const sassImpl = await getSassImplementation() const dirKey = path.basename(sourceBuildDir || outdir) const variantParts = [ isWithoutKatex ? 'no-katex' : 'with-katex', isWithoutTiktoken ? 'no-tiktoken' : 'with-tiktoken', minimal ? 'minimal' : 'full', dirKey, isProduction ? 'prod' : 'dev', ] const variantId = variantParts.join('__') const compiler = webpack({ entry: { 'content-script': { import: './src/content-script/index.jsx', dependOn: 'shared', }, background: { import: './src/background/index.mjs', }, popup: { import: './src/popup/index.jsx', dependOn: 'shared', }, IndependentPanel: { import: './src/pages/IndependentPanel/index.jsx', dependOn: 'shared', }, shared: shared, }, output: { filename: '[name].js', path: path.resolve(__dirname, sourceBuildDir || outdir), }, mode: isProduction ? 'production' : 'development', devtool: isProduction ? false : 'cheap-module-source-map', cache: { type: 'filesystem', name: `webpack-${variantId}`, // Only include dimensions that affect module outputs to avoid // unnecessary cache invalidations across machines/CI runners version: JSON.stringify({ PROD: isProduction }), // default none; override via BUILD_CACHE_COMPRESSION=gzip|brotli compression: cacheCompressionOption, buildDependencies: { config: [ path.resolve('build.mjs'), ...['package.json', 'package-lock.json'] .map((p) => path.resolve(p)) .filter((p) => fs.existsSync(p)), ], }, }, optimization: { minimizer: [ // Use esbuild for JS minification (faster than Terser) new EsbuildPlugin({ target: 'es2017', legalComments: 'none', }), // Use esbuild-based CSS minify via css-minimizer plugin new CssMinimizerPlugin({ minify: CssMinimizerPlugin.esbuildMinify, }), ], concatenateModules: !isAnalyzing, }, plugins: [ minimal ? new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'], }) : new webpack.ProvidePlugin({ process: 'process/browser.js', Buffer: ['buffer', 'Buffer'], }), new ProgressBarPlugin({ format: ' build [:bar] :percent (:elapsed seconds)', clear: false, }), new MiniCssExtractPlugin({ filename: '[name].css', }), new BundleAnalyzerPlugin({ analyzerMode: isAnalyzing ? 'static' : 'disable', }), ...(isWithoutKatex ? [ new webpack.NormalModuleReplacementPlugin(/markdown\.jsx/, (result) => { if (result.request) { result.request = result.request.replace( 'markdown.jsx', 'markdown-without-katex.jsx', ) } }), ] : []), ], resolve: { extensions: ['.jsx', '.mjs', '.js'], // Disable symlink resolution for consistent behavior/perf; enable via BUILD_RESOLVE_SYMLINKS=1 when working with linked deps symlinks: resolveSymlinks, alias: { parse5: path.resolve(__dirname, 'node_modules/parse5'), ...(minimal ? { buffer: path.resolve(__dirname, 'node_modules/buffer') } : { util: path.resolve(__dirname, 'node_modules/util'), buffer: path.resolve(__dirname, 'node_modules/buffer'), stream: 'stream-browserify', crypto: 'crypto-browserify', }), }, }, module: { rules: [ { test: /\.m?jsx?$/, exclude: /(node_modules)/, resolve: { fullySpecified: false, }, use: [ ...(enableThread ? [ { loader: 'thread-loader', options: { workers: threadWorkers, // Ensure one-off dev build exits quickly poolTimeout: isProduction ? PRODUCTION_POOL_TIMEOUT_MS : isWatchOnce ? 0 : Infinity, }, }, ] : []), { loader: 'babel-loader', options: { cacheDirectory: true, cacheCompression: false, presets: ['@babel/preset-env'], plugins: [ ['@babel/plugin-transform-runtime'], [ '@babel/plugin-transform-react-jsx', { runtime: 'automatic', importSource: 'preact', }, ], ], }, }, ], }, { test: /\.s[ac]ss$/, use: [ isProduction ? MiniCssExtractPlugin.loader : 'style-loader', { loader: 'css-loader', options: { importLoaders: 1, }, }, { loader: 'sass-loader', options: { implementation: sassImpl, sassOptions: { quietDeps: true, }, }, }, ], }, { test: /\.less$/, use: [ isProduction ? MiniCssExtractPlugin.loader : 'style-loader', { loader: 'css-loader', options: { importLoaders: 1, }, }, { loader: 'less-loader', }, ], }, { test: /\.css$/, use: [ isProduction ? MiniCssExtractPlugin.loader : 'style-loader', { loader: 'css-loader', }, ], }, { test: /\.(woff|ttf)$/, type: 'asset/resource', generator: { emit: false, }, }, { test: /\.woff2$/, type: 'asset/inline', }, { test: /\.(jpg|png|svg)$/, type: 'asset/inline', }, { test: /\.(graphql|gql)$/, loader: 'graphql-tag/loader', }, isWithoutTiktoken ? { test: /crop-text\.mjs$/, loader: 'string-replace-loader', options: { multiple: [ { search: "import { encode } from '@nem035/gpt-3-encoder'", replace: '', }, { search: 'encode(', replace: 'String(', }, ], }, } : {}, minimal ? { test: /styles\.scss$/, loader: 'string-replace-loader', options: { multiple: [ { search: "@import '../fonts/styles.css';", replace: '', }, ], }, } : {}, minimal ? { test: /index\.mjs$/, loader: 'string-replace-loader', options: { multiple: [ { search: 'import { generateAnswersWithChatGLMApi }', replace: '//', }, { search: 'await generateAnswersWithChatGLMApi', replace: '//', }, ], }, } : {}, ], }, }) if (isProduction) { // Ensure compiler is properly closed after production runs compiler.run((err, stats) => { const hasErrors = !!(err || stats?.hasErrors?.()) let callbackFailed = false const finishClose = () => compiler.close((closeErr) => { if (closeErr) { console.error('Error closing compiler:', closeErr) process.exitCode = 1 } if (hasErrors || callbackFailed) { process.exitCode = 1 } }) try { const ret = callback(err, stats) if (ret && typeof ret.then === 'function') { ret.then(finishClose, () => { callbackFailed = true finishClose() }) } else { finishClose() } } catch (callbackErr) { console.error('[build] Callback error:', callbackErr) callbackFailed = true finishClose() } }) } else { const watching = compiler.watch({}, (err, stats) => { const hasErrors = !!(err || stats?.hasErrors?.()) // Normalize callback return into a Promise to catch synchronous throws const ret = Promise.resolve().then(() => callback(err, stats)) if (isWatchOnce) { const finalize = (callbackFailed = false) => watching.close((closeErr) => { if (closeErr) console.error('Error closing watcher:', closeErr) // Exit explicitly to prevent hanging processes in CI // Use non-zero exit code when errors occurred, including callback failures const shouldFail = hasErrors || closeErr || callbackFailed process.exit(shouldFail ? 1 : 0) }) ret.then( () => finalize(false), () => finalize(true), ) } }) } } async function zipFolder(dir) { const zipPath = `${dir}.zip` await fs.ensureDir(path.dirname(zipPath)) await new Promise((resolve, reject) => { const output = fs.createWriteStream(zipPath) const archive = archiver('zip', { zlib: { level: 9 } }) let settled = false const fail = (err) => { if (!settled) { settled = true reject(err) } } const done = () => { if (!settled) { settled = true resolve() } } output.once('error', fail) archive.once('error', fail) archive.on('warning', (err) => { // Log non-fatal archive warnings for diagnostics console.warn('[build][zip] warning:', err) }) // Resolve on close to ensure FD is flushed and closed output.once('close', done) // Ensure close is emitted after finish on some fast runners output.once('finish', () => { try { if (typeof output.close === 'function') output.close() } catch (_) { // ignore } }) archive.pipe(output) archive.directory(dir, false) archive.finalize() }) } async function copyFiles(entryPoints, targetDir) { await fs.ensureDir(targetDir) await Promise.all( entryPoints.map(async (entryPoint) => { try { await fs.copy(entryPoint.src, `${targetDir}/${entryPoint.dst}`) } catch (e) { const isCss = typeof entryPoint.dst === 'string' && entryPoint.dst.endsWith('.css') if (e && e.code === 'ENOENT') { if (!isProduction && isCss) { console.log( `[build] Skipping missing CSS file: ${entryPoint.src} -> ${entryPoint.dst} (placeholder will be created)`, ) return } console.error('Missing build artifact:', `${entryPoint.src} -> ${entryPoint.dst}`) } else { console.error('Copy failed:', `${entryPoint.src} -> ${entryPoint.dst}`, e) } throw e } }), ) } // In development, create placeholder CSS and sourcemap files to avoid 404 noise async function ensureDevCssPlaceholders(cssFiles) { if (isProduction || cssFiles.length === 0) return await Promise.all( cssFiles.map(async (cssPath) => { if (!(await fs.pathExists(cssPath))) { await fs.outputFile(cssPath, '/* dev placeholder */\n') } const mapPath = `${cssPath}.map` if (!(await fs.pathExists(mapPath))) { await fs.outputFile(mapPath, '{"version":3,"sources":[],"mappings":"","names":[]}') } }), ) } async function finishOutput(outputDirSuffix, sourceBuildDir = outdir) { const commonFiles = [ { src: 'src/logo.png', dst: 'logo.png' }, { src: 'src/rules.json', dst: 'rules.json' }, { src: `${sourceBuildDir}/shared.js`, dst: 'shared.js' }, { src: `${sourceBuildDir}/content-script.css`, dst: 'content-script.css' }, // shared { src: `${sourceBuildDir}/content-script.js`, dst: 'content-script.js' }, { src: `${sourceBuildDir}/background.js`, dst: 'background.js' }, { src: `${sourceBuildDir}/popup.js`, dst: 'popup.js' }, { src: `${sourceBuildDir}/popup.css`, dst: 'popup.css' }, { src: 'src/popup/index.html', dst: 'popup.html' }, { src: `${sourceBuildDir}/IndependentPanel.js`, dst: 'IndependentPanel.js' }, { src: 'src/pages/IndependentPanel/index.html', dst: 'IndependentPanel.html' }, // Dev-only: copy external source maps for CSP-safe debugging ...(isProduction ? [] : [ { src: `${sourceBuildDir}/shared.js.map`, dst: 'shared.js.map' }, { src: `${sourceBuildDir}/content-script.js.map`, dst: 'content-script.js.map' }, { src: `${sourceBuildDir}/background.js.map`, dst: 'background.js.map' }, { src: `${sourceBuildDir}/popup.js.map`, dst: 'popup.js.map' }, { src: `${sourceBuildDir}/IndependentPanel.js.map`, dst: 'IndependentPanel.js.map' }, ]), ] // chromium const chromiumOutputDir = `./${outdir}/chromium${outputDirSuffix}` await copyFiles( [...commonFiles, { src: 'src/manifest.json', dst: 'manifest.json' }], chromiumOutputDir, ) await ensureDevCssPlaceholders( Array.from( new Set( commonFiles .filter((file) => file.dst.endsWith('.css')) .map((file) => path.join(chromiumOutputDir, file.dst)), ), ), ) if (isProduction) await zipFolder(chromiumOutputDir) // firefox const firefoxOutputDir = `./${outdir}/firefox${outputDirSuffix}` await copyFiles( [...commonFiles, { src: 'src/manifest.v2.json', dst: 'manifest.json' }], firefoxOutputDir, ) await ensureDevCssPlaceholders( Array.from( new Set( commonFiles .filter((file) => file.dst.endsWith('.css')) .map((file) => path.join(firefoxOutputDir, file.dst)), ), ), ) if (isProduction) await zipFolder(firefoxOutputDir) } async function build() { await deleteOldDir() function createWebpackBuildPromise(isWithoutKatex, isWithoutTiktoken, minimal, tmpDir, suffix) { return new Promise((resolve, reject) => { const ret = runWebpack( isWithoutKatex, isWithoutTiktoken, minimal, tmpDir, async (err, stats) => { if (err || stats?.hasErrors?.()) { console.error(err || stats.toString()) reject(err || new Error('webpack error')) return } try { await finishOutput(suffix, tmpDir) resolve() } catch (copyErr) { reject(copyErr) } }, ) // runWebpack is async; catch early rejections (e.g., failed dynamic imports) if (ret && typeof ret.then === 'function') ret.catch(reject) }) } if (isProduction && !isAnalyzing) { const tmpFull = `${outdir}/.tmp-full` const tmpMin = `${outdir}/.tmp-min` try { if (parallelBuild) { const results = await Promise.allSettled([ createWebpackBuildPromise(true, true, true, tmpMin, '-without-katex-and-tiktoken'), createWebpackBuildPromise(false, false, false, tmpFull, ''), ]) const failed = results.find((result) => result.status === 'rejected') if (failed) { throw failed.reason } } else { await createWebpackBuildPromise(true, true, true, tmpMin, '-without-katex-and-tiktoken') await createWebpackBuildPromise(false, false, false, tmpFull, '') } } finally { await fs.rm(tmpFull, { recursive: true, force: true }) await fs.rm(tmpMin, { recursive: true, force: true }) } return } await new Promise((resolve, reject) => { const ret = runWebpack(false, false, false, outdir, async (err, stats) => { const hasErrors = !!(err || stats?.hasErrors?.()) if (hasErrors) { console.error(err || stats.toString()) // In normal dev watch, keep process alive on initial errors; only fail when watch-once if (isWatchOnce) { reject(err || new Error('webpack error')) } return } try { await finishOutput('') resolve() } catch (e) { // Packaging failure should stop even in dev to avoid silent success reject(e) if (isWatchOnce) { // Re-throw to surface an error and exit non-zero even if rejection isn't awaited throw e } } }) // Early setup failures (e.g., dynamic imports) should fail fast if (ret && typeof ret.then === 'function') ret.catch(reject) }) } build().catch((e) => { console.error(e) process.exit(1) }) ================================================ FILE: package.json ================================================ { "name": "chatgptbox", "engines": { "node": ">=22" }, "scripts": { "build": "node build.mjs --production", "build:safari": "bash ./safari/build.sh", "dev": "node build.mjs --development", "analyze": "node build.mjs --analyze", "lint": "eslint --ext .js,.mjs,.jsx .", "test": "node --import ./tests/setup/browser-shim.mjs --test", "test:coverage": "c8 --all --reporter=text --reporter=lcov --reporter=json-summary --include=\"src/**/*.{mjs,jsx,js}\" node --import ./tests/setup/browser-shim.mjs --test", "lint:fix": "eslint --ext .js,.mjs,.jsx . --fix", "pretty": "prettier --write ./**/*.{js,mjs,jsx,json,css,scss}", "stage": "run-script-os", "stage:default": "git add $(git diff --name-only --cached --diff-filter=d)", "stage:win32": "powershell git add $(git diff --name-only --cached --diff-filter=d)", "verify": "node .github/workflows/scripts/verify-search-engine-configs.mjs" }, "pre-commit": [ "pretty", "stage", "lint" ], "dependencies": { "@babel/runtime": "^7.24.7", "@mozilla/readability": "^0.6.0", "@nem035/gpt-3-encoder": "^1.1.7", "@picocss/pico": "^1.5.13", "@primer/octicons-react": "^18.3.0", "buffer": "^6.0.3", "countries-list": "^2.6.1", "crypto-browserify": "^3.12.0", "diff": "^5.2.0", "file-saver": "^2.0.5", "github-markdown-css": "^5.6.1", "gpt-3-encoder": "^1.1.4", "graphql": "^16.9.0", "i18next": "^22.4.15", "js-sha3": "^0.9.3", "jsonwebtoken": "9.0.2", "katex": "^0.16.11", "lodash-es": "^4.17.21", "md5": "^2.3.0", "parse5": "^6.0.1", "preact": "^10.22.1", "process": "^0.11.10", "prop-types": "^15.8.1", "random-int": "^3.0.0", "react": "npm:@preact/compat@^17.1.2", "react-bootstrap-icons": "^1.11.4", "react-dom": "npm:@preact/compat@^17.1.2", "react-draggable": "^4.4.6", "react-i18next": "^12.2.0", "react-markdown": "^8.0.7", "react-tabs": "^4.3.0", "react-toastify": "^9.1.3", "rehype-highlight": "^6.0.0", "rehype-katex": "^6.0.3", "rehype-raw": "^6.1.1", "remark-breaks": "^3.0.3", "remark-gfm": "^3.0.1", "remark-math": "^5.1.1", "stream-browserify": "^3.0.0", "util": "^0.12.5", "uuid": "^9.0.1", "webextension-polyfill": "^0.12.0" }, "devDependencies": { "@babel/core": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/preset-env": "^7.24.7", "@types/archiver": "^5.3.4", "@types/fs-extra": "^11.0.4", "@types/jsdom": "^21.1.7", "@types/webextension-polyfill": "^0.10.7", "archiver": "^5.3.2", "babel-loader": "^9.1.3", "c8": "^11.0.0", "css-loader": "^6.11.0", "css-minimizer-webpack-plugin": "^8.0.0", "esbuild": "^0.25.9", "esbuild-loader": "^4.3.0", "eslint": "^8.57.1", "eslint-plugin-react": "^7.34.3", "fs-extra": "^11.2.0", "graphql-tag": "^2.12.6", "jsdom": "^28.1.0", "less-loader": "^11.1.4", "mini-css-extract-plugin": "^2.9.0", "node-fetch": "^3.3.2", "pre-commit": "^1.2.2", "prettier": "^2.8.8", "progress-bar-webpack-plugin": "^2.1.0", "run-script-os": "^1.1.6", "sass": "^1.91.0", "sass-embedded": "^1.91.0", "sass-loader": "^16.0.5", "string-replace-loader": "^3.1.0", "style-loader": "^4.0.0", "thread-loader": "^4.0.4", "webpack": "^5.92.1", "webpack-bundle-analyzer": "^4.10.2" } } ================================================ FILE: safari/appdmg.json ================================================ { "title": "Fission - ChatBox", "icon": "../src/logo.png", "contents": [ { "x": 448, "y": 344, "type": "link", "path": "/Applications" }, { "x": 192, "y": 344, "type": "file", "path": "../build/Fission - ChatBox.app" } ] } ================================================ FILE: safari/build.sh ================================================ git apply safari/project.pre.patch npm run build xcrun safari-web-extension-converter ./build/firefox \ --project-location ./build/safari --app-name "Fission - ChatBox" \ --bundle-identifier dev.josStorer.chatGPTBox --force --no-prompt --no-open git apply safari/project.patch xcodebuild archive -project "./build/safari/Fission - ChatBox/Fission - ChatBox.xcodeproj" \ -scheme "Fission - ChatBox (macOS)" -configuration Release -archivePath "./build/safari/Fission - ChatBox.xcarchive" xcodebuild -exportArchive -archivePath "./build/safari/Fission - ChatBox.xcarchive" \ -exportOptionsPlist ./safari/export-options.plist -exportPath ./build npm install -D appdmg rm ./build/safari.dmg appdmg ./safari/appdmg.json ./build/safari.dmg ================================================ FILE: safari/export-options.plist ================================================ method mac-application ================================================ FILE: safari/project.patch ================================================ --- a/build/safari/Fission - ChatBox/Fission - ChatBox.xcodeproj/project.pbxproj +++ b/build/safari/Fission - ChatBox/Fission - ChatBox.xcodeproj/project.pbxproj ================================================ FILE: safari/project.pre.patch ================================================ --- a/src/manifest.v2.json +++ b/src/manifest.v2.json @@ -1,5 +1,5 @@ { - "name": "ChatGPTBox", + "name": "Fission - ChatBox", "description": "Integrating ChatGPT into your browser deeply, everything you need is here", "version": "0.0.0", "manifest_version": 2, @@ -28,7 +28,7 @@ "scripts": [ "background.js" ], - "persistent": true + "persistent": true }, "browser_action": { "default_popup": "popup.html?popup=true" ================================================ FILE: safari/project_developer.patch ================================================ --- a/build/safari/Fission - ChatBox/Fission - ChatBox.xcodeproj/project.pbxproj +++ b/build/safari/Fission - ChatBox/Fission - ChatBox.xcodeproj/project.pbxproj @@ -675,6 +675,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = SMGV55KD3K; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "iOS (Extension)/Info.plist"; INFOPLIST_KEY_CFBundleDisplayName = "Fission - ChatBox Extension"; @@ -690,7 +691,7 @@ "-framework", SafariServices, ); - PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.Fission---ChatBox.Extension"; + PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.chatGPTBox.Extension"; PRODUCT_NAME = "Fission - ChatBox Extension"; SDKROOT = iphoneos; SKIP_INSTALL = YES; @@ -705,6 +706,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = SMGV55KD3K; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "iOS (Extension)/Info.plist"; INFOPLIST_KEY_CFBundleDisplayName = "Fission - ChatBox Extension"; @@ -720,7 +722,7 @@ "-framework", SafariServices, ); - PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.Fission---ChatBox.Extension"; + PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.chatGPTBox.Extension"; PRODUCT_NAME = "Fission - ChatBox Extension"; SDKROOT = iphoneos; SKIP_INSTALL = YES; @@ -738,10 +740,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = SMGV55KD3K; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "iOS (App)/Info.plist"; INFOPLIST_KEY_CFBundleDisplayName = "Fission - ChatBox"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; @@ -752,14 +756,14 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 0.0.0; OTHER_LDFLAGS = ( "-framework", SafariServices, "-framework", WebKit, ); - PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.Fission---ChatBox"; + PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.chatGPTBox"; PRODUCT_NAME = "Fission - ChatBox"; SDKROOT = iphoneos; SWIFT_EMIT_LOC_STRINGS = YES; @@ -775,10 +779,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = SMGV55KD3K; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "iOS (App)/Info.plist"; INFOPLIST_KEY_CFBundleDisplayName = "Fission - ChatBox"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; @@ -789,14 +795,14 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 0.0.0; OTHER_LDFLAGS = ( "-framework", SafariServices, "-framework", WebKit, ); - PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.Fission---ChatBox"; + PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.chatGPTBox"; PRODUCT_NAME = "Fission - ChatBox"; SDKROOT = iphoneos; SWIFT_EMIT_LOC_STRINGS = YES; @@ -812,6 +818,7 @@ CODE_SIGN_ENTITLEMENTS = "macOS (Extension)/Fission - ChatBox.entitlements"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = SMGV55KD3K; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "macOS (Extension)/Info.plist"; @@ -828,7 +835,7 @@ "-framework", SafariServices, ); - PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.Fission---ChatBox.Extension"; + PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.chatGPTBox.Extension"; PRODUCT_NAME = "Fission - ChatBox Extension"; SDKROOT = macosx; SKIP_INSTALL = YES; @@ -843,6 +850,7 @@ CODE_SIGN_ENTITLEMENTS = "macOS (Extension)/Fission - ChatBox.entitlements"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = SMGV55KD3K; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "macOS (Extension)/Info.plist"; @@ -859,7 +867,7 @@ "-framework", SafariServices, ); - PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.Fission---ChatBox.Extension"; + PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.chatGPTBox.Extension"; PRODUCT_NAME = "Fission - ChatBox Extension"; SDKROOT = macosx; SKIP_INSTALL = YES; @@ -876,11 +884,13 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = "macOS (App)/Fission - ChatBox.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = SMGV55KD3K; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "macOS (App)/Info.plist"; INFOPLIST_KEY_CFBundleDisplayName = "Fission - ChatBox"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_NSMainStoryboardFile = Main; INFOPLIST_KEY_NSPrincipalClass = NSApplication; LD_RUNPATH_SEARCH_PATHS = ( @@ -888,14 +898,14 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.14; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 0.0.0; OTHER_LDFLAGS = ( "-framework", SafariServices, "-framework", WebKit, ); - PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.Fission---ChatBox"; + PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.chatGPTBox"; PRODUCT_NAME = "Fission - ChatBox"; SDKROOT = macosx; SWIFT_EMIT_LOC_STRINGS = YES; @@ -911,11 +921,13 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = "macOS (App)/Fission - ChatBox.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = SMGV55KD3K; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "macOS (App)/Info.plist"; INFOPLIST_KEY_CFBundleDisplayName = "Fission - ChatBox"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_NSMainStoryboardFile = Main; INFOPLIST_KEY_NSPrincipalClass = NSApplication; LD_RUNPATH_SEARCH_PATHS = ( @@ -923,14 +935,14 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.14; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 0.0.0; OTHER_LDFLAGS = ( "-framework", SafariServices, "-framework", WebKit, ); - PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.Fission---ChatBox"; + PRODUCT_BUNDLE_IDENTIFIER = "dev.josStorer.chatGPTBox"; PRODUCT_NAME = "Fission - ChatBox"; SDKROOT = macosx; SWIFT_EMIT_LOC_STRINGS = YES; ================================================ FILE: src/_locales/de/main.json ================================================ { "General": "Allgemein", "Selection Tools": "Auswahlwerkzeuge", "Sites": "Webseiten", "Advanced": "Erweiterte Einstellungen", "Donate": "Spenden", "Triggers": "Auslöser", "Theme": "Thema", "API Mode": "API-Modus", "Get": "Erhalten", "Preferred Language": "Bevorzugte Sprache", "Insert ChatGPT at the top of search results": "ChatGPT am Anfang der Suchergebnisse einfügen", "Lock scrollbar while answering": "Bildlaufleiste beim Beantworten sperren", "Current Version": "Aktuelle Version", "Latest": "Neueste Version", "Help | Changelog ": "Hilfe | Änderungsprotokoll", "Custom ChatGPT Web API Url": "Benutzerdefinierte ChatGPT-Web-API-URL", "Custom ChatGPT Web API Path": "Benutzerdefinierter ChatGPT-Web-API-Pfad", "Custom OpenAI API Url": "Benutzerdefinierte OpenAI-API-URL", "Custom Site Regex": "Benutzerdefinierter Website-Regex", "Exclusively use Custom Site Regex for website matching, ignoring built-in rules": "Nur benutzerdefinierten Website-Regex verwenden, um Website-Übereinstimmungen zu finden und interne Regeln ignorieren", "Input Query": "Eingabeaufforderung", "Append Query": "Am Ende anhängen", "Prepend Query": "Am Anfang hinzufügen", "Wechat Pay": "WeChat-Pay", "Type your question here\nEnter to send, shift + enter to break line": "Geben Sie Ihre Frage hier ein\nEnter zum Senden, Shift + Enter zum Zeilenumbruch", "Type your question here\nEnter to stop generating\nShift + enter to break line": "Geben Sie Ihre Frage hier ein\nEnter zum Stoppen der Generierung\nShift + Enter zum Zeilenumbruch", "Ask ChatGPT": "ChatGPT fragen", "No Input Found": "Keine Eingabe gefunden", "You": "Du", "Collapse": "Verkleinern", "Expand": "Erweitern", "Stop": "Stoppen", "Continue on official website": "Weiter auf der offiziellen Website", "Error": "Fehler", "Copy": "Kopieren", "Question": "Frage", "Answer": "Antwort", "Waiting for response...": "Warte auf Antwort...", "Close the Window": "Fenster schließen", "Pin the Window": "Fenster anheften", "Float the Window": "Fenster aufteilen", "Save Conversation": "Konversation speichern", "UNAUTHORIZED": "Unbefugt", "Please login at https://chatgpt.com first": "Bitte zuerst bei https://chatgpt.com anmelden", "Please login at https://claude.ai first, and then click the retry button": "Bitte zuerst bei https://claude.ai anmelden und dann auf die Schaltfläche Wiederholen klicken", "Please login at https://bing.com first": "Bitte zuerst bei https://bing.com anmelden", "Then open https://chatgpt.com/api/auth/session": "Dann öffne https://chatgpt.com/api/auth/session", "And refresh this page or type you question again": "Klicken Sie anschließend auf die Schaltfläche Wiederholen in der oberen rechten Ecke", "Consider creating an api key at https://platform.openai.com/account/api-keys": "Erwägen Sie ein API-Schlüssel unter https://platform.openai.com/account/api-keys zu erstellen", "OpenAI Security Check Required": "OpenAI-Sicherheitscheck erforderlich", "Please open https://chatgpt.com/api/auth/session": "Bitte öffne https://chatgpt.com/api/auth/session", "Please open https://chatgpt.com": "Bitte öffne https://chatgpt.com", "New Chat": "Neuer Chat", "Summarize Page": "Seite zusammenfassen", "Translate": "Übersetzen", "Translate (Bidirectional)": "Übersetzen (Bidirektional)", "Translate (To English)": "Übersetzen (Ins Englische)", "Translate (To Chinese)": "Übersetzen (Ins Chinesische)", "Summary": "Zusammenfassung", "Polish": "Polieren", "Sentiment Analysis": "Stimmungsanalyse", "Divide Paragraphs": "Abschnitte teilen", "Code Explain": "Code erklären", "Ask": "Fragen", "Always": "Immer", "Manually": "Manuell", "When query ends with question mark (?)": "Wenn die Abfrage mit einem Fragezeichen (?) endet", "Light": "Hell", "Dark": "Dunkel", "Auto": "Automatisch", "ChatGPT (Web)": "ChatGPT (Web)", "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-Turbo)", "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-Turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Benutzerdefiniertes Modell", "Balanced": "Ausgeglichen", "Creative": "Kreativ", "Precise": "Präzise", "Fast": "Schnell", "API Key": "API-Schlüssel", "Model Name": "Modellname", "Custom Model API Url": "Benutzerdefinierte Modell-API-URL", "Loading...": "Laden...", "Feedback": "Feedback", "Confirm": "Bestätigen", "Clear Conversation": "Konversation löschen", "Retry": "Erneut versuchen", "Exceeded maximum context length": "Maximale Kontextlänge überschritten, bitte Konversation löschen und erneut versuchen", "Regenerate the answer after switching model": "Antwort nach dem Wechseln des Modells neu generieren", "Pin": "Anheften", "Unpin": "Loslösen", "Delete Conversation": "Konversation löschen", "Clear conversations": "Konversationen löschen", "Settings": "Einstellungen", "Feature Pages": "Funktionsseiten", "Keyboard Shortcuts": "Tastenkombinationen", "Open Conversation Page": "Konversationsseite öffnen", "Open Conversation Window": "Konversationsfenster öffnen", "Store to Independent Conversation Page": "Auf unabhängiger Konversationsseite speichern", "Keep Conversation Window in Background": "Chatfenster im Hintergrund halten, um es mit Tastenkombinationen in jeder Anwendung aufzurufen", "Max Response Token Length": "Maximale Tokenlänge der Antwort", "Max Conversation Length": "Maximale Gesprächslänge", "Always pin the floating window": "Immer das schwebende Fenster anheften", "Export": "Exportieren", "Always Create New Conversation Window": "Immer ein neues Chatfenster erstellen", "Please keep this tab open. You can now use the web mode of ChatGPTBox": "Bitte halten Sie diesen Tab geöffnet. Sie können jetzt den Webmodus von ChatGPTBox verwenden", "Go Back": "Zurück", "Pin Tab": "Tab anheften", "Modules": "Module", "API Params": "API-Parameter", "API Url": "API-URL", "Others": "Andere", "API Modes": "API-Modi", "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time": "Deaktivieren Sie die Verlaufsfunktion im Webmodus für besseren Datenschutz. Beachten Sie jedoch, dass die Gespräche nach einer gewissen Zeit nicht mehr verfügbar sind", "Display selection tools next to input box to avoid blocking": "Zeigen Sie Auswahlwerkzeuge neben dem Eingabefeld an, um die Sicht nicht zu blockieren", "Close All Chats In This Page": "Alle Chats auf dieser Seite schließen", "When Icon Clicked": "Beim Klicken auf das Symbol", "Open Settings": "Einstellungen öffnen", "Focus to input box after answering": "Nach der Antwort den Fokus auf das Eingabefeld legen", "Bing CaptchaChallenge": "Bing Captcha-Herausforderung: Sie müssen eine Überprüfung von Bing bestehen. Öffnen Sie https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx und senden Sie eine Nachricht.", "Exceeded quota": "Überschrittenes Kontingent: Prüfen Sie Ihr Guthaben oder Ablaufdatum unter folgendem Link: https://platform.openai.com/account/usage", "Rate limit": "Rate-Limit erreicht", "Jump to bottom": "Zum Ende springen", "Explain": "Erklären", "Failed to get arkose token.": "Arkose-Token konnte nicht abgerufen werden.", "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.": "Bitte halten Sie https://chatgpt.com geöffnet und versuchen Sie es erneut. Wenn es immer noch nicht funktioniert, geben Sie einige Zeichen in das Eingabefeld der ChatGPT-Webseite ein und versuchen Sie es erneut.", "Open Side Panel": "Seitenleiste öffnen", "Generating...": "Generieren...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "Moonshot-Token erforderlich, bitte zuerst bei https://kimi.com anmelden und dann auf die Schaltfläche Wiederholen klicken", "Hide context menu of this extension": "Kontextmenü dieser Erweiterung ausblenden", "Custom Anthropic API Url": "Benutzerdefinierte Anthropic-API-URL", "Anthropic API Key": "Anthropic-API-Schlüssel", "Cancel": "Abbrechen", "Name is required": "Name ist erforderlich", "Prompt template should include {{selection}}": "Die Vorlage sollte {{selection}} enthalten", "Save": "Speichern", "Name": "Name", "Icon": "Symbol", "Prompt Template": "Vorlagen-Template", "Explain this: {{selection}}": "Erkläre das: {{selection}}", "New": "Neu", "Always display floating window, disable sidebar for all site adapters": "Immer das schwebende Fenster anzeigen, die Seitenleiste für alle Website-Adapter deaktivieren", "Allow ESC to close all floating windows": "ESC-Taste zum Schließen aller schwebenden Fenster zulassen", "Export All Data": "Alle Daten exportieren", "Import All Data": "Alle Daten importieren", "Keep-Alive Time": "Keep-Alive-Zeit", "5m": "5m", "30m": "30m", "Forever": "Für immer", "You have successfully logged in for ChatGPTBox and can now return": "Sie haben sich erfolgreich für ChatGPTBox angemeldet und können jetzt zurückkehren", "Claude.ai is not available in your region": "Claude.ai ist in Ihrer Region nicht verfügbar", "Claude.ai (Web)": "Claude.ai (Web)", "Kimi.Moonshot (Web)": "Kimi.Moonshot (Web)", "Bing (Web)": "Bing (Web)", "Gemini (Web)": "Gemini (Web)", "Type": "Typ", "Mode": "Modus", "Custom": "Benutzerdefiniert", "OpenAI (API)": "OpenAI (API)", "Anthropic (API)": "Anthropic (API)", "Azure OpenAI (API)": "Azure OpenAI (API)", "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", "Azure OpenAI": "Azure OpenAI", "OpenAI (GPT-5)": "OpenAI (GPT-5)", "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", "OpenAI (GPT-5.4 mini)": "OpenAI (GPT-5.4 mini)", "OpenAI (GPT-5.4 nano)": "OpenAI (GPT-5.4 nano)", "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } ================================================ FILE: src/_locales/en/main.json ================================================ { "General": "General", "Selection Tools": "Selection Tools", "Sites": "Sites", "Advanced": "Advanced", "Donate": "Donate", "Triggers": "Triggers", "Theme": "Theme", "API Mode": "API Mode", "Get": "Get", "Preferred Language": "Preferred Language", "Insert ChatGPT at the top of search results": "Insert ChatGPT at the top of search results", "Lock scrollbar while answering": "Lock scrollbar while answering", "Current Version": "Current Version", "Latest": "Latest", "Help | Changelog ": "Help | Changelog ", "Custom ChatGPT Web API Url": "Custom ChatGPT Web API Url", "Custom ChatGPT Web API Path": "Custom ChatGPT Web API Path", "Custom OpenAI API Url": "Custom OpenAI API Url", "Custom Site Regex": "Custom Site Regex", "Exclusively use Custom Site Regex for website matching, ignoring built-in rules": "Exclusively use Custom Site Regex for website matching, ignoring built-in rules", "Input Query": "Input Query", "Append Query": "Append Query", "Prepend Query": "Prepend Query", "Wechat Pay": "Wechat Pay", "Type your question here\nEnter to send, shift + enter to break line": "Type your question here\nEnter to send\nShift + enter to break line", "Type your question here\nEnter to stop generating\nShift + enter to break line": "Type your question here\nEnter to stop generating\nShift + enter to break line", "Ask ChatGPT": "Ask ChatGPT", "No Input Found": "No Input Found", "You": "You", "Collapse": "Collapse", "Expand": "Expand", "Stop": "Stop", "Continue on official website": "Continue on official website", "Error": "Error", "Copy": "Copy", "Question": "Question", "Answer": "Answer", "Waiting for response...": "Waiting for response...", "Close the Window": "Close the Window", "Pin the Window": "Pin the Window", "Float the Window": "Float the Window", "Save Conversation": "Save Conversation", "UNAUTHORIZED": "UNAUTHORIZED", "Please login at https://chatgpt.com first": "Please login at https://chatgpt.com first", "Please login at https://claude.ai first, and then click the retry button": "Please login at https://claude.ai first, and then click the retry button", "Please login at https://bing.com first": "Please login at https://bing.com first", "Then open https://chatgpt.com/api/auth/session": "Then open https://chatgpt.com/api/auth/session", "And refresh this page or type you question again": "And click the retry button in the top right corner", "Consider creating an api key at https://platform.openai.com/account/api-keys": "Consider creating an api key at https://platform.openai.com/account/api-keys", "OpenAI Security Check Required": "OpenAI Security Check Required", "Please open https://chatgpt.com/api/auth/session": "Please open https://chatgpt.com/api/auth/session", "Please open https://chatgpt.com": "Please open https://chatgpt.com", "New Chat": "New Chat", "Summarize Page": "Summarize Page", "Translate": "Translate", "Translate (Bidirectional)": "Translate (Bidirectional)", "Translate (To English)": "Translate (To English)", "Translate (To Chinese)": "Translate (To Chinese)", "Summary": "Summary", "Polish": "Polish", "Sentiment Analysis": "Sentiment Analysis", "Divide Paragraphs": "Divide Paragraphs", "Code Explain": "Code Explain", "Ask": "Ask", "Always": "Always", "Manually": "Manually", "When query ends with question mark (?)": "When query ends with question mark (?)", "Light": "Light", "Dark": "Dark", "Auto": "Auto", "ChatGPT (Web)": "ChatGPT (Web)", "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Custom Model", "Balanced": "Balanced", "Creative": "Creative", "Precise": "Precise", "Fast": "Fast", "API Key": "API Key", "Model Name": "Model Name", "Custom Model API Url": "Custom Model API Url", "Loading...": "Loading...", "Feedback": "Feedback", "Confirm": "Confirm", "Clear Conversation": "Clear Conversation", "Retry": "Retry", "Exceeded maximum context length": "Exceeded maximum context length, please clear the conversation and try again", "Regenerate the answer after switching model": "Regenerate the answer after switching model", "Pin": "Pin", "Unpin": "Unpin", "Delete Conversation": "Delete Conversation", "Clear conversations": "Clear conversations", "Settings": "Settings", "Feature Pages": "Feature Pages", "Keyboard Shortcuts": "Keyboard Shortcuts", "Open Conversation Page": "Open Conversation Page", "Open Conversation Window": "Open Conversation Window", "Store to Independent Conversation Page": "Store to Independent Conversation Page", "Keep Conversation Window in Background": "Keep conversation window in background, so that you can use shortcut keys to call it up in any program", "Max Response Token Length": "Max Response Token Length", "Max Conversation Length": "Max Conversation Length", "Always pin the floating window": "Always pin the floating window", "Export": "Export", "Always Create New Conversation Window": "Always Create New Conversation Window", "Please keep this tab open. You can now use the web mode of ChatGPTBox": "Please keep this tab open. You can now use the web mode of ChatGPTBox", "Go Back": "Go Back", "Pin Tab": "Pin Tab", "Modules": "Modules", "API Params": "API Params", "API Url": "API Url", "Others": "Others", "API Modes": "API Modes", "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time": "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time", "Display selection tools next to input box to avoid blocking": "Display selection tools next to input box to avoid blocking", "Close All Chats In This Page": "Close All Chats In This Page", "When Icon Clicked": "When Icon Clicked", "Open Settings": "Open Settings", "Focus to input box after answering": "Focus to input box after answering", "Bing CaptchaChallenge": "You must pass Bing's verification. Please go to https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx and send a message", "Exceeded quota": "You exceeded your current quota, check https://platform.openai.com/account/usage", "Rate limit": "Rate limit exceeded", "Jump to bottom": "Jump to bottom", "Explain": "Explain", "Failed to get arkose token.": "Failed to get arkose token.", "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.": "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.", "Open Side Panel": "Open Side Panel", "Generating...": "Generating...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "moonshot token required, please login at https://kimi.com first, and then click the retry button", "Hide context menu of this extension": "Hide context menu of this extension", "Custom Anthropic API Url": "Custom Anthropic API Url", "Anthropic API Key": "Anthropic API Key", "Cancel": "Cancel", "Name is required": "Name is required", "Prompt template should include {{selection}}": "Prompt template should include {{selection}}", "Save": "Save", "Name": "Name", "Icon": "Icon", "Prompt Template": "Prompt Template", "Explain this: {{selection}}": "Explain this: {{selection}}", "New": "New", "Always display floating window, disable sidebar for all site adapters": "Always display floating window, disable sidebar for all site adapters", "Allow ESC to close all floating windows": "Allow ESC to close all floating windows", "Export All Data": "Export All Data", "Import All Data": "Import All Data", "Keep-Alive Time": "Keep-Alive Time", "5m": "5m", "30m": "30m", "Forever": "Forever", "You have successfully logged in for ChatGPTBox and can now return": "You have successfully logged in for ChatGPTBox and can now return", "Claude.ai is not available in your region": "Claude.ai is not available in your region", "Claude.ai (Web)": "Claude.ai (Web)", "Kimi.Moonshot (Web)": "Kimi.Moonshot (Web)", "Bing (Web)": "Bing (Web)", "Gemini (Web)": "Gemini (Web)", "Type": "Type", "Mode": "Mode", "Custom": "Custom", "Crop Text to ensure the input tokens do not exceed the model's limit": "Crop Text to ensure the input tokens do not exceed the model's limit", "OpenAI (API)": "OpenAI (API)", "Anthropic (API)": "Anthropic (API)", "Azure OpenAI (API)": "Azure OpenAI (API)", "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", "Azure OpenAI": "Azure OpenAI", "OpenAI (GPT-5)": "OpenAI (GPT-5)", "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", "OpenAI (GPT-5.4 mini)": "OpenAI (GPT-5.4 mini)", "OpenAI (GPT-5.4 nano)": "OpenAI (GPT-5.4 nano)", "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } ================================================ FILE: src/_locales/es/main.json ================================================ { "General": "General", "Selection Tools": "Herramientas de selección", "Sites": "Adaptaciones de sitios", "Advanced": "Avanzado", "Donate": "Donar", "Triggers": "Disparadores", "Theme": "Tema", "API Mode": "Modo API", "Get": "Obtener", "Preferred Language": "Idioma preferido", "Insert ChatGPT at the top of search results": "Insertar ChatGPT en la parte superior de los resultados de búsqueda", "Lock scrollbar while answering": "Bloquear barra de desplazamiento mientras se responde", "Current Version": "Versión actual", "Latest": "Última", "Help | Changelog ": "Ayuda | Registro de cambios ", "Custom ChatGPT Web API Url": "URL personalizada de la API web de ChatGPT", "Custom ChatGPT Web API Path": "Ruta personalizada de la API web de ChatGPT", "Custom OpenAI API Url": "URL personalizada de la API de OpenAI", "Custom Site Regex": "Expresión regular personalizada del sitio", "Exclusively use Custom Site Regex for website matching, ignoring built-in rules": "Utilice exclusivamente expesiones regulares personalizadas para la coincidencia de sitios web, ignorando las reglas integradas", "Input Query": "Consulta de entrada", "Append Query": "Añadir consulta", "Prepend Query": "Insertar consulta", "Wechat Pay": "Pago de Wechat", "Type your question here\nEnter to send, shift + enter to break line": "Escriba su pregunta aquí\nPresione Enter para enviar, Shift+Enter para saltar de línea", "Type your question here\nEnter to stop generating\nShift + enter to break line": "Escriba su pregunta aquí\nPresione Enter para detener la generación\nShift + Enter para saltar de línea", "Ask ChatGPT": "Preguntar a ChatGPT", "No Input Found": "No se encontró entrada", "You": "Tú", "Collapse": "Colapsar", "Expand": "Expandir", "Stop": "Detener", "Continue on official website": "Continuar en el sitio web oficial", "Error": "Error", "Copy": "Copiar", "Question": "Pregunta", "Answer": "Respuesta", "Waiting for response...": "Esperando respuesta...", "Close the Window": "Cerrar ventana", "Pin the Window": "Fijar ventana", "Float the Window": "Ventana flotante", "Save Conversation": "Guardar conversación", "UNAUTHORIZED": "NO AUTORIZADO", "Please login at https://chatgpt.com first": "Por favor, inicie sesión en https://chatgpt.com primero", "Please login at https://claude.ai first, and then click the retry button": "Por favor, inicie sesión en https://claude.ai primero, y luego haga clic en el botón Reintentar", "Please login at https://bing.com first": "Por favor, inicie sesión en https://bing.com primero", "Then open https://chatgpt.com/api/auth/session": "Luego abra https://chatgpt.com/api/auth/session", "And refresh this page or type you question again": "A continuación, pulse el botón Reintentar situado en la esquina superior derecha.", "Consider creating an api key at https://platform.openai.com/account/api-keys": "Considere crear una clave de API en https://platform.openai.com/account/api-keys", "OpenAI Security Check Required": "Se requiere una comprobación de seguridad de OpenAI", "Please open https://chatgpt.com/api/auth/session": "Por favor, abra https://chatgpt.com/api/auth/session", "Please open https://chatgpt.com": "Por favor, abra https://chatgpt.com", "New Chat": "Nuevo chat", "Summarize Page": "Resumir página", "Translate": "Traducir", "Translate (Bidirectional)": "Traducir (Bidireccional)", "Translate (To English)": "Traducir (Al Inglés)", "Translate (To Chinese)": "Traducir (Al Chino)", "Summary": "Resumen", "Polish": "Pulir", "Sentiment Analysis": "Análisis de sentimientos", "Divide Paragraphs": "Dividir párrafos", "Code Explain": "Explicación de código", "Ask": "Preguntar", "Always": "Siempre", "Manually": "Manualmente", "When query ends with question mark (?)": "Cuando la consulta termina con signo de pregunta (?)", "Light": "Claro", "Dark": "Oscuro", "Auto": "Automático", "ChatGPT (Web)": "ChatGPT (Web)", "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Modelo personalizado", "Balanced": "Equilibrado", "Creative": "Creativo", "Precise": "Preciso", "Fast": "Rápido", "API Key": "Clave de API", "Model Name": "Nombre del modelo", "Custom Model API Url": "URL de la API de modelo personalizada", "Loading...": "Cargando...", "Feedback": "Comentarios", "Confirm": "Confirmar", "Clear Conversation": "Borrar conversación", "Retry": "Reintentar", "Exceeded maximum context length": "Se superó la longitud máxima del contexto, borre la conversación y vuelva a intentarlo", "Regenerate the answer after switching model": "Regenerar la respuesta después de cambiar el modelo", "Pin": "Fijar", "Unpin": "Desfijar", "Delete Conversation": "Eliminar conversación", "Clear conversations": "Borrar todas las conversaciones", "Settings": "Configuración", "Feature Pages": "Páginas de características", "Keyboard Shortcuts": "Atajos de teclado", "Open Conversation Page": "Abrir página de conversación independiente", "Open Conversation Window": "Abrir la ventana de conversación independiente", "Store to Independent Conversation Page": "Guardar en página de conversación independiente", "Keep Conversation Window in Background": "Mantener la ventana de conversación en segundo plano para poder acceder a ella desde cualquier aplicación mediante accesos directos.", "Max Response Token Length": "Longitud máxima de tokens de respuesta", "Max Conversation Length": "Longitud máxima de conversación", "Always pin the floating window": "Siempre fijar la ventana flotante", "Export": "Exportar", "Always Create New Conversation Window": "Siempre crear una nueva ventana de conversación", "Please keep this tab open. You can now use the web mode of ChatGPTBox": "Por favor, mantenga esta pestaña abierta. Ahora puede utilizar el modo web de ChatGPTBox.", "Go Back": "Volver", "Pin Tab": "Fijar pestaña", "Modules": "Módulos", "API Params": "Parámetros de la API", "API Url": "URL de la API", "Others": "Otros", "API Modes": "Modos de la API", "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time": "Desactivar el historial del modo web para una mejor protección de la privacidad, pero esto resultará en conversaciones no disponibles después de un período de tiempo.", "Display selection tools next to input box to avoid blocking": "Mostrar herramientas de selección junto al cuadro de entrada para evitar bloqueos", "Close All Chats In This Page": "Cerrar todos los chats en esta página", "When Icon Clicked": "Cuando se hace clic en el icono", "Open Settings": "Abrir configuración", "Focus to input box after answering": "Enfocar en el cuadro de entrada después de responder", "Bing CaptchaChallenge": "Desafío de Captcha de Bing: Debe pasar una verificación de Bing. Abra https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx y envíe un mensaje.", "Exceeded quota": "Cuota superada: Verifique su saldo o fecha de vencimiento en el siguiente enlace: https://platform.openai.com/account/usage", "Rate limit": "Límite de velocidad alcanzado", "Jump to bottom": "Saltar al final", "Explain": "Explicar", "Failed to get arkose token.": "No se pudo obtener el token de arkose.", "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.": "Por favor, mantenga https://chatgpt.com abierto e inténtelo de nuevo. Si aún no funciona, escriba algunos caracteres en el cuadro de entrada de la página web de chatgpt e inténtelo de nuevo.", "Open Side Panel": "Abrir panel lateral", "Generating...": "Generando...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "se requiere un token de moonshot, por favor inicie sesión en https://kimi.com primero, y luego haga clic en el botón Reintentar", "Hide context menu of this extension": "Ocultar menú contextual de esta extensión", "Custom Anthropic API Url": "URL personalizada de la API de Anthropic", "Anthropic API Key": "Clave API de Anthropic", "Cancel": "Cancelar", "Name is required": "Se requiere un nombre", "Prompt template should include {{selection}}": "La plantilla de sugerencias debe incluir {{selection}}", "Save": "Guardar", "Name": "Nombre", "Icon": "Icono", "Prompt Template": "Plantilla de sugerencias", "Explain this: {{selection}}": "Explicar esto: {{selection}}", "New": "Nuevo", "Always display floating window, disable sidebar for all site adapters": "Mostrar siempre la ventana flotante, desactivar la barra lateral para todos los adaptadores de sitios", "Allow ESC to close all floating windows": "Permitir que ESC cierre todas las ventanas flotantes", "Export All Data": "Exportar todos los datos", "Import All Data": "Importar todos los datos", "Keep-Alive Time": "Tiempo de mantenimiento de la conexión", "5m": "5m", "30m": "30m", "Forever": "Siempre", "You have successfully logged in for ChatGPTBox and can now return": "Ha iniciado sesión correctamente en ChatGPTBox y ahora puede regresar", "Claude.ai is not available in your region": "Claude.ai no está disponible en su región", "Claude.ai (Web)": "Claude.ai (Web)", "Kimi.Moonshot (Web)": "Kimi.Moonshot (Web)", "Bing (Web)": "Bing (Web)", "Gemini (Web)": "Gemini (Web)", "Type": "Tipo", "Mode": "Modo", "Custom": "Personalizado", "OpenAI (API)": "OpenAI (API)", "Anthropic (API)": "Anthropic (API)", "Azure OpenAI (API)": "Azure OpenAI (API)", "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", "Azure OpenAI": "Azure OpenAI", "OpenAI (GPT-5)": "OpenAI (GPT-5)", "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", "OpenAI (GPT-5.4 mini)": "OpenAI (GPT-5.4 mini)", "OpenAI (GPT-5.4 nano)": "OpenAI (GPT-5.4 nano)", "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } ================================================ FILE: src/_locales/fr/main.json ================================================ { "General": "Général", "Selection Tools": "Outils de sélection", "Sites": "Sites", "Advanced": "Avancé", "Donate": "Faire un don", "Triggers": "Déclencheurs", "Theme": "Thème", "API Mode": "Mode API", "Get": "Obtenir", "Preferred Language": "Langue préférée", "Insert ChatGPT at the top of search results": "Insérer ChatGPT en haut des résultats de recherche", "Lock scrollbar while answering": "Verrouiller la barre de défilement pendant la réponse", "Current Version": "Version actuelle", "Latest": "Le plus récent", "Help | Changelog ": "Aide | Journal des modifications", "Custom ChatGPT Web API Url": "URL web API personnalisée ChatGPT", "Custom ChatGPT Web API Path": "Chemin d'accès à l'API Web ChatGPT personnalisée", "Custom OpenAI API Url": "URL de l'API OpenAI personnalisée", "Custom Site Regex": "Expression régulière de site personnalisée", "Exclusively use Custom Site Regex for website matching, ignoring built-in rules": "Utiliser exclusivement l'expression régulière de site personnalisée pour la correspondance de site Web, en ignorant les règles intégrées", "Input Query": "Sélecteur d'entrée", "Append Query": "Sélecteur à ajouter", "Prepend Query": "Sélecteur à insérer", "Wechat Pay": "Paiement Wechat", "Type your question here\nEnter to send, shift + enter to break line": "Tapez votre question ici\nAppuyez sur entrée pour envoyer, shift+entrée pour passer à la ligne suivante", "Type your question here\nEnter to stop generating\nShift + enter to break line": "Tapez votre question ici\nAppuyez sur Entrée pour arrêter la génération\nShift + Entrée pour passer à la ligne suivante", "Ask ChatGPT": "Demander à ChatGPT", "No Input Found": "Aucune entrée trouvée", "You": "Vous", "Collapse": "Réduire", "Expand": "Agrandir", "Stop": "Arrêter", "Continue on official website": "Continuer sur le site officiel", "Error": "Erreur", "Copy": "Copier", "Question": "Question", "Answer": "Réponse", "Waiting for response...": "En attente de réponse...", "Close the Window": "Fermer la fenêtre", "Pin the Window": "Épingler la fenêtre", "Float the Window": "Flotter la fenêtre", "Save Conversation": "Enregistrer la conversation", "UNAUTHORIZED": "NON AUTORISÉ", "Please login at https://chatgpt.com first": "Veuillez vous connecter d'abord sur https://chatgpt.com", "Please login at https://claude.ai first, and then click the retry button": "Veuillez vous connecter d'abord sur https://claude.ai, puis cliquez sur le bouton Réessayer", "Please login at https://bing.com first": "Veuillez vous connecter d'abord sur https://bing.com", "Then open https://chatgpt.com/api/auth/session": "Puis ouvrez https://chatgpt.com/api/auth/session", "And refresh this page or type you question again": "Cliquez ensuite sur le bouton Réessayer dans le coin supérieur droit", "Consider creating an api key at https://platform.openai.com/account/api-keys": "Pensez à créer une clé API sur https://platform.openai.com/account/api-keys", "OpenAI Security Check Required": "Vérification de sécurité OpenAI requise", "Please open https://chatgpt.com/api/auth/session": "Veuillez ouvrir https://chatgpt.com/api/auth/session", "Please open https://chatgpt.com": "Veuillez ouvrir https://chatgpt.com", "New Chat": "Nouveau chat", "Summarize Page": "Résumer la page", "Translate": "Traduire", "Translate (Bidirectional)": "Traduire (Bidirectionnel)", "Translate (To English)": "Traduire (Vers l'anglais)", "Translate (To Chinese)": "Traduire (Vers le chinois)", "Summary": "Résumé", "Polish": "Peaufiner", "Sentiment Analysis": "Analyse de sentiment", "Divide Paragraphs": "Diviser les paragraphes", "Code Explain": "Expliquer le code", "Ask": "Demander", "Always": "Toujours", "Manually": "Manuellement", "When query ends with question mark (?)": "Lorsque la requête se termine par un point d'interrogation (?)", "Light": "Clair", "Dark": "Sombre", "Auto": "Automatique", "ChatGPT (Web)": "ChatGPT (Web)", "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Modèle personnalisé", "Balanced": "Équilibré", "Creative": "Créatif", "Precise": "Précis", "Fast": "Rapide", "API Key": "Clé API", "Model Name": "Nom du modèle", "Custom Model API Url": "URL API personnalisée du modèle", "Loading...": "Chargement...", "Feedback": "Commentaires", "Confirm": "Confirmer", "Clear Conversation": "Effacer la conversation", "Retry": "Réessayer", "Exceeded maximum context length": "Dépassement de la longueur maximale de contexte, veuillez effacer la conversation et réessayer", "Regenerate the answer after switching model": "Régénérer la réponse après avoir changé de modèle", "Pin": "Épingler", "Unpin": "Détacher", "Delete Conversation": "Supprimer la conversation", "Clear conversations": "Effacer les conversations", "Settings": "Paramètres", "Feature Pages": "Pages de fonctionnalités", "Keyboard Shortcuts": "Raccourcis clavier", "Open Conversation Page": "Ouvrir la page de conversation", "Open Conversation Window": "Ouvrir la fenêtre de conversation", "Store to Independent Conversation Page": "Enregistrer sur une page de conversation indépendante", "Keep Conversation Window in Background": "Gardez la fenêtre de conversation en arrière-plan pour l'appeler avec des raccourcis dans n'importe quelle application", "Max Response Token Length": "Longueur maximale des jetons de réponse", "Max Conversation Length": "Longueur maximale de la conversation", "Always pin the floating window": "Épingler toujours la fenêtre flottante", "Export": "Exporter", "Always Create New Conversation Window": "Créer toujours une nouvelle fenêtre de conversation", "Please keep this tab open. You can now use the web mode of ChatGPTBox": "Veuillez laisser cette tabulation ouverte. Vous pouvez désormais utiliser le mode web de ChatGPTBox", "Go Back": "Retour", "Pin Tab": "Épingler l'onglet", "Modules": "Modules", "API Params": "Paramètres de l'API", "API Url": "URL de l'API", "Others": "Autres", "API Modes": "Modes de l'API", "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time": "Désactivez l'historique du mode web pour une meilleure protection de la vie privée, mais cela entraînera des conversations non disponibles après un certain temps", "Display selection tools next to input box to avoid blocking": "Afficher des outils de sélection à côté de la boîte de saisie pour éviter de bloquer la vue", "Close All Chats In This Page": "Fermer tous les chats sur cette page", "When Icon Clicked": "Lorsque l'icône est cliquée", "Open Settings": "Ouvrir les paramètres", "Focus to input box after answering": "Se concentrer sur la boîte de saisie après avoir répondu", "Bing CaptchaChallenge": "Défi Captcha Bing : Vous devez réussir une vérification Bing. Ouvrez https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx et envoyez un message.", "Exceeded quota": "Quota dépassé : Vérifiez votre solde ou la date d'expiration à l'adresse suivante: https://platform.openai.com/account/usage", "Rate limit": "Limite de taux atteinte", "Jump to bottom": "Aller en bas", "Explain": "Expliquer", "Failed to get arkose token.": "Échec de l'obtention du jeton arkose.", "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.": "Veuillez garder https://chatgpt.com ouvert et réessayer. Si cela ne fonctionne toujours pas, tapez quelques caractères dans la boîte de saisie de la page web chatgpt et réessayez.", "Open Side Panel": "Ouvrir le panneau latéral", "Generating...": "Génération...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "jeton moonshot requis, veuillez vous connecter d'abord sur https://kimi.com, puis cliquez sur le bouton Réessayer", "Hide context menu of this extension": "Masquer le menu contextuel de cette extension", "Custom Anthropic API Url": "URL API Anthropic personnalisée", "Anthropic API Key": "Clé API Anthropic", "Cancel": "Annuler", "Name is required": "Le nom est requis", "Prompt template should include {{selection}}": "Le modèle de suggestion doit inclure {{selection}}", "Save": "Enregistrer", "Name": "Nom", "Icon": "Icône", "Prompt Template": "Modèle de suggestion", "Explain this: {{selection}}": "Expliquer ceci : {{selection}}", "New": "Nouveau", "Always display floating window, disable sidebar for all site adapters": "Toujours afficher la fenêtre flottante, désactiver la barre latérale pour tous les adaptateurs de site", "Allow ESC to close all floating windows": "Autoriser la touche ESC pour fermer toutes les fenêtres flottantes", "Export All Data": "Exporter toutes les données", "Import All Data": "Importer toutes les données", "Keep-Alive Time": "Temps de maintien de la connexion", "5m": "5m", "30m": "30m", "Forever": "Toujours", "You have successfully logged in for ChatGPTBox and can now return": "Vous vous êtes connecté avec succès à ChatGPTBox et pouvez maintenant revenir", "Claude.ai is not available in your region": "Claude.ai n'est pas disponible dans votre région", "Claude.ai (Web)": "Claude.ai (Web)", "Kimi.Moonshot (Web)": "Kimi.Moonshot (Web)", "Bing (Web)": "Bing (Web)", "Gemini (Web)": "Gemini (Web)", "Type": "Type", "Mode": "Mode", "Custom": "Personnalisé", "OpenAI (API)": "OpenAI (API)", "Anthropic (API)": "Anthropic (API)", "Azure OpenAI (API)": "Azure OpenAI (API)", "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", "Azure OpenAI": "Azure OpenAI", "OpenAI (GPT-5)": "OpenAI (GPT-5)", "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", "OpenAI (GPT-5.4 mini)": "OpenAI (GPT-5.4 mini)", "OpenAI (GPT-5.4 nano)": "OpenAI (GPT-5.4 nano)", "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } ================================================ FILE: src/_locales/i18n-react.mjs ================================================ import i18n from 'i18next' import { initReactI18next } from 'react-i18next' import { resources } from './resources' i18n.use(initReactI18next).init({ resources, fallbackLng: 'en', interpolation: { escapeValue: false, // not needed for react as it escapes by default }, }) ================================================ FILE: src/_locales/i18n.mjs ================================================ import i18n from 'i18next' import { resources } from './resources' i18n.init({ resources, fallbackLng: 'en', }) ================================================ FILE: src/_locales/in/main.json ================================================ { "General": "Umum", "Selection Tools": "Alat Seleksi", "Sites": "Situs", "Advanced": "Lanjutan", "Donate": "Donasi", "Triggers": "Pemicu", "Theme": "Tema", "API Mode": "Mode API", "Get": "Dapatkan", "Preferred Language": "Bahasa yang Dipilih", "Insert ChatGPT at the top of search results": "Masukkan ChatGPT di bagian atas hasil pencarian", "Lock scrollbar while answering": "Kunci scrollbar saat menjawab", "Current Version": "Versi Saat Ini", "Latest": "Terbaru", "Help | Changelog ": "Bantuan | Perubahan", "Custom ChatGPT Web API Url": "URL Web API ChatGPT Kustom", "Custom ChatGPT Web API Path": "Path Web API ChatGPT Kustom", "Custom OpenAI API Url": "URL API OpenAI Kustom", "Custom Site Regex": "Regex Situs Kustom", "Exclusively use Custom Site Regex for website matching, ignoring built-in rules": "Gunakan secara eksklusif Regex Situs Kustom untuk pencocokan situs web, mengabaikan aturan bawaan", "Input Query": "Query Masukan", "Append Query": "Tambahkan Query", "Prepend Query": "Tambahkan Query di Awal", "Wechat Pay": "Pembayaran Wechat", "Type your question here\nEnter to send, shift + enter to break line": "Ketik pertanyaanmu di sini\nTekan Enter untuk mengirim, Shift + Enter untuk membuat baris baru", "Type your question here\nEnter to stop generating\nShift + enter to break line": "Ketik pertanyaanmu di sini\nTekan Enter untuk menghentikan pembuatan\nShift + Enter untuk membuat baris baru", "Ask ChatGPT": "Tanyakan ke ChatGPT", "No Input Found": "Tidak Ada Input Ditemukan", "You": "Anda", "Collapse": "Ciutkan", "Expand": "Perbesar", "Stop": "Berhenti", "Continue on official website": "Lanjutkan di situs web resmi", "Error": "Kesalahan", "Copy": "Salin", "Question": "Pertanyaan", "Answer": "Jawaban", "Waiting for response...": "Menunggu tanggapan...", "Close the Window": "Tutup Jendela", "Pin the Window": "Sematkan Jendela", "Float the Window": "Mengambangkan Jendela", "Save Conversation": "Simpan Percakapan", "UNAUTHORIZED": "TIDAK DIIZINKAN", "Please login at https://chatgpt.com first": "Silakan masuk di https://chatgpt.com terlebih dahulu", "Please login at https://claude.ai first, and then click the retry button": "Silakan masuk di https://claude.ai terlebih dahulu, lalu klik tombol coba lagi", "Please login at https://bing.com first": "Silakan masuk di https://bing.com terlebih dahulu", "Then open https://chatgpt.com/api/auth/session": "Lalu buka https://chatgpt.com/api/auth/session", "And refresh this page or type you question again": "Setelah itu klik tombol Coba Lagi di sudut kanan atas", "Consider creating an api key at https://platform.openai.com/account/api-keys": "Pertimbangkan untuk membuat kunci API di https://platform.openai.com/account/api-keys", "OpenAI Security Check Required": "Diperlukan Pemeriksaan Keamanan OpenAI", "Please open https://chatgpt.com/api/auth/session": "Harap buka https://chatgpt.com/api/auth/session", "Please open https://chatgpt.com": "Harap buka https://chatgpt.com", "New Chat": "Obrolan Baru", "Summarize Page": "Ringkasan Halaman", "Translate": "Terjemahkan", "Translate (Bidirectional)": "Terjemahkan (Dua Arah)", "Translate (To English)": "Terjemahkan (Ke Bahasa Inggris)", "Translate (To Chinese)": "Terjemahkan (Ke Bahasa Tionghoa)", "Summary": "Ringkasan", "Polish": "Perbaikan", "Sentiment Analysis": "Analisis Sentimen", "Divide Paragraphs": "Bagi Paragraf", "Code Explain": "Penjelasan Kode", "Ask": "Tanya", "Always": "Selalu", "Manually": "Secara Manual", "When query ends with question mark (?)": "Ketika permintaan diakhiri dengan tanda tanya (?)", "Light": "Terang", "Dark": "Gelap", "Auto": "Otomatis", "ChatGPT (Web)": "ChatGPT (Web)", "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Model Kustom", "Balanced": "Seimbang", "Creative": "Kreatif", "Precise": "Tepat", "Fast": "Cepat", "API Key": "Kunci API", "Model Name": "Nama Model", "Custom Model API Url": "URL API Model Kustom", "Loading...": "Sedang Memuat...", "Feedback": "Masukan", "Confirm": "Konfirmasi", "Clear Conversation": "Bersihkan Percakapan", "Retry": "Coba Lagi", "Exceeded maximum context length": "Melampaui batas maksimum panjang konteks, harap bersihkan percakapan dan coba lagi", "Regenerate the answer after switching model": "Hasilkan kembali jawaban setelah beralih ke model lain", "Pin": "Sematkan", "Unpin": "Lepas Sematan", "Delete Conversation": "Hapus Percakapan", "Clear conversations": "Hapus Percakapan", "Settings": "Pengaturan", "Feature Pages": "Halaman Fitur", "Keyboard Shortcuts": "Pintasan Keyboard", "Open Conversation Page": "Buka Halaman Percakapan", "Open Conversation Window": "Buka Jendela Percakapan", "Store to Independent Conversation Page": "Simpan ke Halaman Percakapan Independen", "Keep Conversation Window in Background": "Biarkan jendela percakapan di latar belakang, sehingga Anda dapat menggunakan pintasan keyboard untuk memanggilnya di program mana pun", "Max Response Token Length": "Panjang Token Respon Maksimum", "Max Conversation Length": "Panjang Percakapan Maksimum", "Always pin the floating window": "Selalu selipkan jendela mengambang", "Export": "Ekspor", "Always Create New Conversation Window": "Selalu Buat Jendela Percakapan Baru", "Please keep this tab open. You can now use the web mode of ChatGPTBox": "Silakan tetap buka tab ini. Anda sekarang dapat menggunakan mode web ChatGPTBox", "Go Back": "Kembali", "Pin Tab": "Sematkan Tab", "Modules": "Modul", "API Params": "Parameter API", "API Url": "URL API", "Others": "Lainnya", "API Modes": "Mode API", "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time": "Nonaktifkan riwayat mode web untuk perlindungan privasi yang lebih baik, tetapi ini akan menyebabkan percakapan tidak tersedia setelah jangka waktu tertentu", "Display selection tools next to input box to avoid blocking": "Tampilkan alat pilihan di sebelah kotak masukan untuk menghindari pemblokiran", "Close All Chats In This Page": "Tutup Semua Percakapan di Halaman Ini", "When Icon Clicked": "Saat Ikon Diklik", "Open Settings": "Buka Pengaturan", "Focus to input box after answering": "Fokus pada kotak masukan setelah menjawab", "Bing CaptchaChallenge": "Anda harus melewati verifikasi Bing. Silakan pergi ke https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx dan kirim pesan", "Exceeded quota": "Anda telah melebihi kuota saat ini, periksa https://platform.openai.com/account/usage", "Rate limit": "Batas penggunaan terlampaui", "Jump to bottom": "Lompat ke bawah", "Explain": "Jelaskan", "Failed to get arkose token.": "Gagal mendapatkan token arkose.", "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.": "Harap tetap buka https://chatgpt.com dan coba lagi. Jika masih tidak berhasil, ketik beberapa karakter di kotak masukan halaman web chatgpt dan coba lagi.", "Open Side Panel": "Buka Panel Samping", "Generating...": "Menghasilkan...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "diperlukan token moonshot, silakan masuk di https://kimi.com terlebih dahulu, lalu klik tombol coba lagi", "Hide context menu of this extension": "Sembunyikan menu konteks ekstensi ini", "Custom Anthropic API Url": "URL API Anthropic Kustom", "Anthropic API Key": "Kunci API Anthropic", "Cancel": "Batal", "Name is required": "Nama diperlukan", "Prompt template should include {{selection}}": "Template prompt harus mencakup {{selection}}", "Save": "Simpan", "Name": "Nama", "Icon": "Ikon", "Prompt Template": "Template Prompt", "Explain this: {{selection}}": "Jelaskan ini: {{selection}}", "New": "Baru", "Always display floating window, disable sidebar for all site adapters": "Selalu tampilkan jendela mengambang, nonaktifkan sidebar untuk semua adapter situs", "Allow ESC to close all floating windows": "Izinkan ESC untuk menutup semua jendela mengambang", "Export All Data": "Ekspor Semua Data", "Import All Data": "Impor Semua Data", "Keep-Alive Time": "Waktu Tetap Hidup", "5m": "5m", "30m": "30m", "Forever": "Selamanya", "You have successfully logged in for ChatGPTBox and can now return": "Anda telah berhasil masuk untuk ChatGPTBox dan sekarang dapat kembali", "Claude.ai is not available in your region": "Claude.ai tidak tersedia di wilayah Anda", "Claude.ai (Web)": "Claude.ai (Web)", "Kimi.Moonshot (Web)": "Kimi.Moonshot (Web)", "Bing (Web)": "Bing (Web)", "Gemini (Web)": "Gemini (Web)", "Type": "Jenis", "Mode": "Mode", "Custom": "Kustom", "OpenAI (API)": "OpenAI (API)", "Anthropic (API)": "Anthropic (API)", "Azure OpenAI (API)": "Azure OpenAI (API)", "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", "Azure OpenAI": "Azure OpenAI", "OpenAI (GPT-5)": "OpenAI (GPT-5)", "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", "OpenAI (GPT-5.4 mini)": "OpenAI (GPT-5.4 mini)", "OpenAI (GPT-5.4 nano)": "OpenAI (GPT-5.4 nano)", "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } ================================================ FILE: src/_locales/it/main.json ================================================ { "General": "Generale", "Selection Tools": "Strumenti di selezione", "Sites": "Siti Web", "Advanced": "Avanzato", "Donate": "Donazione", "Triggers": "Trigger", "Theme": "Tema", "API Mode": "Modalità API", "Get": "Ottenere", "Preferred Language": "Lingua preferita", "Insert ChatGPT at the top of search results": "Inserisci ChatGPT in cima ai risultati di ricerca", "Lock scrollbar while answering": "Blocca la barra di scorrimento durante la risposta", "Current Version": "Versione corrente", "Latest": "Ultima", "Help | Changelog ": "Aiuto | Cronologia delle modifiche ", "Custom ChatGPT Web API Url": "URL API Web ChatGPT personalizzato", "Custom ChatGPT Web API Path": "Percorso API Web ChatGPT personalizzato", "Custom OpenAI API Url": "URL API OpenAI personalizzato", "Custom Site Regex": "Espressione regolare del sito personalizzata", "Exclusively use Custom Site Regex for website matching, ignoring built-in rules": "Usa esclusivamente l'espressione regolare del sito personalizzata per la corrispondenza dei siti Web, ignorando le regole incorporate", "Input Query": "Query di input", "Append Query": "Query di appendice", "Prepend Query": "Query di aggiunta in testa", "Wechat Pay": "Paga con Wechat", "Type your question here\nEnter to send, shift + enter to break line": "Digita la tua domanda qui\nInvio per inviare, shift + invio per andare a capo", "Type your question here\nEnter to stop generating\nShift + enter to break line": "Digita la tua domanda qui\nPremi Invio per interrompere la generazione\nShift + Invio per andare a capo", "Ask ChatGPT": "Chiedi a ChatGPT", "No Input Found": "Nessun ingresso trovato", "You": "Tu", "Collapse": "Comprimi", "Expand": "Espandi", "Stop": "Stop", "Continue on official website": "Continua sul sito ufficiale", "Error": "Errore", "Copy": "Copia", "Question": "Domanda", "Answer": "Risposta", "Waiting for response...": "In attesa di risposta...", "Close the Window": "Chiudi la finestra", "Pin the Window": "Fissa la finestra", "Float the Window": "Finestra flottante", "Save Conversation": "Salva la conversazione", "UNAUTHORIZED": "Non autorizzato", "Please login at https://chatgpt.com first": "Effettua il login su https://chatgpt.com prima", "Please login at https://claude.ai first, and then click the retry button": "Effettua il login su https://claude.ai prima, quindi fai clic sul pulsante Riprova", "Please login at https://bing.com first": "Effettua il login su https://bing.com prima", "Then open https://chatgpt.com/api/auth/session": "Quindi apri https://chatgpt.com/api/auth/session", "And refresh this page or type you question again": "Quindi fare clic sul pulsante Riprova nell'angolo in alto a destra", "Consider creating an api key at https://platform.openai.com/account/api-keys": "Considera la creazione di una chiave API su https://platform.openai.com/account/api-keys", "OpenAI Security Check Required": "Richiesta verifica di sicurezza OpenAI", "Please open https://chatgpt.com/api/auth/session": "Apri https://chatgpt.com/api/auth/session", "Please open https://chatgpt.com": "Apri https://chatgpt.com", "New Chat": "Nuova chat", "Summarize Page": "Riassumi la pagina", "Translate": "Traduci", "Translate (Bidirectional)": "Traduci (Bidirezionale)", "Translate (To English)": "Traduci (Verso l'inglese)", "Translate (To Chinese)": "Traduci (Verso il cinese)", "Summary": "Riassumi", "Polish": "Revisiona", "Sentiment Analysis": "Analisi dei sentimenti", "Divide Paragraphs": "Dividi in paragrafi", "Code Explain": "Spiega il codice", "Ask": "Chiedi", "Always": "Sempre", "Manually": "Manualmente", "When query ends with question mark (?)": "Quando la query termina con il punto interrogativo (?)", "Light": "Chiaro", "Dark": "Scuro", "Auto": "Automatico", "ChatGPT (Web)": "ChatGPT (Web)", "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Modello personalizzato", "Balanced": "Bilanciato", "Creative": "Creativo", "Precise": "Preciso", "Fast": "Veloce", "API Key": "Chiave API", "Model Name": "Nome del modello", "Custom Model API Url": "URL API del modello personalizzato", "Loading...": "Caricamento...", "Feedback": "Feedback", "Confirm": "Conferma", "Clear Conversation": "Pulisci la conversazione", "Retry": "Riprova", "Exceeded maximum context length": "Lunghezza massima del contesto superata, si prega di pulire la conversazione e riprovare", "Regenerate the answer after switching model": "Rigenerare la risposta dopo aver cambiato il modello", "Pin": "Fissa", "Unpin": "Sblocca", "Delete Conversation": "Elimina la conversazione", "Clear conversations": "Pulisci le conversazioni", "Settings": "Impostazioni", "Feature Pages": "Pagine delle funzionalità", "Keyboard Shortcuts": "Scorciatoie da tastiera", "Open Conversation Page": "Apri la pagina della conversazione", "Open Conversation Window": "Apri la finestra di conversazione", "Store to Independent Conversation Page": "Conserva sulla pagina della conversazione indipendente", "Keep Conversation Window in Background": "Mantieni la finestra di conversazione in background, per aprirla in qualsiasi programma tramite scorciatoie", "Max Response Token Length": "Lunghezza massima del token di risposta", "Max Conversation Length": "Lunghezza massima della conversazione", "Always pin the floating window": "Fissare sempre la finestra flottante", "Export": "Esporta", "Always Create New Conversation Window": "Crea sempre una nuova finestra di conversazione", "Please keep this tab open. You can now use the web mode of ChatGPTBox": "Per favore, mantieni questa scheda aperta. Ora puoi utilizzare la modalità web di ChatGPTBox", "Go Back": "Torna indietro", "Pin Tab": "Fissa scheda", "Modules": "Moduli", "API Params": "Parametri API", "API Url": "URL API", "Others": "Altri", "API Modes": "Modalità API", "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time": "Disabilita la cronologia della modalità web per una migliore protezione della privacy, ma ciò comporterà conversazioni non disponibili dopo un certo periodo di tempo", "Display selection tools next to input box to avoid blocking": "Mostra gli strumenti di selezione accanto alla casella di input per evitare il blocco", "Close All Chats In This Page": "Chiudi tutte le chat in questa pagina", "When Icon Clicked": "Quando viene cliccata l'icona", "Open Settings": "Apri impostazioni", "Focus to input box after answering": "Focus sulla casella di input dopo aver risposto", "Bing CaptchaChallenge": "Sfida Captcha di Bing: è necessario superare la verifica di Bing. Apri https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx e invia un messaggio.", "Exceeded quota": "Limite superato o scaduto, controlla questo link: https://platform.openai.com/account/usage", "Rate limit": "Limite di frequenza delle richieste raggiunto", "Jump to bottom": "Salta in fondo", "Explain": "Spiega", "Failed to get arkose token.": "Impossibile ottenere il token arkose", "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.": "Per favore, mantieni aperto https://chatgpt.com e riprova. Se ancora non funziona, digita alcuni caratteri nella casella di input della pagina web di chatgpt e riprova.", "Open Side Panel": "Apri il pannello laterale", "Generating...": "Generazione...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "richiesto token moonshot, effettua il login su https://kimi.com prima, quindi fai clic sul pulsante Riprova", "Hide context menu of this extension": "Nascondi il menu contestuale di questa estensione", "Custom Anthropic API Url": "URL API Anthropic personalizzato", "Anthropic API Key": "Chiave API Anthropic", "Cancel": "Annulla", "Name is required": "Il nome è obbligatorio", "Prompt template should include {{selection}}": "Il modello di prompt dovrebbe includere {{selection}}", "Save": "Salva", "Name": "Nome", "Icon": "Icona", "Prompt Template": "Modello di prompt", "Explain this: {{selection}}": "Spiega questo: {{selection}}", "New": "Nuovo", "Always display floating window, disable sidebar for all site adapters": "Mostra sempre la finestra flottante, disabilita la barra laterale per tutti gli adattatori del sito", "Allow ESC to close all floating windows": "Consenti ESC per chiudere tutte le finestre flottanti", "Export All Data": "Esporta tutti i dati", "Import All Data": "Importa tutti i dati", "Keep-Alive Time": "Tempo di mantenimento", "5m": "5m", "30m": "30m", "Forever": "Per sempre", "You have successfully logged in for ChatGPTBox and can now return": "Ti sei autenticato con successo per ChatGPTBox e ora puoi tornare", "Claude.ai is not available in your region": "Claude.ai non è disponibile nella tua regione", "Claude.ai (Web)": "Claude.ai (Web)", "Kimi.Moonshot (Web)": "Kimi.Moonshot (Web)", "Bing (Web)": "Bing (Web)", "Gemini (Web)": "Gemini (Web)", "Type": "Tipo", "Mode": "Modalità", "Custom": "Personalizzato", "OpenAI (API)": "OpenAI (API)", "Anthropic (API)": "Anthropic (API)", "Azure OpenAI (API)": "Azure OpenAI (API)", "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", "Azure OpenAI": "Azure OpenAI", "OpenAI (GPT-5)": "OpenAI (GPT-5)", "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", "OpenAI (GPT-5.4 mini)": "OpenAI (GPT-5.4 mini)", "OpenAI (GPT-5.4 nano)": "OpenAI (GPT-5.4 nano)", "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } ================================================ FILE: src/_locales/ja/main.json ================================================ { "General": "一般", "Selection Tools": "選択ツール", "Sites": "サイト適応", "Advanced": "高度な", "Donate": "寄付", "Triggers": "トリガー", "Theme": "テーマ", "API Mode": "APIモード", "Get": "取得", "Preferred Language": "言語設定", "Insert ChatGPT at the top of search results": "検索結果のトップにチャットGPTを挿入", "Lock scrollbar while answering": "回答中にスクロールバーをロック", "Current Version": "現在のバージョン", "Latest": "最新版", "Help | Changelog ": "ヘルプ | チェンジログ ", "Custom ChatGPT Web API Url": "カスタムChatGPT Web APIのURL", "Custom ChatGPT Web API Path": "カスタムChatGPT Web APIのパス", "Custom OpenAI API Url": "カスタムOpenAI APIのURL", "Custom Site Regex": "カスタムサイトの正規表現", "Exclusively use Custom Site Regex for website matching, ignoring built-in rules": "内蔵ルールを無視して、カスタムサイト用の正規表現のみを使用", "Input Query": "入力クエリ", "Append Query": "末尾に追加するクエリ", "Prepend Query": "先頭に挿入するクエリ", "Wechat Pay": "Wechatペイ", "Type your question here\nEnter to send, shift + enter to break line": "ここに質問を入力してください\nEnterで送信、shift+Enterで改行", "Type your question here\nEnter to stop generating\nShift + enter to break line": "ここに質問を入力してください\nEnterで生成を停止、Shift + Enterで改行", "Ask ChatGPT": "ChatGPTに質問する", "No Input Found": "入力が見つかりません", "You": "あなた", "Collapse": "折りたたむ", "Expand": "展開", "Stop": "停止", "Continue on official website": "公式サイトで続ける", "Error": "エラー", "Copy": "コピー", "Question": "質問", "Answer": "回答", "Waiting for response...": "回答を待機中...", "Close the Window": "ウィンドウを閉じる", "Pin the Window": "ウィンドウをピン留め", "Float the Window": "ウィンドウをフロート/分割表示", "Save Conversation": "会話を保存", "UNAUTHORIZED": "認証されていません", "Please login at https://chatgpt.com first": "最初に https://chatgpt.com にログインしてください", "Please login at https://claude.ai first, and then click the retry button": "最初に https://claude.ai にログインしてから、再試行ボタンをクリックしてください", "Please login at https://bing.com first": "最初に https://bing.com にログインしてください", "Then open https://chatgpt.com/api/auth/session": "次に https://chatgpt.com/api/auth/session にアクセス", "And refresh this page or type you question again": "次に、右上の「再試行」ボタンをクリックします", "Consider creating an api key at https://platform.openai.com/account/api-keys": "https://platform.openai.com/account/api-keys でAPIキーを作成してください", "OpenAI Security Check Required": "OpenAIのセキュリティチェックが必要です", "Please open https://chatgpt.com/api/auth/session": "https://chatgpt.com/api/auth/session にアクセスしてください", "Please open https://chatgpt.com": "https://chatgpt.com にアクセスしてください", "New Chat": "新しいチャット", "Summarize Page": "ページをまとめる", "Translate": "翻訳", "Translate (Bidirectional)": "双向翻訳", "Translate (To English)": "英語に翻訳", "Translate (To Chinese)": "中国語に翻訳", "Summary": "サマリー", "Polish": "ポリッシュ", "Sentiment Analysis": "感情分析", "Divide Paragraphs": "パラグラフ分割", "Code Explain": "コードの解説", "Ask": "質問", "Always": "常時", "Manually": "手動で", "When query ends with question mark (?)": "クエリが「?」で終わる場合", "Light": "ライト", "Dark": "ダーク", "Auto": "オート", "ChatGPT (Web)": "ChatGPT (Web)", "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "カスタムモデル", "Balanced": "バランスの取れた", "Creative": "創造的な", "Precise": "正確な", "Fast": "高速", "API Key": "APIキー", "Model Name": "モデル名", "Custom Model API Url": "カスタムモデルのAPI URL", "Loading...": "読み込み中...", "Feedback": "フィードバック", "Confirm": "確認", "Clear Conversation": "会話をクリア", "Retry": "再試行", "Exceeded maximum context length": "最大コンテキスト長を超えました。会話をクリアして再試行してください", "Regenerate the answer after switching model": "モデルを切り替えた後に回答を再生成", "Pin": "ピン留め", "Unpin": "ピン留め解除", "Delete Conversation": "会話を削除", "Clear conversations": "会話をクリア", "Settings": "設定", "Feature Pages": "機能ページ", "Keyboard Shortcuts": "キーボードショートカット", "Open Conversation Page": "会話ページを開く", "Open Conversation Window": "会話ウィンドウを開く", "Store to Independent Conversation Page": "独立した会話ページに保存", "Keep Conversation Window in Background": "会話ウィンドウをバックグラウンドで保持して、任意のプログラムでショートカットキーを使用できます", "Max Response Token Length": "最大応答トークン長", "Max Conversation Length": "最大会話長", "Always pin the floating window": "常にフローティングウィンドウをピン留め", "Export": "エクスポート", "Always Create New Conversation Window": "常に新しい会話ウィンドウを作成", "Please keep this tab open. You can now use the web mode of ChatGPTBox": "このタブを開いたままにしてください。これでChatGPTBoxのWebモードを使用できます", "Go Back": "戻る", "Pin Tab": "タブをピン留め", "Modules": "モジュール", "API Params": "APIパラメータ", "API Url": "API URL", "Others": "その他", "API Modes": "APIモード", "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time": "プライバシー保護の向上のためにWebモードの履歴を無効にしますが、一定期間後に会話が利用できなくなります", "Display selection tools next to input box to avoid blocking": "ブロッキングを回避するために入力ボックスの隣に選択ツールを表示", "Close All Chats In This Page": "このページのすべてのチャットを閉じる", "When Icon Clicked": "アイコンがクリックされたとき", "Open Settings": "設定を開く", "Focus to input box after answering": "回答後に入力ボックスにフォーカス", "Bing CaptchaChallenge": "Bing CaptchaChallenge:https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx を開いてメッセージを送信する必要があります", "Exceeded quota": "クォータを超過しました。https://platform.openai.com/account/usage で残高を確認してください", "Rate limit": "レート制限", "Jump to bottom": "最下部にジャンプ", "Explain": "説明", "Failed to get arkose token.": "arkoseトークンの取得に失敗しました。", "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.": "https://chatgpt.com を開いたままにして、もう一度試してください。それでもうまくいかない場合は、chatgpt webページの入力ボックスにいくつかの文字を入力してからもう一度試してください。", "Open Side Panel": "サイドパネルを開く", "Generating...": "生成中...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "moonshotトークンが必要です。最初に https://kimi.com にログインしてから、再試行ボタンをクリックしてください", "Hide context menu of this extension": "この拡張機能のコンテキストメニューを非表示", "Custom Anthropic API Url": "カスタムAnthropic APIのURL", "Anthropic API Key": "Anthropic API キー", "Cancel": "キャンセル", "Name is required": "名前は必須です", "Prompt template should include {{selection}}": "プロンプトテンプレートには {{selection}} を含める必要があります", "Save": "保存", "Name": "名前", "Icon": "アイコン", "Prompt Template": "プロンプトテンプレート", "Explain this: {{selection}}": "これを説明する: {{selection}}", "New": "新規", "Always display floating window, disable sidebar for all site adapters": "常にフローティングウィンドウを表示し、すべてのサイトアダプターでサイドバーを無効にします", "Allow ESC to close all floating windows": "ESCキーですべてのフローティングウィンドウを閉じる", "Export All Data": "すべてのデータをエクスポート", "Import All Data": "すべてのデータをインポート", "Keep-Alive Time": "Keep-Alive時間", "5m": "5分", "30m": "30分", "Forever": "永久", "You have successfully logged in for ChatGPTBox and can now return": "ChatGPTBoxに正常にログインしました。これで戻ることができます", "Claude.ai is not available in your region": "Claude.ai はあなたの地域では利用できません", "Claude.ai (Web)": "Claude.ai (Web)", "Kimi.Moonshot (Web)": "Kimi.Moonshot (Web)", "Bing (Web)": "Bing (Web)", "Gemini (Web)": "Gemini (Web)", "Type": "タイプ", "Mode": "モード", "Custom": "カスタム", "OpenAI (API)": "OpenAI (API)", "Anthropic (API)": "Anthropic (API)", "Azure OpenAI (API)": "Azure OpenAI (API)", "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", "Azure OpenAI": "Azure OpenAI", "OpenAI (GPT-5)": "OpenAI (GPT-5)", "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", "OpenAI (GPT-5.4 mini)": "OpenAI (GPT-5.4 mini)", "OpenAI (GPT-5.4 nano)": "OpenAI (GPT-5.4 nano)", "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } ================================================ FILE: src/_locales/ko/main.json ================================================ { "General": "일반", "Selection Tools": "선택 도구", "Sites": "사이트", "Advanced": "고급", "Donate": "기부", "Triggers": "트리거", "Theme": "테마", "API Mode": "API 모드", "Get": "받다", "Preferred Language": "선호하는 언어", "Insert ChatGPT at the top of search results": "검색 결과 상단에 ChatGPT 삽입", "Lock scrollbar while answering": "답변 중 스크롤바 잠금", "Current Version": "현재 버전", "Latest": "최신", "Help | Changelog ": "도움말 | 변경 로그 ", "Custom ChatGPT Web API Url": "사용자 정의 ChatGPT 웹 API URL", "Custom ChatGPT Web API Path": "사용자 정의 ChatGPT 웹 API 경로", "Custom OpenAI API Url": "사용자 정의 OpenAI API URL", "Custom Site Regex": "사용자 정의 사이트 Regex", "Exclusively use Custom Site Regex for website matching, ignoring built-in rules": "사이트 일치에 독점적으로 사용자 정의 사이트 Regex를 사용하며, 내장 규칙을 무시합니다.", "Input Query": "입력 쿼리 선택기", "Append Query": "끝에 추가할 쿼리 선택기", "Prepend Query": "앞에 추가할 쿼리 선택기", "Wechat Pay": "위챗 페이", "Type your question here\nEnter to send, shift + enter to break line": "여기에 질문을 입력하세요. \n 보내려면 엔터, 줄바꿈을 하려면 shift + enter를 누르세요.", "Type your question here\nEnter to stop generating\nShift + enter to break line": "여기에 질문을 입력하세요.\nEnter로 생성을 중지하려면 \nShift + Enter로 줄을 바꾸세요.", "Ask ChatGPT": "ChatGPT에게 물어보세요.", "No Input Found": "입력 없음", "You": "당신", "Collapse": "축소", "Expand": "확장", "Stop": "중지", "Continue on official website": "공식 웹사이트에서 계속하기", "Error": "오류", "Copy": "복사", "Question": "질문", "Answer": "대답", "Waiting for response...": "응답 대기 중...", "Close the Window": "창 닫기", "Pin the Window": "창 고정", "Float the Window": "창 띄우기", "Save Conversation": "대화 저장", "UNAUTHORIZED": "인증되지 않음", "Please login at https://chatgpt.com first": "https://chatgpt.com 에서 로그인하세요.", "Please login at https://claude.ai first, and then click the retry button": "https://claude.ai 에서 로그인한 다음 재시도 버튼을 클릭하세요.", "Please login at https://bing.com first": "https://bing.com 에서 로그인하세요.", "Then open https://chatgpt.com/api/auth/session": "그런 다음 https://chatgpt.com/api/auth/session 을 열거나 다시 질문을 입력하세요.", "And refresh this page or type you question again": "그런 다음 오른쪽 상단의 재시도 버튼을 클릭합니다.", "Consider creating an api key at https://platform.openai.com/account/api-keys": "https://platform.openai.com/account/api-keys 에서 API 키를 생성하는 것을 고려하세요.", "OpenAI Security Check Required": "OpenAI 보안 검사 필요", "Please open https://chatgpt.com/api/auth/session": "https://chatgpt.com/api/auth/session 을 열어주세요.", "Please open https://chatgpt.com": "https://chatgpt.com 을 열어주세요.", "New Chat": "새로운 대화", "Summarize Page": "페이지 요약", "Translate": "번역", "Translate (Bidirectional)": "양방향 번역", "Translate (To English)": "영어로 번역", "Translate (To Chinese)": "중국어로 번역", "Summary": "요약", "Polish": "마무리 작업", "Sentiment Analysis": "감성 분석", "Divide Paragraphs": "문단 나누기", "Code Explain": "코드 설명", "Ask": "문의하기", "Always": "항상", "Manually": "수동으로", "When query ends with question mark (?)": "쿼리가 물음표로 끝날 때", "Light": "라이트", "Dark": "다크", "Auto": "자동", "ChatGPT (Web)": "ChatGPT (Web)", "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "사용자 정의 모델", "Balanced": "균형 잡힌", "Creative": "창의적인", "Precise": "정확한", "Fast": "빠른", "API Key": "API 키", "Model Name": "모델 이름", "Custom Model API Url": "사용자 정의 모델 API URL", "Loading...": "로딩 중...", "Feedback": "피드백", "Confirm": "확인", "Clear Conversation": "대화 내용 지우기", "Retry": "재시도", "Exceeded maximum context length": "최대 컨텍스트 길이를 초과하였습니다. 대화 내용을 지우고 다시 시도해주세요.", "Regenerate the answer after switching model": "모델 전환 후 대답 다시 생성", "Pin": "고정", "Unpin": "고정 해제", "Delete Conversation": "대화 삭제", "Clear conversations": "대화 기록 지우기", "Settings": "설정", "Feature Pages": "기능 페이지", "Keyboard Shortcuts": "키보드 단축키 설정", "Open Conversation Page": "대화 페이지 열기", "Open Conversation Window": "대화 창 열기", "Store to Independent Conversation Page": "독립적인 대화 페이지에 저장", "Keep Conversation Window in Background": "대화 창을 백그라운드로 유지하여 어떤 프로그램에서도 단축키로 호출할 수 있도록 합니다", "Max Response Token Length": "최대 응답 토큰 길이", "Max Conversation Length": "최대 대화 길이", "Always pin the floating window": "항상 떠다니는 창 고정", "Export": "내보내기", "Always Create New Conversation Window": "항상 새 대화 창 만들기", "Please keep this tab open. You can now use the web mode of ChatGPTBox": "이 탭을 열어두세요. 이제 ChatGPTBox의 웹 모드를 사용할 수 있습니다.", "Go Back": "뒤로 가기", "Pin Tab": "탭 고정", "Modules": "모듈", "API Params": "API 매개변수", "API Url": "API 주소", "Others": "기타", "API Modes": "API 모드", "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time": "개인 정보 보호를 위해 웹 모드 기록을 비활성화하지만 일정 시간 이후에 대화를 사용할 수 없게 됩니다.", "Display selection tools next to input box to avoid blocking": "차단을 피하려면 입력 상자 옆에 선택 도구를 표시", "Close All Chats In This Page": "이 페이지의 모든 채팅 닫기", "When Icon Clicked": "아이콘이 클릭되었을 때", "Open Settings": "설정 열기", "Focus to input box after answering": "답변 후 입력 상자에 초점 맞추기", "Bing CaptchaChallenge": "Bing CaptchaChallenge: https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx 링크를 열고 메시지를 보내야 합니다.", "Exceeded quota": "할당량 초과: https://platform.openai.com/account/usage 링크에서 잔액을 확인하세요.", "Rate limit": "요청 비율 제한", "Jump to bottom": "아래로 이동", "Explain": "설명", "Failed to get arkose token.": "arkose 토큰을 가져오지 못했습니다.", "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.": "https://chatgpt.com 을 열어두고 다시 시도하세요. 여전히 작동하지 않으면 chatgpt 웹 페이지의 입력 상자에 몇 가지 문자를 입력한 다음 다시 시도하세요.", "Open Side Panel": "사이드 패널 열기", "Generating...": "생성 중...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "moonshot 토큰이 필요합니다. https://kimi.com 에서 로그인한 다음 재시도 버튼을 클릭하세요.", "Hide context menu of this extension": "이 확장 프로그램의 컨텍스트 메뉴 숨기기", "Custom Anthropic API Url": "사용자 정의 Anthropic API URL", "Anthropic API Key": "Anthropic API 키", "Cancel": "취소", "Name is required": "이름은 필수입니다", "Prompt template should include {{selection}}": "프롬프트 템플릿에는 {{selection}} 이 포함되어야 합니다", "Save": "저장", "Name": "이름", "Icon": "아이콘", "Prompt Template": "프롬프트 템플릿", "Explain this: {{selection}}": "이것을 설명하세요: {{selection}}", "New": "새로 만들기", "Always display floating window, disable sidebar for all site adapters": "항상 떠다니는 창을 표시하고 모든 사이트 어댑터의 사이드바를 비활성화합니다", "Allow ESC to close all floating windows": "ESC를 눌러 모든 떠다니는 창을 닫도록 허용", "Export All Data": "모든 데이터 내보내기", "Import All Data": "모든 데이터 가져오기", "Keep-Alive Time": "Keep-Alive 시간", "5m": "5분", "30m": "30분", "Forever": "영원히", "You have successfully logged in for ChatGPTBox and can now return": "ChatGPTBox에 성공적으로 로그인하였으며 이제 돌아갈 수 있습니다", "Claude.ai is not available in your region": "Claude.ai는 귀하의 지역에서 사용할 수 없습니다", "Claude.ai (Web)": "Claude.ai (웹)", "Kimi.Moonshot (Web)": "Kimi.Moonshot (웹)", "Bing (Web)": "Bing (웹)", "Gemini (Web)": "Gemini (웹)", "Type": "유형", "Mode": "모드", "Custom": "사용자 정의", "OpenAI (API)": "OpenAI (API)", "Anthropic (API)": "Anthropic (API)", "Azure OpenAI (API)": "Azure OpenAI (API)", "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", "Azure OpenAI": "Azure OpenAI", "OpenAI (GPT-5)": "OpenAI (GPT-5)", "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", "OpenAI (GPT-5.4 mini)": "OpenAI (GPT-5.4 mini)", "OpenAI (GPT-5.4 nano)": "OpenAI (GPT-5.4 nano)", "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } ================================================ FILE: src/_locales/pt/main.json ================================================ { "General": "Geral", "Selection Tools": "Ferramentas de Seleção", "Sites": "Adaptação de Sites", "Advanced": "Avançado", "Donate": "Doar", "Triggers": "Acionadores", "Theme": "Tema", "API Mode": "Modo API", "Get": "Obter", "Preferred Language": "Idioma Preferido", "Insert ChatGPT at the top of search results": "Inserir ChatGPT no topo dos resultados de pesquisa", "Lock scrollbar while answering": "Bloquear barra de rolagem ao responder", "Current Version": "Versão Atual", "Latest": "Último", "Help | Changelog ": "Ajuda | Histórico de Mudanças", "Custom ChatGPT Web API Url": "URL da API do ChatGPT Personalizada", "Custom ChatGPT Web API Path": "Caminho da API do ChatGPT Personalizada", "Custom OpenAI API Url": "URL da API Personalizada do OpenAI", "Custom Site Regex": "Expressão Regular do Site Personalizada", "Exclusively use Custom Site Regex for website matching, ignoring built-in rules": "Usar exclusivamente a Expressão Regular do Site Personalizada para combinação de sites, ignorando regras incorporadas", "Input Query": "Consulta de Entrada", "Append Query": "Consulta Anexada", "Prepend Query": "Consulta Prependida", "Wechat Pay": "Pagamento Wechat", "Type your question here\nEnter to send, shift + enter to break line": "Digite sua pergunta aqui\nPressione Enter para enviar, shift + enter para quebrar a linha", "Type your question here\nEnter to stop generating\nShift + enter to break line": "Digite sua pergunta aqui\nPressione Enter para parar a geração\nShift + Enter para quebrar a linha", "Ask ChatGPT": "Perguntar ao ChatGPT", "No Input Found": "Nenhuma Entrada Encontrada", "You": "Você", "Collapse": "Colapso", "Expand": "Expandir", "Stop": "Parar", "Continue on official website": "Continuar no site oficial", "Error": "Erro", "Copy": "Copiar", "Question": "Pergunta", "Answer": "Resposta", "Waiting for response...": "Aguardando resposta...", "Close the Window": "Fechar a Janela", "Pin the Window": "Fixar a Janela", "Float the Window": "Flutuar a Janela", "Save Conversation": "Salvar Conversa", "UNAUTHORIZED": "NÃO AUTORIZADO", "Please login at https://chatgpt.com first": "Por favor, faça login em https://chatgpt.com primeiro", "Please login at https://claude.ai first, and then click the retry button": "Por favor, faça login em https://claude.ai primeiro e depois clique no botão de tentar novamente", "Please login at https://bing.com first": "Por favor, faça login em https://bing.com primeiro", "Then open https://chatgpt.com/api/auth/session": "Então, abra https://chatgpt.com/api/auth/session", "And refresh this page or type you question again": "Depois clique no botão Retry, no canto superior direito", "Consider creating an api key at https://platform.openai.com/account/api-keys": "Considere criar uma chave de API em https://platform.openai.com/account/api-keys", "OpenAI Security Check Required": "Necessário Verificação de Segurança do OpenAI", "Please open https://chatgpt.com/api/auth/session": "Por favor, abra https://chatgpt.com/api/auth/session", "Please open https://chatgpt.com": "Por favor, abra https://chatgpt.com", "New Chat": "Nova Conversa", "Summarize Page": "Resumir a Página", "Translate": "Traduzir", "Translate (Bidirectional)": "Traduzir (Bidirecional)", "Translate (To English)": "Traduzir (Para Inglês)", "Translate (To Chinese)": "Traduzir (Para Chinês)", "Summary": "Resumo", "Polish": "Polir", "Sentiment Analysis": "Análise de Sentimentos", "Divide Paragraphs": "Dividir Parágrafos", "Code Explain": "Explicação do Código", "Ask": "Perguntar", "Always": "Sempre", "Manually": "Manualmente", "When query ends with question mark (?)": "Quando a consulta termina com ponto de interrogação (?)", "Light": "Claro", "Dark": "Escuro", "Auto": "Automático", "ChatGPT (Web)": "ChatGPT (Web)", "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Modelo Personalizado", "Balanced": "Equilibrado", "Creative": "Criativo", "Precise": "Preciso", "Fast": "Rápido", "API Key": "Chave API", "Model Name": "Nome do Modelo", "Custom Model API Url": "URL da API do Modelo Personalizado", "Loading...": "Carregando...", "Feedback": "Feedback", "Confirm": "Confirmar", "Clear Conversation": "Limpar Conversa", "Retry": "Tentar novamente", "Exceeded maximum context length": "Ultrapassou o comprimento máximo do contexto. Limpe a conversa e tente novamente", "Regenerate the answer after switching model": "Regenerar a resposta após trocar o modelo", "Pin": "Fixar", "Unpin": "Desafixar", "Delete Conversation": "Excluir Conversa", "Clear conversations": "Limpar conversas", "Settings": "Configurações", "Feature Pages": "Páginas de Recursos", "Keyboard Shortcuts": "Atalhos de Teclado", "Open Conversation Page": "Abrir Página de Conversa", "Open Conversation Window": "Abrir Janela de Conversa", "Store to Independent Conversation Page": "Armazenar em Página de Conversa Independente", "Keep Conversation Window in Background": "Mantenha a janela de conversa em segundo plano para que possa ser chamada com atalhos em qualquer programa", "Max Response Token Length": "Comprimento Máximo do Token de Resposta", "Max Conversation Length": "Comprimento Máximo da Conversação", "Always pin the floating window": "Sempre Fixar a Janela Flutuante", "Export": "Exportar", "Always Create New Conversation Window": "Sempre Criar Nova Janela de Conversação", "Please keep this tab open. You can now use the web mode of ChatGPTBox": "Por favor, mantenha esta aba aberta. Agora pode usar o modo web do ChatGPTBox.", "Go Back": "Voltar", "Pin Tab": "Fixar Tab", "Modules": "Módulos", "API Params": "Parâmetros da API", "API Url": "URL da API", "Others": "Outros", "API Modes": "Modos da API", "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time": "Desative o histórico do modo web para uma melhor proteção de privacidade, mas isso resultará em conversas indisponíveis após um certo tempo.", "Display selection tools next to input box to avoid blocking": "Exibir ferramentas de seleção ao lado da caixa de entrada para evitar bloqueios", "Close All Chats In This Page": "Fechar Todas as Conversas Nesta Página", "When Icon Clicked": "Quando o Ícone for Clicado", "Open Settings": "Abrir Configurações", "Focus to input box after answering": "Foco na caixa de entrada após a resposta", "Bing CaptchaChallenge": "Desafio de Captcha do Bing: Deve passar pela verificação do Bing. Abra https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx e envie uma mensagem.", "Exceeded quota": "Cota excedida: Verifique o seu saldo ou a validade em https://platform.openai.com/account/usage.", "Rate limit": "Limite de taxa atingido", "Jump to bottom": "Ir para o fundo", "Explain": "Explicar", "Failed to get arkose token.": "Falha ao obter o token arkose.", "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.": "Por favor, mantenha https://chatgpt.com aberto e tente novamente. Se ainda não funcionar, digite alguns caracteres na caixa de entrada da página da web do chatgpt e tente novamente.", "Open Side Panel": "Abrir Painel Lateral", "Generating...": "Gerando...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "token moonshot necessário, faça login em https://kimi.com primeiro e depois clique no botão de tentar novamente", "Hide context menu of this extension": "Ocultar menu de contexto desta extensão", "Custom Anthropic API Url": "URL da API Personalizada do Anthropic", "Anthropic API Key": "Chave API Anthropic", "Cancel": "Cancelar", "Name is required": "Nome é obrigatório", "Prompt template should include {{selection}}": "O modelo de prompt deve incluir {{selection}}", "Save": "Salvar", "Name": "Nome", "Icon": "Ícone", "Prompt Template": "Modelo de Prompt", "Explain this: {{selection}}": "Explique isso: {{selection}}", "New": "Novo", "Always display floating window, disable sidebar for all site adapters": "Sempre exibir janela flutuante, desativar barra lateral para todos os adaptadores de site", "Allow ESC to close all floating windows": "Permitir ESC para fechar todas as janelas flutuantes", "Export All Data": "Exportar Todos os Dados", "Import All Data": "Importar Todos os Dados", "Keep-Alive Time": "Tempo de Manutenção de Conexão", "5m": "5m", "30m": "30m", "Forever": "Para sempre", "You have successfully logged in for ChatGPTBox and can now return": "Você fez login com sucesso no ChatGPTBox e agora pode voltar", "Claude.ai is not available in your region": "Claude.ai não está disponível em sua região", "Claude.ai (Web)": "Claude.ai (Web)", "Kimi.Moonshot (Web)": "Kimi.Moonshot (Web)", "Bing (Web)": "Bing (Web)", "Gemini (Web)": "Gemini (Web)", "Type": "Tipo", "Mode": "Modo", "Custom": "Personalizado", "OpenAI (API)": "OpenAI (API)", "Anthropic (API)": "Anthropic (API)", "Azure OpenAI (API)": "Azure OpenAI (API)", "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", "Azure OpenAI": "Azure OpenAI", "OpenAI (GPT-5)": "OpenAI (GPT-5)", "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", "OpenAI (GPT-5.4 mini)": "OpenAI (GPT-5.4 mini)", "OpenAI (GPT-5.4 nano)": "OpenAI (GPT-5.4 nano)", "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } ================================================ FILE: src/_locales/resources.mjs ================================================ import de from './de/main.json' import en from './en/main.json' import es from './es/main.json' import fr from './fr/main.json' import inTrans from './in/main.json' import it from './it/main.json' import ja from './ja/main.json' import ko from './ko/main.json' import pt from './pt/main.json' import ru from './ru/main.json' import tr from './tr/main.json' import zhHans from './zh-hans/main.json' import zhHant from './zh-hant/main.json' export const resources = { de: { translation: de, }, en: { translation: en, }, es: { translation: es, }, fr: { translation: fr, }, in: { translation: inTrans, }, it: { translation: it, }, ja: { translation: ja, }, ko: { translation: ko, }, pt: { translation: pt, }, ru: { translation: ru, }, tr: { translation: tr, }, zh: { translation: zhHans, }, zhHant: { translation: zhHant, }, } ================================================ FILE: src/_locales/ru/main.json ================================================ { "General": "Общие", "Selection Tools": "Инструменты выбора", "Sites": "Адаптация сайтов", "Advanced": "Расширенный", "Donate": "Пожертвовать", "Triggers": "Триггеры", "Theme": "Тема", "API Mode": "Режим API", "Get": "Получить", "Preferred Language": "Предпочитаемый язык", "Insert ChatGPT at the top of search results": "Вставить ChatGPT в верхней части результатов поиска", "Lock scrollbar while answering": "Начало блокировки прокрутки во время ответа", "Current Version": "Текущая версия", "Latest": "Последняя", "Help | Changelog ": "Помощь | Изменения", "Custom ChatGPT Web API Url": "Пользовательский URL веб-API ChatGPT", "Custom ChatGPT Web API Path": "Пользовательский путь веб-API ChatGPT", "Custom OpenAI API Url": "Пользовательский URL OpenAI API", "Custom Site Regex": "Пользовательское регулярное выражение сайта", "Exclusively use Custom Site Regex for website matching, ignoring built-in rules": "Использовать только пользовательское регулярное выражение сайта для сопоставления сайта, игнорируя встроенные правила.", "Input Query": "Входной запрос", "Append Query": "Добавить запрос", "Prepend Query": "Вставить запрос", "Wechat Pay": "Wechat-платеж", "Type your question here\nEnter to send, shift + enter to break line": "Введите свой вопрос здесь\nНажмите Enter, чтобы отправить, Shift + Enter - для переноса строки", "Type your question here\nEnter to stop generating\nShift + enter to break line": "Введите свой вопрос здесь\nНажмите Enter для остановки генерации\nShift+Enter для переноса строки", "Ask ChatGPT": "Спросить ChatGPT", "No Input Found": "Не найден ввод", "You": "Ты", "Collapse": "Свернуть", "Expand": "Развернуть", "Stop": "Остановить", "Continue on official website": "Продолжить на официальном сайте", "Error": "Ошибка", "Copy": "Копировать", "Question": "Вопрос", "Answer": "Ответ", "Waiting for response...": "Ожидание ответа ...", "Close the Window": "Закрыть окно", "Pin the Window": "Закрепить окно", "Float the Window": "Плавающее окно", "Save Conversation": "Сохранить разговор", "UNAUTHORIZED": "Несанкционированный", "Please login at https://chatgpt.com first": "Пожалуйста, сначала войдите на https://chatgpt.com", "Please login at https://claude.ai first, and then click the retry button": "Пожалуйста, сначала войдите на https://claude.ai, а затем нажмите кнопку повтора", "Please login at https://bing.com first": "Пожалуйста, сначала войдите на https://bing.com", "Then open https://chatgpt.com/api/auth/session": "Затем откройте https://chatgpt.com/api/auth/session", "And refresh this page or type you question again": "После этого нажмите кнопку Retry в правом верхнем углу", "Consider creating an api key at https://platform.openai.com/account/api-keys": "Рассмотрите возможность создания ключа API на https://platform.openai.com/account/api-keys", "OpenAI Security Check Required": "Требуется проверка безопасности OpenAI", "Please open https://chatgpt.com/api/auth/session": "Пожалуйста, откройте https://chatgpt.com/api/auth/session", "Please open https://chatgpt.com": "Пожалуйста, откройте https://chatgpt.com", "New Chat": "Новый чат", "Summarize Page": "Сводка страницы", "Translate": "Перевести", "Translate (Bidirectional)": "Перевести (двусторонний)", "Translate (To English)": "Перевести (на английский)", "Translate (To Chinese)": "Перевести (на китайский)", "Summary": "Обзор", "Polish": "Полировка", "Sentiment Analysis": "Анализ тональности", "Divide Paragraphs": "Разделить абзацы", "Code Explain": "Объяснение кода", "Ask": "Спросить", "Always": "Всегда", "Manually": "Вручную", "When query ends with question mark (?)": "Когда запрос заканчивается вопросительным знаком (?)", "Light": "Светлый", "Dark": "Темный", "Auto": "Авто", "ChatGPT (Web)": "ChatGPT (Веб)", "ChatGPT (Web, GPT-4)": "ChatGPT (Веб, GPT-4)", "Bing (Web, GPT-4)": "Bing (Веб, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-турбо)", "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-турбо)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8к)", "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8к)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32к)", "GPT-3.5": "GPT-3.5", "Custom Model": "Пользовательская модель", "Balanced": "Сбалансированный", "Creative": "Креативный", "Precise": "Точный", "Fast": "Быстрый", "API Key": "Ключ API", "Model Name": "Название модели", "Custom Model API Url": "Custom Model API Url", "Loading...": "Загрузка...", "Feedback": "Обратная связь", "Confirm": "Подтверждение", "Clear Conversation": "Очистить беседу", "Retry": "Повторить", "Exceeded maximum context length": "Превышена максимальная длина контекста, очистите беседу и повторите попытку", "Regenerate the answer after switching model": "Генерировать ответ после смены модели", "Pin": "Закрепить", "Unpin": "Открепить", "Delete Conversation": "Удалить беседу", "Clear conversations": "Очистить историю бесед", "Settings": "Настройки", "Feature Pages": "Страницы функций", "Keyboard Shortcuts": "Горячие клавиши", "Open Conversation Page": "Открыть страницу бесед", "Open Conversation Window": "Открыть окно бесед", "Store to Independent Conversation Page": "Хранить на странице независимых разговоров", "Keep Conversation Window in Background": "Держите окно разговора в фоновом режиме, чтобы вызвать его с помощью горячих клавиш из любой программы", "Max Response Token Length": "Максимальная длина токена в ответе", "Max Conversation Length": "Максимальная длина разговора", "Always pin the floating window": "Всегда прикреплять плавающее окно", "Export": "Экспорт", "Always Create New Conversation Window": "Всегда создавать новое окно разговора", "Please keep this tab open. You can now use the web mode of ChatGPTBox": "Пожалуйста, оставьте эту вкладку открытой. Теперь вы можете использовать веб-режим ChatGPTBox", "Go Back": "Назад", "Pin Tab": "Закрепить вкладку", "Modules": "Модули", "API Params": "Параметры API", "API Url": "URL API", "Others": "Другие", "API Modes": "Режимы API", "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time": "Отключить историю веб-режима для лучшей защиты конфиденциальности, но это приведет к недоступности разговоров после определенного времени", "Display selection tools next to input box to avoid blocking": "Показывать инструменты выбора рядом с полем ввода, чтобы избежать блокировки", "Close All Chats In This Page": "Закрыть все чаты на этой странице", "When Icon Clicked": "При щелчке по значку", "Open Settings": "Открыть настройки", "Focus to input box after answering": "Фокусировка на поле ввода после ответа", "Bing CaptchaChallenge": "Bing CaptchaChallenge: Вам нужно пройти проверку Bing. Откройте https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx и отправьте сообщение.", "Exceeded quota": "Превышено квоту: Проверьте ваш баланс или срок годности по следующей ссылке: https://platform.openai.com/account/usage", "Rate limit": "Лимит запросов", "Jump to bottom": "Перейти вниз", "Explain": "Объяснить", "Failed to get arkose token.": "Не удалось получить токен arkose.", "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.": "Пожалуйста, оставьте открытым https://chatgpt.com и попробуйте еще раз. Если это все еще не работает, введите несколько символов в поле ввода веб-страницы chatgpt и попробуйте еще раз.", "Open Side Panel": "Открыть боковую панель", "Generating...": "Генерация...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "требуется токен moonshot, пожалуйста, сначала войдите на https://kimi.com, а затем нажмите кнопку повтора", "Hide context menu of this extension": "Скрыть контекстное меню этого расширения", "Custom Anthropic API Url": "Пользовательский URL API Anthropic", "Anthropic API Key": "Ключ API Anthropic", "Cancel": "Отмена", "Name is required": "Имя обязательно", "Prompt template should include {{selection}}": "Шаблон запроса должен включать {{selection}}", "Save": "Сохранить", "Name": "Имя", "Icon": "Иконка", "Prompt Template": "Шаблон запроса", "Explain this: {{selection}}": "Объяснить это: {{selection}}", "New": "Новый", "Always display floating window, disable sidebar for all site adapters": "Всегда отображать плавающее окно, отключить боковую панель для всех адаптеров сайтов", "Allow ESC to close all floating windows": "Разрешить ESC для закрытия всех плавающих окон", "Export All Data": "Экспорт всех данных", "Import All Data": "Импорт всех данных", "Keep-Alive Time": "Время поддержания активности", "5m": "5m", "30m": "30m", "Forever": "Вечно", "You have successfully logged in for ChatGPTBox and can now return": "Вы успешно вошли в ChatGPTBox и теперь можете вернуться", "Claude.ai is not available in your region": "Claude.ai недоступен в вашем регионе", "Claude.ai (Web)": "Claude.ai (Веб)", "Kimi.Moonshot (Web)": "Kimi.Moonshot (Веб)", "Bing (Web)": "Bing (Веб)", "Gemini (Web)": "Gemini (Веб)", "Type": "Тип", "Mode": "Режим", "Custom": "Пользовательский", "OpenAI (API)": "OpenAI (API)", "Anthropic (API)": "Anthropic (API)", "Azure OpenAI (API)": "Azure OpenAI (API)", "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", "Azure OpenAI": "Azure OpenAI", "OpenAI (GPT-5)": "OpenAI (GPT-5)", "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", "OpenAI (GPT-5.4 mini)": "OpenAI (GPT-5.4 mini)", "OpenAI (GPT-5.4 nano)": "OpenAI (GPT-5.4 nano)", "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } ================================================ FILE: src/_locales/tr/main.json ================================================ { "General": "Genel", "Selection Tools": "Seçim Araçları", "Sites": "Siteler", "Advanced": "Gelişmiş", "Donate": "Bağış Yap", "Triggers": "Tetikleyiciler", "Theme": "Tema", "API Mode": "API Modu", "Get": "Al", "Preferred Language": "Tercih Edilen Dil", "Insert ChatGPT at the top of search results": "ChatGPT'yi arama sonuçlarının en üstüne ekle", "Lock scrollbar while answering": "Cevap verirken kaydırma çubuğunu kilitle", "Current Version": "Şu anki versiyon", "Latest": "En son", "Help | Changelog ": "Yardım | Değişim günlüğü ", "Custom ChatGPT Web API Url": "Özel ChatGPT Web API Url'si", "Custom ChatGPT Web API Path": "Özel ChatGPT Web API Yolu", "Custom OpenAI API Url": "Özel OpenAI API URL'si", "Custom Site Regex": "Özel Site Regex'i", "Exclusively use Custom Site Regex for website matching, ignoring built-in rules": "Yerleşik kuralları yok sayarak web sitesi eşleştirme için yalnızca Özel Site Regex'i kullan", "Input Query": "Girdi Sorgusu", "Append Query": "Sorgu Ekle", "Prepend Query": "Sorgu Ön Eki", "Wechat Pay": "Wechat Pay", "Type your question here\nEnter to send, shift + enter to break line": "Sorunuzu buraya yazın\nGöndermek için enter\nSatır atlamak için shift + enter", "Type your question here\nEnter to stop generating\nShift + enter to break line": "Sorunuzu buraya yazın\nÜretmeyi durdurmak için enter\nSatır atlamak için shift + enter", "Ask ChatGPT": "ChatGPT'ye Sor", "No Input Found": "Girdi Bulunamadı", "You": "Sen", "Collapse": "Daralt", "Expand": "Genişlet", "Stop": "Durdur", "Continue on official website": "Resmi web sitesinde devam et", "Error": "Hata", "Copy": "Kopyala", "Question": "Soru", "Answer": "Cevap", "Waiting for response...": "Cevap bekleniyor...", "Close the Window": "Pencereyi Kapat", "Pin the Window": "Pencereyi Sabitle", "Float the Window": "Pencereyi Kaydır", "Save Conversation": "Konuşmayı Kaydet", "UNAUTHORIZED": "Yetkilendirilmemiş", "Please login at https://chatgpt.com first": "Lütfen önce https://chatgpt.com adresinde oturum açın", "Please login at https://claude.ai first, and then click the retry button": "Lütfen önce https://claude.ai adresinde oturum açın ve ardından yeniden dene düğmesine tıklayın", "Please login at https://bing.com first": "Lütfen önce https://bing.com adresinde oturum açın", "Then open https://chatgpt.com/api/auth/session": "Ardından https://chatgpt.com/api/auth/session adresini açın", "And refresh this page or type you question again": "Ve bu sayfayı yenileyin veya sorunuzu tekrar yazın", "Consider creating an api key at https://platform.openai.com/account/api-keys": "https://platform.openai.com/account/api-keys adresinde bir api anahtarı oluşturmayı düşünün", "OpenAI Security Check Required": "OpenAI Güvenlik Kontrolü Gerekli", "Please open https://chatgpt.com/api/auth/session": "Lütfen https://chatgpt.com/api/auth/session adresini açın", "Please open https://chatgpt.com": "Lütfen https://chatgpt.com adresini açın", "New Chat": "Yeni Sohbet", "Summarize Page": "Sayfayı Özetle", "Translate": "Çevir", "Translate (Bidirectional)": "Çevir (İki yönlü)", "Translate (To English)": "Çevir (İngilizce'ye)", "Translate (To Chinese)": "Çevir (Çince'ye)", "Summary": "Özetle", "Polish": "Lehçe", "Sentiment Analysis": "Duygu Analizi", "Divide Paragraphs": "Paragrafları Böl", "Code Explain": "Kodu Açıkla", "Ask": "Sor", "Always": "Her zaman", "Manually": "Manuel", "When query ends with question mark (?)": "Sorgu soru işareti (?) ile bittiğinde", "Light": "Açık", "Dark": "Koyu", "Auto": "Otomatik", "ChatGPT (Web)": "ChatGPT (Web)", "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Özel Model", "Balanced": "Dengeli", "Creative": "Yaratıcı", "Precise": "Duyarlı", "Fast": "Hızlı", "API Key": "API Anahtarı", "Model Name": "Model Adı", "Custom Model API Url": "Özel Model API Url'si", "Loading...": "Yükleniyor...", "Feedback": "Geri Bildirim", "Confirm": "Onayla", "Clear Conversation": "Konuşmayı Temizle", "Retry": "Tekrar Dene", "Exceeded maximum context length": "Maksimum bağlam uzunluğu aşıldı", "Regenerate the answer after switching model": "Modeli değiştirdikten sonra cevabı yeniden oluştur", "Pin": "Sabitle", "Unpin": "Sabitlemeyi Kaldır", "Delete Conversation": "Konuşmayı Sil", "Clear conversations": "Konuşmaları temizle", "Settings": "Ayarlar", "Feature Pages": "Özellik Sayfaları", "Keyboard Shortcuts": "Klavye Kısayolları", "Open Conversation Page": "Konuşma Sayfasını Aç", "Open Conversation Window": "Konuşma Penceresini Aç", "Store to Independent Conversation Page": "Bağımsız Konuşma Sayfasına Kaydet", "Keep Conversation Window in Background": "Konuşma penceresini arka planda tut, böylece herhangi bir programda çağırmak için kısayol tuşlarını kullanabilirsiniz", "Max Response Token Length": "Maksimum Cevap Jeton Uzunluğu", "Max Conversation Length": "Maksimum Konuşma Uzunluğu", "Always pin the floating window": "Her zaman kayan pencereyi sabitle", "Export": "Dışa Aktar", "Always Create New Conversation Window": "Her zaman yeni bir konuşma penceresi oluştur", "Please keep this tab open. You can now use the web mode of ChatGPTBox": "Lütfen bu sekme açık kalsın. Artık ChatGPTBox'ın web modunu kullanabilirsiniz", "Go Back": "Geri Dön", "Pin Tab": "Sekmeyi Sabitle", "Modules": "Modüller", "API Params": "API Parametreleri", "API Url": "API Url'si", "Others": "Diğerleri", "API Modes": "API Modları", "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time": "Daha iyi gizlilik koruması için web modu geçmişini devre dışı bırakın, ancak bir süre sonra kullanılamayan konuşmalara neden olacaktır", "Display selection tools next to input box to avoid blocking": "Engellemeyi önlemek için girdi kutusunun yanına seçim araçlarını görüntüleyin", "Close All Chats In This Page": "Bu Sayfadaki Tüm Sohbetleri Kapat", "When Icon Clicked": "Simge Tıklandığında", "Open Settings": "Ayarları Aç", "Focus to input box after answering": "Cevapladıktan sonra girdi kutusuna odaklan", "Bing CaptchaChallenge": "Bing'in doğrulamasını geçmelisiniz. Lütfen https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx adresine gidin ve bir mesaj gönderin", "Exceeded quota": "Mevcut kotanızı aştınız, https://platform.openai.com/account/usage adresini kontrol edin", "Rate limit": "Hız sınırı aşıldı", "Jump to bottom": "En alta git", "Explain": "Açıkla", "Failed to get arkose token.": "Arkose jetonu alınamadı.", "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.": "Lütfen https://chatgpt.com adresini açık tutun ve tekrar deneyin. Hala çalışmazsa, chatgpt web sayfasının girdi kutusuna bazı karakterler yazın ve tekrar deneyin.", "Open Side Panel": "Yan Paneli Aç", "Generating...": "Üretiliyor...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "moonshot jetonu gereklidir, lütfen önce https://kimi.com adresinde oturum açın ve ardından yeniden dene düğmesine tıklayın", "Hide context menu of this extension": "Bu uzantının bağlam menüsünü gizle", "Custom Anthropic API Url": "Özel Anthropic API Url'si", "Anthropic API Key": "Anthropic API Anahtarı", "Cancel": "İptal", "Name is required": "İsim gereklidir", "Prompt template should include {{selection}}": "Prompt şablonu {{selection}} içermelidir", "Save": "Kaydet", "Name": "İsim", "Icon": "Simge", "Prompt Template": "Prompt Şablonu", "Explain this: {{selection}}": "Bunu açıkla: {{selection}}", "New": "Yeni", "Always display floating window, disable sidebar for all site adapters": "Her zaman kayan pencereyi görüntüle, tüm site adaptörleri için kenar çubuğunu devre dışı bırak", "Allow ESC to close all floating windows": "ESC tuşuyla tüm kayan pencereleri kapatmaya izin ver", "Export All Data": "Tüm Verileri Dışa Aktar", "Import All Data": "Tüm Verileri İçe Aktar", "Keep-Alive Time": "Canlı Tutma Süresi", "5m": "5m", "30m": "30m", "Forever": "Sonsuza dek", "You have successfully logged in for ChatGPTBox and can now return": "ChatGPTBox için başarıyla giriş yaptınız ve şimdi geri dönebilirsiniz", "Claude.ai is not available in your region": "Claude.ai bölgenizde mevcut değil", "Claude.ai (Web)": "Claude.ai (Web)", "Kimi.Moonshot (Web)": "Kimi.Moonshot (Web)", "Bing (Web)": "Bing (Web)", "Gemini (Web)": "Gemini (Web)", "Type": "Tür", "Mode": "Mod", "Custom": "Özel", "OpenAI (API)": "OpenAI (API)", "Anthropic (API)": "Anthropic (API)", "Azure OpenAI (API)": "Azure OpenAI (API)", "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", "Azure OpenAI": "Azure OpenAI", "OpenAI (GPT-5)": "OpenAI (GPT-5)", "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", "OpenAI (GPT-5.4 mini)": "OpenAI (GPT-5.4 mini)", "OpenAI (GPT-5.4 nano)": "OpenAI (GPT-5.4 nano)", "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } ================================================ FILE: src/_locales/zh-hans/main.json ================================================ { "General": "常规", "Selection Tools": "选择浮动工具", "Sites": "站点适配", "Advanced": "高级", "Donate": "打赏", "Triggers": "触发方式", "Theme": "主题", "API Mode": "API模式", "Get": "获取", "Preferred Language": "语言偏好", "Insert ChatGPT at the top of search results": "将对话卡片插入到搜索结果顶部", "Lock scrollbar while answering": "回答时锁定滚动条", "Current Version": "当前版本", "Latest": "最新", "Help | Changelog ": "帮助 | 更新日志 ", "Custom ChatGPT Web API Url": "自定义的ChatGPT网页API地址", "Custom ChatGPT Web API Path": "自定义的ChatGPT网页API路径", "Custom OpenAI API Url": "自定义的OpenAI API地址", "Custom Site Regex": "自定义站点正则匹配", "Exclusively use Custom Site Regex for website matching, ignoring built-in rules": "只使用自定义站点正则匹配, 忽略内置站点规则", "Input Query": "输入的查询选择器", "Append Query": "挂载到末尾的查询选择器", "Prepend Query": "插入到开头的查询选择器", "Wechat Pay": "微信打赏", "Type your question here\nEnter to send, shift + enter to break line": "在此输入你的问题\n回车 发送\nshift+回车 换行", "Type your question here\nEnter to stop generating\nShift + enter to break line": "在此输入你的问题\n回车 停止生成\nshift+回车 换行", "Ask ChatGPT": "询问ChatGPT", "No Input Found": "无输入", "You": "你", "Collapse": "折叠", "Expand": "展开", "Stop": "停止", "Continue on official website": "在官网继续", "Error": "错误", "Copy": "复制", "Question": "问题", "Answer": "回答", "Waiting for response...": "等待响应...", "Close the Window": "关闭窗口", "Pin the Window": "固定窗口", "Float the Window": "浮出/分裂窗口", "Save Conversation": "保存对话", "UNAUTHORIZED": "未授权", "Please login at https://chatgpt.com first": "请先登录 https://chatgpt.com", "Please login at https://claude.ai first, and then click the retry button": "请先登录 https://claude.ai, 然后点击重试按钮", "Please login at https://bing.com first": "请先登录 https://bing.com", "Then open https://chatgpt.com/api/auth/session": "然后打开 https://chatgpt.com/api/auth/session", "And refresh this page or type you question again": "之后点击右上角的重试按钮", "Consider creating an api key at https://platform.openai.com/account/api-keys": "考虑在 https://platform.openai.com/account/api-keys 创建一个API Key", "OpenAI Security Check Required": "需要通过OpenAI的安全检查", "Please open https://chatgpt.com/api/auth/session": "请打开 https://chatgpt.com/api/auth/session", "Please open https://chatgpt.com": "请打开 https://chatgpt.com", "New Chat": "新建聊天", "Summarize Page": "总结本页", "Translate": "翻译", "Translate (Bidirectional)": "双向翻译", "Translate (To English)": "翻译为英语", "Translate (To Chinese)": "翻译为中文", "Summary": "总结", "Polish": "润色", "Sentiment Analysis": "情感分析", "Divide Paragraphs": "段落划分", "Code Explain": "代码解释", "Ask": "询问", "Always": "自动触发", "Manually": "手动触发", "When query ends with question mark (?)": "问题以问号结尾时触发", "Light": "浅色", "Dark": "深色", "Auto": "自动", "ChatGPT (Web)": "ChatGPT (网页版)", "ChatGPT (Web, GPT-4)": "ChatGPT (网页版, GPT-4)", "Bing (Web, GPT-4)": "Bing (网页版, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "自定义模型", "Balanced": "平衡", "Creative": "有创造力", "Precise": "精确", "Fast": "快速", "API Key": "API Key", "Model Name": "模型名", "Custom Model API Url": "自定义模型的API地址", "Loading...": "正在读取...", "Feedback": "反馈", "Confirm": "确认", "Clear Conversation": "清理对话", "Retry": "重试", "Exceeded maximum context length": "超出最大上下文长度, 请清理对话并重试", "Regenerate the answer after switching model": "快捷切换模型时自动重新生成回答", "Pin": "固定侧边", "Unpin": "收缩侧边", "Delete Conversation": "删除对话", "Clear conversations": "清空记录", "Settings": "设置", "Feature Pages": "功能页", "Keyboard Shortcuts": "快捷键设置", "Open Conversation Page": "打开独立对话页", "Open Conversation Window": "打开独立对话窗口", "Store to Independent Conversation Page": "收纳到独立对话页", "Keep Conversation Window in Background": "保持对话窗口在后台, 以便在任何程序中使用快捷键呼出", "Max Response Token Length": "响应的最大token长度", "Max Conversation Length": "对话处理的最大长度", "Always pin the floating window": "总是固定浮动窗口", "Export": "导出", "Always Create New Conversation Window": "总是创建新的对话窗口", "Please keep this tab open. You can now use the web mode of ChatGPTBox": "请保持这个页面打开, 现在你可以使用ChatGPTBox的网页版模式", "Go Back": "返回", "Pin Tab": "固定页面", "Modules": "模块", "API Params": "API参数", "API Url": "API地址", "Others": "其他", "API Modes": "API模式", "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time": "禁用网页版模式历史记录以获得更好的隐私保护, 但会导致对话在一段时间后不可用", "Display selection tools next to input box to avoid blocking": "将选择浮动工具显示在输入框旁边以避免遮挡", "Close All Chats In This Page": "关闭本页所有聊天", "When Icon Clicked": "当图标被点击时", "Open Settings": "打开设置", "Focus to input box after answering": "回答结束后自动聚焦到输入框", "Bing CaptchaChallenge": "你必须通过必应的验证, 打开 https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx 并发送一条消息", "Exceeded quota": "余额不足或过期, 检查此链接: https://platform.openai.com/account/usage", "Rate limit": "请求频率过高", "Jump to bottom": "跳转到底部", "Explain": "解释", "Failed to get arkose token.": "获取arkose token失败.", "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.": "请保持 https://chatgpt.com 打开并重试. 如果仍然不起作用, 请在chatgpt网页的输入框中输入一些字符, 然后再试一次.", "Open Side Panel": "打开侧边栏", "Generating...": "正在生成...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "请先登录Kimi: https://kimi.com, 然后点击重试按钮", "Hide context menu of this extension": "隐藏此扩展的右键菜单", "Custom Anthropic API Url": "自定义的Anthropic API地址", "Anthropic API Key": "Anthropic API 密钥", "Cancel": "取消", "Name is required": "名称是必须的", "Prompt template should include {{selection}}": "提示模板应该包含 {{selection}}", "Save": "保存", "Name": "名称", "Icon": "图标", "Prompt Template": "提示模板", "Explain this: {{selection}}": "解释这个: {{selection}}", "New": "新建", "Always display floating window, disable sidebar for all site adapters": "总是显示浮动窗口, 禁用所有站点适配器的侧边栏", "Allow ESC to close all floating windows": "允许按ESC关闭所有浮动窗口", "Export All Data": "导出所有数据", "Import All Data": "导入所有数据", "Keep-Alive Time": "保活时间", "5m": "5分钟", "30m": "半小时", "Forever": "永久", "You have successfully logged in for ChatGPTBox and can now return": "你已成功为ChatGPTBox登录,现在可以返回", "Claude.ai is not available in your region": "Claude.ai 在你的地区不可用", "Claude.ai (Web)": "Claude.ai (网页版)", "Kimi.Moonshot (Web)": "Kimi.Moonshot (网页版)", "Bing (Web)": "必应 (网页版)", "Gemini (Web)": "Gemini (网页版)", "Type": "类型", "Mode": "模式", "Custom": "自定义", "Kimi.Moonshot (Web, 100k)": "Kimi.Moonshot (网页版, 100k)", "ChatGLM (GLM-4-Air, 128k)": "ChatGLM (GLM4Air, 性价比, 128k)", "ChatGLM (GLM-4-0520, 128k)": "ChatGLM (GLM4-0520, 最智能, 128k)", "ChatGLM (Emohaa)": "ChatGLM (Emohaa, 专业情绪咨询)", "ChatGLM (CharGLM-3)": "ChatGLM (CharGLM-3, 角色扮演)", "Crop Text to ensure the input tokens do not exceed the model's limit": "裁剪文本以确保输入token不超过模型限制", "Thinking Content": "思考内容", "OpenAI (API)": "OpenAI (API)", "Anthropic (API)": "Anthropic (API)", "Azure OpenAI (API)": "Azure OpenAI (API)", "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", "Azure OpenAI": "Azure OpenAI", "OpenAI (GPT-5)": "OpenAI (GPT-5)", "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", "OpenAI (GPT-5.4 mini)": "OpenAI (GPT-5.4 mini)", "OpenAI (GPT-5.4 nano)": "OpenAI (GPT-5.4 nano)", "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } ================================================ FILE: src/_locales/zh-hant/main.json ================================================ { "General": "一般", "Selection Tools": "選擇浮動工具", "Sites": "網站適用", "Advanced": "進階", "Donate": "贊助", "Triggers": "觸發方式", "Theme": "主題", "API Mode": "API 模式", "Get": "取得", "Preferred Language": "偏好語言", "Insert ChatGPT at the top of search results": "在搜尋結果頂端插入 ChatGPT 對話卡片", "Lock scrollbar while answering": "回答時鎖定捲軸", "Current Version": "目前版本", "Latest": "最新", "Help | Changelog ": "說明 | 更新日誌", "Custom ChatGPT Web API Url": "自訂 ChatGPT 網頁 API 網址", "Custom ChatGPT Web API Path": "自訂 ChatGPT 網頁 API 路徑", "Custom OpenAI API Url": "自訂 OpenAI API 網址", "Custom Site Regex": "自訂網站正規表達式", "Exclusively use Custom Site Regex for website matching, ignoring built-in rules": "僅使用自訂網站正規表達式進行網站配對,忽略內建規則", "Input Query": "輸入查詢選擇器", "Append Query": "附加查詢選擇器", "Prepend Query": "插入查詢選擇器", "Wechat Pay": "微信支付贊助", "Type your question here\nEnter to send, shift + enter to break line": "在此輸入你的問題\n按 Enter 傳送,Shift + Enter 換行", "Type your question here\nEnter to stop generating\nShift + enter to break line": "在此輸入你的問題\n按 Enter 停止產生,Shift + Enter 換行", "Ask ChatGPT": "詢問 ChatGPT", "No Input Found": "找不到輸入內容", "You": "你", "Collapse": "摺疊", "Expand": "展開", "Stop": "停止", "Continue on official website": "在官方網站繼續", "Error": "錯誤", "Copy": "複製", "Question": "問題", "Answer": "回答", "Waiting for response...": "等待回應中...", "Close the Window": "關閉視窗", "Pin the Window": "釘選視窗", "Float the Window": "浮動視窗", "Save Conversation": "儲存對話", "UNAUTHORIZED": "未授權", "Please login at https://chatgpt.com first": "請先在 https://chatgpt.com 登入", "Please login at https://claude.ai first, and then click the retry button": "請先在 https://claude.ai 登入,然後點擊重試按鈕", "Please login at https://bing.com first": "請先在 https://bing.com 登入", "Then open https://chatgpt.com/api/auth/session": "然後開啟 https://chatgpt.com/api/auth/session", "And refresh this page or type you question again": "接著點擊右上角的「重試」按鈕", "Consider creating an api key at https://platform.openai.com/account/api-keys": "建議在 https://platform.openai.com/account/api-keys 建立一個 API 金鑰", "OpenAI Security Check Required": "需要通過 OpenAI 的安全檢查", "Please open https://chatgpt.com/api/auth/session": "請開啟 https://chatgpt.com/api/auth/session", "Please open https://chatgpt.com": "請開啟 https://chatgpt.com", "New Chat": "新對話", "Summarize Page": "摘要本頁", "Translate": "翻譯", "Translate (Bidirectional)": "雙向翻譯", "Translate (To English)": "翻譯為英文", "Translate (To Chinese)": "翻譯為中文", "Summary": "摘要", "Polish": "潤飾", "Sentiment Analysis": "情感分析", "Divide Paragraphs": "分段", "Code Explain": "程式碼解釋", "Ask": "詢問", "Always": "自動觸發", "Manually": "手動觸發", "When query ends with question mark (?)": "問題以問號結尾時觸發", "Light": "淺色主題", "Dark": "深色主題", "Auto": "自動", "ChatGPT (Web)": "ChatGPT (網頁版)", "ChatGPT (Web, GPT-4)": "ChatGPT (網頁版, GPT-4)", "Bing (Web, GPT-4)": "Bing (網頁版, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "自訂模型", "Balanced": "平衡", "Creative": "有創意", "Precise": "精確", "Fast": "快速", "API Key": "API 金鑰", "Model Name": "模型名稱", "Custom Model API Url": "自訂模型 API 網址", "Loading...": "載入中...", "Feedback": "意見回饋", "Confirm": "確認", "Clear Conversation": "清除對話", "Retry": "重試", "Exceeded maximum context length": "超出最大上下文長度,請清除對話並重試", "Regenerate the answer after switching model": "切換模型後自動重新產生回答", "Pin": "固定側邊", "Unpin": "取消固定側邊", "Delete Conversation": "刪除對話", "Clear conversations": "清空對話記錄", "Settings": "設定", "Feature Pages": "功能頁面", "Keyboard Shortcuts": "快速鍵設定", "Open Conversation Page": "開啟獨立對話頁面", "Open Conversation Window": "開啟獨立對話視窗", "Store to Independent Conversation Page": "收納到獨立對話頁面", "Keep Conversation Window in Background": "保持對話視窗在背景,以便在任何程序中使用快捷鍵呼叫", "Max Response Token Length": "回應的最大 token 長度", "Max Conversation Length": "對話處理的最大長度", "Always pin the floating window": "總是固定浮動視窗", "Export": "匯出", "Always Create New Conversation Window": "總是建立新的對話視窗", "Please keep this tab open. You can now use the web mode of ChatGPTBox": "請保持這個頁面開啟,現在你可以使用 ChatGPTBox 的網頁版模式", "Go Back": "返回", "Pin Tab": "固定頁面", "Modules": "模組", "API Params": "API 參數", "API Url": "API 網址", "Others": "其他", "API Modes": "API 模式", "Disable web mode history for better privacy protection, but it will result in unavailable conversations after a period of time": "停用網頁版模式歷史記錄以提升隱私保護,但會導致對話記錄在一段時間後無法使用", "Display selection tools next to input box to avoid blocking": "將選擇浮動工具顯示在輸入框旁邊以避免遮擋", "Close All Chats In This Page": "關閉本頁所有對話", "When Icon Clicked": "當圖示被點擊時", "Open Settings": "開啟設定", "Focus to input box after answering": "回答結束後自動聚焦到輸入框", "Bing CaptchaChallenge": "你必須通過 Bing 的驗證機制, 打開 https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx 並發送一則訊息", "Exceeded quota": "您已超出目前的使用額度,請至 OpenAI Usage 頁面請確認您的方案和帳單詳細資訊: https://platform.openai.com/account/usage", "Rate limit": "請求太頻繁,超過限制次數", "Jump to bottom": "轉跳至底部", "Explain": "解釋", "Failed to get arkose token.": "無法取得 arkose token.", "Please keep https://chatgpt.com open and try again. If it still doesn't work, type some characters in the input box of chatgpt web page and try again.": "請保持 https://chatgpt.com 開啟並重試,如果還是無法通過驗證,請在 ChatGPT 網頁版輸入框輸入一些文字後再重試", "Open Side Panel": "開啟側邊面板", "Generating...": "產生中...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "需要 moonshot token,請先在 https://kimi.com 登入,然後點擊重試按鈕", "Hide context menu of this extension": "隱藏此擴充功能的右鍵選單", "Custom Anthropic API Url": "自訂 Anthropic API 網址", "Anthropic API Key": "Anthropic API 金鑰", "Cancel": "取消", "Name is required": "名稱是必填的", "Prompt template should include {{selection}}": "提示範本應該包含 {{selection}}", "Save": "儲存", "Name": "名稱", "Icon": "圖示", "Prompt Template": "提示範本", "Explain this: {{selection}}": "解釋這個: {{selection}}", "New": "新增", "Always display floating window, disable sidebar for all site adapters": "總是顯示浮動視窗,停用所有網站適配器的側邊欄", "Allow ESC to close all floating windows": "允許按 ESC 關閉所有浮動視窗", "Export All Data": "匯出所有資料", "Import All Data": "匯入所有資料", "Keep-Alive Time": "保持連線時間", "5m": "5 分鐘", "30m": "30 分鐘", "Forever": "永遠", "You have successfully logged in for ChatGPTBox and can now return": "您已成功為ChatGPTBox登入,現在可以返回", "Claude.ai is not available in your region": "Claude.ai 在您的地區不可用", "Claude.ai (Web)": "Claude.ai (網頁版)", "Kimi.Moonshot (Web)": "Kimi.Moonshot (網頁版)", "Bing (Web)": "Bing (網頁版)", "Gemini (Web)": "Gemini (網頁版)", "Type": "類型", "Mode": "模式", "Custom": "自訂", "Crop Text to ensure the input tokens do not exceed the model's limit": "裁剪文本以確保輸入token不超過模型限制", "Thinking Content": "思考內容", "OpenAI (API)": "OpenAI (API)", "Anthropic (API)": "Anthropic (API)", "Azure OpenAI (API)": "Azure OpenAI (API)", "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", "Azure OpenAI": "Azure OpenAI", "OpenAI (GPT-5)": "OpenAI (GPT-5)", "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", "OpenAI (GPT-5.4 mini)": "OpenAI (GPT-5.4 mini)", "OpenAI (GPT-5.4 nano)": "OpenAI (GPT-5.4 nano)", "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } ================================================ FILE: src/background/commands.mjs ================================================ 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, tab) => { const message = { itemId: command, selectionText: '', useMenuPosition: false, } console.debug('command triggered', message) if (command in menuConfig) { if (menuConfig[command].action) { menuConfig[command].action(true, tab) } 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, }) } } }) } ================================================ FILE: src/background/index.mjs ================================================ import Browser from 'webextension-polyfill' import { deleteConversation, generateAnswersWithChatgptWebApi, sendMessageFeedback, } from '../services/apis/chatgpt-web' import { generateAnswersWithBingWebApi } from '../services/apis/bing-web.mjs' import { generateAnswersWithOpenAiApi, generateAnswersWithGptCompletionApi, } from '../services/apis/openai-api' import { generateAnswersWithCustomApi } from '../services/apis/custom-api.mjs' import { generateAnswersWithOllamaApi } from '../services/apis/ollama-api.mjs' import { generateAnswersWithAzureOpenaiApi } from '../services/apis/azure-openai-api.mjs' import { generateAnswersWithClaudeApi } from '../services/apis/claude-api.mjs' import { generateAnswersWithChatGLMApi } from '../services/apis/chatglm-api.mjs' import { generateAnswersWithWaylaidwandererApi } from '../services/apis/waylaidwanderer-api.mjs' import { generateAnswersWithOpenRouterApi } from '../services/apis/openrouter-api.mjs' import { generateAnswersWithAimlApi } from '../services/apis/aiml-api.mjs' import { defaultConfig, getUserConfig, setUserConfig, isUsingChatgptWebModel, isUsingBingWebModel, isUsingGptCompletionApiModel, isUsingChatgptApiModel, isUsingCustomModel, isUsingOllamaApiModel, isUsingAzureOpenAiApiModel, isUsingClaudeApiModel, isUsingChatGLMApiModel, isUsingGithubThirdPartyApiModel, isUsingGeminiWebModel, isUsingClaudeWebModel, isUsingMoonshotApiModel, isUsingMoonshotWebModel, isUsingOpenRouterApiModel, isUsingAimlApiModel, isUsingDeepSeekApiModel, } from '../config/index.mjs' import '../_locales/i18n' import { openUrl } from '../utils/open-url' import { getBardCookies, getBingAccessToken, getChatGptAccessToken, getClaudeSessionKey, registerPortListener, } from '../services/wrappers.mjs' import { refreshMenu } from './menus.mjs' import { registerCommands } from './commands.mjs' import { generateAnswersWithBardWebApi } from '../services/apis/bard-web.mjs' import { generateAnswersWithClaudeWebApi } from '../services/apis/claude-web.mjs' import { generateAnswersWithMoonshotCompletionApi } from '../services/apis/moonshot-api.mjs' import { generateAnswersWithMoonshotWebApi } from '../services/apis/moonshot-web.mjs' import { isUsingModelName } from '../utils/model-name-convert.mjs' import { generateAnswersWithDeepSeekApi } from '../services/apis/deepseek-api.mjs' import { redactSensitiveFields } from './redact.mjs' const RECONNECT_CONFIG = { MAX_ATTEMPTS: 5, BASE_DELAY_MS: 1000, // Base delay in milliseconds BACKOFF_MULTIPLIER: 2, // Multiplier for exponential backoff STABLE_CONNECT_RESET_DELAY_MS: 3000, // Reset retries only after connection stays stable } function setPortProxy(port, proxyTabId) { try { console.debug(`[background] Attempting to connect to proxy tab: ${proxyTabId}`) if (port._reconnectTimerId) { clearTimeout(port._reconnectTimerId) port._reconnectTimerId = null } if (port._reconnectStabilityTimerId) { clearTimeout(port._reconnectStabilityTimerId) port._reconnectStabilityTimerId = null } if (port.proxy) { const previousProxy = port.proxy try { if (port._proxyOnMessage) previousProxy.onMessage.removeListener(port._proxyOnMessage) if (port._proxyOnDisconnect) { previousProxy.onDisconnect.removeListener(port._proxyOnDisconnect) } } catch (e) { console.warn( '[background] Error removing old listeners from previous port.proxy instance:', e, ) } try { if (typeof previousProxy.disconnect === 'function') { previousProxy.disconnect() } } catch (e) { console.warn('[background] Error disconnecting previous port.proxy instance:', e) } finally { port.proxy = null port._proxyTabId = null } } if (port._portOnMessage) port.onMessage.removeListener(port._portOnMessage) if (port._portOnDisconnect) port.onDisconnect.removeListener(port._portOnDisconnect) port.proxy = Browser.tabs.connect(proxyTabId, { name: 'background-to-content-script-proxy' }) port._proxyTabId = proxyTabId port._isClosed = false console.debug(`[background] Successfully connected to proxy tab: ${proxyTabId}`) port._proxyOnMessage = (msg) => { const redactedMsg = redactSensitiveFields(msg) console.debug('[background] Message from proxy tab (redacted):', redactedMsg) if (port._reconnectAttempts) { port._reconnectAttempts = 0 console.debug('[background] Reset reconnect attempts after successful proxy message.') } if (port._isClosed) { console.debug('[background] Main port closed; skipping proxy message.') return } try { port.postMessage(msg) } catch (e) { console.warn('[background] Failed to post message to main port (likely disconnected):', e) } } port._portOnMessage = (msg) => { if (msg?.session && !msg?.stop) { console.debug('[background] Session message handled by executeApi; skipping proxy forward.') return } const redactedMsg = redactSensitiveFields(msg) console.debug('[background] Message to proxy tab (redacted):', redactedMsg) if (port.proxy) { try { port.proxy.postMessage(msg) } catch (e) { console.error( '[background] Error posting message to proxy tab in _portOnMessage:', e, redactedMsg, ) try { // Attempt to notify the original sender about the failure port.postMessage({ error: 'Failed to forward message to target tab. Tab might be closed or an extension error occurred.', }) } catch (notifyError) { console.error( '[background] Error sending forwarding failure notification back to original sender:', notifyError, ) } } } else { console.warn('[background] Port proxy not available to send message:', redactedMsg) } } port._proxyOnDisconnect = () => { console.warn(`[background] Proxy tab ${proxyTabId} disconnected.`) const proxyRef = port.proxy port.proxy = null port._proxyTabId = null if (port._reconnectTimerId) { clearTimeout(port._reconnectTimerId) port._reconnectTimerId = null } if (port._reconnectStabilityTimerId) { clearTimeout(port._reconnectStabilityTimerId) port._reconnectStabilityTimerId = null } if (proxyRef) { if (port._proxyOnMessage) { try { proxyRef.onMessage.removeListener(port._proxyOnMessage) } catch (e) { console.warn( '[background] Error removing _proxyOnMessage from disconnected proxyRef:', e, ) } } if (port._proxyOnDisconnect) { try { proxyRef.onDisconnect.removeListener(port._proxyOnDisconnect) } catch (e) { console.warn( '[background] Error removing _proxyOnDisconnect from disconnected proxyRef:', e, ) } } } port._reconnectAttempts = (port._reconnectAttempts || 0) + 1 if (port._reconnectAttempts >= RECONNECT_CONFIG.MAX_ATTEMPTS) { console.error( `[background] Max reconnect attempts (${RECONNECT_CONFIG.MAX_ATTEMPTS}) reached for tab ${proxyTabId}. Giving up.`, ) if (port._portOnMessage) { try { port.onMessage.removeListener(port._portOnMessage) } catch (e) { console.warn('[background] Error removing _portOnMessage on max retries:', e) } } if (port._portOnDisconnect) { try { port.onDisconnect.removeListener(port._portOnDisconnect) } catch (e) { console.warn('[background] Error removing _portOnDisconnect on max retries:', e) } } try { port.postMessage({ error: `Connection to ChatGPT tab lost after ${RECONNECT_CONFIG.MAX_ATTEMPTS} attempts. Please refresh the page.`, }) } catch (e) { console.warn('[background] Error sending final error message on max retries:', e) } return } const delay = Math.pow(RECONNECT_CONFIG.BACKOFF_MULTIPLIER, port._reconnectAttempts - 1) * RECONNECT_CONFIG.BASE_DELAY_MS console.log( `[background] Attempting reconnect #${port._reconnectAttempts} in ${ delay / 1000 }s for tab ${proxyTabId}.`, ) port._reconnectTimerId = setTimeout(async () => { if (port._isClosed) { console.debug('[background] Main port closed; skipping proxy reconnect.') return } port._reconnectTimerId = null try { await Browser.tabs.get(proxyTabId) } catch (error) { console.warn( `[background] Proxy tab ${proxyTabId} no longer exists. Aborting reconnect.`, error, ) return } console.debug( `[background] Retrying connection to tab ${proxyTabId}, attempt ${port._reconnectAttempts}.`, ) try { setPortProxy(port, proxyTabId) } catch (error) { console.warn(`[background] Error reconnecting to tab ${proxyTabId}:`, error) } }, delay) } port._portOnDisconnect = () => { console.log( '[background] Main port disconnected (e.g. popup/sidebar closed). Cleaning up proxy connections and listeners.', ) port._isClosed = true if (port._reconnectTimerId) { clearTimeout(port._reconnectTimerId) port._reconnectTimerId = null } if (port._reconnectStabilityTimerId) { clearTimeout(port._reconnectStabilityTimerId) port._reconnectStabilityTimerId = null } if (port._portOnMessage) { try { port.onMessage.removeListener(port._portOnMessage) } catch (e) { console.warn('[background] Error removing _portOnMessage on main port disconnect:', e) } } const proxyRef = port.proxy if (proxyRef) { if (port._proxyOnMessage) { try { proxyRef.onMessage.removeListener(port._proxyOnMessage) } catch (e) { console.warn( '[background] Error removing _proxyOnMessage from proxyRef on main port disconnect:', e, ) } } if (port._proxyOnDisconnect) { try { proxyRef.onDisconnect.removeListener(port._proxyOnDisconnect) } catch (e) { console.warn( '[background] Error removing _proxyOnDisconnect from proxyRef on main port disconnect:', e, ) } } try { proxyRef.disconnect() } catch (e) { console.warn('[background] Error disconnecting proxyRef on main port disconnect:', e) } port.proxy = null port._proxyTabId = null } if (port._portOnDisconnect) { try { port.onDisconnect.removeListener(port._portOnDisconnect) } catch (e) { console.warn('[background] Error removing _portOnDisconnect on main port disconnect:', e) } } port._reconnectAttempts = 0 } port.proxy.onMessage.addListener(port._proxyOnMessage) port.onMessage.addListener(port._portOnMessage) port.proxy.onDisconnect.addListener(port._proxyOnDisconnect) port.onDisconnect.addListener(port._portOnDisconnect) // A connect() call can succeed and then disconnect immediately if the tab isn't ready. // Only reset retries after the new proxy remains connected for a short stable window. const connectedProxy = port.proxy port._reconnectStabilityTimerId = setTimeout(() => { port._reconnectStabilityTimerId = null if (port._isClosed || port.proxy !== connectedProxy) { return } if (port._reconnectAttempts) { port._reconnectAttempts = 0 console.debug('[background] Reset reconnect attempts after stable proxy connection.') } }, RECONNECT_CONFIG.STABLE_CONNECT_RESET_DELAY_MS) } catch (error) { console.error(`[background] Error in setPortProxy for tab ${proxyTabId}:`, error) } } async function executeApi(session, port, config) { console.log( `[background] executeApi called for model: ${session.modelName}, apiMode: ${session.apiMode}`, ) const redactedSession = redactSensitiveFields(session) const redactedConfig = redactSensitiveFields(config) console.debug('[background] Full session details (redacted):', redactedSession) console.debug('[background] Full config details (redacted):', redactedConfig) if (session.apiMode) { console.debug( '[background] Session apiMode details (redacted):', redactSensitiveFields(session.apiMode), ) } try { if (isUsingCustomModel(session)) { console.debug('[background] Using Custom Model API') if (!session.apiMode) await generateAnswersWithCustomApi( port, session.question, session, config.customModelApiUrl.trim() || 'http://localhost:8000/v1/chat/completions', config.customApiKey, config.customModelName, ) else await generateAnswersWithCustomApi( port, session.question, session, session.apiMode.customUrl?.trim() || config.customModelApiUrl.trim() || 'http://localhost:8000/v1/chat/completions', session.apiMode.apiKey?.trim() || config.customApiKey, session.apiMode.customName, ) } else if (isUsingChatgptWebModel(session)) { console.debug('[background] Using ChatGPT Web Model') let tabId if ( config.chatgptTabId && config.customChatGptWebApiUrl === defaultConfig.customChatGptWebApiUrl ) { try { const tab = await Browser.tabs.get(config.chatgptTabId) if (tab) tabId = tab.id } catch (e) { console.warn( `[background] Failed to get ChatGPT tab with ID ${config.chatgptTabId}:`, e.message, ) } } if (tabId) { console.debug(`[background] ChatGPT Tab ID ${tabId} found.`) const hasMatchingProxy = Boolean(port.proxy && port._proxyTabId === tabId) if (!hasMatchingProxy) { if (port.proxy) { console.debug( `[background] Existing proxy tab ${port._proxyTabId} does not match ${tabId}; reconnecting.`, ) } else { console.debug('[background] port.proxy not found, calling setPortProxy.') } setPortProxy(port, tabId) } if (port.proxy && port._proxyTabId === tabId) { if (hasMatchingProxy) { console.debug('[background] Proxy already established; forwarding session.') } console.debug('[background] Posting message to proxy tab:', { session: redactedSession }) try { port.proxy.postMessage({ session }) } catch (e) { console.warn( '[background] Error posting message to existing proxy tab in executeApi (ChatGPT Web Model):', e, '. Attempting to reconnect.', { session: redactedSession }, ) setPortProxy(port, tabId) if (port.proxy) { console.debug('[background] Proxy re-established. Attempting to post message again.') try { port.proxy.postMessage({ session }) console.info('[background] Successfully posted session after proxy reconnection.') } catch (e2) { console.error( '[background] Error posting message even after proxy reconnection:', e2, { session: redactedSession }, ) try { port.postMessage({ error: 'Failed to communicate with ChatGPT tab after reconnection attempt. Try refreshing the page.', }) } catch (notifyError) { console.error( '[background] Error sending final communication failure notification back:', notifyError, ) } } } else { console.error( '[background] Failed to re-establish proxy connection. Cannot send session.', ) try { port.postMessage({ error: 'Could not re-establish connection to ChatGPT tab. Try refreshing the page.', }) } catch (notifyError) { console.error( '[background] Error sending re-establishment failure notification back:', notifyError, ) } } } } else { console.error( '[background] Failed to send message: port.proxy is still not available after initial setPortProxy attempt.', ) try { port.postMessage({ error: 'Failed to initialize connection to ChatGPT tab. Try refreshing the page.', }) } catch (notifyError) { console.error( '[background] Error sending initial connection failure notification back:', notifyError, ) } } } else { console.debug('[background] No valid ChatGPT Tab ID found. Using direct API call.') const accessToken = await getChatGptAccessToken() await generateAnswersWithChatgptWebApi(port, session.question, session, accessToken) } } else if (isUsingClaudeWebModel(session)) { console.debug('[background] Using Claude Web Model') const sessionKey = await getClaudeSessionKey() await generateAnswersWithClaudeWebApi(port, session.question, session, sessionKey) } else if (isUsingMoonshotWebModel(session)) { console.debug('[background] Using Moonshot Web Model') await generateAnswersWithMoonshotWebApi(port, session.question, session, config) } else if (isUsingBingWebModel(session)) { console.debug('[background] Using Bing Web Model') const accessToken = await getBingAccessToken() if (isUsingModelName('bingFreeSydney', session)) { console.debug('[background] Using Bing Free Sydney model') await generateAnswersWithBingWebApi(port, session.question, session, accessToken, true) } else { await generateAnswersWithBingWebApi(port, session.question, session, accessToken) } } else if (isUsingGeminiWebModel(session)) { console.debug('[background] Using Gemini Web Model') const cookies = await getBardCookies() await generateAnswersWithBardWebApi(port, session.question, session, cookies) } else if (isUsingChatgptApiModel(session)) { console.debug('[background] Using OpenAI API Model') await generateAnswersWithOpenAiApi(port, session.question, session, config.apiKey) } else if (isUsingClaudeApiModel(session)) { console.debug('[background] Using Anthropic API Model') await generateAnswersWithClaudeApi(port, session.question, session) } else if (isUsingMoonshotApiModel(session)) { console.debug('[background] Using Moonshot API Model') await generateAnswersWithMoonshotCompletionApi( port, session.question, session, config.moonshotApiKey, ) } else if (isUsingChatGLMApiModel(session)) { console.debug('[background] Using ChatGLM API Model') await generateAnswersWithChatGLMApi(port, session.question, session) } else if (isUsingDeepSeekApiModel(session)) { console.debug('[background] Using DeepSeek API Model') await generateAnswersWithDeepSeekApi(port, session.question, session, config.deepSeekApiKey) } else if (isUsingOllamaApiModel(session)) { console.debug('[background] Using Ollama API Model') await generateAnswersWithOllamaApi(port, session.question, session) } else if (isUsingOpenRouterApiModel(session)) { console.debug('[background] Using OpenRouter API Model') await generateAnswersWithOpenRouterApi( port, session.question, session, config.openRouterApiKey, ) } else if (isUsingAimlApiModel(session)) { console.debug('[background] Using AIML API Model') await generateAnswersWithAimlApi(port, session.question, session, config.aimlApiKey) } else if (isUsingAzureOpenAiApiModel(session)) { console.debug('[background] Using Azure OpenAI API Model') await generateAnswersWithAzureOpenaiApi(port, session.question, session) } else if (isUsingGptCompletionApiModel(session)) { console.debug('[background] Using GPT Completion API Model') await generateAnswersWithGptCompletionApi(port, session.question, session, config.apiKey) } else if (isUsingGithubThirdPartyApiModel(session)) { console.debug('[background] Using Github Third Party API Model') await generateAnswersWithWaylaidwandererApi(port, session.question, session) } else { console.warn('[background] Unknown model or session configuration:', redactedSession) port.postMessage({ error: 'Unknown model configuration' }) } } catch (error) { console.error(`[background] Error in executeApi for model ${session.modelName}:`, error) throw error } } Browser.runtime.onMessage.addListener(async (message, sender) => { console.debug('[background] Received message type:', message?.type, 'from sender:', sender?.id) try { switch (message.type) { case 'FEEDBACK': { console.log('[background] Processing FEEDBACK message') const token = await getChatGptAccessToken() await sendMessageFeedback(token, message.data) break } case 'DELETE_CONVERSATION': { console.log('[background] Processing DELETE_CONVERSATION message') const token = await getChatGptAccessToken() await deleteConversation(token, message.data.conversationId) break } case 'NEW_URL': { console.log('[background] Processing NEW_URL message:', message.data) await Browser.tabs.create({ url: message.data.url, pinned: message.data.pinned, }) if (message.data.jumpBack) { const jumpBackTabId = sender.tab?.id if (!jumpBackTabId) { console.warn('[background] NEW_URL jumpBack missing sender tab id:', sender) return null } console.debug('[background] Setting jumpBackTabId:', jumpBackTabId) await setUserConfig({ notificationJumpBackTabId: jumpBackTabId, }) } break } case 'SET_CHATGPT_TAB': { const chatgptTabId = sender.tab?.id console.log('[background] Processing SET_CHATGPT_TAB message. Tab ID:', chatgptTabId) if (!chatgptTabId) { console.warn('[background] SET_CHATGPT_TAB missing sender tab id:', sender) break } await setUserConfig({ chatgptTabId, }) break } case 'ACTIVATE_URL': console.log('[background] Processing ACTIVATE_URL message:', message.data) await Browser.tabs.update(message.data.tabId, { active: true }) break case 'OPEN_URL': console.log('[background] Processing OPEN_URL message:', message.data) openUrl(message.data.url) break case 'OPEN_CHAT_WINDOW': { console.log('[background] Processing OPEN_CHAT_WINDOW message') const config = await getUserConfig() const url = Browser.runtime.getURL('IndependentPanel.html') const tabs = await Browser.tabs.query({ url: url, windowType: 'popup' }) if (!config.alwaysCreateNewConversationWindow && tabs.length > 0) { console.debug('[background] Focusing existing chat window:', tabs[0].windowId) await Browser.windows.update(tabs[0].windowId, { focused: true }) } else { console.debug('[background] Creating new chat window.') await Browser.windows.create({ url: url, type: 'popup', width: 500, height: 650, }) } break } case 'REFRESH_MENU': console.log('[background] Processing REFRESH_MENU message') refreshMenu() break case 'PIN_TAB': { console.log('[background] Processing PIN_TAB message:', message.data) const data = message.data ?? {} let tabId = data.tabId ?? sender.tab?.id if (tabId) { await Browser.tabs.update(tabId, { pinned: true }) if (data.saveAsChatgptConfig) { console.debug('[background] Saving pinned tab as ChatGPT config tab:', tabId) await setUserConfig({ chatgptTabId: tabId }) } } else { console.warn('[background] No tabId found for PIN_TAB message.') } break } case 'FETCH': { const senderId = sender?.id const senderUrl = sender?.url || sender?.documentUrl || sender?.origin const extensionOrigin = new URL(Browser.runtime.getURL('/')).origin const isTrustedExtensionSenderWithoutId = !senderId && typeof senderUrl === 'string' && senderUrl.startsWith(`${extensionOrigin}/`) if (senderId !== Browser.runtime.id && !isTrustedExtensionSenderWithoutId) { console.warn('[background] Rejecting FETCH message from untrusted sender:', sender) return [null, { message: 'Unauthorized sender' }] } const fetchInput = message.data?.input instanceof URL ? message.data.input.toString() : message.data?.input if (typeof fetchInput !== 'string') { console.warn('[background] Invalid FETCH input:', message.data?.input) return [null, { message: 'Invalid fetch input' }] } let validatedUrl try { const url = new URL(fetchInput) if (url.protocol !== 'https:' && url.protocol !== 'http:') { console.warn('[background] Rejecting FETCH for non-http(s) URL:', fetchInput) return [null, { message: 'Unsupported fetch protocol' }] } validatedUrl = url.toString() } catch (error) { console.warn('[background] Invalid FETCH input URL:', fetchInput, error) return [null, { message: 'Invalid fetch URL' }] } console.log('[background] Processing FETCH message for URL:', validatedUrl) if (validatedUrl.includes('bing.com')) { console.debug('[background] Fetching Bing access token for FETCH message.') const accessToken = await getBingAccessToken() await setUserConfig({ bingAccessToken: accessToken }) } try { const response = await fetch(validatedUrl, message.data?.init) const text = await response.text() const responseObject = { // Defined for clarity before conditional error property body: text, ok: response.ok, status: response.status, statusText: response.statusText, headers: Object.fromEntries(response.headers), } if (!response.ok) { responseObject.error = `HTTP error ${response.status}: ${response.statusText}` console.warn( `[background] FETCH received error status: ${response.status} for ${validatedUrl}`, ) } console.debug( `[background] FETCH successful for ${validatedUrl}, status: ${response.status}`, ) return [responseObject, null] } catch (error) { console.error(`[background] FETCH error for ${validatedUrl}:`, error) return [null, { message: error.message }] } } case 'GET_COOKIE': { const senderId = sender?.id if (!senderId || senderId !== Browser.runtime.id) { console.warn('[background] Rejecting GET_COOKIE message from untrusted sender:', sender) return null } const cookieUrlInput = message?.data?.url const cookieNameInput = message?.data?.name if ( typeof cookieUrlInput !== 'string' || !cookieUrlInput.trim() || typeof cookieNameInput !== 'string' || !cookieNameInput.trim() ) { console.warn('[background] Rejecting GET_COOKIE with invalid payload:', message.data) return null } let cookieUrl try { cookieUrl = new URL(cookieUrlInput.trim()) } catch (error) { console.warn('[background] Rejecting GET_COOKIE with invalid URL:', cookieUrlInput) return null } if (cookieUrl.protocol !== 'http:' && cookieUrl.protocol !== 'https:') { console.warn( '[background] Rejecting GET_COOKIE with disallowed protocol:', cookieUrl.protocol, ) return null } const cookieName = cookieNameInput.trim() console.debug('[background] Processing GET_COOKIE message for:', cookieUrl.href) try { const cookie = await Browser.cookies.get({ url: cookieUrl.href, name: cookieName, }) console.debug('[background] Cookie found:', cookie ? 'yes' : 'no') return cookie?.value } catch (error) { console.error( `[background] Error getting cookie ${cookieName} for ${cookieUrl.href}:`, error, ) return null } } default: console.warn('[background] Unknown message type received:', message.type) } } catch (error) { console.error( `[background] Error processing message type ${message.type}:`, error, 'Original message:', message, ) if (message.type === 'FETCH') { return [null, { message: error.message }] } } }) try { Browser.webRequest.onBeforeRequest.addListener( (details) => { try { console.debug('[background] onBeforeRequest triggered for URL:', details.url) if ( details.url.includes('/public_key') && !details.url.includes(defaultConfig.chatgptArkoseReqParams) ) { console.log('[background] Capturing Arkose public_key request:', details.url) let formData = new URLSearchParams() if (details.requestBody?.formData) { for (const k in details.requestBody.formData) { const values = details.requestBody.formData[k] if (Array.isArray(values)) { for (const value of values) { formData.append(k, value) } } else if (values != null) { formData.append(k, values) } } } const formString = formData.toString() || (details.requestBody?.raw?.[0]?.bytes ? new TextDecoder('utf-8').decode(new Uint8Array(details.requestBody.raw[0].bytes)) : '') if (!formString) { console.warn( '[background] Arkose request captured without body; skipping config update.', ) return } setUserConfig({ chatgptArkoseReqUrl: details.url, chatgptArkoseReqForm: formString, }) .then(() => { console.log('[background] Arkose req url and form saved successfully.') }) .catch((e) => console.error('[background] Error saving Arkose req url and form:', e)) } } catch (error) { console.error('[background] Error in onBeforeRequest listener callback:', error, details) } }, { urls: ['https://*.openai.com/*', 'https://*.chatgpt.com/*'], types: ['xmlhttprequest'], }, ['requestBody'], ) Browser.webRequest.onBeforeSendHeaders.addListener( (details) => { try { console.debug('[background] onBeforeSendHeaders triggered for URL:', details.url) const headers = details.requestHeaders let modified = false for (let i = 0; i < headers.length; i++) { const header = headers[i] if (!header || !header.name) { continue } const headerNameLower = header.name.toLowerCase() if (headerNameLower === 'origin') { header.value = 'https://www.bing.com' modified = true } else if (headerNameLower === 'referer') { header.value = 'https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx' modified = true } } if (modified) { console.debug( '[background] Modified headers for Bing (names only):', headers.map((header) => header?.name).filter(Boolean), ) } return { requestHeaders: headers } } catch (error) { console.error( '[background] Error in onBeforeSendHeaders listener callback:', error, details, ) return { requestHeaders: details.requestHeaders } } }, { urls: ['wss://sydney.bing.com/*', 'https://www.bing.com/*'], types: ['xmlhttprequest', 'websocket'], }, ['requestHeaders', ...(Browser.runtime.getManifest().manifest_version < 3 ? ['blocking'] : [])], ) Browser.webRequest.onBeforeSendHeaders.addListener( (details) => { const headers = details.requestHeaders for (let i = 0; i < headers.length; i++) { const header = headers[i] if (!header || !header.name) { continue } const headerNameLower = header.name.toLowerCase() if (headerNameLower === 'origin') { header.value = 'https://claude.ai' } else if (headerNameLower === 'referer') { header.value = 'https://claude.ai' } } return { requestHeaders: headers } }, { urls: ['https://claude.ai/*'], types: ['xmlhttprequest'], }, ['requestHeaders', ...(Browser.runtime.getManifest().manifest_version < 3 ? ['blocking'] : [])], ) Browser.tabs.onUpdated.addListener(async (tabId, info, tab) => { const outerTryCatchError = (error) => { console.error( '[background] Error in tabs.onUpdated listener callback (outer):', error, tabId, info, ) } try { if (!tab.url) { console.debug( `[background] Skipping side panel update for tabId: ${tabId}. Tab URL: ${tab.url}, Info Status: ${info.status}`, ) return } console.debug( `[background] tabs.onUpdated event for tabId: ${tabId}, status: ${info.status}, url: ${tab.url}. Proceeding with side panel update.`, ) let sidePanelSet = false try { if (Browser.sidePanel && typeof Browser.sidePanel.setOptions === 'function') { await Browser.sidePanel.setOptions({ tabId, path: 'IndependentPanel.html', enabled: true, }) console.debug( `[background] Side panel options set for tab ${tabId} using Browser.sidePanel`, ) sidePanelSet = true } } catch (browserError) { console.warn('[background] Browser.sidePanel.setOptions failed:', browserError.message) } if (!sidePanelSet) { console.debug('[background] Attempting chrome.sidePanel.setOptions as fallback.') const chromeApi = globalThis.chrome if (chromeApi?.sidePanel && typeof chromeApi.sidePanel.setOptions === 'function') { try { await chromeApi.sidePanel.setOptions({ tabId, path: 'IndependentPanel.html', enabled: true, }) console.debug( `[background] Side panel options set for tab ${tabId} using chrome.sidePanel`, ) sidePanelSet = true } catch (chromeError) { console.error( '[background] chrome.sidePanel.setOptions also failed:', chromeError.message, ) } } } if (!sidePanelSet) { console.warn( '[background] SidePanel API (Browser.sidePanel or chrome.sidePanel) not available or setOptions failed in this browser. Side panel options not set for tab:', tabId, ) } } catch (error) { outerTryCatchError(error) } }) } catch (error) { console.error('[background] Error setting up webRequest or tabs listeners:', error) } try { registerPortListener(async (session, port, config) => { console.debug( `[background] Port listener triggered for session: ${session.modelName}, port: ${port.name}`, ) await executeApi(session, port, config) }) console.log('[background] Port listener registered successfully.') } catch (error) { console.error('[background] Error registering port listener:', error) } try { registerCommands() console.log('[background] Commands registered successfully.') } catch (error) { console.error('[background] Error registering commands:', error) } try { refreshMenu() console.log('[background] Menu refreshed successfully.') } catch (error) { console.error('[background] Error refreshing menu:', error) } ================================================ FILE: src/background/menus.mjs ================================================ import Browser from 'webextension-polyfill' import { defaultConfig, getPreferredLanguageKey, getUserConfig } from '../config/index.mjs' import { changeLanguage, t } from 'i18next' import { config as menuConfig } from '../content-script/menu-tools/index.mjs' const menuId = 'ChatGPTBox-Menu' const onClickMenu = (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(true, tab) } if (menuConfig[message.itemId].genPrompt) { Browser.tabs.sendMessage(currentTab.id, { type: 'CREATE_CHAT', data: message, }) } } }) } export function refreshMenu() { if (Browser.contextMenus.onClicked.hasListener(onClickMenu)) Browser.contextMenus.onClicked.removeListener(onClickMenu) Browser.contextMenus.removeAll().then(async () => { if ((await getUserConfig()).hideContextMenu) return await getPreferredLanguageKey().then((lang) => { changeLanguage(lang) }) 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(onClickMenu) }) } ================================================ FILE: src/background/redact.mjs ================================================ const SENSITIVE_KEYWORDS = [ 'apikey', // Covers apiKey, customApiKey, claudeApiKey, etc. 'token', // Covers accessToken, refreshToken, etc. 'secret', 'password', 'kimimoonshotrefreshtoken', 'credential', 'jwt', 'session', ] export function isPromptOrSelectionLikeKey(lowerKey) { lowerKey = lowerKey.toLowerCase() const normalizedKey = lowerKey.replace(/[^a-z0-9]/g, '') return ( normalizedKey.endsWith('question') || normalizedKey.endsWith('prompt') || normalizedKey.endsWith('query') || normalizedKey === 'selection' || normalizedKey === 'selectiontext' ) } export function redactSensitiveFields(obj, recursionDepth = 0, maxDepth = 5, seen = new WeakSet()) { if (recursionDepth > maxDepth) { // Prevent infinite recursion on circular objects or excessively deep structures return 'REDACTED_TOO_DEEP' } if (obj === null || typeof obj !== 'object') { return obj } if (seen.has(obj)) { return 'REDACTED_CIRCULAR_REFERENCE' } seen.add(obj) if (Array.isArray(obj)) { const redactedArray = [] for (let i = 0; i < obj.length; i++) { const item = obj[i] if (item !== null && typeof item === 'object') { redactedArray[i] = redactSensitiveFields(item, recursionDepth + 1, maxDepth, seen) } else { redactedArray[i] = item } } return redactedArray } const redactedObj = {} for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { const lowerKey = key.toLowerCase() let isKeySensitive = isPromptOrSelectionLikeKey(lowerKey) if (!isKeySensitive) { for (const keyword of SENSITIVE_KEYWORDS) { if (lowerKey.includes(keyword)) { isKeySensitive = true break } } } if (isKeySensitive) { redactedObj[key] = 'REDACTED' } else if (obj[key] !== null && typeof obj[key] === 'object') { redactedObj[key] = redactSensitiveFields(obj[key], recursionDepth + 1, maxDepth, seen) } else { redactedObj[key] = obj[key] } } } return redactedObj } ================================================ FILE: src/components/ConfirmButton/index.jsx ================================================ import { useTranslation } from 'react-i18next' import { useEffect, useRef, useState } from 'react' import PropTypes from 'prop-types' ConfirmButton.propTypes = { onConfirm: PropTypes.func.isRequired, text: PropTypes.string.isRequired, } function ConfirmButton({ onConfirm, text }) { const { t } = useTranslation() const [waitConfirm, setWaitConfirm] = useState(false) const confirmRef = useRef(null) useEffect(() => { if (waitConfirm) confirmRef.current.focus() }, [waitConfirm]) return ( ) } export default ConfirmButton ================================================ FILE: src/components/ConversationCard/index.jsx ================================================ import { memo, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' import PropTypes from 'prop-types' import Browser from 'webextension-polyfill' import InputBox from '../InputBox' import ConversationItem from '../ConversationItem' import { apiModeToModelName, createElementAtPosition, getApiModesFromConfig, isApiModeSelected, isFirefox, isMobile, isSafari, isUsingModelName, modelNameToDesc, } from '../../utils' import { ArchiveIcon, DesktopDownloadIcon, LinkExternalIcon, MoveToBottomIcon, SearchIcon, } from '@primer/octicons-react' import { Pin, WindowDesktop, XLg } from 'react-bootstrap-icons' import FileSaver from 'file-saver' import { render } from 'preact' import FloatingToolbar from '../FloatingToolbar' import { useClampWindowSize } from '../../hooks/use-clamp-window-size' import { getUserConfig, isUsingBingWebModel, Models } from '../../config/index.mjs' import { useTranslation } from 'react-i18next' import DeleteButton from '../DeleteButton' import { useConfig } from '../../hooks/use-config.mjs' import { createSession } from '../../services/local-session.mjs' import { v4 as uuidv4 } from 'uuid' import { initSession } from '../../services/init-session.mjs' import { findLastIndex } from 'lodash-es' import { generateAnswersWithBingWebApi } from '../../services/apis/bing-web.mjs' import { handlePortError } from '../../services/wrappers.mjs' const logo = Browser.runtime.getURL('logo.png') class ConversationItemData extends Object { /** * @param {'question'|'answer'|'error'} type * @param {string} content * @param {bool} done */ constructor(type, content, done = false) { super() this.type = type this.content = content this.done = done } } function ConversationCard(props) { const { t } = useTranslation() const [isReady, setIsReady] = useState(!props.question) const [port, setPort] = useState(() => Browser.runtime.connect()) const [triggered, setTriggered] = useState(!props.waitForTrigger) const [session, setSession] = useState(props.session) const windowSize = useClampWindowSize([750, 1500], [250, 1100]) const bodyRef = useRef(null) const [completeDraggable, setCompleteDraggable] = useState(false) const useForegroundFetch = isUsingBingWebModel(session) const [apiModes, setApiModes] = useState([]) /** * @type {[ConversationItemData[], (conversationItemData: ConversationItemData[]) => void]} */ const [conversationItemData, setConversationItemData] = useState([]) const config = useConfig() useLayoutEffect(() => { if (session.conversationRecords.length === 0) { if (props.question && triggered) setConversationItemData([ new ConversationItemData( 'answer', `

${t(`Waiting for response...`)}

`, ), ]) } else { const ret = [] for (const record of session.conversationRecords) { ret.push(new ConversationItemData('question', record.question, true)) ret.push(new ConversationItemData('answer', record.answer, true)) } setConversationItemData(ret) } }, []) useEffect(() => { setCompleteDraggable(!isSafari() && !isFirefox() && !isMobile()) }, []) useEffect(() => { if (props.onUpdate) props.onUpdate(port, session, conversationItemData) }, [session, conversationItemData]) useEffect(() => { const { offsetHeight, scrollHeight, scrollTop } = bodyRef.current if ( config.lockWhenAnswer && scrollHeight <= scrollTop + offsetHeight + config.answerScrollMargin ) { bodyRef.current.scrollTo({ top: scrollHeight, behavior: 'instant', }) } }, [conversationItemData]) useEffect(async () => { // when the page is responsive, session may accumulate redundant data and needs to be cleared after remounting and before making a new request if (props.question && triggered) { const newSession = initSession({ ...session, question: props.question }) setSession(newSession) await postMessage({ session: newSession }) } }, [props.question, triggered]) // usually only triggered once useLayoutEffect(() => { setApiModes(getApiModesFromConfig(config, true)) }, [ config.activeApiModes, config.customApiModes, config.azureDeploymentName, config.ollamaModelName, ]) /** * @param {string} value * @param {boolean} appended * @param {'question'|'answer'|'error'} newType * @param {boolean} done */ const updateAnswer = (value, appended, newType, done = false) => { setConversationItemData((old) => { const copy = [...old] const index = findLastIndex(copy, (v) => v.type === 'answer' || v.type === 'error') if (index === -1) return copy copy[index] = new ConversationItemData( newType, appended ? copy[index].content + value : value, ) copy[index].done = done return copy }) } const portMessageListener = (msg) => { if (msg.answer) { updateAnswer(msg.answer, false, 'answer') } if (msg.session) { if (msg.done) msg.session = { ...msg.session, isRetry: false } setSession(msg.session) } if (msg.done) { updateAnswer('', true, 'answer', true) setIsReady(true) } if (msg.error) { switch (msg.error) { case 'UNAUTHORIZED': updateAnswer( `${t('UNAUTHORIZED')}
${t('Please login at https://chatgpt.com first')}${ isSafari() ? `
${t('Then open https://chatgpt.com/api/auth/session')}` : '' }
${t('And refresh this page or type you question again')}` + `

${t( 'Consider creating an api key at https://platform.openai.com/account/api-keys', )}`, false, 'error', ) break case 'CLOUDFLARE': updateAnswer( `${t('OpenAI Security Check Required')}
${ isSafari() ? t('Please open https://chatgpt.com/api/auth/session') : t('Please open https://chatgpt.com') }
${t('And refresh this page or type you question again')}` + `

${t( 'Consider creating an api key at https://platform.openai.com/account/api-keys', )}`, false, 'error', ) break default: { let formattedError = msg.error if (typeof msg.error === 'string' && msg.error.trimStart().startsWith('{')) try { formattedError = JSON.stringify(JSON.parse(msg.error), null, 2) } catch (e) { /* empty */ } let lastItem if (conversationItemData.length > 0) lastItem = conversationItemData[conversationItemData.length - 1] if (lastItem && (lastItem.content.includes('gpt-loading') || lastItem.type === 'error')) updateAnswer(t(formattedError), false, 'error') else setConversationItemData([ ...conversationItemData, new ConversationItemData('error', t(formattedError)), ]) break } } setIsReady(true) } } const foregroundMessageListeners = useRef([]) /** * @param {Session|undefined} session * @param {boolean|undefined} stop */ const postMessage = async ({ session, stop }) => { if (useForegroundFetch) { foregroundMessageListeners.current.forEach((listener) => listener({ session, stop })) if (session) { const fakePort = { postMessage: (msg) => { portMessageListener(msg) }, onMessage: { addListener: (listener) => { foregroundMessageListeners.current.push(listener) }, removeListener: (listener) => { foregroundMessageListeners.current.splice( foregroundMessageListeners.current.indexOf(listener), 1, ) }, }, onDisconnect: { addListener: () => {}, removeListener: () => {}, }, } try { const bingToken = (await getUserConfig()).bingAccessToken if (isUsingModelName('bingFreeSydney', session)) await generateAnswersWithBingWebApi( fakePort, session.question, session, bingToken, true, ) else await generateAnswersWithBingWebApi(fakePort, session.question, session, bingToken) } catch (err) { handlePortError(session, fakePort, err) } } } else { port.postMessage({ session, stop }) } } useEffect(() => { const portListener = () => { setPort(Browser.runtime.connect()) setIsReady(true) } const closeChatsMessageListener = (message) => { if (message.type === 'CLOSE_CHATS') { port.disconnect() Browser.runtime.onMessage.removeListener(closeChatsMessageListener) window.removeEventListener('keydown', closeChatsEscListener) if (props.onClose) props.onClose() } } const closeChatsEscListener = async (e) => { if (e.key === 'Escape' && (await getUserConfig()).allowEscToCloseAll) { closeChatsMessageListener({ type: 'CLOSE_CHATS' }) } } if (props.closeable) { Browser.runtime.onMessage.addListener(closeChatsMessageListener) window.addEventListener('keydown', closeChatsEscListener) } port.onDisconnect.addListener(portListener) return () => { if (props.closeable) { Browser.runtime.onMessage.removeListener(closeChatsMessageListener) window.removeEventListener('keydown', closeChatsEscListener) } port.onDisconnect.removeListener(portListener) } }, [port]) useEffect(() => { if (useForegroundFetch) { return () => {} } else { port.onMessage.addListener(portMessageListener) return () => { port.onMessage.removeListener(portMessageListener) } } }, [conversationItemData]) const getRetryFn = (session) => async () => { updateAnswer(`

${t('Waiting for response...')}

`, false, 'answer') setIsReady(false) if (session.conversationRecords.length > 0) { const lastRecord = session.conversationRecords[session.conversationRecords.length - 1] if ( conversationItemData[conversationItemData.length - 1].done && conversationItemData.length > 1 && lastRecord.question === conversationItemData[conversationItemData.length - 2].content ) { session.conversationRecords.pop() } } const newSession = { ...session, isRetry: true } setSession(newSession) try { await postMessage({ stop: true }) await postMessage({ session: newSession }) } catch (e) { updateAnswer(e, false, 'error') } } const retryFn = useMemo(() => getRetryFn(session), [session]) return (
{props.closeable ? ( { port.disconnect() if (props.onClose) props.onClose() }} > ) : props.dockable ? ( { if (props.onDock) props.onDock() }} > ) : ( )} {props.draggable && !completeDraggable && (
)} {!config.disableWebModeHistory && session && session.conversationId && ( )} { const position = { x: window.innerWidth / 2 - 300, y: window.innerHeight / 2 - 200 } const toolbarContainer = createElementAtPosition(position.x, position.y) toolbarContainer.className = 'chatgptbox-toolbar-container-not-queryable' render( , toolbarContainer, ) }} > { await postMessage({ stop: true }) Browser.runtime.sendMessage({ type: 'DELETE_CONVERSATION', data: { conversationId: session.conversationId, }, }) setConversationItemData([]) const newSession = initSession({ ...session, question: null, conversationRecords: [], }) newSession.sessionId = session.sessionId setSession(newSession) }} /> {!props.pageMode && ( { const newSession = { ...session, sessionName: new Date().toLocaleString(), autoClean: false, sessionId: uuidv4(), } setSession(newSession) createSession(newSession).then(() => Browser.runtime.sendMessage({ type: 'OPEN_URL', data: { url: Browser.runtime.getURL('IndependentPanel.html') + '?from=store', }, }), ) }} > )} {conversationItemData.length > 0 && ( { bodyRef.current.scrollTo({ top: bodyRef.current.scrollHeight, behavior: 'smooth', }) }} > )} { let output = '' session.conversationRecords.forEach((data) => { output += `${t('Question')}:\n\n${data.question}\n\n${t('Answer')}:\n\n${ data.answer }\n\n
\n\n` }) const blob = new Blob([output], { type: 'text/plain;charset=utf-8' }) FileSaver.saveAs(blob, 'conversation.md') }} >

{conversationItemData.map((data, idx) => ( ))}
{props.waitForTrigger && !triggered ? (

{ setConversationItemData([ new ConversationItemData( 'answer', `

${t(`Waiting for response...`)}

`, ), ]) setTriggered(true) setIsReady(false) }} > {t('Ask ChatGPT')}

) : ( { const newQuestion = new ConversationItemData('question', question) const newAnswer = new ConversationItemData( 'answer', `

${t('Waiting for response...')}

`, ) setConversationItemData([...conversationItemData, newQuestion, newAnswer]) setIsReady(false) const newSession = { ...session, question, isRetry: false } setSession(newSession) try { await postMessage({ session: newSession }) } catch (e) { updateAnswer(e, false, 'error') } bodyRef.current.scrollTo({ top: bodyRef.current.scrollHeight, behavior: 'instant', }) }} /> )}
) } ConversationCard.propTypes = { session: PropTypes.object.isRequired, question: PropTypes.string, onUpdate: PropTypes.func, draggable: PropTypes.bool, closeable: PropTypes.bool, onClose: PropTypes.func, dockable: PropTypes.bool, onDock: PropTypes.func, notClampSize: PropTypes.bool, pageMode: PropTypes.bool, waitForTrigger: PropTypes.bool, } export default memo(ConversationCard) ================================================ FILE: src/components/ConversationItem/index.jsx ================================================ import { memo, useState } from 'react' import { ChevronDownIcon, XCircleIcon, SyncIcon } from '@primer/octicons-react' import CopyButton from '../CopyButton' import ReadButton from '../ReadButton' import PropTypes from 'prop-types' import MarkdownRender from '../MarkdownRender/markdown.jsx' import { useTranslation } from 'react-i18next' function AnswerTitle({ descName }) { const { t } = useTranslation() return

{descName ? `${descName}:` : t('Loading...')}

} AnswerTitle.propTypes = { descName: PropTypes.string, } export function ConversationItem({ type, content, descName, onRetry }) { const { t } = useTranslation() const [collapsed, setCollapsed] = useState(false) switch (type) { case 'question': return (

{t('You')}:

content.replace(/\n$/, '')} size={14} /> content} size={14} /> {!collapsed ? ( setCollapsed(true)} > ) : ( setCollapsed(false)} > )}
{!collapsed && {content}}
) case 'answer': return (
{onRetry && ( )} {descName && ( content.replace(/\n$/, '')} size={14} /> )} {descName && content} size={14} />} {!collapsed ? ( setCollapsed(true)} > ) : ( setCollapsed(false)} > )}
{!collapsed && {content}}
) case 'error': return (

{t('Error')}:

{onRetry && ( )} content.replace(/\n$/, '')} size={14} /> {!collapsed ? ( setCollapsed(true)} > ) : ( setCollapsed(false)} > )}
{!collapsed && {content}}
) } } ConversationItem.propTypes = { type: PropTypes.oneOf(['question', 'answer', 'error']).isRequired, content: PropTypes.string.isRequired, descName: PropTypes.string, onRetry: PropTypes.func, } export default memo(ConversationItem) ================================================ FILE: src/components/CopyButton/index.jsx ================================================ import { useState } from 'react' import { CheckIcon, CopyIcon } from '@primer/octicons-react' import PropTypes from 'prop-types' import { useTranslation } from 'react-i18next' CopyButton.propTypes = { contentFn: PropTypes.func.isRequired, size: PropTypes.number.isRequired, className: PropTypes.string, } function CopyButton({ className, contentFn, size }) { const { t } = useTranslation() const [copied, setCopied] = useState(false) const onClick = () => { navigator.clipboard .writeText(contentFn()) .then(() => setCopied(true)) .then(() => setTimeout(() => { setCopied(false) }, 600), ) } return ( {copied ? : } ) } export default CopyButton ================================================ FILE: src/components/DecisionCard/index.jsx ================================================ import { LightBulbIcon, SearchIcon } from '@primer/octicons-react' import { useState, useEffect } from 'react' import PropTypes from 'prop-types' import ConversationCard from '../ConversationCard' import { getPossibleElementByQuerySelector, endsWithQuestionMark } from '../../utils' import { useTranslation } from 'react-i18next' import { useConfig } from '../../hooks/use-config.mjs' function DecisionCard(props) { const { t } = useTranslation() const [triggered, setTriggered] = useState(false) const [render, setRender] = useState(false) const config = useConfig(() => { setRender(true) }) const question = props.question const updatePosition = () => { if (!render) return const container = props.container const siteConfig = props.siteConfig container.classList.remove('chatgptbox-sidebar-free') if (config.appendQuery) { const appendContainer = getPossibleElementByQuerySelector([config.appendQuery]) if (appendContainer) { appendContainer.appendChild(container) return } } if (config.prependQuery) { const prependContainer = getPossibleElementByQuerySelector([config.prependQuery]) if (prependContainer) { prependContainer.prepend(container) return } } if (!siteConfig) return if (config.insertAtTop) { const resultsContainerQuery = getPossibleElementByQuerySelector( siteConfig.resultsContainerQuery, ) if (resultsContainerQuery) resultsContainerQuery.prepend(container) } else { const sidebarContainer = getPossibleElementByQuerySelector(siteConfig.sidebarContainerQuery) if (sidebarContainer) { sidebarContainer.prepend(container) } else { const appendContainer = getPossibleElementByQuerySelector(siteConfig.appendContainerQuery) if (appendContainer) { container.classList.add('chatgptbox-sidebar-free') appendContainer.appendChild(container) } else { const resultsContainerQuery = getPossibleElementByQuerySelector( siteConfig.resultsContainerQuery, ) if (resultsContainerQuery) resultsContainerQuery.prepend(container) } } } } useEffect(() => updatePosition(), [config]) return ( render && (
{(() => { if (question) switch (config.triggerMode) { case 'always': return case 'manually': if (triggered) { return } return (

setTriggered(true)}> {t('Ask ChatGPT')}

) case 'questionMark': if (endsWithQuestionMark(question.trim())) { return } if (triggered) { return } return (

setTriggered(true)}> {t('Ask ChatGPT')}

) } else return (

{t('No Input Found')}

) })()}
) ) } DecisionCard.propTypes = { session: PropTypes.object.isRequired, question: PropTypes.string.isRequired, siteConfig: PropTypes.object.isRequired, container: PropTypes.object.isRequired, } export default DecisionCard ================================================ FILE: src/components/DeleteButton/index.jsx ================================================ import { useEffect, useRef, useState } from 'react' import PropTypes from 'prop-types' import { useTranslation } from 'react-i18next' import { TrashIcon } from '@primer/octicons-react' DeleteButton.propTypes = { onConfirm: PropTypes.func.isRequired, size: PropTypes.number.isRequired, text: PropTypes.string.isRequired, } function DeleteButton({ onConfirm, size, text }) { const { t } = useTranslation() const [waitConfirm, setWaitConfirm] = useState(false) const confirmRef = useRef(null) useEffect(() => { if (waitConfirm) confirmRef.current.focus() }, [waitConfirm]) return ( { setWaitConfirm(true) }} > ) } export default DeleteButton ================================================ FILE: src/components/FeedbackForChatGPTWeb/index.jsx ================================================ import PropTypes from 'prop-types' import { memo, useCallback, useState } from 'react' import { ThumbsupIcon, ThumbsdownIcon } from '@primer/octicons-react' import Browser from 'webextension-polyfill' import { useTranslation } from 'react-i18next' const FeedbackForChatGPTWeb = (props) => { const { t } = useTranslation() const [action, setAction] = useState(null) const clickThumbsUp = useCallback(async () => { if (action) { return } setAction('thumbsUp') await Browser.runtime.sendMessage({ type: 'FEEDBACK', data: { conversation_id: props.conversationId, message_id: props.messageId, rating: 'thumbsUp', }, }) }, [props, action]) const clickThumbsDown = useCallback(async () => { if (action) { return } setAction('thumbsDown') await Browser.runtime.sendMessage({ type: 'FEEDBACK', data: { conversation_id: props.conversationId, message_id: props.messageId, rating: 'thumbsDown', text: '', tags: [], }, }) }, [props, action]) return (
) } FeedbackForChatGPTWeb.propTypes = { messageId: PropTypes.string.isRequired, conversationId: PropTypes.string.isRequired, } export default memo(FeedbackForChatGPTWeb) ================================================ FILE: src/components/FloatingToolbar/index.jsx ================================================ import { cloneElement, useCallback, useEffect, useState } from 'react' import ConversationCard from '../ConversationCard' import PropTypes from 'prop-types' import { config as toolsConfig } from '../../content-script/selection-tools' import { getClientPosition, isMobile, setElementPositionInViewport } from '../../utils' import Draggable from 'react-draggable' import { useClampWindowSize } from '../../hooks/use-clamp-window-size' import { useTranslation } from 'react-i18next' import { useConfig } from '../../hooks/use-config.mjs' // const logo = Browser.runtime.getURL('logo.png') function FloatingToolbar(props) { const { t } = useTranslation() const [selection, setSelection] = useState(props.selection) const [prompt, setPrompt] = useState(props.prompt) const [triggered, setTriggered] = useState(props.triggered) const [render, setRender] = useState(false) const [closeable, setCloseable] = useState(props.closeable) const [position, setPosition] = useState(getClientPosition(props.container)) const [virtualPosition, setVirtualPosition] = useState({ x: 0, y: 0 }) const windowSize = useClampWindowSize([750, 1500], [0, Infinity]) const config = useConfig(() => { setRender(true) if (!triggered && selection) { props.container.style.position = 'absolute' setTimeout(() => { const left = Math.min( Math.max(0, window.innerWidth - props.container.offsetWidth - 30), Math.max(0, position.x), ) props.container.style.left = left + 'px' }) } }) useEffect(() => { if (isMobile()) { const selectionListener = () => { const currentSelection = window.getSelection()?.toString() if (currentSelection) setSelection(currentSelection) } document.addEventListener('selectionchange', selectionListener) return () => { document.removeEventListener('selectionchange', selectionListener) } } }, []) if (!render) return
if (triggered || (prompt && !selection)) { const updatePosition = () => { const newPosition = setElementPositionInViewport(props.container, position.x, position.y) if (position.x !== newPosition.x || position.y !== newPosition.y) setPosition(newPosition) // clear extra virtual position offset } const dragEvent = { onDrag: (e, ui) => { setVirtualPosition({ x: virtualPosition.x + ui.deltaX, y: virtualPosition.y + ui.deltaY }) }, onStop: () => { setPosition({ x: position.x + virtualPosition.x, y: position.y + virtualPosition.y }) setVirtualPosition({ x: 0, y: 0 }) }, } if (virtualPosition.x === 0 && virtualPosition.y === 0) { updatePosition() // avoid jitter } const onClose = useCallback(() => { props.container.remove() }, []) const onDock = useCallback(() => { props.container.className = 'chatgptbox-toolbar-container-not-queryable' setCloseable(true) }, []) const onUpdate = useCallback(() => { updatePosition() }, [position]) if (config.alwaysPinWindow) onDock() return (
) } else { if ( config.activeSelectionTools.length === 0 && config.customSelectionTools.reduce((count, tool) => count + (tool.active ? 1 : 0), 0) === 0 ) return
const tools = [] const pushTool = (iconKey, name, genPrompt) => { tools.push( cloneElement(toolsConfig[iconKey].icon, { size: 24, className: 'chatgptbox-selection-toolbar-button', title: name, onClick: async () => { const p = getClientPosition(props.container) props.container.style.position = 'fixed' setPosition(p) setPrompt(await genPrompt(selection)) setTriggered(true) }, }), ) } for (const key in toolsConfig) { if (config.activeSelectionTools.includes(key)) { const toolConfig = toolsConfig[key] pushTool(key, t(toolConfig.label), toolConfig.genPrompt) } } for (const tool of config.customSelectionTools) { if (tool.active) { pushTool(tool.iconKey, tool.name, async (selection) => { return tool.prompt.replace('{{selection}}', selection) }) } } return (
{tools}
) } } FloatingToolbar.propTypes = { session: PropTypes.object.isRequired, selection: PropTypes.string.isRequired, container: PropTypes.object.isRequired, triggered: PropTypes.bool, closeable: PropTypes.bool, dockable: PropTypes.bool, prompt: PropTypes.string, } export default FloatingToolbar ================================================ FILE: src/components/InputBox/index.jsx ================================================ import { useEffect, useRef, useState } from 'react' import PropTypes from 'prop-types' import { isFirefox, isMobile, isSafari, updateRefHeight } from '../../utils' import { useTranslation } from 'react-i18next' import { getUserConfig } from '../../config/index.mjs' export function InputBox({ onSubmit, enabled, postMessage, reverseResizeDir }) { const { t } = useTranslation() const [value, setValue] = useState('') const reverseDivRef = useRef(null) const inputRef = useRef(null) const resizedRef = useRef(false) const [internalReverseResizeDir, setInternalReverseResizeDir] = useState(reverseResizeDir) useEffect(() => { setInternalReverseResizeDir( !isSafari() && !isFirefox() && !isMobile() ? internalReverseResizeDir : false, ) }, []) const virtualInputRef = internalReverseResizeDir ? reverseDivRef : inputRef useEffect(() => { inputRef.current.focus() const onResizeY = () => { if (virtualInputRef.current.h !== virtualInputRef.current.offsetHeight) { virtualInputRef.current.h = virtualInputRef.current.offsetHeight if (!resizedRef.current) { resizedRef.current = true virtualInputRef.current.style.maxHeight = '' } } } virtualInputRef.current.h = virtualInputRef.current.offsetHeight virtualInputRef.current.addEventListener('mousemove', onResizeY) }, []) useEffect(() => { if (!resizedRef.current) { if (!internalReverseResizeDir) { updateRefHeight(inputRef) virtualInputRef.current.h = virtualInputRef.current.offsetHeight virtualInputRef.current.style.maxHeight = '160px' } } }) useEffect(() => { if (enabled) getUserConfig().then((config) => { if (config.focusAfterAnswer) inputRef.current.focus() }) }, [enabled]) const handleKeyDownOrClick = (e) => { e.stopPropagation() if (e.type === 'click' || (e.keyCode === 13 && e.shiftKey === false)) { e.preventDefault() if (enabled) { if (!value) return onSubmit(value) setValue('') } else { postMessage({ stop: true }) } } } return (