|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|