update: 更新设置页面测试功能,新增temperature和max_tokens参数

This commit is contained in:
xiamuceer-j
2026-01-14 14:30:06 +08:00
parent 46debab624
commit e412e809eb
3 changed files with 143 additions and 114 deletions
+126 -106
View File
@@ -1,9 +1,9 @@
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Card, Form, Input, Button, Select, Slider, InputNumber, message, Space, Typography, Spin, Modal, Alert, Grid, Tabs, List, Tag, Popconfirm, Empty, Row, Col } from 'antd';
import { SettingOutlined, SaveOutlined, DeleteOutlined, ReloadOutlined, ArrowLeftOutlined, InfoCircleOutlined, CheckCircleOutlined, CloseCircleOutlined, ThunderboltOutlined, PlusOutlined, EditOutlined, CopyOutlined, WarningOutlined } from '@ant-design/icons';
import { SaveOutlined, DeleteOutlined, ReloadOutlined, InfoCircleOutlined, CheckCircleOutlined, CloseCircleOutlined, ThunderboltOutlined, PlusOutlined, EditOutlined, CopyOutlined, WarningOutlined } from '@ant-design/icons';
import { settingsApi, mcpPluginApi } from '../services/api';
import type { SettingsUpdate, APIKeyPreset, PresetCreateRequest, APIKeyPresetConfig } from '../types';
import { eventBus, EventNames } from '../store/eventBus';
const { Title, Text } = Typography;
const { Option } = Select;
@@ -11,7 +11,6 @@ const { useBreakpoint } = Grid;
const { TextArea } = Input;
export default function SettingsPage() {
const navigate = useNavigate();
const screens = useBreakpoint();
const isMobile = !screens.md; // md断点是768px
const [form] = Form.useForm();
@@ -50,6 +49,7 @@ export default function SettingsPage() {
if (activeTab === 'presets') {
loadPresets();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
@@ -72,6 +72,7 @@ export default function SettingsPage() {
setIsDefaultSettings(false);
setHasSettings(true);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
// 如果404表示还没有设置,使用默认值
if (error?.response?.status === 404) {
@@ -167,7 +168,7 @@ export default function SettingsPage() {
okText: '前往 MCP 页面',
cancelText: '稍后处理',
onOk: () => {
navigate('/mcp-plugins');
eventBus.emit(EventNames.SWITCH_TO_MCP_VIEW);
},
});
}
@@ -175,7 +176,7 @@ export default function SettingsPage() {
console.error('Failed to disable MCP plugins:', err);
}
}
} catch (error) {
} catch {
message.error('保存设置失败');
} finally {
setLoading(false);
@@ -218,7 +219,7 @@ export default function SettingsPage() {
message.success('设置已删除');
setHasSettings(false);
form.resetFields();
} catch (error) {
} catch {
message.error('删除设置失败');
} finally {
setLoading(false);
@@ -268,6 +269,7 @@ export default function SettingsPage() {
if (!silent) {
message.success(`成功获取 ${response.count || response.models.length} 个可用模型`);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
const errorMsg = error?.response?.data?.detail || '获取模型列表失败';
if (!silent) {
@@ -292,6 +294,8 @@ export default function SettingsPage() {
const apiBaseUrl = form.getFieldValue('api_base_url');
const provider = form.getFieldValue('api_provider');
const modelName = form.getFieldValue('llm_model');
const temperature = form.getFieldValue('temperature');
const maxTokens = form.getFieldValue('max_tokens');
if (!apiKey || !apiBaseUrl || !provider || !modelName) {
message.warning('请先填写完整的配置信息');
@@ -306,7 +310,9 @@ export default function SettingsPage() {
api_key: apiKey,
api_base_url: apiBaseUrl,
provider: provider,
llm_model: modelName
llm_model: modelName,
temperature: temperature,
max_tokens: maxTokens
});
setTestResult(result);
@@ -317,6 +323,7 @@ export default function SettingsPage() {
} else {
message.error('API 测试失败,请查看详细信息');
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
const errorMsg = error?.response?.data?.detail || '测试请求失败';
message.error(errorMsg);
@@ -416,6 +423,7 @@ export default function SettingsPage() {
await settingsApi.deletePreset(presetId);
message.success('预设已删除');
loadPresets();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
message.error(error.response?.data?.detail || '删除失败');
console.error(error);
@@ -503,7 +511,7 @@ export default function SettingsPage() {
okText: '前往 MCP 页面',
cancelText: '稍后处理',
onOk: () => {
navigate('/mcp-plugins');
eventBus.emit(EventNames.SWITCH_TO_MCP_VIEW);
},
});
}
@@ -784,11 +792,12 @@ export default function SettingsPage() {
<>
{contextHolder}
<div style={{
minHeight: '100vh',
minHeight: '90vh',
background: 'linear-gradient(180deg, var(--color-bg-base) 0%, #EEF2F3 100%)',
padding: isMobile ? '20px 16px' : '40px 24px',
padding: isMobile ? '20px 16px' : '24px 24px',
display: 'flex',
flexDirection: 'column',
marginBottom: '55px',
}}>
<div style={{
maxWidth: 1400,
@@ -820,7 +829,6 @@ export default function SettingsPage() {
<Col xs={24} sm={12}>
<Space direction="vertical" size={4}>
<Title level={isMobile ? 3 : 2} style={{ margin: 0, color: '#fff', textShadow: '0 2px 4px rgba(0,0,0,0.1)' }}>
<SettingOutlined style={{ color: 'rgba(255,255,255,0.9)', marginRight: 8 }} />
AI API
</Title>
<Text style={{ fontSize: isMobile ? 12 : 14, color: 'rgba(255,255,255,0.85)', marginLeft: isMobile ? 40 : 48 }}>
@@ -829,31 +837,7 @@ export default function SettingsPage() {
</Space>
</Col>
<Col xs={24} sm={12}>
<Space size={12} style={{ display: 'flex', justifyContent: isMobile ? 'flex-start' : 'flex-end', width: '100%' }}>
<Button
icon={<ArrowLeftOutlined />}
onClick={() => navigate('/')}
style={{
borderRadius: 12,
background: 'rgba(255, 255, 255, 0.15)',
border: '1px solid rgba(255, 255, 255, 0.3)',
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
color: '#fff',
backdropFilter: 'blur(10px)',
transition: 'all 0.3s ease'
}}
onMouseEnter={(e) => {
e.currentTarget.style.background = 'rgba(255, 255, 255, 0.25)';
e.currentTarget.style.transform = 'translateY(-1px)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.background = 'rgba(255, 255, 255, 0.15)';
e.currentTarget.style.transform = 'none';
}}
>
</Button>
</Space>
{/* 按钮区域预留 */}
</Col>
</Row>
</Card>
@@ -1399,99 +1383,135 @@ export default function SettingsPage() {
open={isPresetModalVisible}
onOk={handlePresetSave}
onCancel={handlePresetCancel}
width={isMobile ? '90%' : 600}
width={isMobile ? '95%' : 640}
centered
okText="保存"
cancelText="取消"
styles={{
body: {
padding: isMobile ? '16px' : '20px 24px'
}
}}
>
<Form
form={presetForm}
layout="vertical"
size={isMobile ? 'middle' : 'large'}
>
<Form.Item
name="name"
label="预设名称"
rules={[
{ required: true, message: '请输入预设名称' },
{ max: 50, message: '名称不能超过50个字符' },
]}
>
<Input placeholder="例如:工作账号-GPT4" />
</Form.Item>
{/* 基本信息 */}
<Row gutter={16}>
<Col xs={24} sm={16}>
<Form.Item
name="name"
label="预设名称"
rules={[
{ required: true, message: '请输入预设名称' },
{ max: 50, message: '名称不能超过50个字符' },
]}
style={{ marginBottom: 16 }}
>
<Input placeholder="例如:工作账号-GPT4" />
</Form.Item>
</Col>
<Col xs={24} sm={8}>
<Form.Item
name="api_provider"
label="API 提供商"
rules={[{ required: true, message: '请选择' }]}
style={{ marginBottom: 16 }}
>
<Select placeholder="选择提供商">
<Select.Option value="openai">OpenAI</Select.Option>
<Select.Option value="gemini">Google Gemini</Select.Option>
</Select>
</Form.Item>
</Col>
</Row>
<Form.Item
name="description"
label="预设描述"
rules={[{ max: 200, message: '描述不能超过200个字符' }]}
style={{ marginBottom: 16 }}
>
<TextArea rows={2} placeholder="例如:用于日常写作任务(可选)" />
<Input placeholder="例如:用于日常写作任务(可选)" />
</Form.Item>
<Form.Item
name="api_provider"
label="API 提供商"
rules={[{ required: true, message: '请选择API提供商' }]}
>
<Select>
<Select.Option value="openai">OpenAI</Select.Option>
{/* <Select.Option value="anthropic">Anthropic (Claude)</Select.Option> */}
<Select.Option value="gemini">Google Gemini</Select.Option>
</Select>
</Form.Item>
{/* API 配置 */}
<Row gutter={16}>
<Col xs={24} sm={12}>
<Form.Item
name="api_key"
label="API Key"
rules={[{ required: true, message: '请输入API Key' }]}
style={{ marginBottom: 16 }}
>
<Input.Password placeholder="sk-..." />
</Form.Item>
</Col>
<Col xs={24} sm={12}>
<Form.Item
name="api_base_url"
label="API Base URL"
style={{ marginBottom: 16 }}
>
<Input placeholder="https://api.openai.com/v1" />
</Form.Item>
</Col>
</Row>
<Form.Item
name="api_key"
label="API Key"
rules={[{ required: true, message: '请输入API Key' }]}
>
<Input.Password placeholder="sk-..." />
</Form.Item>
<Form.Item name="api_base_url" label="API Base URL">
<Input placeholder="https://api.openai.com/v1(可选)" />
</Form.Item>
<Form.Item
name="llm_model"
label="模型名称"
rules={[{ required: true, message: '请输入模型名称' }]}
>
<Input placeholder="例如:gpt-4, claude-3-opus-20240229" />
</Form.Item>
<Form.Item
name="temperature"
label="温度参数"
rules={[{ required: true, message: '请输入温度参数' }]}
>
<InputNumber
min={0}
max={2}
step={0.1}
style={{ width: '100%' }}
placeholder="0.7"
/>
</Form.Item>
<Form.Item
name="max_tokens"
label="最大 Tokens"
rules={[{ required: true, message: '请输入最大tokens' }]}
>
<InputNumber
min={1}
max={100000}
style={{ width: '100%' }}
placeholder="2000"
/>
</Form.Item>
{/* 模型配置 */}
<Row gutter={16}>
<Col xs={24} sm={12}>
<Form.Item
name="llm_model"
label="模型名称"
rules={[{ required: true, message: '请输入模型名称' }]}
style={{ marginBottom: 16 }}
>
<Input placeholder="例如:gpt-4" />
</Form.Item>
</Col>
<Col xs={12} sm={6}>
<Form.Item
name="temperature"
label="温度"
rules={[{ required: true, message: '必填' }]}
style={{ marginBottom: 16 }}
>
<InputNumber
min={0}
max={2}
step={0.1}
style={{ width: '100%' }}
placeholder="0.7"
/>
</Form.Item>
</Col>
<Col xs={12} sm={6}>
<Form.Item
name="max_tokens"
label="最大Tokens"
rules={[{ required: true, message: '必填' }]}
style={{ marginBottom: 16 }}
>
<InputNumber
min={1}
max={100000}
style={{ width: '100%' }}
placeholder="2000"
/>
</Form.Item>
</Col>
</Row>
<Form.Item
name="system_prompt"
label="系统提示词"
style={{ marginBottom: 0 }}
>
<TextArea
rows={3}
rows={isMobile ? 2 : 3}
placeholder="例如:你是一个专业的小说创作助手...(可选)"
maxLength={10000}
showCount