From ebe2806467b2117766034d02c19d34d8b90de2de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=A2=E5=A5=8B=E7=8C=AB?= Date: Sat, 30 Aug 2025 20:09:35 +0800 Subject: [PATCH] feat: add cherryin provider (#9681) * feat: add Zhipu logo and update related images - Introduced a new Zhipu logo component in SVG format. - Updated existing image assets for chatglm, zhipu, and zhipu_dark. - Added a new zhipu image for search functionality. * feat: integrate Cherryin signature generation - Added a new integration for Cherryin, including a signature generation feature. - Updated IPC channels to handle Cherryin requests. - Introduced a new JavaScript file for Cherryin integration. - Modified configuration files to include Cherryin client secrets and paths. - Enhanced the ESLint and TypeScript configurations to accommodate the new integration. * feat: add Zhipu search provider and logo integration - Implemented a new ZhipuProvider for web search functionality. - Added Zhipu logo to the WebSearchButton component. - Updated WebSearchProviderFactory to include Zhipu as a search option. - Enhanced error handling and logging for Zhipu search requests. * feat: add cherryin provider * fix: correct import path for CherryinAPIClient and update paintings state structure in migration * chore: update version number to 1.5.8 in package.json * feat: enhance model filtering in SelectModelPopup - Added support for identifying free trial models in the model filtering logic. - Updated the condition for determining free models to include both free and free trial models. * refactor: update navigation to use query parameters for provider settings - Modified navigation logic in FreeTrialModelTag and related utilities to use query parameters instead of state for provider identification. - Removed unused useLocation hook in ProviderList component to streamline state management. * fix: remove provider ID from search parameters on selection change in ProviderList * refactor: remove free trial model references and update related logic - Eliminated the FreeTrialTag component and its associated logic from ModelTagsWithLabel and SelectModelPopup. - Updated model filtering to only consider free models without the free trial distinction. - Removed translations and utility functions related to free trial models across multiple locales. * fix: prevent mutation of read-only properties in web search provider - Updated the addWebSearchProvider function to clone the provider object before pushing it to the state, preventing mutation of read-only properties. - Enhanced the migration logic to update the apiKey for the zhipu web search provider if it exists. * refactor: streamline provider selection and navigation logic - Updated FreeTrialModelTag to directly navigate to provider settings using query parameters, removing unnecessary provider fetching. - Simplified ProviderList by eliminating the EventEmitter for provider selection and ensuring search parameters are updated correctly. --- .github/workflows/nightly-build.yml | 15 +- .github/workflows/release.yml | 3 + .prettierignore | 1 + eslint.config.mjs | 3 +- package.json | 2 +- packages/shared/IpcChannel.ts | 5 +- src/main/config.ts | 2 + src/main/integration/cherryin/index.js | 1 + src/main/ipc.ts | 4 + src/preload/index.ts | 4 + .../index.clientCompatibilityTypes.test.ts | 13 +- .../src/aiCore/clients/ApiClientFactory.ts | 27 +- .../__tests__/ApiClientFactory.test.ts | 8 +- .../{ => aihubmix}/AihubmixAPIClient.ts | 12 +- .../clients/cherryin/CherryinAPIClient.ts | 51 ++ src/renderer/src/aiCore/clients/index.ts | 2 + .../clients/{ => newapi}/NewAPIClient.ts | 12 +- .../aiCore/clients/openai/OpenAIApiClient.ts | 6 +- .../aiCore/clients/zhipu/ZhipuAPIClient.ts | 100 +++ src/renderer/src/aiCore/index.ts | 4 +- .../common/ErrorHandlerMiddleware.ts | 84 ++- .../src/assets/images/models/chatglm.png | Bin 8504 -> 19746 bytes .../src/assets/images/models/zhipu.png | Bin 7284 -> 19746 bytes .../src/assets/images/models/zhipu_dark.png | Bin 8943 -> 19746 bytes .../src/assets/images/providers/cherryin.png | Bin 0 -> 7754 bytes .../src/assets/images/providers/zhipu.png | Bin 7284 -> 19746 bytes .../src/assets/images/search/zhipu.png | Bin 0 -> 19746 bytes .../src/components/FreeTrialModelTag.tsx | 81 +++ src/renderer/src/components/Icons/SVGIcon.tsx | 12 + .../Popups/SelectModelPopup/popup.tsx | 27 +- .../src/components/Tags/CustomTag.tsx | 4 +- .../src/components/Tags/Model/FreeTag.tsx | 3 +- src/renderer/src/config/minapps.ts | 5 +- src/renderer/src/config/models.ts | 163 ++--- src/renderer/src/config/providers.ts | 44 +- src/renderer/src/config/webSearchProviders.ts | 12 + src/renderer/src/hooks/usePaintings.ts | 39 +- src/renderer/src/i18n/label.ts | 41 +- src/renderer/src/i18n/locales/en-us.json | 10 +- src/renderer/src/i18n/locales/ja-jp.json | 10 +- src/renderer/src/i18n/locales/ru-ru.json | 10 +- src/renderer/src/i18n/locales/zh-cn.json | 10 +- src/renderer/src/i18n/locales/zh-tw.json | 10 +- src/renderer/src/i18n/translate/el-gr.json | 10 +- src/renderer/src/i18n/translate/es-es.json | 10 +- src/renderer/src/i18n/translate/fr-fr.json | 10 +- src/renderer/src/i18n/translate/pt-pt.json | 10 +- src/renderer/src/pages/code/CodeToolsPage.tsx | 3 + src/renderer/src/pages/files/FilesPage.tsx | 7 +- .../pages/home/Inputbar/WebSearchButton.tsx | 4 +- .../pages/home/Messages/Blocks/ErrorBlock.tsx | 84 ++- .../src/pages/home/Messages/Message.tsx | 2 +- .../home/components/SelectModelButton.tsx | 2 +- .../src/pages/knowledge/KnowledgeContent.tsx | 2 +- .../knowledge/items/KnowledgeDirectories.tsx | 2 +- .../pages/knowledge/items/KnowledgeFiles.tsx | 2 +- .../pages/knowledge/items/KnowledgeNotes.tsx | 2 +- .../knowledge/items/KnowledgeSitemaps.tsx | 2 +- .../pages/knowledge/items/KnowledgeUrls.tsx | 2 +- .../src/pages/paintings/AihubmixPage.tsx | 51 +- .../src/pages/paintings/DmxapiPage.tsx | 54 +- .../src/pages/paintings/NewApiPage.tsx | 21 +- .../pages/paintings/PaintingsRoutePage.tsx | 6 +- .../src/pages/paintings/SiliconPage.tsx | 45 +- .../src/pages/paintings/TokenFluxPage.tsx | 35 +- .../src/pages/paintings/ZhipuPage.tsx | 588 ++++++++++++++++++ .../src/pages/paintings/config/ZhipuConfig.ts | 48 ++ .../pages/paintings/config/aihubmixConfig.tsx | 8 +- .../src/pages/paintings/utils/index.ts | 24 + .../settings/MCPSettings/McpMarketList.tsx | 7 + .../ProviderSettings/ModelList/ModelList.tsx | 40 +- .../ModelList/ModelListItem.tsx | 2 + .../ProviderSettings/ProviderList.tsx | 15 +- .../ProviderSettings/ProviderSetting.tsx | 12 +- .../WebSearchProviderSetting.tsx | 3 + .../src/pages/translate/TranslatePage.tsx | 2 +- .../WebSearchProviderFactory.ts | 3 + .../WebSearchProvider/ZhipuProvider.ts | 91 +++ src/renderer/src/services/ApiService.ts | 2 +- src/renderer/src/services/FileAction.ts | 8 +- src/renderer/src/services/ModelService.ts | 5 +- src/renderer/src/services/ProviderService.ts | 31 +- .../callbacks/baseCallbacks.ts | 4 +- src/renderer/src/store/index.ts | 2 +- src/renderer/src/store/migrate.ts | 94 ++- src/renderer/src/store/paintings.ts | 20 +- src/renderer/src/store/settings.ts | 5 +- src/renderer/src/types/index.ts | 26 +- src/renderer/src/utils/model.ts | 4 + tsconfig.web.json | 3 +- 90 files changed, 1812 insertions(+), 441 deletions(-) create mode 100644 src/main/integration/cherryin/index.js rename src/renderer/src/aiCore/clients/{ => aihubmix}/AihubmixAPIClient.ts (88%) create mode 100644 src/renderer/src/aiCore/clients/cherryin/CherryinAPIClient.ts rename src/renderer/src/aiCore/clients/{ => newapi}/NewAPIClient.ts (89%) create mode 100644 src/renderer/src/aiCore/clients/zhipu/ZhipuAPIClient.ts create mode 100644 src/renderer/src/assets/images/providers/cherryin.png create mode 100644 src/renderer/src/assets/images/search/zhipu.png create mode 100644 src/renderer/src/components/FreeTrialModelTag.tsx create mode 100644 src/renderer/src/pages/paintings/ZhipuPage.tsx create mode 100644 src/renderer/src/pages/paintings/config/ZhipuConfig.ts create mode 100644 src/renderer/src/pages/paintings/utils/index.ts create mode 100644 src/renderer/src/providers/WebSearchProvider/ZhipuProvider.ts diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml index 96c2e73aad..f886d01f8b 100644 --- a/.github/workflows/nightly-build.yml +++ b/.github/workflows/nightly-build.yml @@ -98,8 +98,11 @@ jobs: yarn build:linux env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - RENDERER_VITE_AIHUBMIX_SECRET: ${{ vars.RENDERER_VITE_AIHUBMIX_SECRET }} NODE_OPTIONS: --max-old-space-size=8192 + MAIN_VITE_CHERRYIN_CLIENT_SECRET: ${{ secrets.MAIN_VITE_CHERRYIN_CLIENT_SECRET }} + MAIN_VITE_MINERU_API_KEY: ${{ vars.MAIN_VITE_MINERU_API_KEY }} + RENDERER_VITE_AIHUBMIX_SECRET: ${{ vars.RENDERER_VITE_AIHUBMIX_SECRET }} + RENDERER_VITE_PPIO_APP_SECRET: ${{ vars.RENDERER_VITE_PPIO_APP_SECRET }} - name: Build Mac if: matrix.os == 'macos-latest' @@ -112,9 +115,12 @@ jobs: APPLE_ID: ${{ vars.APPLE_ID }} APPLE_APP_SPECIFIC_PASSWORD: ${{ vars.APPLE_APP_SPECIFIC_PASSWORD }} APPLE_TEAM_ID: ${{ vars.APPLE_TEAM_ID }} - RENDERER_VITE_AIHUBMIX_SECRET: ${{ vars.RENDERER_VITE_AIHUBMIX_SECRET }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} NODE_OPTIONS: --max-old-space-size=8192 + MAIN_VITE_CHERRYIN_CLIENT_SECRET: ${{ secrets.MAIN_VITE_CHERRYIN_CLIENT_SECRET }} + MAIN_VITE_MINERU_API_KEY: ${{ vars.MAIN_VITE_MINERU_API_KEY }} + RENDERER_VITE_AIHUBMIX_SECRET: ${{ vars.RENDERER_VITE_AIHUBMIX_SECRET }} + RENDERER_VITE_PPIO_APP_SECRET: ${{ vars.RENDERER_VITE_PPIO_APP_SECRET }} - name: Build Windows if: matrix.os == 'windows-latest' @@ -123,8 +129,11 @@ jobs: yarn build:win env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - RENDERER_VITE_AIHUBMIX_SECRET: ${{ vars.RENDERER_VITE_AIHUBMIX_SECRET }} NODE_OPTIONS: --max-old-space-size=8192 + MAIN_VITE_CHERRYIN_CLIENT_SECRET: ${{ secrets.MAIN_VITE_CHERRYIN_CLIENT_SECRET }} + MAIN_VITE_MINERU_API_KEY: ${{ vars.MAIN_VITE_MINERU_API_KEY }} + RENDERER_VITE_AIHUBMIX_SECRET: ${{ vars.RENDERER_VITE_AIHUBMIX_SECRET }} + RENDERER_VITE_PPIO_APP_SECRET: ${{ vars.RENDERER_VITE_PPIO_APP_SECRET }} - name: Rename artifacts with nightly format shell: bash diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fa3aa91a19..41b915953c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -86,6 +86,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} NODE_OPTIONS: --max-old-space-size=8192 + MAIN_VITE_CHERRYIN_CLIENT_SECRET: ${{ secrets.MAIN_VITE_CHERRYIN_CLIENT_SECRET }} MAIN_VITE_MINERU_API_KEY: ${{ vars.MAIN_VITE_MINERU_API_KEY }} RENDERER_VITE_AIHUBMIX_SECRET: ${{ vars.RENDERER_VITE_AIHUBMIX_SECRET }} RENDERER_VITE_PPIO_APP_SECRET: ${{ vars.RENDERER_VITE_PPIO_APP_SECRET }} @@ -104,6 +105,7 @@ jobs: APPLE_TEAM_ID: ${{ vars.APPLE_TEAM_ID }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} NODE_OPTIONS: --max-old-space-size=8192 + MAIN_VITE_CHERRYIN_CLIENT_SECRET: ${{ secrets.MAIN_VITE_CHERRYIN_CLIENT_SECRET }} MAIN_VITE_MINERU_API_KEY: ${{ vars.MAIN_VITE_MINERU_API_KEY }} RENDERER_VITE_AIHUBMIX_SECRET: ${{ vars.RENDERER_VITE_AIHUBMIX_SECRET }} RENDERER_VITE_PPIO_APP_SECRET: ${{ vars.RENDERER_VITE_PPIO_APP_SECRET }} @@ -116,6 +118,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} NODE_OPTIONS: --max-old-space-size=8192 + MAIN_VITE_CHERRYIN_CLIENT_SECRET: ${{ secrets.MAIN_VITE_CHERRYIN_CLIENT_SECRET }} MAIN_VITE_MINERU_API_KEY: ${{ vars.MAIN_VITE_MINERU_API_KEY }} RENDERER_VITE_AIHUBMIX_SECRET: ${{ vars.RENDERER_VITE_AIHUBMIX_SECRET }} RENDERER_VITE_PPIO_APP_SECRET: ${{ vars.RENDERER_VITE_PPIO_APP_SECRET }} diff --git a/.prettierignore b/.prettierignore index 4ff98b4519..5f6cea6dad 100644 --- a/.prettierignore +++ b/.prettierignore @@ -7,3 +7,4 @@ tsconfig.*.json CHANGELOG*.md agents.json src/renderer/src/integration/nutstore/sso/lib +src/main/integration/cherryin/index.js diff --git a/eslint.config.mjs b/eslint.config.mjs index abaadac841..133025b1fd 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -122,7 +122,8 @@ export default defineConfig([ '.yarn/**', '.gitignore', 'scripts/cloudflare-worker.js', - 'src/main/integration/nutstore/sso/lib/**' + 'src/main/integration/nutstore/sso/lib/**', + 'src/main/integration/cherryin/index.js' ] } ]) diff --git a/package.json b/package.json index cc36229f26..517f914748 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "CherryStudio", - "version": "1.5.7-rc.2", + "version": "1.5.8", "private": true, "description": "A powerful AI assistant for producer.", "main": "./out/main/index.js", diff --git a/packages/shared/IpcChannel.ts b/packages/shared/IpcChannel.ts index f2b856ef1d..19df95332e 100644 --- a/packages/shared/IpcChannel.ts +++ b/packages/shared/IpcChannel.ts @@ -285,5 +285,8 @@ export enum IpcChannel { CodeTools_Run = 'code-tools:run', // OCR - OCR_ocr = 'ocr:ocr' + OCR_ocr = 'ocr:ocr', + + // Cherryin + Cherryin_GetSignature = 'cherryin:get-signature' } diff --git a/src/main/config.ts b/src/main/config.ts index 5a6f667d18..0cffcd1768 100644 --- a/src/main/config.ts +++ b/src/main/config.ts @@ -20,3 +20,5 @@ export const titleBarOverlayLight = { color: 'rgba(255,255,255,0)', symbolColor: '#000' } + +global.CHERRYIN_CLIENT_SECRET = import.meta.env.MAIN_VITE_CHERRYIN_CLIENT_SECRET diff --git a/src/main/integration/cherryin/index.js b/src/main/integration/cherryin/index.js new file mode 100644 index 0000000000..af185389eb --- /dev/null +++ b/src/main/integration/cherryin/index.js @@ -0,0 +1 @@ +var _0x6gg;const crypto=require("\u0063\u0072\u0079\u0070\u0074\u006F");_0x6gg='\u006D\u006F\u006C\u006A\u0065\u0065';var _0x111cbe;const CLIENT_ID="oiduts-yrrehc".split("").reverse().join("");_0x111cbe=(977158^977167)+(164595^164594);var _0x6d6adc=(756649^756650)+(497587^497587);const CLIENT_SECRET_SUFFIX="\u0047\u0076\u0049\u0036\u0049\u0035\u005A\u0072\u0045\u0048\u0063\u0047\u004F\u0057\u006A\u004F\u0035\u0041\u004B\u0068\u004A\u004B\u0047\u006D\u006E\u0077\u0077\u0047\u0066\u004D\u0036\u0032\u0058\u004B\u0070\u0057\u0071\u006B\u006A\u0068\u0076\u007A\u0052\u0055\u0032\u004E\u005A\u0049\u0069\u006E\u004D\u0037\u0037\u0061\u0054\u0047\u0049\u0071\u0068\u0071\u0079\u0073\u0030\u0067";_0x6d6adc=233169^233176;const CLIENT_SECRET=global['\u0043\u0048\u0045\u0052\u0052\u0059\u0049\u004E\u005F\u0043\u004C\u0049\u0045\u004E\u0054\u005F\u0053\u0045\u0043\u0052\u0045\u0054']+"\u002E"+CLIENT_SECRET_SUFFIX;class SignatureClient{constructor(clientId,clientSecret){this['\u0063\u006C\u0069\u0065\u006E\u0074\u0049\u0064']=clientId||CLIENT_ID;this['\u0063\u006C\u0069\u0065\u006E\u0074\u0053\u0065\u0063\u0072\u0065\u0074']=clientSecret||CLIENT_SECRET;this['\u0067\u0065\u006E\u0065\u0072\u0061\u0074\u0065\u0053\u0069\u0067\u006E\u0061\u0074\u0075\u0072\u0065']=this['\u0067\u0065\u006E\u0065\u0072\u0061\u0074\u0065\u0053\u0069\u0067\u006E\u0061\u0074\u0075\u0072\u0065']['\u0062\u0069\u006E\u0064'](this);}generateSignature(options){const{"method":method,"path":path,"query":query='',"body":body=''}=options;const timestamp=Math['\u0066\u006C\u006F\u006F\u0072'](Date['\u006E\u006F\u0077']()/(110765^111429))['\u0074\u006F\u0053\u0074\u0072\u0069\u006E\u0067']();var _0xe08cc=(212246^212244)+(773521^773523);let bodyString='';_0xe08cc=(606778^606776)+(962748^962740);if(body){if(typeof body==="\u006F\u0062\u006A\u0065\u0063\u0074"){bodyString=JSON['\u0073\u0074\u0072\u0069\u006E\u0067\u0069\u0066\u0079'](body);}else{bodyString=body['\u0074\u006F\u0053\u0074\u0072\u0069\u006E\u0067']();}}const signatureParts=[method['\u0074\u006F\u0055\u0070\u0070\u0065\u0072\u0043\u0061\u0073\u0065'](),path,query,this['\u0063\u006C\u0069\u0065\u006E\u0074\u0049\u0064'],timestamp,bodyString];var _0x5693g=(936664^936668)+(685268^685277);const signatureString=signatureParts['\u006A\u006F\u0069\u006E']("\u000A");_0x5693g=(266582^266576)+(337322^337315);const hmac=crypto['\u0063\u0072\u0065\u0061\u0074\u0065\u0048\u006D\u0061\u0063']("\u0073\u0068\u0061\u0032\u0035\u0036",this['\u0063\u006C\u0069\u0065\u006E\u0074\u0053\u0065\u0063\u0072\u0065\u0074']);hmac['\u0075\u0070\u0064\u0061\u0074\u0065'](signatureString);var _0x5fba=(354480^354481)+(537437^537434);const signature=hmac['\u0064\u0069\u0067\u0065\u0073\u0074']("\u0068\u0065\u0078");_0x5fba=(249614^249610)+(915906^915914);return{'X-Client-ID':this['\u0063\u006C\u0069\u0065\u006E\u0074\u0049\u0064'],'X-Timestamp':timestamp,'X-Signature':signature};}}const signatureClient=new SignatureClient();const generateSignature=signatureClient['\u0067\u0065\u006E\u0065\u0072\u0061\u0074\u0065\u0053\u0069\u0067\u006E\u0061\u0074\u0075\u0072\u0065'];module['\u0065\u0078\u0070\u006F\u0072\u0074\u0073']={'\u0053\u0069\u0067\u006E\u0061\u0074\u0075\u0072\u0065\u0043\u006C\u0069\u0065\u006E\u0074':SignatureClient,'\u0067\u0065\u006E\u0065\u0072\u0061\u0074\u0065\u0053\u0069\u0067\u006E\u0061\u0074\u0075\u0072\u0065':generateSignature}; \ No newline at end of file diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 20ccf06d76..33d45531e0 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -4,6 +4,7 @@ import path from 'node:path' import { loggerService } from '@logger' import { isLinux, isMac, isPortable, isWin } from '@main/constant' +import { generateSignature } from '@main/integration/cherryin' import { getBinaryPath, isBinaryExists, runInstallScript } from '@main/utils/process' import { handleZoomFactor } from '@main/utils/zoom' import { SpanEntity, TokenUsage } from '@mcp-trace/trace-core' @@ -714,4 +715,7 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) { // OCR ipcMain.handle(IpcChannel.OCR_ocr, (_, ...args: Parameters) => ocrService.ocr(...args)) + + // CherryIN + ipcMain.handle(IpcChannel.Cherryin_GetSignature, (_, params) => generateSignature(params)) } diff --git a/src/preload/index.ts b/src/preload/index.ts index 49c40d1166..fb9e37c89e 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -415,6 +415,10 @@ const api = { ocr: { ocr: (file: SupportedOcrFile, provider: OcrProvider): Promise => ipcRenderer.invoke(IpcChannel.OCR_ocr, file, provider) + }, + cherryin: { + generateSignature: (params: { method: string; path: string; query: string; body: Record }) => + ipcRenderer.invoke(IpcChannel.Cherryin_GetSignature, params) } } diff --git a/src/renderer/src/aiCore/__tests__/index.clientCompatibilityTypes.test.ts b/src/renderer/src/aiCore/__tests__/index.clientCompatibilityTypes.test.ts index b69d761307..12571875db 100644 --- a/src/renderer/src/aiCore/__tests__/index.clientCompatibilityTypes.test.ts +++ b/src/renderer/src/aiCore/__tests__/index.clientCompatibilityTypes.test.ts @@ -1,9 +1,9 @@ -import { AihubmixAPIClient } from '@renderer/aiCore/clients/AihubmixAPIClient' +import { AihubmixAPIClient } from '@renderer/aiCore/clients/aihubmix/AihubmixAPIClient' import { AnthropicAPIClient } from '@renderer/aiCore/clients/anthropic/AnthropicAPIClient' import { ApiClientFactory } from '@renderer/aiCore/clients/ApiClientFactory' import { GeminiAPIClient } from '@renderer/aiCore/clients/gemini/GeminiAPIClient' import { VertexAPIClient } from '@renderer/aiCore/clients/gemini/VertexAPIClient' -import { NewAPIClient } from '@renderer/aiCore/clients/NewAPIClient' +import { NewAPIClient } from '@renderer/aiCore/clients/newapi/NewAPIClient' import { OpenAIAPIClient } from '@renderer/aiCore/clients/openai/OpenAIApiClient' import { OpenAIResponseAPIClient } from '@renderer/aiCore/clients/openai/OpenAIResponseAPIClient' import { EndpointType, Model, Provider } from '@renderer/types' @@ -16,6 +16,7 @@ vi.mock('@renderer/config/models', () => ({ { id: 'gpt-4', name: 'GPT-4' }, { id: 'gpt-4', name: 'GPT-4' } ], + zhipu: [], silicon: [], openai: [], anthropic: [], @@ -32,7 +33,13 @@ vi.mock('@renderer/config/models', () => ({ isWebSearchModel: vi.fn().mockReturnValue(false), findTokenLimit: vi.fn().mockReturnValue(4096), isFunctionCallingModel: vi.fn().mockReturnValue(false), - DEFAULT_MAX_TOKENS: 4096 + DEFAULT_MAX_TOKENS: 4096, + glm45FlashModel: { + id: 'glm-4.5-flash', + name: 'GLM-4.5-Flash', + provider: 'cherryin', + group: 'GLM-4.5' + } })) vi.mock('@renderer/services/AssistantService', () => ({ diff --git a/src/renderer/src/aiCore/clients/ApiClientFactory.ts b/src/renderer/src/aiCore/clients/ApiClientFactory.ts index e708ab8c42..7c5575aa08 100644 --- a/src/renderer/src/aiCore/clients/ApiClientFactory.ts +++ b/src/renderer/src/aiCore/clients/ApiClientFactory.ts @@ -1,16 +1,18 @@ import { loggerService } from '@logger' import { Provider } from '@renderer/types' -import { AihubmixAPIClient } from './AihubmixAPIClient' +import { AihubmixAPIClient } from './aihubmix/AihubmixAPIClient' import { AnthropicAPIClient } from './anthropic/AnthropicAPIClient' import { AwsBedrockAPIClient } from './aws/AwsBedrockAPIClient' import { BaseApiClient } from './BaseApiClient' +import { CherryinAPIClient } from './cherryin/CherryinAPIClient' import { GeminiAPIClient } from './gemini/GeminiAPIClient' import { VertexAPIClient } from './gemini/VertexAPIClient' -import { NewAPIClient } from './NewAPIClient' +import { NewAPIClient } from './newapi/NewAPIClient' import { OpenAIAPIClient } from './openai/OpenAIApiClient' import { OpenAIResponseAPIClient } from './openai/OpenAIResponseAPIClient' import { PPIOAPIClient } from './ppio/PPIOAPIClient' +import { ZhipuAPIClient } from './zhipu/ZhipuAPIClient' const logger = loggerService.withContext('ApiClientFactory') @@ -31,24 +33,36 @@ export class ApiClientFactory { let instance: BaseApiClient - // 首先检查特殊的provider id + // 首先检查特殊的 Provider ID + if (provider.id === 'cherryin') { + instance = new CherryinAPIClient(provider) as BaseApiClient + return instance + } + if (provider.id === 'aihubmix') { logger.debug(`Creating AihubmixAPIClient for provider: ${provider.id}`) instance = new AihubmixAPIClient(provider) as BaseApiClient return instance } + if (provider.id === 'new-api') { logger.debug(`Creating NewAPIClient for provider: ${provider.id}`) instance = new NewAPIClient(provider) as BaseApiClient return instance } + if (provider.id === 'ppio') { logger.debug(`Creating PPIOAPIClient for provider: ${provider.id}`) instance = new PPIOAPIClient(provider) as BaseApiClient return instance } - // 然后检查标准的provider type + if (provider.id === 'zhipu') { + instance = new ZhipuAPIClient(provider) as BaseApiClient + return instance + } + + // 然后检查标准的 Provider Type switch (provider.type) { case 'openai': instance = new OpenAIAPIClient(provider) as BaseApiClient @@ -78,8 +92,3 @@ export class ApiClientFactory { return instance } } - -// 移除这个函数,它已经移动到 utils/index.ts -// export function isOpenAIProvider(provider: Provider) { -// return !['anthropic', 'gemini'].includes(provider.type) -// } diff --git a/src/renderer/src/aiCore/clients/__tests__/ApiClientFactory.test.ts b/src/renderer/src/aiCore/clients/__tests__/ApiClientFactory.test.ts index 5ec3bf6404..4d58c78772 100644 --- a/src/renderer/src/aiCore/clients/__tests__/ApiClientFactory.test.ts +++ b/src/renderer/src/aiCore/clients/__tests__/ApiClientFactory.test.ts @@ -2,13 +2,13 @@ import { Provider } from '@renderer/types' import { isOpenAIProvider } from '@renderer/utils' import { beforeEach, describe, expect, it, vi } from 'vitest' -import { AihubmixAPIClient } from '../AihubmixAPIClient' +import { AihubmixAPIClient } from '../aihubmix/AihubmixAPIClient' import { AnthropicAPIClient } from '../anthropic/AnthropicAPIClient' import { ApiClientFactory } from '../ApiClientFactory' import { AwsBedrockAPIClient } from '../aws/AwsBedrockAPIClient' import { GeminiAPIClient } from '../gemini/GeminiAPIClient' import { VertexAPIClient } from '../gemini/VertexAPIClient' -import { NewAPIClient } from '../NewAPIClient' +import { NewAPIClient } from '../newapi/NewAPIClient' import { OpenAIAPIClient } from '../openai/OpenAIApiClient' import { OpenAIResponseAPIClient } from '../openai/OpenAIResponseAPIClient' import { PPIOAPIClient } from '../ppio/PPIOAPIClient' @@ -26,7 +26,7 @@ const createTestProvider = (id: string, type: string): Provider => ({ }) // Mock 所有客户端模块 -vi.mock('../AihubmixAPIClient', () => ({ +vi.mock('../aihubmix/AihubmixAPIClient', () => ({ AihubmixAPIClient: vi.fn().mockImplementation(() => ({})) })) vi.mock('../anthropic/AnthropicAPIClient', () => ({ @@ -41,7 +41,7 @@ vi.mock('../gemini/GeminiAPIClient', () => ({ vi.mock('../gemini/VertexAPIClient', () => ({ VertexAPIClient: vi.fn().mockImplementation(() => ({})) })) -vi.mock('../NewAPIClient', () => ({ +vi.mock('../newapi/NewAPIClient', () => ({ NewAPIClient: vi.fn().mockImplementation(() => ({})) })) vi.mock('../openai/OpenAIApiClient', () => ({ diff --git a/src/renderer/src/aiCore/clients/AihubmixAPIClient.ts b/src/renderer/src/aiCore/clients/aihubmix/AihubmixAPIClient.ts similarity index 88% rename from src/renderer/src/aiCore/clients/AihubmixAPIClient.ts rename to src/renderer/src/aiCore/clients/aihubmix/AihubmixAPIClient.ts index f27674174d..1149c04b35 100644 --- a/src/renderer/src/aiCore/clients/AihubmixAPIClient.ts +++ b/src/renderer/src/aiCore/clients/aihubmix/AihubmixAPIClient.ts @@ -1,12 +1,12 @@ import { isOpenAILLMModel } from '@renderer/config/models' import { Model, Provider } from '@renderer/types' -import { AnthropicAPIClient } from './anthropic/AnthropicAPIClient' -import { BaseApiClient } from './BaseApiClient' -import { GeminiAPIClient } from './gemini/GeminiAPIClient' -import { MixedBaseAPIClient } from './MixedBaseApiClient' -import { OpenAIAPIClient } from './openai/OpenAIApiClient' -import { OpenAIResponseAPIClient } from './openai/OpenAIResponseAPIClient' +import { AnthropicAPIClient } from '../anthropic/AnthropicAPIClient' +import { BaseApiClient } from '../BaseApiClient' +import { GeminiAPIClient } from '../gemini/GeminiAPIClient' +import { MixedBaseAPIClient } from '../MixedBaseApiClient' +import { OpenAIAPIClient } from '../openai/OpenAIApiClient' +import { OpenAIResponseAPIClient } from '../openai/OpenAIResponseAPIClient' /** * AihubmixAPIClient - 根据模型类型自动选择合适的ApiClient diff --git a/src/renderer/src/aiCore/clients/cherryin/CherryinAPIClient.ts b/src/renderer/src/aiCore/clients/cherryin/CherryinAPIClient.ts new file mode 100644 index 0000000000..bf3ed7d718 --- /dev/null +++ b/src/renderer/src/aiCore/clients/cherryin/CherryinAPIClient.ts @@ -0,0 +1,51 @@ +import { Provider } from '@renderer/types' +import { OpenAISdkParams, OpenAISdkRawOutput } from '@renderer/types/sdk' +import OpenAI from 'openai' + +import { OpenAIAPIClient } from '../openai/OpenAIApiClient' + +export class CherryinAPIClient extends OpenAIAPIClient { + constructor(provider: Provider) { + super(provider) + } + + override async createCompletions( + payload: OpenAISdkParams, + options?: OpenAI.RequestOptions + ): Promise { + const sdk = await this.getSdkInstance() + options = options || {} + options.headers = options.headers || {} + + const signature = await window.api.cherryin.generateSignature({ + method: 'POST', + path: '/chat/completions', + query: '', + body: payload + }) + + options.headers = { + ...options.headers, + ...signature + } + + // @ts-ignore - SDK参数可能有额外的字段 + return await sdk.chat.completions.create(payload, options) + } + + override getClientCompatibilityType(): string[] { + return ['CherryinAPIClient'] + } + + public async listModels(): Promise { + const models = ['glm-4.5-flash', 'Qwen/Qwen3-8B'] + + const created = Date.now() + return models.map((id) => ({ + id, + owned_by: 'cherryin', + object: 'model' as const, + created + })) + } +} diff --git a/src/renderer/src/aiCore/clients/index.ts b/src/renderer/src/aiCore/clients/index.ts index ec7f9d9d7e..f364dbcee6 100644 --- a/src/renderer/src/aiCore/clients/index.ts +++ b/src/renderer/src/aiCore/clients/index.ts @@ -3,4 +3,6 @@ export * from './BaseApiClient' export * from './types' // Export specific clients from subdirectories +export * from './anthropic/AnthropicAPIClient' export * from './openai/OpenAIApiClient' +export * from './openai/OpenAIResponseAPIClient' diff --git a/src/renderer/src/aiCore/clients/NewAPIClient.ts b/src/renderer/src/aiCore/clients/newapi/NewAPIClient.ts similarity index 89% rename from src/renderer/src/aiCore/clients/NewAPIClient.ts rename to src/renderer/src/aiCore/clients/newapi/NewAPIClient.ts index e87d54ae3e..58b349a2be 100644 --- a/src/renderer/src/aiCore/clients/NewAPIClient.ts +++ b/src/renderer/src/aiCore/clients/newapi/NewAPIClient.ts @@ -3,12 +3,12 @@ import { isSupportedModel } from '@renderer/config/models' import { Model, Provider } from '@renderer/types' import { NewApiModel } from '@renderer/types/sdk' -import { AnthropicAPIClient } from './anthropic/AnthropicAPIClient' -import { BaseApiClient } from './BaseApiClient' -import { GeminiAPIClient } from './gemini/GeminiAPIClient' -import { MixedBaseAPIClient } from './MixedBaseApiClient' -import { OpenAIAPIClient } from './openai/OpenAIApiClient' -import { OpenAIResponseAPIClient } from './openai/OpenAIResponseAPIClient' +import { AnthropicAPIClient } from '../anthropic/AnthropicAPIClient' +import { BaseApiClient } from '../BaseApiClient' +import { GeminiAPIClient } from '../gemini/GeminiAPIClient' +import { MixedBaseAPIClient } from '../MixedBaseApiClient' +import { OpenAIAPIClient } from '../openai/OpenAIApiClient' +import { OpenAIResponseAPIClient } from '../openai/OpenAIResponseAPIClient' const logger = loggerService.withContext('NewAPIClient') diff --git a/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts b/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts index 1665c580de..b9da840164 100644 --- a/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts +++ b/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts @@ -122,13 +122,11 @@ export class OpenAIAPIClient extends OpenAIBaseClient< if (!isReasoningModel(model)) { return {} } + const reasoningEffort = assistant?.settings?.reasoning_effort if (isSupportedThinkingTokenZhipuModel(model)) { - if (!reasoningEffort) { - return { thinking: { type: 'disabled' } } - } - return { thinking: { type: 'enabled' } } + return { thinking: { type: reasoningEffort ? 'enabled' : 'disabled' } } } if (!reasoningEffort) { diff --git a/src/renderer/src/aiCore/clients/zhipu/ZhipuAPIClient.ts b/src/renderer/src/aiCore/clients/zhipu/ZhipuAPIClient.ts new file mode 100644 index 0000000000..c1d7b8f562 --- /dev/null +++ b/src/renderer/src/aiCore/clients/zhipu/ZhipuAPIClient.ts @@ -0,0 +1,100 @@ +import { loggerService } from '@logger' +import { Provider } from '@renderer/types' +import { GenerateImageParams } from '@renderer/types' +import OpenAI from 'openai' + +import { OpenAIAPIClient } from '../openai/OpenAIApiClient' + +const logger = loggerService.withContext('ZhipuAPIClient') + +export class ZhipuAPIClient extends OpenAIAPIClient { + constructor(provider: Provider) { + super(provider) + } + + override getClientCompatibilityType(): string[] { + return ['ZhipuAPIClient'] + } + + override async generateImage({ + model, + prompt, + negativePrompt, + imageSize, + batchSize, + signal, + quality + }: GenerateImageParams): Promise { + const sdk = await this.getSdkInstance() + + // 智谱AI使用不同的参数格式 + const body: any = { + model, + prompt + } + + // 智谱AI特有的参数格式 + body.size = imageSize + body.n = batchSize + if (negativePrompt) { + body.negative_prompt = negativePrompt + } + + // 只有cogview-4-250304模型支持quality和style参数 + if (model === 'cogview-4-250304') { + if (quality) { + body.quality = quality + } + body.style = 'vivid' + } + + try { + logger.debug('Calling Zhipu image generation API with params:', body) + + const response = await sdk.images.generate(body, { signal }) + + if (response.data && response.data.length > 0) { + return response.data.map((image: any) => image.url).filter(Boolean) + } + + return [] + } catch (error) { + logger.error('Zhipu image generation failed:', error as Error) + throw error + } + } + + public async listModels(): Promise { + const models = [ + 'glm-4.5', + 'glm-4.5-x', + 'glm-4.5-air', + 'glm-4.5-airx', + 'glm-4.5-flash', + 'glm-4.5v', + 'glm-z1-air', + 'glm-z1-airx', + 'cogview-3-flash', + 'cogview-4-250304', + 'glm-4-long', + 'glm-4-plus', + 'glm-4-air-250414', + 'glm-4-airx', + 'glm-4-flashx', + 'glm-4v', + 'glm-4v-flash', + 'glm-4v-plus-0111', + 'glm-4.1v-thinking-flash', + 'glm-4-alltools', + 'embedding-3' + ] + + const created = Date.now() + return models.map((id) => ({ + id, + owned_by: 'zhipu', + object: 'model' as const, + created + })) + } +} diff --git a/src/renderer/src/aiCore/index.ts b/src/renderer/src/aiCore/index.ts index 99eb6c940b..2b48137b24 100644 --- a/src/renderer/src/aiCore/index.ts +++ b/src/renderer/src/aiCore/index.ts @@ -9,9 +9,9 @@ import type { GenerateImageParams, Model, Provider } from '@renderer/types' import type { RequestOptions, SdkModel } from '@renderer/types/sdk' import { isEnabledToolUse } from '@renderer/utils/mcp-tools' -import { AihubmixAPIClient } from './clients/AihubmixAPIClient' +import { AihubmixAPIClient } from './clients/aihubmix/AihubmixAPIClient' import { VertexAPIClient } from './clients/gemini/VertexAPIClient' -import { NewAPIClient } from './clients/NewAPIClient' +import { NewAPIClient } from './clients/newapi/NewAPIClient' import { OpenAIResponseAPIClient } from './clients/openai/OpenAIResponseAPIClient' import { CompletionsMiddlewareBuilder } from './middleware/builder' import { MIDDLEWARE_NAME as AbortHandlerMiddlewareName } from './middleware/common/AbortHandlerMiddleware' diff --git a/src/renderer/src/aiCore/middleware/common/ErrorHandlerMiddleware.ts b/src/renderer/src/aiCore/middleware/common/ErrorHandlerMiddleware.ts index 26d9342ebc..d80c9d2f83 100644 --- a/src/renderer/src/aiCore/middleware/common/ErrorHandlerMiddleware.ts +++ b/src/renderer/src/aiCore/middleware/common/ErrorHandlerMiddleware.ts @@ -1,7 +1,9 @@ import { loggerService } from '@logger' +import { isZhipuModel } from '@renderer/config/models' +import store from '@renderer/store' import { Chunk } from '@renderer/types/chunk' -import { CompletionsResult } from '../schemas' +import { CompletionsParams, CompletionsResult } from '../schemas' import { CompletionsContext } from '../types' import { createErrorChunk } from '../utils' @@ -28,17 +30,22 @@ export const ErrorHandlerMiddleware = // 尝试执行下一个中间件 return await next(ctx, params) } catch (error: any) { - logger.error('ErrorHandlerMiddleware_error', error) + logger.error(error) + + let processedError = error + processedError = handleError(error, params) + // 1. 使用通用的工具函数将错误解析为标准格式 - const errorChunk = createErrorChunk(error) + const errorChunk = createErrorChunk(processedError) + // 2. 调用从外部传入的 onError 回调 if (params.onError) { - params.onError(error) + params.onError(processedError) } // 3. 根据配置决定是重新抛出错误,还是将其作为流的一部分向下传递 if (shouldThrow) { - throw error + throw processedError } // 如果不抛出,则创建一个只包含该错误块的流并向下传递 @@ -57,3 +64,70 @@ export const ErrorHandlerMiddleware = } } } + +function handleError(error: any, params: CompletionsParams): any { + if (isZhipuModel(params.assistant.model) && error.status && !params.enableGenerateImage) { + return handleZhipuError(error) + } + + if (error.status === 401 || error.message.includes('401')) { + return { + ...error, + i18nKey: 'chat.no_api_key', + providerId: params.assistant?.model?.provider + } + } + + return error +} + +/** + * 处理智谱特定错误 + * 1. 只有对话功能(enableGenerateImage为false)才使用自定义错误处理 + * 2. 绘画功能(enableGenerateImage为true)使用通用错误处理 + */ +function handleZhipuError(error: any): any { + const provider = store.getState().llm.providers.find((p) => p.id === 'zhipu') + const logger = loggerService.withContext('handleZhipuError') + + // 定义错误模式映射 + const errorPatterns = [ + { + condition: () => error.status === 401 || /令牌已过期|AuthenticationError|Unauthorized/i.test(error.message), + i18nKey: 'chat.no_api_key', + providerId: provider?.id + }, + { + condition: () => error.error?.code === '1304' || /限额|免费配额|free quota|rate limit/i.test(error.message), + i18nKey: 'chat.quota_exceeded', + providerId: provider?.id + }, + { + condition: () => + (error.status === 429 && error.error?.code === '1113') || /余额不足|insufficient balance/i.test(error.message), + i18nKey: 'chat.insufficient_balance', + providerId: provider?.id + }, + { + condition: () => !provider?.apiKey?.trim(), + i18nKey: 'chat.no_api_key', + providerId: provider?.id + } + ] + + // 遍历错误模式,返回第一个匹配的错误 + for (const pattern of errorPatterns) { + if (pattern.condition()) { + return { + ...error, + providerId: pattern.providerId, + i18nKey: pattern.i18nKey + } + } + } + + // 如果不是智谱特定错误,返回原始错误 + logger.debug('🔧 不是智谱特定错误,返回原始错误') + + return error +} diff --git a/src/renderer/src/assets/images/models/chatglm.png b/src/renderer/src/assets/images/models/chatglm.png index 6ef7f44519994d364a302f37e834260b005d5d08..f078fbfe15b9fdf5d0eef48bb51e25a41ee1d765 100644 GIT binary patch literal 19746 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 literal 8504 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 diff --git a/src/renderer/src/assets/images/models/zhipu.png b/src/renderer/src/assets/images/models/zhipu.png index aedb3811c726de374438988f74510647dcc642a5..f078fbfe15b9fdf5d0eef48bb51e25a41ee1d765 100644 GIT binary patch literal 19746 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 literal 7284 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 literal 8943 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 K72nBQME(z_V8YV? diff --git a/src/renderer/src/assets/images/providers/cherryin.png b/src/renderer/src/assets/images/providers/cherryin.png new file mode 100644 index 0000000000000000000000000000000000000000..1a75ff570a381d99e2fe1376e53fd43d54b380ca GIT binary patch literal 7754 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 literal 7284 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 literal 0 HcmV?d00001 diff --git a/src/renderer/src/components/FreeTrialModelTag.tsx b/src/renderer/src/components/FreeTrialModelTag.tsx new file mode 100644 index 0000000000..0ce63ade37 --- /dev/null +++ b/src/renderer/src/components/FreeTrialModelTag.tsx @@ -0,0 +1,81 @@ +import { getProviderLabel } from '@renderer/i18n/label' +import NavigationService from '@renderer/services/NavigationService' +import { Model } from '@renderer/types' +import { ArrowUpRight } from 'lucide-react' +import { FC, MouseEvent } from 'react' +import styled from 'styled-components' + +import IndicatorLight from './IndicatorLight' +import SelectModelPopup from './Popups/SelectModelPopup' +import CustomTag from './Tags/CustomTag' + +interface Props { + model: Model + showLabel?: boolean +} + +export const FreeTrialModelTag: FC = ({ model, showLabel = true }) => { + if (model.provider !== 'cherryin') { + return null + } + + let providerId + + if (model.id === 'glm-4.5-flash') { + providerId = 'zhipu' + } + + if (model.id === 'Qwen/Qwen3-8B') { + providerId = 'silicon' + } + + const onSelectProvider = () => { + NavigationService.navigate!(`/settings/provider?id=${providerId}`) + } + + const onNavigateProvider = (e: MouseEvent) => { + e.stopPropagation() + SelectModelPopup.hide() + NavigationService.navigate!(`/settings/provider?id=${providerId}`) + } + + if (!showLabel) { + return ( + + + {getProviderLabel(providerId)} + + + + ) + } + + return ( + + + Powered by + {getProviderLabel(providerId)} + + ) +} + +const Container = styled.div` + display: flex; + flex-direction: row; + align-items: center; + gap: 4px; +` + +const PoweredBy = styled.span` + font-size: 12px; + color: var(--color-text-2); +` + +const LinkText = styled.a` + font-size: 12px; + color: var(--color-link); +` diff --git a/src/renderer/src/components/Icons/SVGIcon.tsx b/src/renderer/src/components/Icons/SVGIcon.tsx index 8cae9c94de..a83685e4db 100644 --- a/src/renderer/src/components/Icons/SVGIcon.tsx +++ b/src/renderer/src/components/Icons/SVGIcon.tsx @@ -239,6 +239,18 @@ export function BochaLogo(props: SVGProps) { ) } +export function ZhipuLogo(props: SVGProps) { + return ( + + + + ) +} export function PoeLogo(props: SVGProps) { return ( = ({ model, resolve, modelFilter, userFilt (model: Model, provider: Provider, isPinned: boolean): FlatListModel => { const modelId = getModelUniqId(model) const groupName = getFancyProviderName(provider) + const isCherryin = provider.id === 'cherryin' return { key: isPinned ? `${modelId}_pinned` : modelId, @@ -209,11 +211,12 @@ const PopupContainer: React.FC = ({ model, resolve, modelFilter, userFilt {model.name} {isPinned && | {groupName}} + {isCherryin && } ), tags: ( - + ), icon: ( @@ -280,7 +283,7 @@ const PopupContainer: React.FC = ({ model, resolve, modelFilter, userFilt type="text" size="small" shape="circle" - icon={} + icon={} onClick={(e) => { e.stopPropagation() setOpen(false) @@ -576,7 +579,7 @@ const ListContainer = styled.div` const GroupItem = styled.div` display: flex; align-items: center; - justify-content: space-between; + gap: 2px; position: relative; font-size: 12px; font-weight: normal; @@ -585,6 +588,17 @@ const GroupItem = styled.div` color: var(--color-text-3); z-index: 1; background: var(--modal-background); + + &:hover { + .ant-btn { + opacity: 1; + } + } + + .ant-btn { + opacity: 0; + transition: opacity 0.2s; + } ` const ModelItem = styled.div` @@ -640,13 +654,16 @@ const ModelItemLeft = styled.div` } ` -const ModelName = styled.span` +const ModelName = styled.div` + display: flex; + flex-direction: row; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; margin: 0 8px; min-width: 0; + gap: 5px; ` const TagsContainer = styled.div` diff --git a/src/renderer/src/components/Tags/CustomTag.tsx b/src/renderer/src/components/Tags/CustomTag.tsx index c7abd15a62..d078d46d38 100644 --- a/src/renderer/src/components/Tags/CustomTag.tsx +++ b/src/renderer/src/components/Tags/CustomTag.tsx @@ -1,6 +1,6 @@ import { CloseOutlined } from '@ant-design/icons' import { Tooltip } from 'antd' -import { CSSProperties, FC, memo, useMemo } from 'react' +import { CSSProperties, FC, memo, MouseEventHandler, useMemo } from 'react' import styled from 'styled-components' export interface CustomTagProps { @@ -12,7 +12,7 @@ export interface CustomTagProps { tooltip?: string closable?: boolean onClose?: () => void - onClick?: () => void + onClick?: MouseEventHandler disabled?: boolean inactive?: boolean } diff --git a/src/renderer/src/components/Tags/Model/FreeTag.tsx b/src/renderer/src/components/Tags/Model/FreeTag.tsx index a046449dcf..44b19012e0 100644 --- a/src/renderer/src/components/Tags/Model/FreeTag.tsx +++ b/src/renderer/src/components/Tags/Model/FreeTag.tsx @@ -15,6 +15,7 @@ export const FreeTag = ({ size, showTooltip, ...restProps }: Props) => { color="#7cb305" icon={t('models.type.free')} tooltip={showTooltip ? t('models.type.free') : undefined} - {...restProps}> + {...restProps} + /> ) } diff --git a/src/renderer/src/config/minapps.ts b/src/renderer/src/config/minapps.ts index aa2cee372c..8fdfff9beb 100644 --- a/src/renderer/src/config/minapps.ts +++ b/src/renderer/src/config/minapps.ts @@ -35,7 +35,6 @@ import NamiAiSearchLogo from '@renderer/assets/images/apps/nm-search.webp?url' import NotebookLMAppLogo from '@renderer/assets/images/apps/notebooklm.svg?url' import PerplexityAppLogo from '@renderer/assets/images/apps/perplexity.webp?url' import PoeAppLogo from '@renderer/assets/images/apps/poe.webp?url' -import ZhipuProviderLogo from '@renderer/assets/images/apps/qingyan.png?url' import QwenlmAppLogo from '@renderer/assets/images/apps/qwenlm.webp?url' import SensetimeAppLogo from '@renderer/assets/images/apps/sensetime.png?url' import SparkDeskAppLogo from '@renderer/assets/images/apps/sparkdesk.webp?url' @@ -56,6 +55,7 @@ import DeepSeekProviderLogo from '@renderer/assets/images/providers/deepseek.png import GroqProviderLogo from '@renderer/assets/images/providers/groq.png?url' import OpenAiProviderLogo from '@renderer/assets/images/providers/openai.png?url' import SiliconFlowProviderLogo from '@renderer/assets/images/providers/silicon.png?url' +import ZhipuProviderLogo from '@renderer/assets/images/providers/zhipu.png?url' import i18n from '@renderer/i18n' import { MinAppType } from '@renderer/types' @@ -126,7 +126,8 @@ const ORIGIN_DEFAULT_MIN_APPS: MinAppType[] = [ id: 'zhipu', name: i18n.t('minapps.chatglm'), url: 'https://chatglm.cn/main/alltoolsdetail', - logo: ZhipuProviderLogo + logo: ZhipuProviderLogo, + bodered: true }, { id: 'moonshot', diff --git a/src/renderer/src/config/models.ts b/src/renderer/src/config/models.ts index bba48781f4..a5fae53794 100644 --- a/src/renderer/src/config/models.ts +++ b/src/renderer/src/config/models.ts @@ -146,8 +146,11 @@ import XirangModelLogo from '@renderer/assets/images/models/xirang.png' import XirangModelLogoDark from '@renderer/assets/images/models/xirang_dark.png' import YiModelLogo from '@renderer/assets/images/models/yi.png' import YiModelLogoDark from '@renderer/assets/images/models/yi_dark.png' +import ZhipuModelLogo from '@renderer/assets/images/models/zhipu.png' +import ZhipuModelLogoDark from '@renderer/assets/images/models/zhipu_dark.png' import YoudaoLogo from '@renderer/assets/images/providers/netease-youdao.svg' import NomicLogo from '@renderer/assets/images/providers/nomic.png' +import ZhipuProviderLogo from '@renderer/assets/images/providers/zhipu.png' import { getProviderByModel } from '@renderer/services/AssistantService' import { isSystemProviderId, @@ -277,7 +280,8 @@ const FUNCTION_CALLING_EXCLUDED_MODELS = [ 'AIDC-AI/Marco-o1', 'gemini-1(?:\\.[\\w-]+)?', 'qwen-mt(?:-[\\w-]+)?', - 'gpt-5-chat(?:-[\\w-]+)?' + 'gpt-5-chat(?:-[\\w-]+)?', + 'glm-4\\.5v' ] export const FUNCTION_CALLING_REGEX = new RegExp( @@ -515,6 +519,7 @@ export function getModelLogo(modelId: string) { xirang: isLight ? XirangModelLogo : XirangModelLogoDark, hugging: isLight ? HuggingfaceModelLogo : HuggingfaceModelLogoDark, youdao: YoudaoLogo, + 'embedding-3': ZhipuProviderLogo, embedding: isLight ? EmbeddingModelLogo : EmbeddingModelLogoDark, perplexity: isLight ? PerplexityModelLogo : PerplexityModelLogoDark, sonar: isLight ? PerplexityModelLogo : PerplexityModelLogoDark, @@ -522,7 +527,9 @@ export function getModelLogo(modelId: string) { 'voyage-': VoyageModelLogo, tokenflux: isLight ? TokenFluxModelLogo : TokenFluxModelLogoDark, 'nomic-': NomicLogo, - 'pangu-': PanguModelLogo + 'pangu-': PanguModelLogo, + cogview: isLight ? ZhipuModelLogo : ZhipuModelLogoDark, + zhipu: isLight ? ZhipuModelLogo : ZhipuModelLogoDark } for (const key in logoMap) { @@ -535,35 +542,43 @@ export function getModelLogo(modelId: string) { return undefined } +export const glm45FlashModel: Model = { + id: 'glm-4.5-flash', + name: 'GLM-4.5-Flash', + provider: 'cherryin', + group: 'GLM-4.5' +} + +export const qwen38bModel: Model = { + id: 'Qwen/Qwen3-8B', + name: 'Qwen3-8B', + provider: 'cherryin', + group: 'Qwen' +} + export const SYSTEM_MODELS: Record = { defaultModel: [ + // Default assistant model + glm45FlashModel, + // Default topic naming model + qwen38bModel, + // Default translation model + glm45FlashModel, + // Default quick assistant model + glm45FlashModel + ], + cherryin: [ { - // 默认助手模型 - id: 'deepseek-ai/DeepSeek-V3', - name: 'deepseek-ai/DeepSeek-V3', - provider: 'silicon', - group: 'deepseek-ai' + id: 'glm-4.5-flash', + name: 'GLM-4.5-Flash', + provider: 'cherryin', + group: 'GLM-4.5' }, { - // 默认话题命名模型 id: 'Qwen/Qwen3-8B', - name: 'Qwen/Qwen3-8B', - provider: 'silicon', + name: 'Qwen3-8B', + provider: 'cherryin', group: 'Qwen' - }, - { - // 默认翻译模型 - id: 'deepseek-ai/DeepSeek-V3', - name: 'deepseek-ai/DeepSeek-V3', - provider: 'silicon', - group: 'deepseek-ai' - }, - { - // 默认快捷助手模型 - id: 'deepseek-ai/DeepSeek-V3', - name: 'deepseek-ai/DeepSeek-V3', - provider: 'silicon', - group: 'deepseek-ai' } ], vertexai: [], @@ -1225,113 +1240,35 @@ export const SYSTEM_MODELS: Record = { id: 'yi-vision-v2', name: 'Yi Vision v2', provider: 'yi', group: 'yi-vision', owned_by: '01.ai' } ], zhipu: [ - { - id: 'glm-4.5', - provider: 'zhipu', - name: 'GLM-4.5', - group: 'GLM-4.5' - }, { id: 'glm-4.5-flash', provider: 'zhipu', name: 'GLM-4.5-Flash', group: 'GLM-4.5' }, + { + id: 'glm-4.5', + provider: 'zhipu', + name: 'GLM-4.5', + group: 'GLM-4.5' + }, { id: 'glm-4.5-air', provider: 'zhipu', - name: 'GLM-4.5-AIR', + name: 'GLM-4.5-Air', group: 'GLM-4.5' }, { id: 'glm-4.5-airx', provider: 'zhipu', - name: 'GLM-4.5-AIRX', + name: 'GLM-4.5-AirX', group: 'GLM-4.5' }, { - id: 'glm-4.5-x', + id: 'glm-4.5v', provider: 'zhipu', - name: 'GLM-4.5-X', - group: 'GLM-4.5' - }, - { - id: 'glm-z1-air', - provider: 'zhipu', - name: 'GLM-Z1-AIR', - group: 'GLM-Z1' - }, - { - id: 'glm-z1-airx', - provider: 'zhipu', - name: 'GLM-Z1-AIRX', - group: 'GLM-Z1' - }, - { - id: 'glm-z1-flash', - provider: 'zhipu', - name: 'GLM-Z1-FLASH', - group: 'GLM-Z1' - }, - { - id: 'glm-4-long', - provider: 'zhipu', - name: 'GLM-4-Long', - group: 'GLM-4' - }, - { - id: 'glm-4-plus', - provider: 'zhipu', - name: 'GLM-4-Plus', - group: 'GLM-4' - }, - { - id: 'glm-4-air-250414', - provider: 'zhipu', - name: 'GLM-4-Air-250414', - group: 'GLM-4' - }, - { - id: 'glm-4-airx', - provider: 'zhipu', - name: 'GLM-4-AirX', - group: 'GLM-4' - }, - { - id: 'glm-4-flash-250414', - provider: 'zhipu', - name: 'GLM-4-Flash-250414', - group: 'GLM-4' - }, - { - id: 'glm-4-flashx', - provider: 'zhipu', - name: 'GLM-4-FlashX', - group: 'GLM-4' - }, - { - id: 'glm-4v', - provider: 'zhipu', - name: 'GLM 4V', - group: 'GLM-4v' - }, - { - id: 'glm-4v-flash', - provider: 'zhipu', - name: 'GLM-4V-Flash', - group: 'GLM-4v' - }, - { - id: 'glm-4v-plus-0111', - provider: 'zhipu', - name: 'GLM-4V-Plus-0111', - group: 'GLM-4v' - }, - { - id: 'glm-4-alltools', - provider: 'zhipu', - name: 'GLM-4-AllTools', - group: 'GLM-4-AllTools' + name: 'GLM-4.5V', + group: 'GLM-4.5V' }, { id: 'embedding-3', diff --git a/src/renderer/src/config/providers.ts b/src/renderer/src/config/providers.ts index 795b243c62..2ad123f32f 100644 --- a/src/renderer/src/config/providers.ts +++ b/src/renderer/src/config/providers.ts @@ -11,6 +11,7 @@ import BaiduCloudProviderLogo from '@renderer/assets/images/providers/baidu-clou import BailianProviderLogo from '@renderer/assets/images/providers/bailian.png' import BurnCloudProviderLogo from '@renderer/assets/images/providers/burncloud.png' import CephalonProviderLogo from '@renderer/assets/images/providers/cephalon.jpeg' +import CherryInProviderLogo from '@renderer/assets/images/providers/cherryin.png' import DeepSeekProviderLogo from '@renderer/assets/images/providers/deepseek.png' import DmxapiProviderLogo from '@renderer/assets/images/providers/DMXAPI.png' import FireworksProviderLogo from '@renderer/assets/images/providers/fireworks.png' @@ -65,6 +66,16 @@ import { TOKENFLUX_HOST } from './constant' import { SYSTEM_MODELS } from './models' export const SYSTEM_PROVIDERS_CONFIG: Record = { + cherryin: { + id: 'cherryin', + name: 'CherryIN', + type: 'openai', + apiKey: '', + apiHost: 'https://api.cherry-ai.com/', + models: SYSTEM_MODELS.cherryin, + isSystem: true, + enabled: true + }, silicon: { id: 'silicon', name: 'Silicon', @@ -73,7 +84,7 @@ export const SYSTEM_PROVIDERS_CONFIG: Record = apiHost: 'https://api.siliconflow.cn', models: SYSTEM_MODELS.silicon, isSystem: true, - enabled: true + enabled: false }, aihubmix: { id: 'aihubmix', @@ -95,6 +106,16 @@ export const SYSTEM_PROVIDERS_CONFIG: Record = isSystem: true, enabled: false }, + zhipu: { + id: 'zhipu', + name: 'ZhiPu', + type: 'openai', + apiKey: '', + apiHost: 'https://open.bigmodel.cn/api/paas/v4/', + models: SYSTEM_MODELS.zhipu, + isSystem: true, + enabled: false + }, deepseek: { id: 'deepseek', name: 'deepseek', @@ -320,16 +341,6 @@ export const SYSTEM_PROVIDERS_CONFIG: Record = enabled: false, isAuthed: false }, - zhipu: { - id: 'zhipu', - name: 'ZhiPu', - type: 'openai', - apiKey: '', - apiHost: 'https://open.bigmodel.cn/api/paas/v4/', - models: SYSTEM_MODELS.zhipu, - isSystem: true, - enabled: false - }, yi: { id: 'yi', name: 'Yi', @@ -595,6 +606,7 @@ export const SYSTEM_PROVIDERS_CONFIG: Record = export const SYSTEM_PROVIDERS: SystemProvider[] = Object.values(SYSTEM_PROVIDERS_CONFIG) export const PROVIDER_LOGO_MAP: AtLeast = { + cherryin: CherryInProviderLogo, ph8: Ph8ProviderLogo, '302ai': Ai302ProviderLogo, openai: OpenAiProviderLogo, @@ -673,6 +685,16 @@ type ProviderUrls = { } export const PROVIDER_URLS: Record = { + cherryin: { + api: { + url: 'https://api.cherry-ai.com' + }, + websites: { + official: 'https://cherry-ai.com', + docs: 'https://docs.cherry-ai.com', + models: 'https://docs.cherry-ai.com/pre-basic/providers/cherryin' + } + }, ph8: { api: { url: 'https://ph8.co' diff --git a/src/renderer/src/config/webSearchProviders.ts b/src/renderer/src/config/webSearchProviders.ts index 62c0536f4d..abeac52938 100644 --- a/src/renderer/src/config/webSearchProviders.ts +++ b/src/renderer/src/config/webSearchProviders.ts @@ -8,6 +8,12 @@ type WebSearchProviderConfig = { } export const WEB_SEARCH_PROVIDER_CONFIG: Record = { + zhipu: { + websites: { + official: 'https://docs.bigmodel.cn/cn/guide/tools/web-search', + apiKey: 'https://zhipuaishengchan.datasink.sensorsdata.cn/t/yv' + } + }, tavily: { websites: { official: 'https://tavily.com', @@ -49,6 +55,12 @@ export const WEB_SEARCH_PROVIDER_CONFIG: Record state.paintings.paintings) - const generate = useAppSelector((state) => state.paintings.generate) - const remix = useAppSelector((state) => state.paintings.remix) - const edit = useAppSelector((state) => state.paintings.edit) - const upscale = useAppSelector((state) => state.paintings.upscale) - const DMXAPIPaintings = useAppSelector((state) => state.paintings.DMXAPIPaintings) - const tokenFluxPaintings = useAppSelector((state) => state.paintings.tokenFluxPaintings) + const siliconflow_paintings = useAppSelector((state) => state.paintings.siliconflow_paintings) + const dmxapi_paintings = useAppSelector((state) => state.paintings.dmxapi_paintings) + const tokenflux_paintings = useAppSelector((state) => state.paintings.tokenflux_paintings) + const zhipu_paintings = useAppSelector((state) => state.paintings.zhipu_paintings) + const aihubmix_image_generate = useAppSelector((state) => state.paintings.aihubmix_image_generate) + const aihubmix_image_remix = useAppSelector((state) => state.paintings.aihubmix_image_remix) + const aihubmix_image_edit = useAppSelector((state) => state.paintings.aihubmix_image_edit) + const aihubmix_image_upscale = useAppSelector((state) => state.paintings.aihubmix_image_upscale) const openai_image_generate = useAppSelector((state) => state.paintings.openai_image_generate) const openai_image_edit = useAppSelector((state) => state.paintings.openai_image_edit) const dispatch = useAppDispatch() return { - paintings, - DMXAPIPaintings, - tokenFluxPaintings, - persistentData: { - generate, - remix, - edit, - upscale, - tokenFluxPaintings - }, - newApiPaintings: { - openai_image_generate, - openai_image_edit - }, + siliconflow_paintings, + dmxapi_paintings, + tokenflux_paintings, + zhipu_paintings, + aihubmix_image_generate, + aihubmix_image_remix, + aihubmix_image_edit, + aihubmix_image_upscale, + openai_image_generate, + openai_image_edit, addPainting: (namespace: keyof PaintingsState, painting: PaintingAction) => { dispatch(addPainting({ namespace, painting })) return painting diff --git a/src/renderer/src/i18n/label.ts b/src/renderer/src/i18n/label.ts index 2e85dbaf62..63ffc2e40e 100644 --- a/src/renderer/src/i18n/label.ts +++ b/src/renderer/src/i18n/label.ts @@ -13,7 +13,7 @@ const t = i18n.t const logger = loggerService.withContext('i18n:label') -const getLabel = (key: string, keyMap: Record, fallback?: string) => { +const getLabel = (keyMap: Record, key: string, fallback?: string) => { const result = keyMap[key] if (result) { return t(result) @@ -34,6 +34,7 @@ const providerKeyMap = { 'baidu-cloud': 'provider.baidu-cloud', burncloud: 'provider.burncloud', cephalon: 'provider.cephalon', + cherryin: 'provider.cherryin', copilot: 'provider.copilot', dashscope: 'provider.dashscope', deepseek: 'provider.deepseek', @@ -92,7 +93,7 @@ const providerKeyMap = { * 对于可能处理自定义供应商的情况,使用 getProviderName 或 getFancyProviderName 更安全 */ export const getProviderLabel = (id: string): string => { - return getLabel(id, providerKeyMap) + return getLabel(providerKeyMap, id) } const backupProgressKeyMap = { @@ -106,7 +107,7 @@ const backupProgressKeyMap = { } as const export const getBackupProgressLabel = (key: string): string => { - return getLabel(key, backupProgressKeyMap) + return getLabel(backupProgressKeyMap, key) } const restoreProgressKeyMap = { @@ -120,7 +121,7 @@ const restoreProgressKeyMap = { } export const getRestoreProgressLabel = (key: string): string => { - return getLabel(key, restoreProgressKeyMap) + return getLabel(restoreProgressKeyMap, key) } const titleKeyMap = { @@ -139,7 +140,7 @@ const titleKeyMap = { } as const export const getTitleLabel = (key: string): string => { - return getLabel(key, titleKeyMap) + return getLabel(titleKeyMap, key) } const themeModeKeyMap = { @@ -149,7 +150,7 @@ const themeModeKeyMap = { } as const export const getThemeModeLabel = (key: string): string => { - return getLabel(key, themeModeKeyMap) + return getLabel(themeModeKeyMap, key) } const sidebarIconKeyMap = { @@ -164,7 +165,7 @@ const sidebarIconKeyMap = { } as const export const getSidebarIconLabel = (key: string): string => { - return getLabel(key, sidebarIconKeyMap) + return getLabel(sidebarIconKeyMap, key) } const shortcutKeyMap = { @@ -198,7 +199,7 @@ const shortcutKeyMap = { } as const export const getShortcutLabel = (key: string): string => { - return getLabel(key, shortcutKeyMap) + return getLabel(shortcutKeyMap, key) } const selectionDescriptionKeyMap = { @@ -207,7 +208,7 @@ const selectionDescriptionKeyMap = { } as const export const getSelectionDescriptionLabel = (key: string): string => { - return getLabel(key, selectionDescriptionKeyMap) + return getLabel(selectionDescriptionKeyMap, key) } const paintingsImageSizeOptionsKeyMap = { @@ -215,7 +216,7 @@ const paintingsImageSizeOptionsKeyMap = { } as const export const getPaintingsImageSizeOptionsLabel = (key: string): string => { - return getLabel(key, paintingsImageSizeOptionsKeyMap) + return getLabel(paintingsImageSizeOptionsKeyMap, key) } const paintingsQualityOptionsKeyMap = { @@ -226,7 +227,7 @@ const paintingsQualityOptionsKeyMap = { } as const export const getPaintingsQualityOptionsLabel = (key: string): string => { - return getLabel(key, paintingsQualityOptionsKeyMap) + return getLabel(paintingsQualityOptionsKeyMap, key) } const paintingsModerationOptionsKeyMap = { @@ -235,7 +236,7 @@ const paintingsModerationOptionsKeyMap = { } as const export const getPaintingsModerationOptionsLabel = (key: string): string => { - return getLabel(key, paintingsModerationOptionsKeyMap) + return getLabel(paintingsModerationOptionsKeyMap, key) } const paintingsBackgroundOptionsKeyMap = { @@ -245,7 +246,7 @@ const paintingsBackgroundOptionsKeyMap = { } as const export const getPaintingsBackgroundOptionsLabel = (key: string): string => { - return getLabel(key, paintingsBackgroundOptionsKeyMap) + return getLabel(paintingsBackgroundOptionsKeyMap, key) } const mcpTypeKeyMap = { @@ -256,7 +257,7 @@ const mcpTypeKeyMap = { } as const export const getMcpTypeLabel = (key: string): string => { - return getLabel(key, mcpTypeKeyMap) + return getLabel(mcpTypeKeyMap, key) } const miniappsStatusKeyMap = { @@ -265,7 +266,7 @@ const miniappsStatusKeyMap = { } as const export const getMiniappsStatusLabel = (key: string): string => { - return getLabel(key, miniappsStatusKeyMap) + return getLabel(miniappsStatusKeyMap, key) } const httpMessageKeyMap = { @@ -281,7 +282,7 @@ const httpMessageKeyMap = { } as const export const getHttpMessageLabel = (key: string): string => { - return getLabel(key, httpMessageKeyMap) + return getLabel(httpMessageKeyMap, key) } const reasoningEffortOptionsKeyMap: Record = { @@ -294,7 +295,7 @@ const reasoningEffortOptionsKeyMap: Record = { } as const export const getReasoningEffortOptionsLabel = (key: string): string => { - return getLabel(key, reasoningEffortOptionsKeyMap) + return getLabel(reasoningEffortOptionsKeyMap, key) } const fileFieldKeyMap = { @@ -304,7 +305,7 @@ const fileFieldKeyMap = { } as const export const getFileFieldLabel = (key: string): string => { - return getLabel(key, fileFieldKeyMap) + return getLabel(fileFieldKeyMap, key) } const builtInMcpDescriptionKeyMap: Record = { @@ -319,7 +320,7 @@ const builtInMcpDescriptionKeyMap: Record = { } as const export const getBuiltInMcpServerDescriptionLabel = (key: string): string => { - return getLabel(key, builtInMcpDescriptionKeyMap, t('settings.mcp.builtinServersDescriptions.no')) + return getLabel(builtInMcpDescriptionKeyMap, key, t('settings.mcp.builtinServersDescriptions.no')) } const builtinOcrProviderKeyMap = { @@ -329,5 +330,5 @@ const builtinOcrProviderKeyMap = { export const getBuiltinOcrProviderLabel = (key: BuiltinOcrProviderId) => { if (key === 'tesseract') return 'Tesseract' - else return getLabel(key, builtinOcrProviderKeyMap) + else return getLabel(builtinOcrProviderKeyMap, key) } diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index b87aa8f686..86e278fadd 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -756,6 +756,7 @@ "footnote": "Reference content", "footnotes": "References", "fullscreen": "Entered fullscreen mode. Press F11 to exit", + "go_to_settings": "Go to settings", "i_know": "I know", "inspect": "Inspect", "knowledge_base": "Knowledge Base", @@ -824,6 +825,9 @@ "chunk": { "non_json": "Returned an invalid data format" }, + "insufficient_balance": "Please go to the {{provider}} to recharge.", + "no_api_key": "You have not configured an API key. Please go to the {{provider}} to obtain an API key.", + "quota_exceeded": "Your daily {{quota}} free quota has been exhausted. Please go to the {{provider}} to obtain an API key and configure the API key to continue using.", "response": "Something went wrong. Please check if you have set your API key in the Settings > Providers" }, "http": { @@ -1824,6 +1828,7 @@ "baidu-cloud": "Baidu Cloud", "burncloud": "BurnCloud", "cephalon": "Cephalon", + "cherryin": "CherryIN", "copilot": "GitHub Copilot", "dashscope": "Alibaba Cloud", "deepseek": "DeepSeek", @@ -1869,7 +1874,7 @@ "xirang": "State Cloud Xirang", "yi": "Yi", "zhinao": "360AI", - "zhipu": "ZHIPU AI" + "zhipu": "BigModel" }, "restore": { "confirm": { @@ -2911,7 +2916,8 @@ "modelscope": "ModelScope Community MCP Server", "official": "Official MCP Server Collection", "pulsemcp": "Pulse MCP Server", - "smithery": "Smithery MCP Tools" + "smithery": "Smithery MCP Tools", + "zhipu": "Curated MCP, Fast Integration" }, "name": "Name", "newServer": "MCP Server", diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index d8c33f98ad..8c0570a9e8 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -756,6 +756,7 @@ "footnote": "引用内容", "footnotes": "脚注", "fullscreen": "全画面モードに入りました。F11キーで終了します", + "go_to_settings": "設定に移動", "i_know": "わかりました", "inspect": "検査", "knowledge_base": "ナレッジベース", @@ -824,6 +825,9 @@ "chunk": { "non_json": "無効なデータ形式が返されました" }, + "insufficient_balance": "{{provider}}でチャージしてください。", + "no_api_key": "APIキーが設定されていません。{{provider}}でAPIキーを取得してください。", + "quota_exceeded": "本日の{{quota}}無料クォータが使い果たされました。{{provider}}でAPIキーを取得し、APIキーを設定して使用を続けてください。", "response": "エラーが発生しました。APIキーが設定されていない場合は、設定 > プロバイダーでキーを設定してください" }, "http": { @@ -1824,6 +1828,7 @@ "baidu-cloud": "Baidu Cloud", "burncloud": "BurnCloud", "cephalon": "Cephalon", + "cherryin": "CherryIN", "copilot": "GitHub Copilot", "dashscope": "Alibaba Cloud", "deepseek": "DeepSeek", @@ -1869,7 +1874,7 @@ "xirang": "天翼クラウド 息壤", "yi": "零一万物", "zhinao": "360智脳", - "zhipu": "智譜AI" + "zhipu": "BigModel" }, "restore": { "confirm": { @@ -2911,7 +2916,8 @@ "modelscope": "魔搭コミュニティ MCP サーバー", "official": "公式 MCP サーバーコレクション", "pulsemcp": "Pulse MCP サーバー", - "smithery": "Smithery MCP ツール" + "smithery": "Smithery MCP ツール", + "zhipu": "厳選MCP、高速統合" }, "name": "名前", "newServer": "MCP サーバー", diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index 929c574906..d3211cfcad 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -756,6 +756,7 @@ "footnote": "Цитируемый контент", "footnotes": "Сноски", "fullscreen": "Вы вошли в полноэкранный режим. Нажмите F11 для выхода", + "go_to_settings": "Перейти в настройки", "i_know": "Я понял", "inspect": "Осмотреть", "knowledge_base": "База знаний", @@ -824,6 +825,9 @@ "chunk": { "non_json": "Вернулся недопустимый формат данных" }, + "insufficient_balance": "Пожалуйста, перейдите в {{provider}} для пополнения баланса.", + "no_api_key": "Вы не настроили ключ API. Пожалуйста, перейдите в {{provider}} для получения ключа API.", + "quota_exceeded": "Ваша ежедневная {{quota}} бесплатная квота исчерпана. Пожалуйста, перейдите в {{provider}} для получения ключа API и настройте ключ API для продолжения использования.", "response": "Что-то пошло не так. Пожалуйста, проверьте, установлен ли ваш ключ API в Настройки > Провайдеры" }, "http": { @@ -1824,6 +1828,7 @@ "baidu-cloud": "Baidu Cloud", "burncloud": "BurnCloud", "cephalon": "Cephalon", + "cherryin": "CherryIN", "copilot": "GitHub Copilot", "dashscope": "Alibaba Cloud", "deepseek": "DeepSeek", @@ -1869,7 +1874,7 @@ "xirang": "State Cloud Xirang", "yi": "Yi", "zhinao": "360AI", - "zhipu": "ZHIPU AI" + "zhipu": "BigModel" }, "restore": { "confirm": { @@ -2911,7 +2916,8 @@ "modelscope": "Сервер MCP сообщества ModelScope", "official": "Официальная коллекция серверов MCP", "pulsemcp": "Сервер Pulse MCP", - "smithery": "Инструменты Smithery MCP" + "smithery": "Инструменты Smithery MCP", + "zhipu": "Кураторские MCP, быстрая интеграция" }, "name": "Имя", "newServer": "MCP сервер", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 794ed78bc5..6361f705ed 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -756,6 +756,7 @@ "footnote": "引用内容", "footnotes": "引用内容", "fullscreen": "已进入全屏模式,按 F11 退出", + "go_to_settings": "前往设置", "i_know": "我知道了", "inspect": "检查", "knowledge_base": "知识库", @@ -824,6 +825,9 @@ "chunk": { "non_json": "返回了无效的数据格式" }, + "insufficient_balance": "请前往 {{provider}} 充值", + "no_api_key": "您未配置 API 密钥,请前往 {{provider}} 获取API密钥", + "quota_exceeded": "您今日免费配额已用尽,请前往 {{provider}} 获取API密钥,配置API密钥后继续使用", "response": "出错了,如果没有配置 API 密钥,请前往设置 > 模型提供商中配置密钥" }, "http": { @@ -1824,6 +1828,7 @@ "baidu-cloud": "百度云千帆", "burncloud": "BurnCloud", "cephalon": "Cephalon", + "cherryin": "CherryIN", "copilot": "GitHub Copilot", "dashscope": "阿里云百炼", "deepseek": "深度求索", @@ -1869,7 +1874,7 @@ "xirang": "天翼云息壤", "yi": "零一万物", "zhinao": "360 智脑", - "zhipu": "智谱 AI" + "zhipu": "智谱开放平台" }, "restore": { "confirm": { @@ -2911,7 +2916,8 @@ "modelscope": "魔搭社区 MCP 服务器", "official": "官方 MCP 服务器集合", "pulsemcp": "Pulse MCP 服务器", - "smithery": "Smithery MCP 工具" + "smithery": "Smithery MCP 工具", + "zhipu": "精选MCP,极速接入" }, "name": "名称", "newServer": "MCP 服务器", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 8622b64b3a..eaf621da8f 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -756,6 +756,7 @@ "footnote": "引用內容", "footnotes": "引用", "fullscreen": "已進入全螢幕模式,按 F11 結束", + "go_to_settings": "前往設定", "i_know": "我知道了", "inspect": "檢查", "knowledge_base": "知識庫", @@ -824,6 +825,9 @@ "chunk": { "non_json": "返回了無效的資料格式" }, + "insufficient_balance": "請前往 {{provider}} 充值", + "no_api_key": "您未配置 API 密钥,请前往 {{provider}} 获取API密钥", + "quota_exceeded": "您今日{{quota}}免费配额已用尽,请前往 {{provider}} 获取API密钥,配置API密钥后继续使用", "response": "出現錯誤。如果尚未設定 API 金鑰,請前往設定 > 模型提供者中設定金鑰" }, "http": { @@ -1824,6 +1828,7 @@ "baidu-cloud": "百度雲千帆", "burncloud": "BurnCloud", "cephalon": "Cephalon", + "cherryin": "CherryIN", "copilot": "GitHub Copilot", "dashscope": "阿里雲百鍊", "deepseek": "深度求索", @@ -1869,7 +1874,7 @@ "xirang": "天翼雲息壤", "yi": "零一萬物", "zhinao": "360 智腦", - "zhipu": "智譜 AI" + "zhipu": "智譜開放平台" }, "restore": { "confirm": { @@ -2911,7 +2916,8 @@ "modelscope": "魔搭社區 MCP 伺服器", "official": "官方 MCP 伺服器集合", "pulsemcp": "Pulse MCP 伺服器", - "smithery": "Smithery MCP 工具" + "smithery": "Smithery MCP 工具", + "zhipu": "精選MCP,極速接入" }, "name": "名稱", "newServer": "MCP 伺服器", diff --git a/src/renderer/src/i18n/translate/el-gr.json b/src/renderer/src/i18n/translate/el-gr.json index ff51752b1e..ca305f0013 100644 --- a/src/renderer/src/i18n/translate/el-gr.json +++ b/src/renderer/src/i18n/translate/el-gr.json @@ -756,6 +756,7 @@ "footnote": "Παραπομπή", "footnotes": "Παραπομπές", "fullscreen": "Εισήχθη σε πλήρη οθόνη, πατήστε F11 για να έξω", + "go_to_settings": "Πηγαίνετε στις ρυθμίσεις", "i_know": "Το έχω καταλάβει", "inspect": "Επιθεώρηση", "knowledge_base": "Βάση Γνώσεων", @@ -824,6 +825,9 @@ "chunk": { "non_json": "Επέστρεψε μη έγκυρη μορφή δεδομένων" }, + "insufficient_balance": "Παρακαλώ μεταβείτε στο {{provider}} για επαναφόρτωση.", + "no_api_key": "Δεν έχετε ρυθμίσει το κλειδί API. Παρακαλώ μεταβείτε στο {{provider}} για να λάβετε ένα κλειδί API.", + "quota_exceeded": "Η ημερήσια δωρεάν ποσόστωση {{quota}} tokens σας έχει εξαντληθεί. Παρακαλώ μεταβείτε στο {{provider}} για να λάβετε ένα κλειδί API και να ρυθμίσετε το κλειδί API για να συνεχίσετε τη χρήση.", "response": "Σφάλμα. Εάν δεν έχετε ρυθμίσει το κλειδί API, πηγαίνετε στο ρυθμισμένα > παρέχοντας το πρόσωπο του μοντέλου" }, "http": { @@ -1824,6 +1828,7 @@ "baidu-cloud": "Baidu Cloud Qianfan", "burncloud": "BurnCloud", "cephalon": "Cephalon", + "cherryin": "CherryIN", "copilot": "GitHub Copilot", "dashscope": "AliCloud Bailian", "deepseek": "Βαθιά Αναζήτηση", @@ -1869,7 +1874,7 @@ "xirang": "China Telecom Xiran", "yi": "Zero One Wanyiwu", "zhinao": "360 Intelligent Brain", - "zhipu": "Zhipu AI" + "zhipu": "BigModel" }, "restore": { "confirm": { @@ -2911,7 +2916,8 @@ "modelscope": "Διακομιστής MCP κοινότητας ModelScope", "official": "Επίσημη συλλογή διακομιστών MCP", "pulsemcp": "Διακομιστής Pulse MCP", - "smithery": "Εργαλείο Smithery MCP" + "smithery": "Εργαλείο Smithery MCP", + "zhipu": "Επιλεγμένο MCP, Γρήγορη Ενσωμάτωση" }, "name": "Όνομα", "newServer": "Διακομιστής MCP", diff --git a/src/renderer/src/i18n/translate/es-es.json b/src/renderer/src/i18n/translate/es-es.json index 679e62b39f..890192771c 100644 --- a/src/renderer/src/i18n/translate/es-es.json +++ b/src/renderer/src/i18n/translate/es-es.json @@ -756,6 +756,7 @@ "footnote": "Nota al pie", "footnotes": "Notas al pie", "fullscreen": "En modo pantalla completa, presione F11 para salir", + "go_to_settings": "Ir a la configuración", "i_know": "Entendido", "inspect": "Inspeccionar", "knowledge_base": "Base de conocimiento", @@ -824,6 +825,9 @@ "chunk": { "non_json": "Devuelve un formato de datos no válido" }, + "insufficient_balance": "Por favor, vaya a {{provider}} para recargar.", + "no_api_key": "No ha configurado una clave API. Por favor, vaya a {{provider}} para obtener una clave API.", + "quota_exceeded": "Su cuota gratuita diaria de {{quota}} tokens se ha agotado. Por favor, vaya a {{provider}} para obtener una clave API y configurar la clave API para continuar usando.", "response": "Ha ocurrido un error, si no ha configurado la clave API, vaya a Configuración > Proveedor de modelos para configurar la clave" }, "http": { @@ -1824,6 +1828,7 @@ "baidu-cloud": "Baidu Nube Qiánfān", "burncloud": "BurnCloud", "cephalon": "Cephalon", + "cherryin": "CherryIN", "copilot": "GitHub Copiloto", "dashscope": "Álibaba Nube BaiLiàn", "deepseek": "Profundo Buscar", @@ -1869,7 +1874,7 @@ "xirang": "Telecom Nube XiRang", "yi": "Cero Uno Todo", "zhinao": "360 Inteligente", - "zhipu": "ZhiPu IA" + "zhipu": "BigModel" }, "restore": { "confirm": { @@ -2911,7 +2916,8 @@ "modelscope": "Servidor MCP de la comunidad ModelScope", "official": "Colección oficial de servidores MCP", "pulsemcp": "Servidor MCP Pulse", - "smithery": "Herramienta Smithery MCP" + "smithery": "Herramienta Smithery MCP", + "zhipu": "MCP Curado, Integración Rápida" }, "name": "Nombre", "newServer": "Servidor MCP", diff --git a/src/renderer/src/i18n/translate/fr-fr.json b/src/renderer/src/i18n/translate/fr-fr.json index ba76018ae9..4adcb04286 100644 --- a/src/renderer/src/i18n/translate/fr-fr.json +++ b/src/renderer/src/i18n/translate/fr-fr.json @@ -756,6 +756,7 @@ "footnote": "Note de bas de page", "footnotes": "Notes de bas de page", "fullscreen": "Mode plein écran, appuyez sur F11 pour quitter", + "go_to_settings": "Aller aux paramètres", "i_know": "J'ai compris", "inspect": "Vérifier", "knowledge_base": "Base de connaissances", @@ -824,6 +825,9 @@ "chunk": { "non_json": "a renvoyé un format de données invalide" }, + "insufficient_balance": "Veuillez vous rendre sur {{provider}} pour recharger.", + "no_api_key": "Vous n'avez pas configuré de clé API. Veuillez vous rendre sur {{provider}} pour obtenir une clé API.", + "quota_exceeded": "Votre quota gratuit quotidien de {{quota}} tokens a été épuisé. Veuillez vous rendre sur {{provider}} pour obtenir une clé API et configurer la clé API pour continuer à utiliser.", "response": "Une erreur s'est produite, si l'API n'est pas configurée, veuillez aller dans Paramètres > Fournisseurs de modèles pour configurer la clé" }, "http": { @@ -1824,6 +1828,7 @@ "baidu-cloud": "Baidu Cloud Qianfan", "burncloud": "BurnCloud", "cephalon": "Cephalon", + "cherryin": "CherryIN", "copilot": "GitHub Copilote", "dashscope": "AliCloud BaiLian", "deepseek": "DeepSeek", @@ -1869,7 +1874,7 @@ "xirang": "CTyun XiRang", "yi": "ZéroUnInfini", "zhinao": "360 ZhiNao", - "zhipu": "ZhiPu IA" + "zhipu": "BigModel" }, "restore": { "confirm": { @@ -2911,7 +2916,8 @@ "modelscope": "Serveur MCP de la communauté ModelScope", "official": "Collection officielle de serveurs MCP", "pulsemcp": "Serveur MCP Pulse", - "smithery": "Outils Smithery MCP" + "smithery": "Outils Smithery MCP", + "zhipu": "MCP Curaté, Intégration Rapide" }, "name": "Nom", "newServer": "Сервер MCP", diff --git a/src/renderer/src/i18n/translate/pt-pt.json b/src/renderer/src/i18n/translate/pt-pt.json index 777d512173..3e3d83b030 100644 --- a/src/renderer/src/i18n/translate/pt-pt.json +++ b/src/renderer/src/i18n/translate/pt-pt.json @@ -756,6 +756,7 @@ "footnote": "Nota de rodapé", "footnotes": "Notas de rodapé", "fullscreen": "Entrou no modo de tela cheia, pressione F11 para sair", + "go_to_settings": "Ir para configurações", "i_know": "Entendi", "inspect": "Verificar", "knowledge_base": "Base de Conhecimento", @@ -824,6 +825,9 @@ "chunk": { "non_json": "Devolveu um formato de dados inválido" }, + "insufficient_balance": "Por favor, vá para {{provider}} para recarregar.", + "no_api_key": "Você não configurou uma chave API. Por favor, vá para {{provider}} para obter uma chave API.", + "quota_exceeded": "Sua cota gratuita diária de {{quota}} tokens foi esgotada. Por favor, vá para {{provider}} para obter uma chave API e configurar a chave API para continuar usando.", "response": "Ocorreu um erro, se a chave da API não foi configurada, por favor vá para Configurações > Provedores de Modelo para configurar a chave" }, "http": { @@ -1824,6 +1828,7 @@ "baidu-cloud": "Nuvem Baidu", "burncloud": "BurnCloud", "cephalon": "Cephalon", + "cherryin": "CherryIN", "copilot": "GitHub Copiloto", "dashscope": "Área de Atuação AliCloud", "deepseek": "Busca Profunda", @@ -1869,7 +1874,7 @@ "xirang": "XiRang do Nuvem Telecom", "yi": "ZeroUmTudo", "zhinao": "360 Inteligência Artificial", - "zhipu": "ZhiPu IA" + "zhipu": "BigModel" }, "restore": { "confirm": { @@ -2911,7 +2916,8 @@ "modelscope": "Servidor MCP da comunidade ModelScope", "official": "Coleção oficial de servidores MCP", "pulsemcp": "Servidor MCP Pulse", - "smithery": "Ferramentas Smithery MCP" + "smithery": "Ferramentas Smithery MCP", + "zhipu": "MCP Curado, Integração Rápida" }, "name": "Nome", "newServer": "Servidor MCP", diff --git a/src/renderer/src/pages/code/CodeToolsPage.tsx b/src/renderer/src/pages/code/CodeToolsPage.tsx index 22b98408dd..2b600547fe 100644 --- a/src/renderer/src/pages/code/CodeToolsPage.tsx +++ b/src/renderer/src/pages/code/CodeToolsPage.tsx @@ -57,6 +57,9 @@ const CodeToolsPage: FC = () => { if (isEmbeddingModel(m) || isRerankModel(m) || isTextToImageModel(m)) { return false } + if (m.provider === 'cherryin') { + return false + } if (selectedCliTool === 'claude-code') { return m.id.includes('claude') || CLAUDE_OFFICIAL_SUPPORTED_PROVIDERS.includes(m.provider) } diff --git a/src/renderer/src/pages/files/FilesPage.tsx b/src/renderer/src/pages/files/FilesPage.tsx index edf2b38273..3a7a3f445c 100644 --- a/src/renderer/src/pages/files/FilesPage.tsx +++ b/src/renderer/src/pages/files/FilesPage.tsx @@ -53,8 +53,11 @@ const FilesPage: FC = () => { const selectedFiles = await Promise.all(selectedFileIds.map((id) => FileManager.getFile(id))) const validFiles = selectedFiles.filter((file) => file !== null && file !== undefined) - const paintings = store.getState().paintings.paintings - const paintingsFiles = paintings.flatMap((p) => p.files) + const paintings = store.getState().paintings + const paintingsFiles = Object.values(paintings) + .flat() + .filter((painting) => painting?.files?.length > 0) + .flatMap((painting) => painting.files) const filesInPaintings = validFiles.filter((file) => paintingsFiles.some((p) => p.id === file.id)) diff --git a/src/renderer/src/pages/home/Inputbar/WebSearchButton.tsx b/src/renderer/src/pages/home/Inputbar/WebSearchButton.tsx index 9f71e0a84d..07a9e29107 100644 --- a/src/renderer/src/pages/home/Inputbar/WebSearchButton.tsx +++ b/src/renderer/src/pages/home/Inputbar/WebSearchButton.tsx @@ -1,6 +1,6 @@ import { BaiduOutlined, GoogleOutlined } from '@ant-design/icons' import { loggerService } from '@logger' -import { BingLogo, BochaLogo, ExaLogo, SearXNGLogo, TavilyLogo } from '@renderer/components/Icons' +import { BingLogo, BochaLogo, ExaLogo, SearXNGLogo, TavilyLogo, ZhipuLogo } from '@renderer/components/Icons' import { QuickPanelListItem, useQuickPanel } from '@renderer/components/QuickPanel' import { isGeminiModel, isWebSearchModel } from '@renderer/config/models' import { isGeminiWebSearchProvider } from '@renderer/config/providers' @@ -50,6 +50,8 @@ const WebSearchButton: FC = ({ ref, assistant, ToolbarButton }) => { return case 'tavily': return + case 'zhipu': + return case 'searxng': return case 'local-baidu': diff --git a/src/renderer/src/pages/home/Messages/Blocks/ErrorBlock.tsx b/src/renderer/src/pages/home/Messages/Blocks/ErrorBlock.tsx index 1ed33e7475..514eb96634 100644 --- a/src/renderer/src/pages/home/Messages/Blocks/ErrorBlock.tsx +++ b/src/renderer/src/pages/home/Messages/Blocks/ErrorBlock.tsx @@ -1,13 +1,17 @@ import { useTimer } from '@renderer/hooks/useTimer' -import { getHttpMessageLabel } from '@renderer/i18n/label' +import { getHttpMessageLabel, getProviderLabel } from '@renderer/i18n/label' +import { getProviderById } from '@renderer/services/ProviderService' import { useAppDispatch } from '@renderer/store' import { removeBlocksThunk } from '@renderer/store/thunk/messageThunk' import type { ErrorMessageBlock, Message } from '@renderer/types/newMessage' import { Alert as AntdAlert } from 'antd' import React from 'react' -import { useTranslation } from 'react-i18next' +import { Trans, useTranslation } from 'react-i18next' +import { Link } from 'react-router-dom' import styled from 'styled-components' +const HTTP_ERROR_CODES = [400, 401, 403, 404, 429, 500, 502, 503, 504] + interface Props { block: ErrorMessageBlock message: Message @@ -17,36 +21,68 @@ const ErrorBlock: React.FC = ({ block, message }) => { return } -const MessageErrorInfo: React.FC<{ block: ErrorMessageBlock; message: Message }> = ({ block, message }) => { +const ErrorMessage: React.FC<{ block: ErrorMessageBlock }> = ({ block }) => { const { t, i18n } = useTranslation() + + const i18nKey = `error.${block.error?.i18nKey}` + const errorKey = `error.${block.error?.message}` + const errorStatus = block.error?.status + + if (i18n.exists(i18nKey)) { + const providerId = block.error?.providerId + if (providerId) { + return ( + + ) + }} + /> + ) + } + } + + if (i18n.exists(errorKey)) { + return t(errorKey) + } + + if (HTTP_ERROR_CODES.includes(errorStatus)) { + return ( +
+ {getHttpMessageLabel(errorStatus)} {block.error?.message} +
+ ) + } + + return block.error?.message || '' +} + +const ErrorDescription: React.FC<{ block: ErrorMessageBlock }> = ({ block }) => { + const { t } = useTranslation() + + if (block.error) { + return + } + + return <>{t('error.chat.response')} +} + +const MessageErrorInfo: React.FC<{ block: ErrorMessageBlock; message: Message }> = ({ block, message }) => { const dispatch = useAppDispatch() const { setTimeoutTimer } = useTimer() - const HTTP_ERROR_CODES = [400, 401, 403, 404, 429, 500, 502, 503, 504] - const onRemoveBlock = () => { setTimeoutTimer('onRemoveBlock', () => dispatch(removeBlocksThunk(message.topicId, message.id, [block.id])), 350) } - if (block.error && HTTP_ERROR_CODES.includes(block.error?.status)) { - return ( - - ) - } - - if (block?.error?.message) { - const errorKey = `error.${block.error.message}` - const pauseErrorLanguagePlaceholder = i18n.exists(errorKey) ? t(errorKey) : block.error.message - return - } - - return + return } type="error" closable onClose={onRemoveBlock} /> } const Alert = styled(AntdAlert)` diff --git a/src/renderer/src/pages/home/Messages/Message.tsx b/src/renderer/src/pages/home/Messages/Message.tsx index f6f6926b6f..10e01bb0b6 100644 --- a/src/renderer/src/pages/home/Messages/Message.tsx +++ b/src/renderer/src/pages/home/Messages/Message.tsx @@ -264,7 +264,7 @@ const MessageContainer = styled.div` const MessageContentContainer = styled(Scrollbar)` max-width: 100%; padding-left: 46px; - margin-top: 5px; + margin-top: 0; overflow-y: auto; ` diff --git a/src/renderer/src/pages/home/components/SelectModelButton.tsx b/src/renderer/src/pages/home/components/SelectModelButton.tsx index a912fb78e5..b4fa5e5074 100644 --- a/src/renderer/src/pages/home/components/SelectModelButton.tsx +++ b/src/renderer/src/pages/home/components/SelectModelButton.tsx @@ -49,7 +49,7 @@ const SelectModelButton: FC = ({ assistant }) => { return null } - const providerName = getProviderName(model?.provider) + const providerName = getProviderName(model) return ( diff --git a/src/renderer/src/pages/knowledge/KnowledgeContent.tsx b/src/renderer/src/pages/knowledge/KnowledgeContent.tsx index 6d0e350ac0..e7135f66f3 100644 --- a/src/renderer/src/pages/knowledge/KnowledgeContent.tsx +++ b/src/renderer/src/pages/knowledge/KnowledgeContent.tsx @@ -34,7 +34,7 @@ const KnowledgeContent: FC = ({ selectedBase }) => { const [progressMap, setProgressMap] = useState>(new Map()) const [preprocessMap, setPreprocessMap] = useState>(new Map()) - const providerName = getProviderName(base?.model.provider || '') + const providerName = getProviderName(base?.model) useEffect(() => { const handlers = [ diff --git a/src/renderer/src/pages/knowledge/items/KnowledgeDirectories.tsx b/src/renderer/src/pages/knowledge/items/KnowledgeDirectories.tsx index 7ece478b17..4868a3f483 100644 --- a/src/renderer/src/pages/knowledge/items/KnowledgeDirectories.tsx +++ b/src/renderer/src/pages/knowledge/items/KnowledgeDirectories.tsx @@ -43,7 +43,7 @@ const KnowledgeDirectories: FC = ({ selectedBase, progres selectedBase.id || '' ) - const providerName = getProviderName(base?.model.provider || '') + const providerName = getProviderName(base?.model) const disabled = !base?.version || !providerName const reversedItems = useMemo(() => [...directoryItems].reverse(), [directoryItems]) diff --git a/src/renderer/src/pages/knowledge/items/KnowledgeFiles.tsx b/src/renderer/src/pages/knowledge/items/KnowledgeFiles.tsx index aa461d6878..9dfcd955b6 100644 --- a/src/renderer/src/pages/knowledge/items/KnowledgeFiles.tsx +++ b/src/renderer/src/pages/knowledge/items/KnowledgeFiles.tsx @@ -62,7 +62,7 @@ const KnowledgeFiles: FC = ({ selectedBase, progressMap, return () => window.removeEventListener('resize', handleResize) }, []) - const providerName = getProviderName(base?.model.provider || '') + const providerName = getProviderName(base?.model) const disabled = !base?.version || !providerName const estimateSize = useCallback(() => 75, []) diff --git a/src/renderer/src/pages/knowledge/items/KnowledgeNotes.tsx b/src/renderer/src/pages/knowledge/items/KnowledgeNotes.tsx index aa340a5c9f..0fb1b14d10 100644 --- a/src/renderer/src/pages/knowledge/items/KnowledgeNotes.tsx +++ b/src/renderer/src/pages/knowledge/items/KnowledgeNotes.tsx @@ -31,7 +31,7 @@ const KnowledgeNotes: FC = ({ selectedBase }) => { selectedBase.id || '' ) - const providerName = getProviderName(base?.model.provider || '') + const providerName = getProviderName(base?.model) const disabled = !base?.version || !providerName const reversedItems = useMemo(() => [...noteItems].reverse(), [noteItems]) diff --git a/src/renderer/src/pages/knowledge/items/KnowledgeSitemaps.tsx b/src/renderer/src/pages/knowledge/items/KnowledgeSitemaps.tsx index 8bb6556672..06aa8d4c19 100644 --- a/src/renderer/src/pages/knowledge/items/KnowledgeSitemaps.tsx +++ b/src/renderer/src/pages/knowledge/items/KnowledgeSitemaps.tsx @@ -43,7 +43,7 @@ const KnowledgeSitemaps: FC = ({ selectedBase }) => { selectedBase.id || '' ) - const providerName = getProviderName(base?.model.provider || '') + const providerName = getProviderName(base?.model) const disabled = !base?.version || !providerName const reversedItems = useMemo(() => [...sitemapItems].reverse(), [sitemapItems]) diff --git a/src/renderer/src/pages/knowledge/items/KnowledgeUrls.tsx b/src/renderer/src/pages/knowledge/items/KnowledgeUrls.tsx index 7ffe98c9fb..93673ad7a8 100644 --- a/src/renderer/src/pages/knowledge/items/KnowledgeUrls.tsx +++ b/src/renderer/src/pages/knowledge/items/KnowledgeUrls.tsx @@ -40,7 +40,7 @@ const KnowledgeUrls: FC = ({ selectedBase }) => { selectedBase.id || '' ) - const providerName = getProviderName(base?.model.provider || '') + const providerName = getProviderName(base?.model) const disabled = !base?.version || !providerName const reversedItems = useMemo(() => [...urlItems].reverse(), [urlItems]) diff --git a/src/renderer/src/pages/paintings/AihubmixPage.tsx b/src/renderer/src/pages/paintings/AihubmixPage.tsx index 2c3075148c..6c9236e7dd 100644 --- a/src/renderer/src/pages/paintings/AihubmixPage.tsx +++ b/src/renderer/src/pages/paintings/AihubmixPage.tsx @@ -36,6 +36,7 @@ import { SettingHelpLink, SettingTitle } from '../settings' import Artboard from './components/Artboard' import PaintingsList from './components/PaintingsList' import { type ConfigItem, createModeConfigs, DEFAULT_PAINTING } from './config/aihubmixConfig' +import { checkProviderEnabled } from './utils' const logger = loggerService.withContext('AihubmixPage') @@ -43,9 +44,27 @@ const logger = loggerService.withContext('AihubmixPage') const modeConfigs = createModeConfigs() const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => { - const [mode, setMode] = useState('generate') - const { addPainting, removePainting, updatePainting, persistentData } = usePaintings() - const filteredPaintings = useMemo(() => persistentData[mode] || [], [persistentData, mode]) + const [mode, setMode] = useState('aihubmix_image_generate') + const { + addPainting, + removePainting, + updatePainting, + aihubmix_image_generate, + aihubmix_image_remix, + aihubmix_image_edit, + aihubmix_image_upscale + } = usePaintings() + + const paintings = useMemo(() => { + return { + aihubmix_image_generate, + aihubmix_image_remix, + aihubmix_image_edit, + aihubmix_image_upscale + } + }, [aihubmix_image_generate, aihubmix_image_remix, aihubmix_image_edit, aihubmix_image_upscale]) + + const filteredPaintings = useMemo(() => paintings[mode] || [], [paintings, mode]) const [painting, setPainting] = useState(filteredPaintings[0] || DEFAULT_PAINTING) const [currentImageIndex, setCurrentImageIndex] = useState(0) const [isLoading, setIsLoading] = useState(false) @@ -88,7 +107,7 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => { const getNewPainting = useCallback(() => { return { ...DEFAULT_PAINTING, - model: mode === 'generate' ? 'gpt-image-1' : 'V_3', + model: mode === 'aihubmix_image_generate' ? 'gpt-image-1' : 'V_3', id: uuid() } }, [mode]) @@ -143,6 +162,8 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => { } const onGenerate = async () => { + await checkProviderEnabled(aihubmixProvider, t) + if (painting.files.length > 0) { const confirmed = await window.modal.confirm({ content: t('paintings.regenerate.confirm'), @@ -156,14 +177,6 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => { const prompt = textareaRef.current?.resizableTextArea?.textArea?.value || '' updatePaintingState({ prompt }) - if (!aihubmixProvider.enabled) { - window.modal.error({ - content: t('error.provider_disabled'), - centered: true - }) - return - } - if (!aihubmixProvider.apiKey) { window.modal.error({ content: t('error.no_api_key'), @@ -188,7 +201,7 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => { let url = aihubmixProvider.apiHost + `/ideogram/` + mode try { - if (mode === 'generate') { + if (mode === 'aihubmix_image_generate') { if (painting.model.startsWith('imagen-')) { const AI = new AiProvider(aihubmixProvider) const base64s = await AI.generateImage({ @@ -344,7 +357,7 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => { body = JSON.stringify(requestData) headers['Content-Type'] = 'application/json' } - } else if (mode === 'remix') { + } else if (mode === 'aihubmix_image_remix') { if (!painting.imageFile) { window.modal.error({ content: t('paintings.image_file_required'), @@ -439,7 +452,7 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => { form.append('image_file', fileMap[painting.imageFile] as unknown as Blob) body = form } - } else if (mode === 'upscale') { + } else if (mode === 'aihubmix_image_upscale') { if (!painting.imageFile) { window.modal.error({ content: t('paintings.image_file_required'), @@ -470,7 +483,7 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => { } // 只针对非V3模型使用通用接口 - if (!painting.model?.includes('V_3') || mode === 'upscale') { + if (!painting.model?.includes('V_3') || mode === 'aihubmix_image_upscale') { // 直接调用自定义接口 const response = await fetch(url, { method: 'POST', headers, body }) @@ -617,8 +630,8 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => { // 处理模式切换 const handleModeChange = (value: string) => { setMode(value as keyof PaintingsState) - if (persistentData[value as keyof PaintingsState] && persistentData[value as keyof PaintingsState].length > 0) { - setPainting(persistentData[value as keyof PaintingsState][0]) + if (paintings[value as keyof PaintingsState] && paintings[value as keyof PaintingsState].length > 0) { + setPainting(paintings[value as keyof PaintingsState][0]) } else { setPainting(DEFAULT_PAINTING) } @@ -843,7 +856,7 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => { - {providerOptions.map((provider) => ( diff --git a/src/renderer/src/pages/paintings/DmxapiPage.tsx b/src/renderer/src/pages/paintings/DmxapiPage.tsx index d9167ac69e..21a784397f 100644 --- a/src/renderer/src/pages/paintings/DmxapiPage.tsx +++ b/src/renderer/src/pages/paintings/DmxapiPage.tsx @@ -12,7 +12,7 @@ import { getProviderLabel } from '@renderer/i18n/label' import FileManager from '@renderer/services/FileManager' import { useAppDispatch } from '@renderer/store' import { setGenerating } from '@renderer/store/runtime' -import type { FileMetadata, PaintingsState } from '@renderer/types' +import type { FileMetadata } from '@renderer/types' import { convertToBase64, uuid } from '@renderer/utils' import { DmxapiPainting } from '@types' import { Avatar, Button, Input, InputNumber, Segmented, Select, Switch, Tooltip } from 'antd' @@ -37,13 +37,13 @@ import { STYLE_TYPE_OPTIONS, TOP_UP_URL } from './config/DmxapiConfig' +import { checkProviderEnabled } from './utils' const generateRandomSeed = () => Math.floor(Math.random() * 1000000).toString() const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { - const [mode] = useState('DMXAPIPaintings') - const { DMXAPIPaintings, addPainting, removePainting, updatePainting } = usePaintings() - const [painting, setPainting] = useState(DMXAPIPaintings?.[0] || DEFAULT_PAINTING) + const { dmxapi_paintings, addPainting, removePainting, updatePainting } = usePaintings() + const [painting, setPainting] = useState(dmxapi_paintings?.[0] || DEFAULT_PAINTING) const { t } = useTranslation() const providers = useAllProviders() const providerOptions = Options.map((option) => { @@ -144,7 +144,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { const updatePaintingState = (updates: Partial) => { const updatedPainting = { ...painting, ...updates } setPainting(updatedPainting) - updatePainting('DMXAPIPaintings', updatedPainting) + updatePainting('dmxapi_paintings', updatedPainting) } const getFirstModelInfo = (v: generationModeType) => { @@ -197,7 +197,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { id: uuid() } - setPainting(addPainting('DMXAPIPaintings', copyPainting)) + setPainting(addPainting('dmxapi_paintings', copyPainting)) } const onSelectModel = (modelId: string) => { @@ -316,7 +316,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { generationMode: v, model }) - const addedPainting = addPainting('DMXAPIPaintings', newPainting) + const addedPainting = addPainting('dmxapi_paintings', newPainting) setPainting(addedPainting) } else { // 否则更新当前painting @@ -333,7 +333,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { if (isLoading) { return } - setPainting(addPainting('DMXAPIPaintings', getNewPainting())) + setPainting(addPainting('dmxapi_paintings', getNewPainting())) } // 检查提供者状态函数 @@ -536,6 +536,12 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { if (isLoading) { return } + + if (!dmxapiProvider.enabled) { + checkProviderEnabled(dmxapiProvider, t) + return + } + try { // 获取提示词 const prompt = textareaRef.current?.resizableTextArea?.textArea?.value || '' @@ -624,23 +630,23 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { return } - const currentIndex = DMXAPIPaintings.findIndex((p) => p.id === paintingToDelete.id) + const currentIndex = dmxapi_paintings.findIndex((p) => p.id === paintingToDelete.id) if (currentIndex > 0) { - setPainting(DMXAPIPaintings[currentIndex - 1]) - } else if (DMXAPIPaintings.length > 1) { - setPainting(DMXAPIPaintings[1]) + setPainting(dmxapi_paintings[currentIndex - 1]) + } else if (dmxapi_paintings.length > 1) { + setPainting(dmxapi_paintings[1]) } } // 删除绘画 - await removePainting(mode, paintingToDelete) + await removePainting('dmxapi_paintings', paintingToDelete) // 检查是否删除空了 - if (!DMXAPIPaintings || DMXAPIPaintings.length === 1) { + if (!dmxapi_paintings || dmxapi_paintings.length === 1) { // 如果删除后没有绘画了,创建一个新的 const newPainting = getNewPainting() - const addedPainting = addPainting('DMXAPIPaintings', newPainting) + const addedPainting = addPainting('dmxapi_paintings', newPainting) setPainting(addedPainting) } } @@ -692,7 +698,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { } } - if (painting?.urls?.length > 0 || DMXAPIPaintings?.length > 1) { + if (painting?.urls?.length > 0 || dmxapi_paintings?.length > 1) { return null } else { return ( @@ -733,22 +739,22 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { return } - if (!DMXAPIPaintings || DMXAPIPaintings.length === 0) { + if (!dmxapi_paintings || dmxapi_paintings.length === 0) { const newPainting = getNewPainting() - addPainting('DMXAPIPaintings', newPainting) + addPainting('dmxapi_paintings', newPainting) setPainting(newPainting) } else if (painting && !painting.generationMode) { // 如果当前painting没有generationMode,添加默认值 const updatedPainting = { ...painting, generationMode: MODEOPTIONS[0].value } setPainting(updatedPainting) - updatePainting('DMXAPIPaintings', updatedPainting) + updatePainting('dmxapi_paintings', updatedPainting) } // 确保所有paintings都有generationMode属性 - DMXAPIPaintings.forEach((p) => { + dmxapi_paintings.forEach((p) => { if (!p.generationMode) { const updatedPainting = { ...p, generationMode: MODEOPTIONS[0].value } - updatePainting('DMXAPIPaintings', updatedPainting) + updatePainting('dmxapi_paintings', updatedPainting) } }) @@ -816,7 +822,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { /> - {providerOptions.map((provider) => ( @@ -1005,8 +1011,8 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { = ({ Options }) => { const [mode, setMode] = useState('openai_image_generate') - const { addPainting, removePainting, updatePainting, newApiPaintings } = usePaintings() + const { addPainting, removePainting, updatePainting, openai_image_generate, openai_image_edit } = usePaintings() + + const newApiPaintings = useMemo(() => { + return { + openai_image_generate, + openai_image_edit + } + }, [openai_image_generate, openai_image_edit]) + const filteredPaintings = useMemo(() => newApiPaintings[mode] || [], [newApiPaintings, mode]) const [painting, setPainting] = useState(filteredPaintings[0] || DEFAULT_PAINTING) const [currentImageIndex, setCurrentImageIndex] = useState(0) @@ -216,6 +225,8 @@ const NewApiPage: FC<{ Options: string[] }> = ({ Options }) => { } const onGenerate = async () => { + await checkProviderEnabled(newApiProvider, t) + if (painting.files.length > 0) { const confirmed = await window.modal.confirm({ content: t('paintings.regenerate.confirm'), @@ -229,14 +240,6 @@ const NewApiPage: FC<{ Options: string[] }> = ({ Options }) => { const prompt = textareaRef.current?.resizableTextArea?.textArea?.value || '' updatePaintingState({ prompt }) - if (!newApiProvider.enabled) { - window.modal.error({ - content: t('error.provider_disabled'), - centered: true - }) - return - } - const AI = new AiProvider(newApiProvider) if (!AI.getApiKey()) { diff --git a/src/renderer/src/pages/paintings/PaintingsRoutePage.tsx b/src/renderer/src/pages/paintings/PaintingsRoutePage.tsx index 0de582065c..9c0ec8a2af 100644 --- a/src/renderer/src/pages/paintings/PaintingsRoutePage.tsx +++ b/src/renderer/src/pages/paintings/PaintingsRoutePage.tsx @@ -10,10 +10,11 @@ import DmxapiPage from './DmxapiPage' import NewApiPage from './NewApiPage' import SiliconPage from './SiliconPage' import TokenFluxPage from './TokenFluxPage' +import ZhipuPage from './ZhipuPage' const logger = loggerService.withContext('PaintingsRoutePage') -const Options = ['aihubmix', 'silicon', 'dmxapi', 'tokenflux', 'new-api'] +const Options = ['zhipu', 'aihubmix', 'silicon', 'dmxapi', 'tokenflux', 'new-api'] const PaintingsRoutePage: FC = () => { const params = useParams() @@ -29,7 +30,8 @@ const PaintingsRoutePage: FC = () => { return ( - } /> + } /> + } /> } /> } /> } /> diff --git a/src/renderer/src/pages/paintings/SiliconPage.tsx b/src/renderer/src/pages/paintings/SiliconPage.tsx index 1d09bcfb96..3d23e8fdbc 100644 --- a/src/renderer/src/pages/paintings/SiliconPage.tsx +++ b/src/renderer/src/pages/paintings/SiliconPage.tsx @@ -40,6 +40,7 @@ import SendMessageButton from '../home/Inputbar/SendMessageButton' import { SettingTitle } from '../settings' import Artboard from './components/Artboard' import PaintingsList from './components/PaintingsList' +import { checkProviderEnabled } from './utils' const logger = loggerService.withContext('SiliconPage') @@ -95,8 +96,8 @@ const DEFAULT_PAINTING: Painting = { const SiliconPage: FC<{ Options: string[] }> = ({ Options }) => { const { t } = useTranslation() - const { paintings, addPainting, removePainting, updatePainting } = usePaintings() - const [painting, setPainting] = useState(paintings[0] || DEFAULT_PAINTING) + const { siliconflow_paintings, addPainting, removePainting, updatePainting } = usePaintings() + const [painting, setPainting] = useState(siliconflow_paintings[0] || DEFAULT_PAINTING) const { theme } = useTheme() const providers = useAllProviders() const providerOptions = Options.map((option) => { @@ -113,6 +114,8 @@ const SiliconPage: FC<{ Options: string[] }> = ({ Options }) => { } } }) + + const siliconflowProvider = providers.find((p) => p.id === 'silicon') const [currentImageIndex, setCurrentImageIndex] = useState(0) const [isLoading, setIsLoading] = useState(false) @@ -141,7 +144,7 @@ const SiliconPage: FC<{ Options: string[] }> = ({ Options }) => { const updatePaintingState = (updates: Partial) => { const updatedPainting = { ...painting, ...updates } setPainting(updatedPainting) - updatePainting('paintings', updatedPainting) + updatePainting('siliconflow_paintings', updatedPainting) } const onSelectModel = (modelId: string) => { @@ -152,6 +155,8 @@ const SiliconPage: FC<{ Options: string[] }> = ({ Options }) => { } const onGenerate = async () => { + await checkProviderEnabled(siliconflowProvider!, t) + if (painting.files.length > 0) { const confirmed = await window.modal.confirm({ content: t('paintings.regenerate.confirm'), @@ -172,14 +177,6 @@ const SiliconPage: FC<{ Options: string[] }> = ({ Options }) => { const model = TEXT_TO_IMAGES_MODELS.find((m) => m.id === painting.model) const provider = getProviderByModel(model) - if (!provider.enabled) { - window.modal.error({ - content: t('error.provider_disabled'), - centered: true - }) - return - } - if (!provider.apiKey) { window.modal.error({ content: t('error.no_api_key'), @@ -280,16 +277,16 @@ const SiliconPage: FC<{ Options: string[] }> = ({ Options }) => { const onDeletePainting = (paintingToDelete: Painting) => { if (paintingToDelete.id === painting.id) { - const currentIndex = paintings.findIndex((p) => p.id === paintingToDelete.id) + const currentIndex = siliconflow_paintings.findIndex((p) => p.id === paintingToDelete.id) if (currentIndex > 0) { - setPainting(paintings[currentIndex - 1]) - } else if (paintings.length > 1) { - setPainting(paintings[1]) + setPainting(siliconflow_paintings[currentIndex - 1]) + } else if (siliconflow_paintings.length > 1) { + setPainting(siliconflow_paintings[1]) } } - removePainting('paintings', paintingToDelete) + removePainting('siliconflow_paintings', paintingToDelete) } const onSelectPainting = (newPainting: Painting) => { @@ -351,9 +348,9 @@ const SiliconPage: FC<{ Options: string[] }> = ({ Options }) => { } useEffect(() => { - if (paintings.length === 0) { + if (siliconflow_paintings.length === 0) { const newPainting = getNewPainting() - addPainting('paintings', newPainting) + addPainting('siliconflow_paintings', newPainting) setPainting(newPainting) } @@ -362,7 +359,7 @@ const SiliconPage: FC<{ Options: string[] }> = ({ Options }) => { clearTimeout(spaceClickTimer.current) } } - }, [paintings.length, addPainting]) + }, [siliconflow_paintings.length, addPainting]) return ( @@ -374,7 +371,7 @@ const SiliconPage: FC<{ Options: string[] }> = ({ Options }) => { size="small" className="nodrag" icon={} - onClick={() => setPainting(addPainting('paintings', getNewPainting()))}> + onClick={() => setPainting(addPainting('siliconflow_paintings', getNewPainting()))}> {t('paintings.button.new.image')} @@ -383,7 +380,7 @@ const SiliconPage: FC<{ Options: string[] }> = ({ Options }) => { {t('common.provider')} - {t('common.model')} + {providerOptions.map((provider) => ( + + + + {provider.label} + + + ))} + + + {t('common.model')} + + {IMAGE_SIZES.map((size) => ( + + {size.label} + + ))} + + {t('paintings.custom_size')} + + + + {/* 自定义尺寸输入框 */} + {isCustomSize && ( +
+ + onCustomSizeChange(value || undefined, 'width')} + min={512} + max={2048} + style={{ width: 80, flex: 1 }} + /> + x + onCustomSizeChange(value || undefined, 'height')} + min={512} + max={2048} + style={{ width: 80, flex: 1 }} + /> + px + +
+ 长宽均需满足512px-2048px之间, 需被16整除, 并保证最大像素数不超过2^21px +
+
+ )} +
+ + + +