update: 更新设置页面测试功能,新增temperature和max_tokens参数
This commit is contained in:
@@ -349,6 +349,8 @@ class ApiTestRequest(BaseModel):
|
||||
api_base_url: str
|
||||
provider: str
|
||||
llm_model: str
|
||||
temperature: Optional[float] = None
|
||||
max_tokens: Optional[int] = None
|
||||
|
||||
|
||||
@router.post("/check-function-calling")
|
||||
@@ -578,7 +580,7 @@ async def test_api_connection(data: ApiTestRequest):
|
||||
测试 API 连接和配置是否正确
|
||||
|
||||
Args:
|
||||
data: 包含 API 配置的请求数据
|
||||
data: 包含 API 配置的请求数据(包括 temperature 和 max_tokens)
|
||||
|
||||
Returns:
|
||||
测试结果包含状态、响应时间和详细信息
|
||||
@@ -587,19 +589,22 @@ async def test_api_connection(data: ApiTestRequest):
|
||||
api_base_url = data.api_base_url
|
||||
provider = data.provider
|
||||
llm_model = data.llm_model
|
||||
# 使用前端传递的参数,如果未传递则使用默认值
|
||||
temperature = data.temperature if data.temperature is not None else 0.7
|
||||
max_tokens = data.max_tokens if data.max_tokens is not None else 2000
|
||||
import time
|
||||
|
||||
try:
|
||||
start_time = time.time()
|
||||
|
||||
# 创建临时 AI 服务实例
|
||||
# 创建临时 AI 服务实例,使用前端传递的参数
|
||||
test_service = AIService(
|
||||
api_provider=provider,
|
||||
api_key=api_key,
|
||||
api_base_url=api_base_url,
|
||||
default_model=llm_model,
|
||||
default_temperature=0.7,
|
||||
default_max_tokens=100
|
||||
default_temperature=temperature,
|
||||
default_max_tokens=max_tokens
|
||||
)
|
||||
|
||||
# 发送简单的测试请求
|
||||
@@ -609,13 +614,15 @@ async def test_api_connection(data: ApiTestRequest):
|
||||
logger.info(f" - 提供商: {provider}")
|
||||
logger.info(f" - 模型: {llm_model}")
|
||||
logger.info(f" - Base URL: {api_base_url}")
|
||||
logger.info(f" - Temperature: {temperature}")
|
||||
logger.info(f" - Max Tokens: {max_tokens}")
|
||||
|
||||
response = await test_service.generate_text(
|
||||
prompt=test_prompt,
|
||||
provider=provider,
|
||||
model=llm_model,
|
||||
temperature=0.7,
|
||||
max_tokens=8000,
|
||||
temperature=temperature,
|
||||
max_tokens=max_tokens,
|
||||
auto_mcp=False # 测试时不加载MCP工具
|
||||
)
|
||||
|
||||
@@ -639,7 +646,9 @@ async def test_api_connection(data: ApiTestRequest):
|
||||
"details": {
|
||||
"api_available": True,
|
||||
"model_accessible": True,
|
||||
"response_valid": bool(response)
|
||||
"response_valid": bool(response),
|
||||
"temperature": temperature,
|
||||
"max_tokens": max_tokens
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -184,7 +184,7 @@ else:
|
||||
@app.get("/")
|
||||
async def root():
|
||||
return {
|
||||
"message": "欢迎使用AI Story Creator",
|
||||
"message": "欢迎使用MuMuAINovel",
|
||||
"version": config_settings.app_version,
|
||||
"docs": "/docs",
|
||||
"notice": "请先构建前端: cd frontend && npm run build"
|
||||
|
||||
+126
-106
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user