| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| import React from 'react';
|
| import { Card, Select, Typography, Button, Switch } from '@douyinfe/semi-ui';
|
| import { Sparkles, Users, ToggleLeft, X, Settings } from 'lucide-react';
|
| import { useTranslation } from 'react-i18next';
|
| import { renderGroupOption, selectFilter } from '../../helpers';
|
| import ParameterControl from './ParameterControl';
|
| import ImageUrlInput from './ImageUrlInput';
|
| import ConfigManager from './ConfigManager';
|
| import CustomRequestEditor from './CustomRequestEditor';
|
|
|
| const SettingsPanel = ({
|
| inputs,
|
| parameterEnabled,
|
| models,
|
| groups,
|
| styleState,
|
| showDebugPanel,
|
| customRequestMode,
|
| customRequestBody,
|
| onInputChange,
|
| onParameterToggle,
|
| onCloseSettings,
|
| onConfigImport,
|
| onConfigReset,
|
| onCustomRequestModeChange,
|
| onCustomRequestBodyChange,
|
| previewPayload,
|
| messages,
|
| }) => {
|
| const { t } = useTranslation();
|
|
|
| const currentConfig = {
|
| inputs,
|
| parameterEnabled,
|
| showDebugPanel,
|
| customRequestMode,
|
| customRequestBody,
|
| };
|
|
|
| return (
|
| <Card
|
| className='h-full flex flex-col'
|
| bordered={false}
|
| bodyStyle={{
|
| padding: styleState.isMobile ? '16px' : '24px',
|
| height: '100%',
|
| display: 'flex',
|
| flexDirection: 'column',
|
| }}
|
| >
|
| {/* 标题区域 - 与调试面板保持一致 */}
|
| <div className='flex items-center justify-between mb-6 flex-shrink-0'>
|
| <div className='flex items-center'>
|
| <div className='w-10 h-10 rounded-full bg-gradient-to-r from-purple-500 to-pink-500 flex items-center justify-center mr-3'>
|
| <Settings size={20} className='text-white' />
|
| </div>
|
| <Typography.Title heading={5} className='mb-0'>
|
| {t('模型配置')}
|
| </Typography.Title>
|
| </div>
|
|
|
| {styleState.isMobile && onCloseSettings && (
|
| <Button
|
| icon={<X size={16} />}
|
| onClick={onCloseSettings}
|
| theme='borderless'
|
| type='tertiary'
|
| size='small'
|
| className='!rounded-lg'
|
| />
|
| )}
|
| </div>
|
|
|
| {/* 移动端配置管理 */}
|
| {styleState.isMobile && (
|
| <div className='mb-4 flex-shrink-0'>
|
| <ConfigManager
|
| currentConfig={currentConfig}
|
| onConfigImport={onConfigImport}
|
| onConfigReset={onConfigReset}
|
| styleState={{ ...styleState, isMobile: false }}
|
| messages={messages}
|
| />
|
| </div>
|
| )}
|
|
|
| <div className='space-y-6 overflow-y-auto flex-1 pr-2 model-settings-scroll'>
|
| {/* 自定义请求体编辑器 */}
|
| <CustomRequestEditor
|
| customRequestMode={customRequestMode}
|
| customRequestBody={customRequestBody}
|
| onCustomRequestModeChange={onCustomRequestModeChange}
|
| onCustomRequestBodyChange={onCustomRequestBodyChange}
|
| defaultPayload={previewPayload}
|
| />
|
|
|
| {/* 分组选择 */}
|
| <div className={customRequestMode ? 'opacity-50' : ''}>
|
| <div className='flex items-center gap-2 mb-2'>
|
| <Users size={16} className='text-gray-500' />
|
| <Typography.Text strong className='text-sm'>
|
| {t('分组')}
|
| </Typography.Text>
|
| {customRequestMode && (
|
| <Typography.Text className='text-xs text-orange-600'>
|
| ({t('已在自定义模式中忽略')})
|
| </Typography.Text>
|
| )}
|
| </div>
|
| <Select
|
| placeholder={t('请选择分组')}
|
| name='group'
|
| required
|
| selection
|
| filter={selectFilter}
|
| autoClearSearchValue={false}
|
| onChange={(value) => onInputChange('group', value)}
|
| value={inputs.group}
|
| autoComplete='new-password'
|
| optionList={groups}
|
| renderOptionItem={renderGroupOption}
|
| style={{ width: '100%' }}
|
| dropdownStyle={{ width: '100%', maxWidth: '100%' }}
|
| className='!rounded-lg'
|
| disabled={customRequestMode}
|
| />
|
| </div>
|
|
|
| {/* 模型选择 */}
|
| <div className={customRequestMode ? 'opacity-50' : ''}>
|
| <div className='flex items-center gap-2 mb-2'>
|
| <Sparkles size={16} className='text-gray-500' />
|
| <Typography.Text strong className='text-sm'>
|
| {t('模型')}
|
| </Typography.Text>
|
| {customRequestMode && (
|
| <Typography.Text className='text-xs text-orange-600'>
|
| ({t('已在自定义模式中忽略')})
|
| </Typography.Text>
|
| )}
|
| </div>
|
| <Select
|
| placeholder={t('请选择模型')}
|
| name='model'
|
| required
|
| selection
|
| filter={selectFilter}
|
| autoClearSearchValue={false}
|
| onChange={(value) => onInputChange('model', value)}
|
| value={inputs.model}
|
| autoComplete='new-password'
|
| optionList={models}
|
| style={{ width: '100%' }}
|
| dropdownStyle={{ width: '100%', maxWidth: '100%' }}
|
| className='!rounded-lg'
|
| disabled={customRequestMode}
|
| />
|
| </div>
|
|
|
| {/* 图片URL输入 */}
|
| <div className={customRequestMode ? 'opacity-50' : ''}>
|
| <ImageUrlInput
|
| imageUrls={inputs.imageUrls}
|
| imageEnabled={inputs.imageEnabled}
|
| onImageUrlsChange={(urls) => onInputChange('imageUrls', urls)}
|
| onImageEnabledChange={(enabled) =>
|
| onInputChange('imageEnabled', enabled)
|
| }
|
| disabled={customRequestMode}
|
| />
|
| </div>
|
|
|
| {/* 参数控制组件 */}
|
| <div className={customRequestMode ? 'opacity-50' : ''}>
|
| <ParameterControl
|
| inputs={inputs}
|
| parameterEnabled={parameterEnabled}
|
| onInputChange={onInputChange}
|
| onParameterToggle={onParameterToggle}
|
| disabled={customRequestMode}
|
| />
|
| </div>
|
|
|
| {/* 流式输出开关 */}
|
| <div className={customRequestMode ? 'opacity-50' : ''}>
|
| <div className='flex items-center justify-between'>
|
| <div className='flex items-center gap-2'>
|
| <ToggleLeft size={16} className='text-gray-500' />
|
| <Typography.Text strong className='text-sm'>
|
| {t('流式输出')}
|
| </Typography.Text>
|
| {customRequestMode && (
|
| <Typography.Text className='text-xs text-orange-600'>
|
| ({t('已在自定义模式中忽略')})
|
| </Typography.Text>
|
| )}
|
| </div>
|
| <Switch
|
| checked={inputs.stream}
|
| onChange={(checked) => onInputChange('stream', checked)}
|
| checkedText={t('开')}
|
| uncheckedText={t('关')}
|
| size='small'
|
| disabled={customRequestMode}
|
| />
|
| </div>
|
| </div>
|
| </div>
|
|
|
| {/* 桌面端的配置管理放在底部 */}
|
| {!styleState.isMobile && (
|
| <div className='flex-shrink-0 pt-3'>
|
| <ConfigManager
|
| currentConfig={currentConfig}
|
| onConfigImport={onConfigImport}
|
| onConfigReset={onConfigReset}
|
| styleState={styleState}
|
| messages={messages}
|
| />
|
| </div>
|
| )}
|
| </Card>
|
| );
|
| };
|
|
|
| export default SettingsPanel;
|
|
|