mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-10 23:59:45 +08:00
Merge branch 'main' of github.com:CherryHQ/cherry-studio into v2
This commit is contained in:
commit
23f7b39753
@ -77,7 +77,7 @@ Please review the following critical information before submitting your Pull Req
|
|||||||
Our core team is currently focused on significant architectural updates that involve these data structures. To ensure stability and focus during this period, contributions of this nature will be temporarily managed internally.
|
Our core team is currently focused on significant architectural updates that involve these data structures. To ensure stability and focus during this period, contributions of this nature will be temporarily managed internally.
|
||||||
|
|
||||||
* **PRs that require changes to Redux state shape or IndexedDB schemas will be closed.**
|
* **PRs that require changes to Redux state shape or IndexedDB schemas will be closed.**
|
||||||
* **This restriction is temporary and will be lifted with the release of `v2.0.0`.** You can track the progress of `v2.0.0` and its related discussions on issue [#10162](https://github.com/YOUR_ORG/YOUR_REPO/issues/10162) (please replace with your actual repo link).
|
* **This restriction is temporary and will be lifted with the release of `v2.0.0`.** You can track the progress of `v2.0.0` and its related discussions on issue [#10162](https://github.com/CherryHQ/cherry-studio/pull/10162).
|
||||||
|
|
||||||
We highly encourage contributions for:
|
We highly encourage contributions for:
|
||||||
* Bug fixes 🐞
|
* Bug fixes 🐞
|
||||||
|
|||||||
@ -81,7 +81,7 @@ git commit --signoff -m "Your commit message"
|
|||||||
我们的核心团队目前正专注于涉及这些数据结构的关键架构更新和基础工作。为确保在此期间的稳定性与专注,此类贡献将暂时由内部进行管理。
|
我们的核心团队目前正专注于涉及这些数据结构的关键架构更新和基础工作。为确保在此期间的稳定性与专注,此类贡献将暂时由内部进行管理。
|
||||||
|
|
||||||
* **需要更改 Redux 状态结构或 IndexedDB schema 的 PR 将会被关闭。**
|
* **需要更改 Redux 状态结构或 IndexedDB schema 的 PR 将会被关闭。**
|
||||||
* **此限制是临时性的,并将在 `v2.0.0` 版本发布后解除。** 您可以通过 Issue [#10162](https://github.com/YOUR_ORG/YOUR_REPO/issues/10162) (请替换为您的实际仓库链接) 跟踪 `v2.0.0` 的进展及相关讨论。
|
* **此限制是临时性的,并将在 `v2.0.0` 版本发布后解除。** 您可以通过 Issue [#10162](https://github.com/CherryHQ/cherry-studio/pull/10162) 跟踪 `v2.0.0` 的进展及相关讨论。
|
||||||
|
|
||||||
我们非常鼓励以下类型的贡献:
|
我们非常鼓励以下类型的贡献:
|
||||||
* 错误修复 🐞
|
* 错误修复 🐞
|
||||||
|
|||||||
@ -334,13 +334,13 @@
|
|||||||
--cs-ring: hsla(84, 81%, 44%, 0.4);
|
--cs-ring: hsla(84, 81%, 44%, 0.4);
|
||||||
|
|
||||||
/* UI Element Colors */
|
/* UI Element Colors */
|
||||||
--cs-secondary: hsla(0, 0%, 0%, 0.05); /* Secondary Button Background */
|
--cs-secondary: hsla(0, 0%, 0%, 0.05); /* Secondary Button Background */
|
||||||
--cs-secondary-hover: hsla(0, 0%, 0%, 0.85);
|
--cs-secondary-hover: hsla(0, 0%, 0%, 0.85);
|
||||||
--cs-secondary-active: hsla(0, 0%, 0%, 0.7);
|
--cs-secondary-active: hsla(0, 0%, 0%, 0.7);
|
||||||
--cs-muted: hsla(0, 0%, 0%, 0.05); /* Muted/Subtle Background */
|
--cs-muted: hsla(0, 0%, 0%, 0.05); /* Muted/Subtle Background */
|
||||||
--cs-accent: hsla(0, 0%, 0%, 0.05); /* Accent Background */
|
--cs-accent: hsla(0, 0%, 0%, 0.05); /* Accent Background */
|
||||||
--cs-ghost-hover: hsla(0, 0%, 0%, 0.05); /* Ghost Button Hover */
|
--cs-ghost-hover: hsla(0, 0%, 0%, 0.05); /* Ghost Button Hover */
|
||||||
--cs-ghost-active: hsla(0, 0%, 0%, 0.1); /* Ghost Button Active */
|
--cs-ghost-active: hsla(0, 0%, 0%, 0.1); /* Ghost Button Active */
|
||||||
|
|
||||||
/* Sidebar */
|
/* Sidebar */
|
||||||
--cs-sidebar: var(--cs-white);
|
--cs-sidebar: var(--cs-white);
|
||||||
@ -390,43 +390,43 @@
|
|||||||
/* Spacing & Sizing (合并) */
|
/* Spacing & Sizing (合并) */
|
||||||
/* ==================== */
|
/* ==================== */
|
||||||
|
|
||||||
--cs-size-5xs: 0.25rem; /* 4px */
|
--cs-size-5xs: 0.25rem; /* 4px */
|
||||||
--cs-size-4xs: 0.5rem; /* 8px */
|
--cs-size-4xs: 0.5rem; /* 8px */
|
||||||
--cs-size-3xs: 0.75rem; /* 12px */
|
--cs-size-3xs: 0.75rem; /* 12px */
|
||||||
--cs-size-2xs: 1rem; /* 16px */
|
--cs-size-2xs: 1rem; /* 16px */
|
||||||
--cs-size-xs: 1.5rem; /* 24px */
|
--cs-size-xs: 1.5rem; /* 24px */
|
||||||
--cs-size-sm: 2rem; /* 32px */
|
--cs-size-sm: 2rem; /* 32px */
|
||||||
--cs-size-md: 2.5rem; /* 40px */
|
--cs-size-md: 2.5rem; /* 40px */
|
||||||
--cs-size-lg: 3rem; /* 48px */
|
--cs-size-lg: 3rem; /* 48px */
|
||||||
--cs-size-xl: 3.5rem; /* 56px */
|
--cs-size-xl: 3.5rem; /* 56px */
|
||||||
--cs-size-2xl: 4rem; /* 64px */
|
--cs-size-2xl: 4rem; /* 64px */
|
||||||
--cs-size-3xl: 4.5rem; /* 72px */
|
--cs-size-3xl: 4.5rem; /* 72px */
|
||||||
--cs-size-4xl: 5rem; /* 80px */
|
--cs-size-4xl: 5rem; /* 80px */
|
||||||
--cs-size-5xl: 5.5rem; /* 88px */
|
--cs-size-5xl: 5.5rem; /* 88px */
|
||||||
--cs-size-6xl: 6rem; /* 96px */
|
--cs-size-6xl: 6rem; /* 96px */
|
||||||
--cs-size-7xl: 6.5rem; /* 104px */
|
--cs-size-7xl: 6.5rem; /* 104px */
|
||||||
--cs-size-8xl: 7rem; /* 112px */
|
--cs-size-8xl: 7rem; /* 112px */
|
||||||
|
|
||||||
/* ==================== */
|
/* ==================== */
|
||||||
/* Border Radius */
|
/* Border Radius */
|
||||||
/* ==================== */
|
/* ==================== */
|
||||||
|
|
||||||
--cs-radius-4xs: 0.25rem; /* 4px */
|
--cs-radius-4xs: 0.25rem; /* 4px */
|
||||||
--cs-radius-3xs: 0.5rem; /* 8px */
|
--cs-radius-3xs: 0.5rem; /* 8px */
|
||||||
--cs-radius-2xs: 0.75rem; /* 12px */
|
--cs-radius-2xs: 0.75rem; /* 12px */
|
||||||
--cs-radius-xs: 1rem; /* 16px */
|
--cs-radius-xs: 1rem; /* 16px */
|
||||||
--cs-radius-sm: 1.5rem; /* 24px */
|
--cs-radius-sm: 1.5rem; /* 24px */
|
||||||
--cs-radius-md: 2rem; /* 32px */
|
--cs-radius-md: 2rem; /* 32px */
|
||||||
--cs-radius-lg: 2.5rem; /* 40px */
|
--cs-radius-lg: 2.5rem; /* 40px */
|
||||||
--cs-radius-xl: 3rem; /* 48px */
|
--cs-radius-xl: 3rem; /* 48px */
|
||||||
--cs-radius-2xl: 3.5rem; /* 56px */
|
--cs-radius-2xl: 3.5rem; /* 56px */
|
||||||
--cs-radius-3xl: 4rem; /* 64px */
|
--cs-radius-3xl: 4rem; /* 64px */
|
||||||
--cs-radius-round: 999px; /* 保持 px,因为是特殊值 */
|
--cs-radius-round: 999px; /* 保持 px,因为是特殊值 */
|
||||||
|
|
||||||
/* Border Width */
|
/* Border Width */
|
||||||
--cs-border-width-sm: 1px; /* 1px */
|
--cs-border-width-sm: 1px; /* 1px */
|
||||||
--cs-border-width-md: 2px; /* 2px */
|
--cs-border-width-md: 2px; /* 2px */
|
||||||
--cs-border-width-lg: 3px; /* 3px */
|
--cs-border-width-lg: 3px; /* 3px */
|
||||||
|
|
||||||
/* ==================== */
|
/* ==================== */
|
||||||
/* Typography */
|
/* Typography */
|
||||||
@ -442,43 +442,43 @@
|
|||||||
--cs-font-weight-bold: 700;
|
--cs-font-weight-bold: 700;
|
||||||
|
|
||||||
/* Font Sizes - Body */
|
/* Font Sizes - Body */
|
||||||
--cs-font-size-body-xs: 0.75rem; /* 12px */
|
--cs-font-size-body-xs: 0.75rem; /* 12px */
|
||||||
--cs-font-size-body-sm: 0.875rem; /* 14px */
|
--cs-font-size-body-sm: 0.875rem; /* 14px */
|
||||||
--cs-font-size-body-md: 1rem; /* 16px */
|
--cs-font-size-body-md: 1rem; /* 16px */
|
||||||
--cs-font-size-body-lg: 1.125rem; /* 18px */
|
--cs-font-size-body-lg: 1.125rem; /* 18px */
|
||||||
|
|
||||||
/* Font Sizes - Heading */
|
/* Font Sizes - Heading */
|
||||||
--cs-font-size-heading-xs: 1.25rem; /* 20px */
|
--cs-font-size-heading-xs: 1.25rem; /* 20px */
|
||||||
--cs-font-size-heading-sm: 1.5rem; /* 24px */
|
--cs-font-size-heading-sm: 1.5rem; /* 24px */
|
||||||
--cs-font-size-heading-md: 2rem; /* 32px */
|
--cs-font-size-heading-md: 2rem; /* 32px */
|
||||||
--cs-font-size-heading-lg: 2.5rem; /* 40px */
|
--cs-font-size-heading-lg: 2.5rem; /* 40px */
|
||||||
--cs-font-size-heading-xl: 3rem; /* 48px */
|
--cs-font-size-heading-xl: 3rem; /* 48px */
|
||||||
--cs-font-size-heading-2xl: 3.75rem; /* 60px */
|
--cs-font-size-heading-2xl: 3.75rem; /* 60px */
|
||||||
|
|
||||||
/* Line Heights - Body */
|
/* Line Heights - Body */
|
||||||
--cs-line-height-body-xs: 1.25rem; /* 20px */
|
--cs-line-height-body-xs: 1.25rem; /* 20px */
|
||||||
--cs-line-height-body-sm: 1.5rem; /* 24px */
|
--cs-line-height-body-sm: 1.5rem; /* 24px */
|
||||||
--cs-line-height-body-md: 1.5rem; /* 24px */
|
--cs-line-height-body-md: 1.5rem; /* 24px */
|
||||||
--cs-line-height-body-lg: 1.75rem; /* 28px */
|
--cs-line-height-body-lg: 1.75rem; /* 28px */
|
||||||
|
|
||||||
/* Line Heights - Heading */
|
/* Line Heights - Heading */
|
||||||
--cs-line-height-heading-xs: 2rem; /* 32px */
|
--cs-line-height-heading-xs: 2rem; /* 32px */
|
||||||
--cs-line-height-heading-sm: 2.5rem; /* 40px */
|
--cs-line-height-heading-sm: 2.5rem; /* 40px */
|
||||||
--cs-line-height-heading-md: 3rem; /* 48px */
|
--cs-line-height-heading-md: 3rem; /* 48px */
|
||||||
--cs-line-height-heading-lg: 3.75rem; /* 60px */
|
--cs-line-height-heading-lg: 3.75rem; /* 60px */
|
||||||
--cs-line-height-heading-xl: 5rem; /* 80px */
|
--cs-line-height-heading-xl: 5rem; /* 80px */
|
||||||
|
|
||||||
/* Paragraph Spacing */
|
/* Paragraph Spacing */
|
||||||
--cs-paragraph-spacing-body-xs: 0.75rem; /* 12px */
|
--cs-paragraph-spacing-body-xs: 0.75rem; /* 12px */
|
||||||
--cs-paragraph-spacing-body-sm: 0.875rem; /* 14px */
|
--cs-paragraph-spacing-body-sm: 0.875rem; /* 14px */
|
||||||
--cs-paragraph-spacing-body-md: 1rem; /* 16px */
|
--cs-paragraph-spacing-body-md: 1rem; /* 16px */
|
||||||
--cs-paragraph-spacing-body-lg: 1.125rem; /* 18px */
|
--cs-paragraph-spacing-body-lg: 1.125rem; /* 18px */
|
||||||
--cs-paragraph-spacing-heading-xs: 1.25rem; /* 20px */
|
--cs-paragraph-spacing-heading-xs: 1.25rem; /* 20px */
|
||||||
--cs-paragraph-spacing-heading-sm: 1.5rem; /* 24px */
|
--cs-paragraph-spacing-heading-sm: 1.5rem; /* 24px */
|
||||||
--cs-paragraph-spacing-heading-md: 2rem; /* 32px */
|
--cs-paragraph-spacing-heading-md: 2rem; /* 32px */
|
||||||
--cs-paragraph-spacing-heading-lg: 2.5rem; /* 40px */
|
--cs-paragraph-spacing-heading-lg: 2.5rem; /* 40px */
|
||||||
--cs-paragraph-spacing-heading-xl: 3rem; /* 48px */
|
--cs-paragraph-spacing-heading-xl: 3rem; /* 48px */
|
||||||
--cs-paragraph-spacing-heading-2xl: 3.75rem; /* 60px */
|
--cs-paragraph-spacing-heading-2xl: 3.75rem; /* 60px */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== */
|
/* ==================== */
|
||||||
@ -506,13 +506,13 @@
|
|||||||
--cs-ring: hsla(84, 81%, 44%, 0.4);
|
--cs-ring: hsla(84, 81%, 44%, 0.4);
|
||||||
|
|
||||||
/* UI Element Colors - Dark Mode */
|
/* UI Element Colors - Dark Mode */
|
||||||
--cs-secondary: hsla(0, 0%, 100%, 0.1); /* Secondary Button Background */
|
--cs-secondary: hsla(0, 0%, 100%, 0.1); /* Secondary Button Background */
|
||||||
--cs-secondary-hover: hsla(0, 0%, 100%, 0.2);
|
--cs-secondary-hover: hsla(0, 0%, 100%, 0.2);
|
||||||
--cs-secondary-active: hsla(0, 0%, 100%, 0.25);
|
--cs-secondary-active: hsla(0, 0%, 100%, 0.25);
|
||||||
--cs-muted: hsla(0, 0%, 100%, 0.1); /* Muted/Subtle Background */
|
--cs-muted: hsla(0, 0%, 100%, 0.1); /* Muted/Subtle Background */
|
||||||
--cs-accent: hsla(0, 0%, 100%, 0.1); /* Accent Background */
|
--cs-accent: hsla(0, 0%, 100%, 0.1); /* Accent Background */
|
||||||
--cs-ghost-hover: hsla(0, 0%, 100%, 0.1); /* Ghost Button Hover */
|
--cs-ghost-hover: hsla(0, 0%, 100%, 0.1); /* Ghost Button Hover */
|
||||||
--cs-ghost-active: hsla(0, 0%, 100%, 0.15); /* Ghost Button Active */
|
--cs-ghost-active: hsla(0, 0%, 100%, 0.15); /* Ghost Button Active */
|
||||||
|
|
||||||
/* Sidebar */
|
/* Sidebar */
|
||||||
--cs-sidebar: var(--cs-black);
|
--cs-sidebar: var(--cs-black);
|
||||||
@ -558,4 +558,3 @@
|
|||||||
--cs-ghost-button-background-hover: var(--cs-ghost-hover);
|
--cs-ghost-button-background-hover: var(--cs-ghost-hover);
|
||||||
--cs-ghost-button-background-active: var(--cs-ghost-active);
|
--cs-ghost-button-background-active: var(--cs-ghost-active);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
@import 'tw-animate-css';
|
@import 'tw-animate-css';
|
||||||
@import './theme.css'; /* 已包含 design-tokens.css 和所有 cs-* 工具类 */
|
@import './theme.css'; /* 已包含 design-tokens.css 和所有 cs-* 工具类 */
|
||||||
|
|
||||||
@custom-variant dark (&:is(.dark *));
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
|
|||||||
@ -239,4 +239,3 @@
|
|||||||
--border-width-cs-md: var(--cs-border-width-md);
|
--border-width-cs-md: var(--cs-border-width-md);
|
||||||
--border-width-cs-lg: var(--cs-border-width-lg);
|
--border-width-cs-lg: var(--cs-border-width-lg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import '@renderer/databases'
|
import '@renderer/databases'
|
||||||
|
|
||||||
|
import { Spinner } from '@heroui/react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useMemo } from 'react'
|
import { lazy, Suspense, useMemo } from 'react'
|
||||||
import { HashRouter, Route, Routes } from 'react-router-dom'
|
import { HashRouter, Route, Routes } from 'react-router-dom'
|
||||||
|
|
||||||
import Sidebar from './components/app/Sidebar'
|
import Sidebar from './components/app/Sidebar'
|
||||||
@ -9,18 +10,25 @@ import { ErrorBoundary } from './components/ErrorBoundary'
|
|||||||
import TabsContainer from './components/Tab/TabContainer'
|
import TabsContainer from './components/Tab/TabContainer'
|
||||||
import NavigationHandler from './handler/NavigationHandler'
|
import NavigationHandler from './handler/NavigationHandler'
|
||||||
import { useNavbarPosition } from './hooks/useNavbar'
|
import { useNavbarPosition } from './hooks/useNavbar'
|
||||||
import CodeToolsPage from './pages/code/CodeToolsPage'
|
|
||||||
import FilesPage from './pages/files/FilesPage'
|
const HomePage = lazy(() => import('./pages/home/HomePage'))
|
||||||
import HomePage from './pages/home/HomePage'
|
const AssistantPresetsPage = lazy(() => import('./pages/store/assistants/presets/AssistantPresetsPage'))
|
||||||
import KnowledgePage from './pages/knowledge/KnowledgePage'
|
const PaintingsRoutePage = lazy(() => import('./pages/paintings/PaintingsRoutePage'))
|
||||||
import LaunchpadPage from './pages/launchpad/LaunchpadPage'
|
const TranslatePage = lazy(() => import('./pages/translate/TranslatePage'))
|
||||||
import MinAppPage from './pages/minapps/MinAppPage'
|
const FilesPage = lazy(() => import('./pages/files/FilesPage'))
|
||||||
import MinAppsPage from './pages/minapps/MinAppsPage'
|
const NotesPage = lazy(() => import('./pages/notes/NotesPage'))
|
||||||
import NotesPage from './pages/notes/NotesPage'
|
const KnowledgePage = lazy(() => import('./pages/knowledge/KnowledgePage'))
|
||||||
import PaintingsRoutePage from './pages/paintings/PaintingsRoutePage'
|
const MinAppPage = lazy(() => import('./pages/minapps/MinAppPage'))
|
||||||
import SettingsPage from './pages/settings/SettingsPage'
|
const MinAppsPage = lazy(() => import('./pages/minapps/MinAppsPage'))
|
||||||
import AssistantPresetsPage from './pages/store/assistants/presets/AssistantPresetsPage'
|
const CodeToolsPage = lazy(() => import('./pages/code/CodeToolsPage'))
|
||||||
import TranslatePage from './pages/translate/TranslatePage'
|
const SettingsPage = lazy(() => import('./pages/settings/SettingsPage'))
|
||||||
|
const LaunchpadPage = lazy(() => import('./pages/launchpad/LaunchpadPage'))
|
||||||
|
|
||||||
|
const RouterFallback: FC = () => (
|
||||||
|
<div className="flex h-full w-full items-center justify-center">
|
||||||
|
<Spinner color="primary" size="lg" label="Loading" />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
const Router: FC = () => {
|
const Router: FC = () => {
|
||||||
const { navbarPosition } = useNavbarPosition()
|
const { navbarPosition } = useNavbarPosition()
|
||||||
@ -28,20 +36,22 @@ const Router: FC = () => {
|
|||||||
const routes = useMemo(() => {
|
const routes = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<Routes>
|
<Suspense fallback={<RouterFallback />}>
|
||||||
<Route path="/" element={<HomePage />} />
|
<Routes>
|
||||||
<Route path="/store" element={<AssistantPresetsPage />} />
|
<Route path="/" element={<HomePage />} />
|
||||||
<Route path="/paintings/*" element={<PaintingsRoutePage />} />
|
<Route path="/store" element={<AssistantPresetsPage />} />
|
||||||
<Route path="/translate" element={<TranslatePage />} />
|
<Route path="/paintings/*" element={<PaintingsRoutePage />} />
|
||||||
<Route path="/files" element={<FilesPage />} />
|
<Route path="/translate" element={<TranslatePage />} />
|
||||||
<Route path="/notes" element={<NotesPage />} />
|
<Route path="/files" element={<FilesPage />} />
|
||||||
<Route path="/knowledge" element={<KnowledgePage />} />
|
<Route path="/notes" element={<NotesPage />} />
|
||||||
<Route path="/apps/:appId" element={<MinAppPage />} />
|
<Route path="/knowledge" element={<KnowledgePage />} />
|
||||||
<Route path="/apps" element={<MinAppsPage />} />
|
<Route path="/apps/:appId" element={<MinAppPage />} />
|
||||||
<Route path="/code" element={<CodeToolsPage />} />
|
<Route path="/apps" element={<MinAppsPage />} />
|
||||||
<Route path="/settings/*" element={<SettingsPage />} />
|
<Route path="/code" element={<CodeToolsPage />} />
|
||||||
<Route path="/launchpad" element={<LaunchpadPage />} />
|
<Route path="/settings/*" element={<SettingsPage />} />
|
||||||
</Routes>
|
<Route path="/launchpad" element={<LaunchpadPage />} />
|
||||||
|
</Routes>
|
||||||
|
</Suspense>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
)
|
)
|
||||||
}, [])
|
}, [])
|
||||||
|
|||||||
@ -20,6 +20,7 @@ export interface EditableNumberProps {
|
|||||||
suffix?: string
|
suffix?: string
|
||||||
prefix?: string
|
prefix?: string
|
||||||
align?: 'start' | 'center' | 'end'
|
align?: 'start' | 'center' | 'end'
|
||||||
|
formatter?: (value: number | null) => string | number
|
||||||
}
|
}
|
||||||
|
|
||||||
const EditableNumber: FC<EditableNumberProps> = ({
|
const EditableNumber: FC<EditableNumberProps> = ({
|
||||||
@ -36,7 +37,8 @@ const EditableNumber: FC<EditableNumberProps> = ({
|
|||||||
style,
|
style,
|
||||||
className,
|
className,
|
||||||
size = 'middle',
|
size = 'middle',
|
||||||
align = 'end'
|
align = 'end',
|
||||||
|
formatter
|
||||||
}) => {
|
}) => {
|
||||||
const [isEditing, setIsEditing] = useState(false)
|
const [isEditing, setIsEditing] = useState(false)
|
||||||
const [inputValue, setInputValue] = useState(value)
|
const [inputValue, setInputValue] = useState(value)
|
||||||
@ -90,7 +92,7 @@ const EditableNumber: FC<EditableNumberProps> = ({
|
|||||||
changeOnBlur={changeOnBlur}
|
changeOnBlur={changeOnBlur}
|
||||||
/>
|
/>
|
||||||
<DisplayText style={style} className={className} $align={align} $isEditing={isEditing}>
|
<DisplayText style={style} className={className} $align={align} $isEditing={isEditing}>
|
||||||
{value ?? placeholder}
|
{formatter ? formatter(value ?? null) : (value ?? placeholder)}
|
||||||
</DisplayText>
|
</DisplayText>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -838,7 +838,7 @@
|
|||||||
"label": "Context",
|
"label": "Context",
|
||||||
"tip": "The number of previous messages to keep in the context."
|
"tip": "The number of previous messages to keep in the context."
|
||||||
},
|
},
|
||||||
"max": "Max",
|
"max": "Unlimited",
|
||||||
"max_tokens": {
|
"max_tokens": {
|
||||||
"confirm": "Set max tokens",
|
"confirm": "Set max tokens",
|
||||||
"confirm_content": "Set the maximum number of tokens the model can generate. Need to consider the context limit of the model, otherwise an error will be reported",
|
"confirm_content": "Set the maximum number of tokens the model can generate. Need to consider the context limit of the model, otherwise an error will be reported",
|
||||||
@ -1051,6 +1051,7 @@
|
|||||||
"copied": "Copied",
|
"copied": "Copied",
|
||||||
"copy": "Copy",
|
"copy": "Copy",
|
||||||
"copy_failed": "Copy failed",
|
"copy_failed": "Copy failed",
|
||||||
|
"current": "Current",
|
||||||
"cut": "Cut",
|
"cut": "Cut",
|
||||||
"default": "Default",
|
"default": "Default",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
|
|||||||
@ -1051,6 +1051,7 @@
|
|||||||
"copied": "已复制",
|
"copied": "已复制",
|
||||||
"copy": "复制",
|
"copy": "复制",
|
||||||
"copy_failed": "复制失败",
|
"copy_failed": "复制失败",
|
||||||
|
"current": "当前",
|
||||||
"cut": "剪切",
|
"cut": "剪切",
|
||||||
"default": "默认",
|
"default": "默认",
|
||||||
"delete": "删除",
|
"delete": "删除",
|
||||||
|
|||||||
@ -838,7 +838,7 @@
|
|||||||
"label": "上下文",
|
"label": "上下文",
|
||||||
"tip": "在上下文中保留的前幾則訊息"
|
"tip": "在上下文中保留的前幾則訊息"
|
||||||
},
|
},
|
||||||
"max": "最大",
|
"max": "不限",
|
||||||
"max_tokens": {
|
"max_tokens": {
|
||||||
"confirm": "設置最大 Token 數",
|
"confirm": "設置最大 Token 數",
|
||||||
"confirm_content": "設置單次交互所用的最大 Token 數,會影響返回結果的長度。要根據模型上下文限制來設定,否則會發生錯誤",
|
"confirm_content": "設置單次交互所用的最大 Token 數,會影響返回結果的長度。要根據模型上下文限制來設定,否則會發生錯誤",
|
||||||
@ -1051,6 +1051,7 @@
|
|||||||
"copied": "已複製",
|
"copied": "已複製",
|
||||||
"copy": "複製",
|
"copy": "複製",
|
||||||
"copy_failed": "複製失敗",
|
"copy_failed": "複製失敗",
|
||||||
|
"current": "当前",
|
||||||
"cut": "剪下",
|
"cut": "剪下",
|
||||||
"default": "預設",
|
"default": "預設",
|
||||||
"delete": "刪除",
|
"delete": "刪除",
|
||||||
|
|||||||
@ -1051,6 +1051,7 @@
|
|||||||
"copied": "Kopiert",
|
"copied": "Kopiert",
|
||||||
"copy": "Kopieren",
|
"copy": "Kopieren",
|
||||||
"copy_failed": "Kopieren fehlgeschlagen",
|
"copy_failed": "Kopieren fehlgeschlagen",
|
||||||
|
"current": "Aktuell",
|
||||||
"cut": "Ausschneiden",
|
"cut": "Ausschneiden",
|
||||||
"default": "Standard",
|
"default": "Standard",
|
||||||
"delete": "Löschen",
|
"delete": "Löschen",
|
||||||
|
|||||||
@ -838,7 +838,7 @@
|
|||||||
"label": "Πλήθος ενδιάμεσων",
|
"label": "Πλήθος ενδιάμεσων",
|
||||||
"tip": "Πλήθος των μηνυμάτων που θα παραμείνουν στα ενδιάμεσα, όσο μεγαλύτερο είναι το αριθμός, τόσο μεγαλύτερο είναι το μήκος του ενδιάμεσου και τόσο περισσότερα tokens χρησιμοποιούνται. Συνομιλία συνήθως συνιστάται μεταξύ 5-10"
|
"tip": "Πλήθος των μηνυμάτων που θα παραμείνουν στα ενδιάμεσα, όσο μεγαλύτερο είναι το αριθμός, τόσο μεγαλύτερο είναι το μήκος του ενδιάμεσου και τόσο περισσότερα tokens χρησιμοποιούνται. Συνομιλία συνήθως συνιστάται μεταξύ 5-10"
|
||||||
},
|
},
|
||||||
"max": "Όχι ορισμένο",
|
"max": "άπειρος",
|
||||||
"max_tokens": {
|
"max_tokens": {
|
||||||
"confirm": "Ενεργοποίηση περιορισμού μήκους μηνύματος",
|
"confirm": "Ενεργοποίηση περιορισμού μήκους μηνύματος",
|
||||||
"confirm_content": "Μετά την ενεργοποίηση του περιορισμού μήκους μηνύματος, ο μέγιστος αριθμός των tokens που χρησιμοποιούνται κάθε φορά, θα επηρεάζει το μήκος της απάντησης. Πρέπει να το ρυθμίζετε βάσει των περιορισμών του πλαισίου του μοντέλου, διαφορετικά θα σφάλλεται.",
|
"confirm_content": "Μετά την ενεργοποίηση του περιορισμού μήκους μηνύματος, ο μέγιστος αριθμός των tokens που χρησιμοποιούνται κάθε φορά, θα επηρεάζει το μήκος της απάντησης. Πρέπει να το ρυθμίζετε βάσει των περιορισμών του πλαισίου του μοντέλου, διαφορετικά θα σφάλλεται.",
|
||||||
@ -1051,6 +1051,7 @@
|
|||||||
"copied": "Αντιγράφηκε",
|
"copied": "Αντιγράφηκε",
|
||||||
"copy": "Αντιγραφή",
|
"copy": "Αντιγραφή",
|
||||||
"copy_failed": "Αποτυχία αντιγραφής",
|
"copy_failed": "Αποτυχία αντιγραφής",
|
||||||
|
"current": "Τρέχων",
|
||||||
"cut": "Κοπή",
|
"cut": "Κοπή",
|
||||||
"default": "Προεπιλογή",
|
"default": "Προεπιλογή",
|
||||||
"delete": "Διαγραφή",
|
"delete": "Διαγραφή",
|
||||||
|
|||||||
@ -1051,6 +1051,7 @@
|
|||||||
"copied": "Copiado",
|
"copied": "Copiado",
|
||||||
"copy": "Copiar",
|
"copy": "Copiar",
|
||||||
"copy_failed": "Error al copiar",
|
"copy_failed": "Error al copiar",
|
||||||
|
"current": "Actual",
|
||||||
"cut": "Cortar",
|
"cut": "Cortar",
|
||||||
"default": "Predeterminado",
|
"default": "Predeterminado",
|
||||||
"delete": "Eliminar",
|
"delete": "Eliminar",
|
||||||
|
|||||||
@ -1051,6 +1051,7 @@
|
|||||||
"copied": "Copié",
|
"copied": "Copié",
|
||||||
"copy": "Copier",
|
"copy": "Copier",
|
||||||
"copy_failed": "Échec de la copie",
|
"copy_failed": "Échec de la copie",
|
||||||
|
"current": "Actuel",
|
||||||
"cut": "Couper",
|
"cut": "Couper",
|
||||||
"default": "Défaut",
|
"default": "Défaut",
|
||||||
"delete": "Supprimer",
|
"delete": "Supprimer",
|
||||||
|
|||||||
@ -838,7 +838,7 @@
|
|||||||
"label": "コンテキスト",
|
"label": "コンテキスト",
|
||||||
"tip": "コンテキストに保持する以前のメッセージの数"
|
"tip": "コンテキストに保持する以前のメッセージの数"
|
||||||
},
|
},
|
||||||
"max": "最大",
|
"max": "制限なし",
|
||||||
"max_tokens": {
|
"max_tokens": {
|
||||||
"confirm": "最大トークン数",
|
"confirm": "最大トークン数",
|
||||||
"confirm_content": "最大トークン数を設定すると、モデルが生成できる最大トークン数が制限されます。これにより、返される結果の長さに影響が出る可能性があります。モデルのコンテキスト制限に基づいて設定する必要があります。そうしないとエラーが発生します",
|
"confirm_content": "最大トークン数を設定すると、モデルが生成できる最大トークン数が制限されます。これにより、返される結果の長さに影響が出る可能性があります。モデルのコンテキスト制限に基づいて設定する必要があります。そうしないとエラーが発生します",
|
||||||
@ -1051,6 +1051,7 @@
|
|||||||
"copied": "コピーされました",
|
"copied": "コピーされました",
|
||||||
"copy": "コピー",
|
"copy": "コピー",
|
||||||
"copy_failed": "コピーに失敗しました",
|
"copy_failed": "コピーに失敗しました",
|
||||||
|
"current": "現在",
|
||||||
"cut": "切り取り",
|
"cut": "切り取り",
|
||||||
"default": "デフォルト",
|
"default": "デフォルト",
|
||||||
"delete": "削除",
|
"delete": "削除",
|
||||||
|
|||||||
@ -1051,6 +1051,7 @@
|
|||||||
"copied": "Copiado",
|
"copied": "Copiado",
|
||||||
"copy": "Copiar",
|
"copy": "Copiar",
|
||||||
"copy_failed": "Falha ao copiar",
|
"copy_failed": "Falha ao copiar",
|
||||||
|
"current": "Atual",
|
||||||
"cut": "Cortar",
|
"cut": "Cortar",
|
||||||
"default": "Padrão",
|
"default": "Padrão",
|
||||||
"delete": "Excluir",
|
"delete": "Excluir",
|
||||||
|
|||||||
@ -838,7 +838,7 @@
|
|||||||
"label": "Контекст",
|
"label": "Контекст",
|
||||||
"tip": "Количество предыдущих сообщений, которые нужно сохранить в контексте."
|
"tip": "Количество предыдущих сообщений, которые нужно сохранить в контексте."
|
||||||
},
|
},
|
||||||
"max": "Максимум",
|
"max": "без ограничений",
|
||||||
"max_tokens": {
|
"max_tokens": {
|
||||||
"confirm": "Максимальное количество токенов",
|
"confirm": "Максимальное количество токенов",
|
||||||
"confirm_content": "Установить максимальное количество токенов, влияет на длину результата. Нужно учитывать контекст модели, иначе будет ошибка",
|
"confirm_content": "Установить максимальное количество токенов, влияет на длину результата. Нужно учитывать контекст модели, иначе будет ошибка",
|
||||||
@ -1051,6 +1051,7 @@
|
|||||||
"copied": "Скопировано",
|
"copied": "Скопировано",
|
||||||
"copy": "Копировать",
|
"copy": "Копировать",
|
||||||
"copy_failed": "Не удалось скопировать",
|
"copy_failed": "Не удалось скопировать",
|
||||||
|
"current": "Текущий",
|
||||||
"cut": "Вырезать",
|
"cut": "Вырезать",
|
||||||
"default": "По умолчанию",
|
"default": "По умолчанию",
|
||||||
"delete": "Удалить",
|
"delete": "Удалить",
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import type { GlobToolInput as GlobToolInputType, GlobToolOutput as GlobToolOutp
|
|||||||
|
|
||||||
export function GlobTool({ input, output }: { input: GlobToolInputType; output?: GlobToolOutputType }) {
|
export function GlobTool({ input, output }: { input: GlobToolInputType; output?: GlobToolOutputType }) {
|
||||||
// 如果有输出,计算文件数量
|
// 如果有输出,计算文件数量
|
||||||
const fileCount = output ? output.split('\n').filter((line) => line.trim()).length : 0
|
const lineCount = output ? output.split('\n').filter((line) => line.trim()).length : 0
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AccordionItem
|
<AccordionItem
|
||||||
@ -17,7 +17,7 @@ export function GlobTool({ input, output }: { input: GlobToolInputType; output?:
|
|||||||
icon={<FolderSearch className="h-4 w-4" />}
|
icon={<FolderSearch className="h-4 w-4" />}
|
||||||
label="Glob"
|
label="Glob"
|
||||||
params={input.pattern}
|
params={input.pattern}
|
||||||
stats={output ? `${fileCount} found` : undefined}
|
stats={output ? `${lineCount} of output` : undefined}
|
||||||
/>
|
/>
|
||||||
}>
|
}>
|
||||||
<div>{output}</div>
|
<div>{output}</div>
|
||||||
|
|||||||
@ -8,20 +8,31 @@ import type { ReadToolInput as ReadToolInputType, ReadToolOutput as ReadToolOutp
|
|||||||
import { AgentToolsType } from './types'
|
import { AgentToolsType } from './types'
|
||||||
|
|
||||||
export function ReadTool({ input, output }: { input: ReadToolInputType; output?: ReadToolOutputType }) {
|
export function ReadTool({ input, output }: { input: ReadToolInputType; output?: ReadToolOutputType }) {
|
||||||
|
// 移除 system-reminder 标签及其内容的辅助函数
|
||||||
|
const removeSystemReminderTags = (text: string): string => {
|
||||||
|
// 使用正则表达式匹配 <system-reminder> 标签及其内容,包括换行符
|
||||||
|
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/gi, '')
|
||||||
|
}
|
||||||
|
|
||||||
// 将 output 统一转换为字符串
|
// 将 output 统一转换为字符串
|
||||||
const outputString = useMemo(() => {
|
const outputString = useMemo(() => {
|
||||||
if (!output) return null
|
if (!output) return null
|
||||||
|
|
||||||
|
let processedOutput: string
|
||||||
|
|
||||||
// 如果是 TextOutput[] 类型,提取所有 text 内容
|
// 如果是 TextOutput[] 类型,提取所有 text 内容
|
||||||
if (Array.isArray(output)) {
|
if (Array.isArray(output)) {
|
||||||
return output
|
processedOutput = output
|
||||||
.filter((item): item is TextOutput => item.type === 'text')
|
.filter((item): item is TextOutput => item.type === 'text')
|
||||||
.map((item) => item.text)
|
.map((item) => removeSystemReminderTags(item.text))
|
||||||
.join('')
|
.join('')
|
||||||
|
} else {
|
||||||
|
// 如果是字符串,直接使用
|
||||||
|
processedOutput = output
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是字符串,直接返回
|
// 移除 system-reminder 标签及其内容
|
||||||
return output
|
return removeSystemReminderTags(processedOutput)
|
||||||
}, [output])
|
}, [output])
|
||||||
|
|
||||||
// 如果有输出,计算统计信息
|
// 如果有输出,计算统计信息
|
||||||
|
|||||||
@ -2,11 +2,7 @@ import { AccordionItem, Card, CardBody, Chip } from '@heroui/react'
|
|||||||
import { CheckCircle, Circle, Clock, ListTodo } from 'lucide-react'
|
import { CheckCircle, Circle, Clock, ListTodo } from 'lucide-react'
|
||||||
|
|
||||||
import { ToolTitle } from './GenericTools'
|
import { ToolTitle } from './GenericTools'
|
||||||
import type {
|
import type { TodoItem, TodoWriteToolInput as TodoWriteToolInputType } from './types'
|
||||||
TodoItem,
|
|
||||||
TodoWriteToolInput as TodoWriteToolInputType,
|
|
||||||
TodoWriteToolOutput as TodoWriteToolOutputType
|
|
||||||
} from './types'
|
|
||||||
import { AgentToolsType } from './types'
|
import { AgentToolsType } from './types'
|
||||||
|
|
||||||
const getStatusConfig = (status: TodoItem['status']) => {
|
const getStatusConfig = (status: TodoItem['status']) => {
|
||||||
@ -34,7 +30,7 @@ const getStatusConfig = (status: TodoItem['status']) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TodoWriteTool({ input, output }: { input: TodoWriteToolInputType; output?: TodoWriteToolOutputType }) {
|
export function TodoWriteTool({ input }: { input: TodoWriteToolInputType }) {
|
||||||
const doneCount = input.todos.filter((todo) => todo.status === 'completed').length
|
const doneCount = input.todos.filter((todo) => todo.status === 'completed').length
|
||||||
return (
|
return (
|
||||||
<AccordionItem
|
<AccordionItem
|
||||||
@ -72,7 +68,6 @@ export function TodoWriteTool({ input, output }: { input: TodoWriteToolInputType
|
|||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
{output}
|
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,12 @@ import { Button, DescriptionSwitch, HelpTooltip, RowFlex, Selector, type Selecto
|
|||||||
import { useMultiplePreferences, usePreference } from '@data/hooks/usePreference'
|
import { useMultiplePreferences, usePreference } from '@data/hooks/usePreference'
|
||||||
import EditableNumber from '@renderer/components/EditableNumber'
|
import EditableNumber from '@renderer/components/EditableNumber'
|
||||||
import Scrollbar from '@renderer/components/Scrollbar'
|
import Scrollbar from '@renderer/components/Scrollbar'
|
||||||
import { DEFAULT_CONTEXTCOUNT, DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
|
import {
|
||||||
|
DEFAULT_CONTEXTCOUNT,
|
||||||
|
DEFAULT_MAX_TOKENS,
|
||||||
|
DEFAULT_TEMPERATURE,
|
||||||
|
MAX_CONTEXT_COUNT
|
||||||
|
} from '@renderer/config/constant'
|
||||||
import { isOpenAIModel } from '@renderer/config/models'
|
import { isOpenAIModel } from '@renderer/config/models'
|
||||||
import { UNKNOWN } from '@renderer/config/translate'
|
import { UNKNOWN } from '@renderer/config/translate'
|
||||||
import { useCodeStyle } from '@renderer/context/CodeStyleProvider'
|
import { useCodeStyle } from '@renderer/context/CodeStyleProvider'
|
||||||
@ -214,9 +219,6 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
setStreamOutput(assistant?.settings?.streamOutput ?? true)
|
setStreamOutput(assistant?.settings?.streamOutput ?? true)
|
||||||
}, [assistant])
|
}, [assistant])
|
||||||
|
|
||||||
const assistantContextCount = assistant?.settings?.contextCount || 20
|
|
||||||
const maxContextCount = assistantContextCount > 20 ? assistantContextCount : 20
|
|
||||||
|
|
||||||
const model = assistant.model || getDefaultModel()
|
const model = assistant.model || getDefaultModel()
|
||||||
|
|
||||||
const isOpenAI = isOpenAIModel(model)
|
const isOpenAI = isOpenAIModel(model)
|
||||||
@ -269,21 +271,44 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
) : (
|
) : (
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
)}
|
)}
|
||||||
<Row align="middle">
|
<Row align="middle" gutter={10} justify="space-between">
|
||||||
<SettingRowTitleSmall>
|
<SettingRowTitleSmall>
|
||||||
{t('chat.settings.context_count.label')}
|
{t('chat.settings.context_count.label')}
|
||||||
<HelpTooltip title={t('chat.settings.context_count.tip')} />
|
<HelpTooltip title={t('chat.settings.context_count.tip')} />
|
||||||
</SettingRowTitleSmall>
|
</SettingRowTitleSmall>
|
||||||
|
<Col span={8}>
|
||||||
|
<EditableNumber
|
||||||
|
min={0}
|
||||||
|
max={20}
|
||||||
|
step={1}
|
||||||
|
value={contextCount}
|
||||||
|
changeOnBlur
|
||||||
|
onChange={(value) => {
|
||||||
|
if (value !== null && value >= 0 && value <= 20) {
|
||||||
|
setContextCount(value)
|
||||||
|
onContextCountChange(value)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
formatter={(value) => (value === MAX_CONTEXT_COUNT ? t('chat.settings.max') : (value ?? ''))}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row align="middle" gutter={10}>
|
<Row align="middle" gutter={10}>
|
||||||
<Col span={23}>
|
<Col span={24}>
|
||||||
<Slider
|
<Slider
|
||||||
min={0}
|
min={0}
|
||||||
max={maxContextCount}
|
max={20}
|
||||||
onChange={setContextCount}
|
onChange={setContextCount}
|
||||||
onChangeComplete={onContextCountChange}
|
onChangeComplete={onContextCountChange}
|
||||||
value={typeof contextCount === 'number' ? contextCount : 0}
|
value={Math.min(contextCount, 20)}
|
||||||
|
tooltip={{ open: false }}
|
||||||
step={1}
|
step={1}
|
||||||
|
marks={{
|
||||||
|
0: '0',
|
||||||
|
10: '10',
|
||||||
|
20: '20'
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
@ -360,6 +360,7 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
|
|||||||
setTimeoutTimer('contextCount_onChange', () => updateAssistantSettings({ contextCount: value }), 500)
|
setTimeoutTimer('contextCount_onChange', () => updateAssistantSettings({ contextCount: value }), 500)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
formatter={(value) => (value === MAX_CONTEXT_COUNT ? t('chat.settings.max') : (value ?? ''))}
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -374,7 +375,7 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
|
|||||||
value={typeof contextCount === 'number' ? contextCount : 0}
|
value={typeof contextCount === 'number' ? contextCount : 0}
|
||||||
marks={{ 0: '0', 25: '25', 50: '50', 75: '75', 100: t('chat.settings.max') }}
|
marks={{ 0: '0', 25: '25', 50: '50', 75: '75', 100: t('chat.settings.max') }}
|
||||||
step={1}
|
step={1}
|
||||||
tooltip={{ formatter: formatSliderTooltip }}
|
tooltip={{ formatter: formatSliderTooltip, open: false }}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user