Some checks failed
Publish Docker image (Multi Registries, native amd64+arm64) / Build & push (amd64) [native] (push) Has been cancelled
Publish Docker image (Multi Registries, native amd64+arm64) / Build & push (arm64) [native] (push) Has been cancelled
Publish Docker image (Multi Registries, native amd64+arm64) / Create multi-arch manifests (Docker Hub) (push) Has been cancelled
* feat: 引入通用 HTTP BodyStorage/DiskCache 缓存配置与管理 - 新增 common/body_storage.go 提供 HTTP 请求体存储抽象和文件缓存能力 - 增加 common/disk_cache_config.go 支持全局磁盘缓存配置 - main.go 挂载缓存初始化流程 - 新增和补充 controller/performance.go (及 unix/windows) 用于缓存性能监控接口 - middleware/body_cleanup.go 自动清理缓存文件 - router 挂载相关接口 - 前端 settings 页面新增性能监控设置 PerformanceSetting - 优化缓存开关状态和模块热插拔能力 - 其他相关文件同步适配缓存扩展 * fix: 修复 BodyStorage 并发安全和错误处理问题 - 修复 diskStorage.Close() 竞态条件,先获取锁再执行 CAS - 为 memoryStorage 添加互斥锁和 closed 状态检查 - 修复 CreateBodyStorageFromReader 在磁盘存储失败时的回退逻辑 - 添加缓存命中统计调用 (IncrementDiskCacheHits/IncrementMemoryCacheHits) - 修复 gin.go 中 Seek 错误被忽略的问题 - 在 api-router 添加 BodyStorageCleanup 中间件 - 修复前端 formatBytes 对异常值的处理 Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
218 lines
6.3 KiB
JavaScript
218 lines
6.3 KiB
JavaScript
/*
|
|
Copyright (C) 2025 QuantumNous
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as
|
|
published by the Free Software Foundation, either version 3 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
For commercial licensing, please contact support@quantumnous.com
|
|
*/
|
|
|
|
import React, { useEffect, useState } from 'react';
|
|
import { Layout, TabPane, Tabs } from '@douyinfe/semi-ui';
|
|
import { useNavigate, useLocation } from 'react-router-dom';
|
|
import { useTranslation } from 'react-i18next';
|
|
import {
|
|
Settings,
|
|
Calculator,
|
|
Gauge,
|
|
Shapes,
|
|
Cog,
|
|
MoreHorizontal,
|
|
LayoutDashboard,
|
|
MessageSquare,
|
|
Palette,
|
|
CreditCard,
|
|
Server,
|
|
Activity,
|
|
} from 'lucide-react';
|
|
|
|
import SystemSetting from '../../components/settings/SystemSetting';
|
|
import { isRoot } from '../../helpers';
|
|
import OtherSetting from '../../components/settings/OtherSetting';
|
|
import OperationSetting from '../../components/settings/OperationSetting';
|
|
import RateLimitSetting from '../../components/settings/RateLimitSetting';
|
|
import ModelSetting from '../../components/settings/ModelSetting';
|
|
import DashboardSetting from '../../components/settings/DashboardSetting';
|
|
import RatioSetting from '../../components/settings/RatioSetting';
|
|
import ChatsSetting from '../../components/settings/ChatsSetting';
|
|
import DrawingSetting from '../../components/settings/DrawingSetting';
|
|
import PaymentSetting from '../../components/settings/PaymentSetting';
|
|
import ModelDeploymentSetting from '../../components/settings/ModelDeploymentSetting';
|
|
import PerformanceSetting from '../../components/settings/PerformanceSetting';
|
|
|
|
const Setting = () => {
|
|
const { t } = useTranslation();
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
const [tabActiveKey, setTabActiveKey] = useState('1');
|
|
let panes = [];
|
|
|
|
if (isRoot()) {
|
|
panes.push({
|
|
tab: (
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
|
<Settings size={18} />
|
|
{t('运营设置')}
|
|
</span>
|
|
),
|
|
content: <OperationSetting />,
|
|
itemKey: 'operation',
|
|
});
|
|
panes.push({
|
|
tab: (
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
|
<LayoutDashboard size={18} />
|
|
{t('仪表盘设置')}
|
|
</span>
|
|
),
|
|
content: <DashboardSetting />,
|
|
itemKey: 'dashboard',
|
|
});
|
|
panes.push({
|
|
tab: (
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
|
<MessageSquare size={18} />
|
|
{t('聊天设置')}
|
|
</span>
|
|
),
|
|
content: <ChatsSetting />,
|
|
itemKey: 'chats',
|
|
});
|
|
panes.push({
|
|
tab: (
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
|
<Palette size={18} />
|
|
{t('绘图设置')}
|
|
</span>
|
|
),
|
|
content: <DrawingSetting />,
|
|
itemKey: 'drawing',
|
|
});
|
|
panes.push({
|
|
tab: (
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
|
<CreditCard size={18} />
|
|
{t('支付设置')}
|
|
</span>
|
|
),
|
|
content: <PaymentSetting />,
|
|
itemKey: 'payment',
|
|
});
|
|
panes.push({
|
|
tab: (
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
|
<Calculator size={18} />
|
|
{t('分组与模型定价设置')}
|
|
</span>
|
|
),
|
|
content: <RatioSetting />,
|
|
itemKey: 'ratio',
|
|
});
|
|
panes.push({
|
|
tab: (
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
|
<Gauge size={18} />
|
|
{t('速率限制设置')}
|
|
</span>
|
|
),
|
|
content: <RateLimitSetting />,
|
|
itemKey: 'ratelimit',
|
|
});
|
|
panes.push({
|
|
tab: (
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
|
<Shapes size={18} />
|
|
{t('模型相关设置')}
|
|
</span>
|
|
),
|
|
content: <ModelSetting />,
|
|
itemKey: 'models',
|
|
});
|
|
panes.push({
|
|
tab: (
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
|
<Server size={18} />
|
|
{t('模型部署设置')}
|
|
</span>
|
|
),
|
|
content: <ModelDeploymentSetting />,
|
|
itemKey: 'model-deployment',
|
|
});
|
|
panes.push({
|
|
tab: (
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
|
<Activity size={18} />
|
|
{t('性能设置')}
|
|
</span>
|
|
),
|
|
content: <PerformanceSetting />,
|
|
itemKey: 'performance',
|
|
});
|
|
panes.push({
|
|
tab: (
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
|
<Cog size={18} />
|
|
{t('系统设置')}
|
|
</span>
|
|
),
|
|
content: <SystemSetting />,
|
|
itemKey: 'system',
|
|
});
|
|
panes.push({
|
|
tab: (
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
|
<MoreHorizontal size={18} />
|
|
{t('其他设置')}
|
|
</span>
|
|
),
|
|
content: <OtherSetting />,
|
|
itemKey: 'other',
|
|
});
|
|
}
|
|
const onChangeTab = (key) => {
|
|
setTabActiveKey(key);
|
|
navigate(`?tab=${key}`);
|
|
};
|
|
useEffect(() => {
|
|
const searchParams = new URLSearchParams(window.location.search);
|
|
const tab = searchParams.get('tab');
|
|
if (tab) {
|
|
setTabActiveKey(tab);
|
|
} else {
|
|
onChangeTab('operation');
|
|
}
|
|
}, [location.search]);
|
|
return (
|
|
<div className='mt-[60px] px-2'>
|
|
<Layout>
|
|
<Layout.Content>
|
|
<Tabs
|
|
type='card'
|
|
collapsible
|
|
activeKey={tabActiveKey}
|
|
onChange={(key) => onChangeTab(key)}
|
|
>
|
|
{panes.map((pane) => (
|
|
<TabPane itemKey={pane.itemKey} tab={pane.tab} key={pane.itemKey}>
|
|
{tabActiveKey === pane.itemKey && pane.content}
|
|
</TabPane>
|
|
))}
|
|
</Tabs>
|
|
</Layout.Content>
|
|
</Layout>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Setting;
|