| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| 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'> |
| (已在自定义模式中忽略) |
| </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'> |
| (已在自定义模式中忽略) |
| </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'> |
| 流式输出 |
| </Typography.Text> |
| {customRequestMode && ( |
| <Typography.Text className='text-xs text-orange-600'> |
| (已在自定义模式中忽略) |
| </Typography.Text> |
| )} |
| </div> |
| <Switch |
| checked={inputs.stream} |
| onChange={(checked) => onInputChange('stream', checked)} |
| checkedText='开' |
| uncheckedText='关' |
| 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; |
|
|