diff --git a/.yarn/patches/openai-npm-4.96.0-0665b05cb9.patch b/.yarn/patches/openai-npm-4.96.0-0665b05cb9.patch deleted file mode 100644 index d79275839..000000000 --- a/.yarn/patches/openai-npm-4.96.0-0665b05cb9.patch +++ /dev/null @@ -1,85 +0,0 @@ -diff --git a/core.js b/core.js -index 862d66101f441fb4f47dfc8cff5e2d39e1f5a11e..6464bebbf696c39d35f0368f061ea4236225c162 100644 ---- a/core.js -+++ b/core.js -@@ -159,7 +159,7 @@ class APIClient { - Accept: 'application/json', - 'Content-Type': 'application/json', - 'User-Agent': this.getUserAgent(), -- ...getPlatformHeaders(), -+ // ...getPlatformHeaders(), - ...this.authHeaders(opts), - }; - } -diff --git a/core.mjs b/core.mjs -index 05dbc6cfde51589a2b100d4e4b5b3c1a33b32b89..789fbb4985eb952a0349b779fa83b1a068af6e7e 100644 ---- a/core.mjs -+++ b/core.mjs -@@ -152,7 +152,7 @@ export class APIClient { - Accept: 'application/json', - 'Content-Type': 'application/json', - 'User-Agent': this.getUserAgent(), -- ...getPlatformHeaders(), -+ // ...getPlatformHeaders(), - ...this.authHeaders(opts), - }; - } -diff --git a/error.mjs b/error.mjs -index 7d19f5578040afa004bc887aab1725e8703d2bac..59ec725b6142299a62798ac4bdedb63ba7d9932c 100644 ---- a/error.mjs -+++ b/error.mjs -@@ -36,7 +36,7 @@ export class APIError extends OpenAIError { - if (!status || !headers) { - return new APIConnectionError({ message, cause: castToError(errorResponse) }); - } -- const error = errorResponse?.['error']; -+ const error = errorResponse?.['error'] || errorResponse; - if (status === 400) { - return new BadRequestError(status, error, message, headers); - } -diff --git a/resources/embeddings.js b/resources/embeddings.js -index aae578404cb2d09a39ac33fc416f1c215c45eecd..25c54b05bdae64d5c3b36fbb30dc7c8221b14034 100644 ---- a/resources/embeddings.js -+++ b/resources/embeddings.js -@@ -36,6 +36,9 @@ class Embeddings extends resource_1.APIResource { - // No encoding_format specified, defaulting to base64 for performance reasons - // See https://github.com/openai/openai-node/pull/1312 - let encoding_format = hasUserProvidedEncodingFormat ? body.encoding_format : 'base64'; -+ if (body.model.includes('jina')) { -+ encoding_format = undefined; -+ } - if (hasUserProvidedEncodingFormat) { - Core.debug('Request', 'User defined encoding_format:', body.encoding_format); - } -@@ -47,7 +50,7 @@ class Embeddings extends resource_1.APIResource { - ...options, - }); - // if the user specified an encoding_format, return the response as-is -- if (hasUserProvidedEncodingFormat) { -+ if (hasUserProvidedEncodingFormat || body.model.includes('jina')) { - return response; - } - // in this stage, we are sure the user did not specify an encoding_format -diff --git a/resources/embeddings.mjs b/resources/embeddings.mjs -index 0df3c6cc79a520e54acb4c2b5f77c43b774035ff..aa488b8a11b2c413c0a663d9a6059d286d7b5faf 100644 ---- a/resources/embeddings.mjs -+++ b/resources/embeddings.mjs -@@ -10,6 +10,9 @@ export class Embeddings extends APIResource { - // No encoding_format specified, defaulting to base64 for performance reasons - // See https://github.com/openai/openai-node/pull/1312 - let encoding_format = hasUserProvidedEncodingFormat ? body.encoding_format : 'base64'; -+ if (body.model.includes('jina')) { -+ encoding_format = undefined; -+ } - if (hasUserProvidedEncodingFormat) { - Core.debug('Request', 'User defined encoding_format:', body.encoding_format); - } -@@ -21,7 +24,7 @@ export class Embeddings extends APIResource { - ...options, - }); - // if the user specified an encoding_format, return the response as-is -- if (hasUserProvidedEncodingFormat) { -+ if (hasUserProvidedEncodingFormat || body.model.includes('jina')) { - return response; - } - // in this stage, we are sure the user did not specify an encoding_format diff --git a/.yarn/patches/openai-npm-5.1.0-0e7b3ccb07.patch b/.yarn/patches/openai-npm-5.1.0-0e7b3ccb07.patch new file mode 100644 index 000000000..dbf07cb47 --- /dev/null +++ b/.yarn/patches/openai-npm-5.1.0-0e7b3ccb07.patch @@ -0,0 +1,279 @@ +diff --git a/client.js b/client.js +index 33b4ff6309d5f29187dab4e285d07dac20340bab..8f568637ee9e4677585931fb0284c8165a933f69 100644 +--- a/client.js ++++ b/client.js +@@ -433,7 +433,7 @@ class OpenAI { + 'User-Agent': this.getUserAgent(), + 'X-Stainless-Retry-Count': String(retryCount), + ...(options.timeout ? { 'X-Stainless-Timeout': String(Math.trunc(options.timeout / 1000)) } : {}), +- ...(0, detect_platform_1.getPlatformHeaders)(), ++ // ...(0, detect_platform_1.getPlatformHeaders)(), + 'OpenAI-Organization': this.organization, + 'OpenAI-Project': this.project, + }, +diff --git a/client.mjs b/client.mjs +index c34c18213073540ebb296ea540b1d1ad39527906..1ce1a98256d7e90e26ca963582f235b23e996e73 100644 +--- a/client.mjs ++++ b/client.mjs +@@ -430,7 +430,7 @@ export class OpenAI { + 'User-Agent': this.getUserAgent(), + 'X-Stainless-Retry-Count': String(retryCount), + ...(options.timeout ? { 'X-Stainless-Timeout': String(Math.trunc(options.timeout / 1000)) } : {}), +- ...getPlatformHeaders(), ++ // ...getPlatformHeaders(), + 'OpenAI-Organization': this.organization, + 'OpenAI-Project': this.project, + }, +diff --git a/core/error.js b/core/error.js +index a12d9d9ccd242050161adeb0f82e1b98d9e78e20..fe3a5462480558bc426deea147f864f12b36f9bd 100644 +--- a/core/error.js ++++ b/core/error.js +@@ -40,7 +40,7 @@ class APIError extends OpenAIError { + if (!status || !headers) { + return new APIConnectionError({ message, cause: (0, errors_1.castToError)(errorResponse) }); + } +- const error = errorResponse?.['error']; ++ const error = errorResponse?.['error'] || errorResponse; + if (status === 400) { + return new BadRequestError(status, error, message, headers); + } +diff --git a/core/error.mjs b/core/error.mjs +index 83cefbaffeb8c657536347322d8de9516af479a2..63334b7972ec04882aa4a0800c1ead5982345045 100644 +--- a/core/error.mjs ++++ b/core/error.mjs +@@ -36,7 +36,7 @@ export class APIError extends OpenAIError { + if (!status || !headers) { + return new APIConnectionError({ message, cause: castToError(errorResponse) }); + } +- const error = errorResponse?.['error']; ++ const error = errorResponse?.['error'] || errorResponse; + if (status === 400) { + return new BadRequestError(status, error, message, headers); + } +diff --git a/resources/embeddings.js b/resources/embeddings.js +index 2404264d4ba0204322548945ebb7eab3bea82173..8f1bc45cc45e0797d50989d96b51147b90ae6790 100644 +--- a/resources/embeddings.js ++++ b/resources/embeddings.js +@@ -5,52 +5,64 @@ exports.Embeddings = void 0; + const resource_1 = require("../core/resource.js"); + const utils_1 = require("../internal/utils.js"); + class Embeddings extends resource_1.APIResource { +- /** +- * Creates an embedding vector representing the input text. +- * +- * @example +- * ```ts +- * const createEmbeddingResponse = +- * await client.embeddings.create({ +- * input: 'The quick brown fox jumped over the lazy dog', +- * model: 'text-embedding-3-small', +- * }); +- * ``` +- */ +- create(body, options) { +- const hasUserProvidedEncodingFormat = !!body.encoding_format; +- // No encoding_format specified, defaulting to base64 for performance reasons +- // See https://github.com/openai/openai-node/pull/1312 +- let encoding_format = hasUserProvidedEncodingFormat ? body.encoding_format : 'base64'; +- if (hasUserProvidedEncodingFormat) { +- (0, utils_1.loggerFor)(this._client).debug('embeddings/user defined encoding_format:', body.encoding_format); +- } +- const response = this._client.post('/embeddings', { +- body: { +- ...body, +- encoding_format: encoding_format, +- }, +- ...options, +- }); +- // if the user specified an encoding_format, return the response as-is +- if (hasUserProvidedEncodingFormat) { +- return response; +- } +- // in this stage, we are sure the user did not specify an encoding_format +- // and we defaulted to base64 for performance reasons +- // we are sure then that the response is base64 encoded, let's decode it +- // the returned result will be a float32 array since this is OpenAI API's default encoding +- (0, utils_1.loggerFor)(this._client).debug('embeddings/decoding base64 embeddings from base64'); +- return response._thenUnwrap((response) => { +- if (response && response.data) { +- response.data.forEach((embeddingBase64Obj) => { +- const embeddingBase64Str = embeddingBase64Obj.embedding; +- embeddingBase64Obj.embedding = (0, utils_1.toFloat32Array)(embeddingBase64Str); +- }); +- } +- return response; +- }); +- } ++ /** ++ * Creates an embedding vector representing the input text. ++ * ++ * @example ++ * ```ts ++ * const createEmbeddingResponse = ++ * await client.embeddings.create({ ++ * input: 'The quick brown fox jumped over the lazy dog', ++ * model: 'text-embedding-3-small', ++ * }); ++ * ``` ++ */ ++ create(body, options) { ++ const hasUserProvidedEncodingFormat = !!body.encoding_format; ++ // No encoding_format specified, defaulting to base64 for performance reasons ++ // See https://github.com/openai/openai-node/pull/1312 ++ let encoding_format = hasUserProvidedEncodingFormat ++ ? body.encoding_format ++ : "base64"; ++ if (body.model.includes("jina")) { ++ encoding_format = undefined; ++ } ++ if (hasUserProvidedEncodingFormat) { ++ (0, utils_1.loggerFor)(this._client).debug( ++ "embeddings/user defined encoding_format:", ++ body.encoding_format ++ ); ++ } ++ const response = this._client.post("/embeddings", { ++ body: { ++ ...body, ++ encoding_format: encoding_format, ++ }, ++ ...options, ++ }); ++ // if the user specified an encoding_format, return the response as-is ++ if (hasUserProvidedEncodingFormat || body.model.includes("jina")) { ++ return response; ++ } ++ // in this stage, we are sure the user did not specify an encoding_format ++ // and we defaulted to base64 for performance reasons ++ // we are sure then that the response is base64 encoded, let's decode it ++ // the returned result will be a float32 array since this is OpenAI API's default encoding ++ (0, utils_1.loggerFor)(this._client).debug( ++ "embeddings/decoding base64 embeddings from base64" ++ ); ++ return response._thenUnwrap((response) => { ++ if (response && response.data) { ++ response.data.forEach((embeddingBase64Obj) => { ++ const embeddingBase64Str = embeddingBase64Obj.embedding; ++ embeddingBase64Obj.embedding = (0, utils_1.toFloat32Array)( ++ embeddingBase64Str ++ ); ++ }); ++ } ++ return response; ++ }); ++ } + } + exports.Embeddings = Embeddings; + //# sourceMappingURL=embeddings.js.map +diff --git a/resources/embeddings.mjs b/resources/embeddings.mjs +index 19dcaef578c194a89759c4360073cfd4f7dd2cbf..0284e9cc615c900eff508eb595f7360a74bd9200 100644 +--- a/resources/embeddings.mjs ++++ b/resources/embeddings.mjs +@@ -2,51 +2,61 @@ + import { APIResource } from "../core/resource.mjs"; + import { loggerFor, toFloat32Array } from "../internal/utils.mjs"; + export class Embeddings extends APIResource { +- /** +- * Creates an embedding vector representing the input text. +- * +- * @example +- * ```ts +- * const createEmbeddingResponse = +- * await client.embeddings.create({ +- * input: 'The quick brown fox jumped over the lazy dog', +- * model: 'text-embedding-3-small', +- * }); +- * ``` +- */ +- create(body, options) { +- const hasUserProvidedEncodingFormat = !!body.encoding_format; +- // No encoding_format specified, defaulting to base64 for performance reasons +- // See https://github.com/openai/openai-node/pull/1312 +- let encoding_format = hasUserProvidedEncodingFormat ? body.encoding_format : 'base64'; +- if (hasUserProvidedEncodingFormat) { +- loggerFor(this._client).debug('embeddings/user defined encoding_format:', body.encoding_format); +- } +- const response = this._client.post('/embeddings', { +- body: { +- ...body, +- encoding_format: encoding_format, +- }, +- ...options, +- }); +- // if the user specified an encoding_format, return the response as-is +- if (hasUserProvidedEncodingFormat) { +- return response; +- } +- // in this stage, we are sure the user did not specify an encoding_format +- // and we defaulted to base64 for performance reasons +- // we are sure then that the response is base64 encoded, let's decode it +- // the returned result will be a float32 array since this is OpenAI API's default encoding +- loggerFor(this._client).debug('embeddings/decoding base64 embeddings from base64'); +- return response._thenUnwrap((response) => { +- if (response && response.data) { +- response.data.forEach((embeddingBase64Obj) => { +- const embeddingBase64Str = embeddingBase64Obj.embedding; +- embeddingBase64Obj.embedding = toFloat32Array(embeddingBase64Str); +- }); +- } +- return response; +- }); +- } ++ /** ++ * Creates an embedding vector representing the input text. ++ * ++ * @example ++ * ```ts ++ * const createEmbeddingResponse = ++ * await client.embeddings.create({ ++ * input: 'The quick brown fox jumped over the lazy dog', ++ * model: 'text-embedding-3-small', ++ * }); ++ * ``` ++ */ ++ create(body, options) { ++ const hasUserProvidedEncodingFormat = !!body.encoding_format; ++ // No encoding_format specified, defaulting to base64 for performance reasons ++ // See https://github.com/openai/openai-node/pull/1312 ++ let encoding_format = hasUserProvidedEncodingFormat ++ ? body.encoding_format ++ : "base64"; ++ if (body.model.includes("jina")) { ++ encoding_format = undefined; ++ } ++ if (hasUserProvidedEncodingFormat) { ++ loggerFor(this._client).debug( ++ "embeddings/user defined encoding_format:", ++ body.encoding_format ++ ); ++ } ++ const response = this._client.post("/embeddings", { ++ body: { ++ ...body, ++ encoding_format: encoding_format, ++ }, ++ ...options, ++ }); ++ // if the user specified an encoding_format, return the response as-is ++ if (hasUserProvidedEncodingFormat || body.model.includes("jina")) { ++ return response; ++ } ++ // in this stage, we are sure the user did not specify an encoding_format ++ // and we defaulted to base64 for performance reasons ++ // we are sure then that the response is base64 encoded, let's decode it ++ // the returned result will be a float32 array since this is OpenAI API's default encoding ++ loggerFor(this._client).debug( ++ "embeddings/decoding base64 embeddings from base64" ++ ); ++ return response._thenUnwrap((response) => { ++ if (response && response.data) { ++ response.data.forEach((embeddingBase64Obj) => { ++ const embeddingBase64Str = embeddingBase64Obj.embedding; ++ embeddingBase64Obj.embedding = toFloat32Array(embeddingBase64Str); ++ }); ++ } ++ return response; ++ }); ++ } + } + //# sourceMappingURL=embeddings.mjs.map diff --git a/package.json b/package.json index 83edefd40..d7ea1e980 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "CherryStudio", - "version": "1.5.0-rc.1", + "version": "1.4.1", "private": true, "description": "A powerful AI assistant for producer.", "main": "./out/main/index.js", @@ -185,7 +185,7 @@ "mime": "^4.0.4", "motion": "^12.10.5", "npx-scope-finder": "^1.2.0", - "openai": "patch:openai@npm%3A4.96.0#~/.yarn/patches/openai-npm-4.96.0-0665b05cb9.patch", + "openai": "patch:openai@npm%3A5.1.0#~/.yarn/patches/openai-npm-5.1.0-0e7b3ccb07.patch", "p-queue": "^8.1.0", "playwright": "^1.52.0", "prettier": "^3.5.3", @@ -226,11 +226,10 @@ "@langchain/openai@npm:^0.3.16": "patch:@langchain/openai@npm%3A0.3.16#~/.yarn/patches/@langchain-openai-npm-0.3.16-e525b59526.patch", "@langchain/openai@npm:>=0.1.0 <0.4.0": "patch:@langchain/openai@npm%3A0.3.16#~/.yarn/patches/@langchain-openai-npm-0.3.16-e525b59526.patch", "libsql@npm:^0.4.4": "patch:libsql@npm%3A0.4.7#~/.yarn/patches/libsql-npm-0.4.7-444e260fb1.patch", - "openai@npm:^4.77.0": "patch:openai@npm%3A4.96.0#~/.yarn/patches/openai-npm-4.96.0-0665b05cb9.patch", - "canvas": "3.1.0", + "openai@npm:^4.77.0": "patch:openai@npm%3A5.1.0#~/.yarn/patches/openai-npm-5.1.0-0e7b3ccb07.patch", "pkce-challenge@npm:^4.1.0": "patch:pkce-challenge@npm%3A4.1.0#~/.yarn/patches/pkce-challenge-npm-4.1.0-fbc51695a3.patch", "app-builder-lib@npm:26.0.13": "patch:app-builder-lib@npm%3A26.0.13#~/.yarn/patches/app-builder-lib-npm-26.0.13-a064c9e1d0.patch", - "openai@npm:^4.87.3": "patch:openai@npm%3A4.96.0#~/.yarn/patches/openai-npm-4.96.0-0665b05cb9.patch", + "openai@npm:^4.87.3": "patch:openai@npm%3A5.1.0#~/.yarn/patches/openai-npm-5.1.0-0e7b3ccb07.patch", "app-builder-lib@npm:26.0.15": "patch:app-builder-lib@npm%3A26.0.15#~/.yarn/patches/app-builder-lib-npm-26.0.15-360e5b0476.patch", "@langchain/core@npm:^0.3.26": "patch:@langchain/core@npm%3A0.3.44#~/.yarn/patches/@langchain-core-npm-0.3.44-41d5c3cb0a.patch" }, diff --git a/src/main/services/SelectionService.ts b/src/main/services/SelectionService.ts index f785683b5..ea5bede2d 100644 --- a/src/main/services/SelectionService.ts +++ b/src/main/services/SelectionService.ts @@ -841,8 +841,9 @@ export class SelectionService { //ctrlkey pressed if (this.lastCtrlkeyDownTime === 0) { this.lastCtrlkeyDownTime = Date.now() - //add the mouse-wheel listener, detect if user is zooming in/out + //add the mouse-wheel&mouse-down listener, detect if user is zooming in/out or multi-selecting this.selectionHook!.on('mouse-wheel', this.handleMouseWheelCtrlkeyMode) + this.selectionHook!.on('mouse-down', this.handleMouseDownCtrlkeyMode) return } @@ -866,8 +867,9 @@ export class SelectionService { */ private handleKeyUpCtrlkeyMode = (data: KeyboardEventData) => { if (!this.isCtrlkey(data.vkCode)) return - //remove the mouse-wheel listener + //remove the mouse-wheel&mouse-down listener this.selectionHook!.off('mouse-wheel', this.handleMouseWheelCtrlkeyMode) + this.selectionHook!.off('mouse-down', this.handleMouseDownCtrlkeyMode) this.lastCtrlkeyDownTime = 0 } @@ -880,6 +882,15 @@ export class SelectionService { this.lastCtrlkeyDownTime = -1 } + /** + * Handle mouse down events in ctrlkey trigger mode + * ignore CtrlKey pressing when mouse down is used + * because user is multi-selecting + */ + private handleMouseDownCtrlkeyMode = () => { + this.lastCtrlkeyDownTime = -1 + } + //check if the key is ctrl key private isCtrlkey(vkCode: number) { return vkCode === 162 || vkCode === 163 diff --git a/src/renderer/src/assets/styles/color.scss b/src/renderer/src/assets/styles/color.scss index 278d732a4..6100e1d0e 100644 --- a/src/renderer/src/assets/styles/color.scss +++ b/src/renderer/src/assets/styles/color.scss @@ -44,6 +44,9 @@ --color-reference-text: #ffffff; --color-reference-background: #0b0e12; + --color-list-item: #222; + --color-list-item-hover: #1e1e1e; + --modal-background: #1f1f1f; --color-highlight: rgba(0, 0, 0, 1); @@ -68,7 +71,7 @@ --chat-background-assistant: #2c2c2c; --chat-text-user: var(--color-black); - --list-item-border-radius: 16px; + --list-item-border-radius: 20px; } [theme-mode='light'] { @@ -117,6 +120,9 @@ --color-reference-text: #000000; --color-reference-background: #f1f7ff; + --color-list-item: #eee; + --color-list-item-hover: #f5f5f5; + --modal-background: var(--color-white); --color-highlight: initial; diff --git a/src/renderer/src/components/app/Sidebar.tsx b/src/renderer/src/components/app/Sidebar.tsx index c221e04dd..5e4365c3c 100644 --- a/src/renderer/src/components/app/Sidebar.tsx +++ b/src/renderer/src/components/app/Sidebar.tsx @@ -9,6 +9,7 @@ import { useMinapps } from '@renderer/hooks/useMinapps' import useNavBackgroundColor from '@renderer/hooks/useNavBackgroundColor' import { modelGenerating, useRuntime } from '@renderer/hooks/useRuntime' import { useSettings } from '@renderer/hooks/useSettings' +import i18n from '@renderer/i18n' import { ThemeMode } from '@renderer/types' import { isEmoji } from '@renderer/utils' import type { MenuProps } from 'antd' @@ -19,7 +20,7 @@ import { Folder, Languages, LayoutGrid, - MessageSquareQuote, + MessageSquare, Moon, Palette, Settings, @@ -35,7 +36,6 @@ import styled from 'styled-components' import DragableList from '../DragableList' import MinAppIcon from '../Icons/MinAppIcon' import UserPopup from '../Popups/UserPopup' -import i18n from '@renderer/i18n' const Sidebar: FC = () => { const { hideMinappPopup, openMinapp } = useMinappPopup() @@ -67,9 +67,7 @@ const Sidebar: FC = () => { openMinapp({ id: docsId, name: t('docs.title'), - url: isChinese - ? 'https://docs.cherry-ai.com/' - : 'https://docs.cherry-ai.com/cherry-studio-wen-dang/en-us', + url: isChinese ? 'https://docs.cherry-ai.com/' : 'https://docs.cherry-ai.com/cherry-studio-wen-dang/en-us', logo: AppLogo }) } @@ -151,7 +149,7 @@ const MainMenus: FC = () => { const isRoutes = (path: string): string => (pathname.startsWith(path) && !minappShow ? 'active' : '') const iconMap = { - assistants: , + assistants: , agents: , paintings: , translate: , diff --git a/src/renderer/src/context/AntdProvider.tsx b/src/renderer/src/context/AntdProvider.tsx index 570da9fc4..592121ccc 100644 --- a/src/renderer/src/context/AntdProvider.tsx +++ b/src/renderer/src/context/AntdProvider.tsx @@ -48,6 +48,10 @@ const AntdProvider: FC = ({ children }) => { }, ColorPicker: { fontFamily: 'var(--code-font-family)' + }, + Segmented: { + itemActiveBg: 'var(--color-background-mute)', + itemHoverBg: 'var(--color-background-mute)' } }, token: { diff --git a/src/renderer/src/hooks/usePaintings.ts b/src/renderer/src/hooks/usePaintings.ts index cf7dbc3ce..47528622f 100644 --- a/src/renderer/src/hooks/usePaintings.ts +++ b/src/renderer/src/hooks/usePaintings.ts @@ -10,16 +10,19 @@ export function usePaintings() { 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 dispatch = useAppDispatch() return { paintings, DMXAPIPaintings, + tokenFluxPaintings, persistentData: { generate, remix, edit, - upscale + upscale, + tokenFluxPaintings }, addPainting: (namespace: keyof PaintingsState, painting: PaintingAction) => { dispatch(addPainting({ namespace, painting })) diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index aeac3e754..00e4bc70b 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -960,7 +960,17 @@ "text_desc_required": "Please enter image description first", "req_error_text": "Operation failed. Please try again. Avoid using 'copyrighted' or 'sensitive' words in your prompt.", "auto_create_paint": "Auto-create image", - "auto_create_paint_tip": "After the image is generated, a new image will be created automatically." + "auto_create_paint_tip": "After the image is generated, a new image will be created automatically.", + "select_model": "Select Model", + "input_parameters": "Input Parameters", + "input_image": "Input Image", + "generated_image": "Generated Image", + "pricing": "Pricing", + "model_and_pricing": "Model & Pricing", + "per_image": "per image", + "per_images": "per images", + "required_field": "Required field", + "uploaded_input": "Uploaded input" }, "prompts": { "explanation": "Explain this concept to me", diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index 3c05bfb16..fb45a779f 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -960,7 +960,17 @@ "text_desc_required": "画像の説明を先に入力してください", "req_error_text": "実行に失敗しました。もう一度お試しください。プロンプトに「著作権用語」や「センシティブな用語」を含めないでください。", "auto_create_paint": "画像を自動作成", - "auto_create_paint_tip": "画像が生成された後、自動的に新しい画像が作成されます。" + "auto_create_paint_tip": "画像が生成された後、自動的に新しい画像が作成されます。", + "select_model": "モデルを選択", + "input_parameters": "パラメータ入力", + "input_image": "入力画像", + "generated_image": "生成画像", + "pricing": "料金", + "model_and_pricing": "モデルと料金", + "per_image": "1枚あたり", + "per_images": "複数枚あたり", + "required_field": "必須項目", + "uploaded_input": "アップロード済みの入力" }, "prompts": { "explanation": "この概念を説明してください", @@ -1128,26 +1138,6 @@ "markdown_export.show_model_provider.help": "Markdownエクスポート時にモデルプロバイダー(例:OpenAI、Geminiなど)を表示します。", "minute_interval_one": "{{count}} 分", "minute_interval_other": "{{count}} 分", - "notion": { - "api_key": "Notion APIキー", - "api_key_placeholder": "Notion APIキーを入力してください", - "check": { - "button": "確認", - "empty_api_key": "Api_keyが設定されていません", - "empty_database_id": "Database_idが設定されていません", - "error": "接続エラー、ネットワーク設定とApi_keyとDatabase_idを確認してください", - "fail": "接続エラー、ネットワーク設定とApi_keyとDatabase_idを確認してください", - "success": "接続に成功しました。" - }, - "database_id": "Notion データベースID", - "database_id_placeholder": "Notion データベースIDを入力してください", - "help": "Notion 設定ドキュメント", - "page_name_key": "ページタイトルフィールド名", - "page_name_key_placeholder": "ページタイトルフィールド名を入力してください。デフォルトは Name です", - "title": "Notion 設定", - "export_reasoning.title": "エクスポート時に思考チェーンを含める", - "export_reasoning.help": "有効にすると、Notionにエクスポートする際に思考チェーンの内容が含まれます。" - }, "title": "データ設定", "webdav": { "autoSync": "自動バックアップ", @@ -1267,7 +1257,25 @@ "new_folder.button": "新しいフォルダー" }, "message_title.use_topic_naming.title": "トピック命名モデルを使用してメッセージのタイトルを作成", - "message_title.use_topic_naming.help": "この設定は、すべてのMarkdownエクスポート方法に影響します。" + "message_title.use_topic_naming.help": "この設定は、すべてのMarkdownエクスポート方法に影響します。", + "notion.api_key": "Notion APIキー", + "notion.api_key_placeholder": "Notion APIキーを入力してください", + "notion.check": { + "button": "確認", + "empty_api_key": "Api_keyが設定されていません", + "empty_database_id": "Database_idが設定されていません", + "error": "接続エラー、ネットワーク設定とApi_keyとDatabase_idを確認してください", + "fail": "接続エラー、ネットワーク設定とApi_keyとDatabase_idを確認してください", + "success": "接続に成功しました。" + }, + "notion.database_id": "Notion データベースID", + "notion.database_id_placeholder": "Notion データベースIDを入力してください", + "notion.help": "Notion 設定ドキュメント", + "notion.page_name_key": "ページタイトルフィールド名", + "notion.page_name_key_placeholder": "ページタイトルフィールド名を入力してください。デフォルトは Name です", + "notion.title": "Notion 設定", + "notion.export_reasoning.title": "エクスポート時に思考チェーンを含める", + "notion.export_reasoning.help": "有効にすると、Notionにエクスポートする際に思考チェーンの内容が含まれます。" }, "display.assistant.title": "アシスタント設定", "display.custom.css": "カスタムCSS", diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index a79d4454b..f2321ddd9 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -960,7 +960,17 @@ "text_desc_required": "Пожалуйста, сначала введите описание изображения", "req_error_text": "Операция не удалась, повторите попытку. Пожалуйста, избегайте защищенных авторским правом терминов и конфиденциальных слов в запросах.", "auto_create_paint": "Автоматическое создание изображения", - "auto_create_paint_tip": "После генерации изображения будет автоматически создано новое." + "auto_create_paint_tip": "После генерации изображения будет автоматически создано новое.", + "select_model": "Выбрать модель", + "input_parameters": "Ввести параметры", + "input_image": "Входное изображение", + "generated_image": "Сгенерированное изображение", + "pricing": "Цены", + "model_and_pricing": "Модель и цены", + "per_image": "за изображение", + "per_images": "за изображения", + "required_field": "Обязательное поле", + "uploaded_input": "Загруженный ввод" }, "prompts": { "explanation": "Объясните мне этот концепт", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index f891a95f2..745ad4148 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -960,7 +960,17 @@ "text_desc_required": "请先输入图片描述", "req_error_text": "运行失败,请重试。提示词避免“版权词”和”敏感词”哦。", "auto_create_paint": "自动新建图片", - "auto_create_paint_tip": "在图片生成后,会自动新建图片" + "auto_create_paint_tip": "在图片生成后,会自动新建图片", + "select_model": "选择模型", + "input_parameters": "输入参数", + "input_image": "输入图片", + "generated_image": "生成图片", + "pricing": "定价", + "model_and_pricing": "模型与定价", + "per_image": "每张图片", + "per_images": "每张图片", + "required_field": "必填项", + "uploaded_input": "已上传输入" }, "prompts": { "explanation": "帮我解释一下这个概念", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index b4bc2a3b1..2bd7c7c37 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -960,7 +960,17 @@ "text_desc_required": "請先輸入圖片描述", "req_error_text": "运行失败,请重试。提示词避免“版权词”和”敏感词”哦。", "auto_create_paint": "自動新增圖片", - "auto_create_paint_tip": "圖片生成後,會自動新增圖片" + "auto_create_paint_tip": "圖片生成後,會自動新增圖片", + "select_model": "選擇模型", + "input_parameters": "輸入參數", + "input_image": "輸入圖片", + "generated_image": "生成圖片", + "pricing": "定價", + "model_and_pricing": "模型與定價", + "per_image": "每張圖片", + "per_images": "每張圖片", + "required_field": "必填欄位", + "uploaded_input": "已上傳輸入" }, "prompts": { "explanation": "幫我解釋一下這個概念", diff --git a/src/renderer/src/pages/home/Messages/Prompt.tsx b/src/renderer/src/pages/home/Messages/Prompt.tsx index 4de680923..1fe67eca4 100644 --- a/src/renderer/src/pages/home/Messages/Prompt.tsx +++ b/src/renderer/src/pages/home/Messages/Prompt.tsx @@ -34,7 +34,7 @@ const Container = styled.div<{ $isDark: boolean }>` margin: 5px 20px 0 20px; border-radius: 10px; cursor: pointer; - border: 1px solid var(--color-border); + border: 0.5px solid var(--color-border); ` const Text = styled.div` diff --git a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx index 16048a0f1..ac1851df3 100644 --- a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx +++ b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx @@ -58,12 +58,14 @@ const Assistants: FC = ({
{getGroupedAssistants.map((group) => ( - - - {group.tag} - - - + {group.tag !== t('assistants.tags.untagged') && ( + + + {group.tag} + + + + )} {group.assistants.map((assistant) => ( = (props) => { - const { assistant, updateAssistantSettings, updateAssistant } = useAssistant(props.assistant.id) + const { assistant, updateAssistantSettings } = useAssistant(props.assistant.id) const { provider } = useProvider(assistant.model.provider) const { messageStyle, fontSize, language } = useSettings() @@ -140,24 +140,6 @@ const SettingsTab: FC = (props) => { } } - const onReset = () => { - setTemperature(DEFAULT_TEMPERATURE) - setContextCount(DEFAULT_CONTEXTCOUNT) - updateAssistant({ - ...assistant, - settings: { - ...assistant.settings, - temperature: DEFAULT_TEMPERATURE, - contextCount: DEFAULT_CONTEXTCOUNT, - enableMaxTokens: false, - maxTokens: DEFAULT_MAX_TOKENS, - streamOutput: true, - hideMessages: false, - customParameters: [] - } - }) - } - const codeStyle = useMemo(() => { return codeEditor.enabled ? theme === ThemeMode.light @@ -211,14 +193,6 @@ const SettingsTab: FC = (props) => { defaultExpanded={true} extra={ - - + + )} + + + + {/* Provider Section */} + + {t('common.provider')} + + {t('paintings.learn_more')} + + + + + + + {/* Model & Pricing Section */} + + {t('paintings.model_and_pricing')} + {selectedModel && selectedModel.pricing && ( + + + {selectedModel.pricing.price} {selectedModel.pricing.currency}{' '} + {selectedModel.pricing.unit > 1 ? t('paintings.per_images') : t('paintings.per_image')} + + + )} + + + + {/* Input Parameters Section */} + {selectedModel && selectedModel.input_schema && ( + <> + {t('paintings.input_parameters')} + + {Object.entries(selectedModel.input_schema.properties).map(([key, property]: [string, any]) => { + if (key === 'prompt') return null // Skip prompt as it's handled separately + + const isRequired = selectedModel.input_schema.required?.includes(key) + + return ( + + + + {readI18nContext(property, 'title')} + {isRequired && *} + + {property.description && ( + + + + )} + + + + ) + })} + + + )} + + + + {/* Check if any form field contains an uploaded image */} + {Object.keys(formData).some((key) => key.toLowerCase().includes('image') && formData[key]) ? ( + + + {t('paintings.input_image')} + + {Object.entries(formData).map(([key, value]) => { + if (key.toLowerCase().includes('image') && value) { + return ( + + {t('paintings.uploaded_input')} + + ) + } + return null + })} + + + + {t('paintings.generated_image')} + + + + ) : ( + + )} + +