|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import React from 'react'; |
|
|
import { Input, Slider, Typography, Button, Tag } from '@douyinfe/semi-ui'; |
|
|
import { |
|
|
Hash, |
|
|
Thermometer, |
|
|
Target, |
|
|
Repeat, |
|
|
Ban, |
|
|
Shuffle, |
|
|
Check, |
|
|
X, |
|
|
} from 'lucide-react'; |
|
|
|
|
|
const ParameterControl = ({ |
|
|
inputs, |
|
|
parameterEnabled, |
|
|
onInputChange, |
|
|
onParameterToggle, |
|
|
disabled = false, |
|
|
}) => { |
|
|
return ( |
|
|
<> |
|
|
{/* Temperature */} |
|
|
<div |
|
|
className={`transition-opacity duration-200 mb-4 ${!parameterEnabled.temperature || disabled ? 'opacity-50' : ''}`} |
|
|
> |
|
|
<div className='flex items-center justify-between mb-2'> |
|
|
<div className='flex items-center gap-2'> |
|
|
<Thermometer size={16} className='text-gray-500' /> |
|
|
<Typography.Text strong className='text-sm'> |
|
|
Temperature |
|
|
</Typography.Text> |
|
|
<Tag size='small' shape='circle'> |
|
|
{inputs.temperature} |
|
|
</Tag> |
|
|
</div> |
|
|
<Button |
|
|
theme={parameterEnabled.temperature ? 'solid' : 'borderless'} |
|
|
type={parameterEnabled.temperature ? 'primary' : 'tertiary'} |
|
|
size='small' |
|
|
icon={ |
|
|
parameterEnabled.temperature ? ( |
|
|
<Check size={10} /> |
|
|
) : ( |
|
|
<X size={10} /> |
|
|
) |
|
|
} |
|
|
onClick={() => onParameterToggle('temperature')} |
|
|
className='!rounded-full !w-4 !h-4 !p-0 !min-w-0' |
|
|
disabled={disabled} |
|
|
/> |
|
|
</div> |
|
|
<Typography.Text className='text-xs text-gray-500 mb-2'> |
|
|
控制输出的随机性和创造性 |
|
|
</Typography.Text> |
|
|
<Slider |
|
|
step={0.1} |
|
|
min={0.1} |
|
|
max={1} |
|
|
value={inputs.temperature} |
|
|
onChange={(value) => onInputChange('temperature', value)} |
|
|
className='mt-2' |
|
|
disabled={!parameterEnabled.temperature || disabled} |
|
|
/> |
|
|
</div> |
|
|
|
|
|
{/* Top P */} |
|
|
<div |
|
|
className={`transition-opacity duration-200 mb-4 ${!parameterEnabled.top_p || disabled ? 'opacity-50' : ''}`} |
|
|
> |
|
|
<div className='flex items-center justify-between mb-2'> |
|
|
<div className='flex items-center gap-2'> |
|
|
<Target size={16} className='text-gray-500' /> |
|
|
<Typography.Text strong className='text-sm'> |
|
|
Top P |
|
|
</Typography.Text> |
|
|
<Tag size='small' shape='circle'> |
|
|
{inputs.top_p} |
|
|
</Tag> |
|
|
</div> |
|
|
<Button |
|
|
theme={parameterEnabled.top_p ? 'solid' : 'borderless'} |
|
|
type={parameterEnabled.top_p ? 'primary' : 'tertiary'} |
|
|
size='small' |
|
|
icon={ |
|
|
parameterEnabled.top_p ? <Check size={10} /> : <X size={10} /> |
|
|
} |
|
|
onClick={() => onParameterToggle('top_p')} |
|
|
className='!rounded-full !w-4 !h-4 !p-0 !min-w-0' |
|
|
disabled={disabled} |
|
|
/> |
|
|
</div> |
|
|
<Typography.Text className='text-xs text-gray-500 mb-2'> |
|
|
核采样,控制词汇选择的多样性 |
|
|
</Typography.Text> |
|
|
<Slider |
|
|
step={0.1} |
|
|
min={0.1} |
|
|
max={1} |
|
|
value={inputs.top_p} |
|
|
onChange={(value) => onInputChange('top_p', value)} |
|
|
className='mt-2' |
|
|
disabled={!parameterEnabled.top_p || disabled} |
|
|
/> |
|
|
</div> |
|
|
|
|
|
{/* Frequency Penalty */} |
|
|
<div |
|
|
className={`transition-opacity duration-200 mb-4 ${!parameterEnabled.frequency_penalty || disabled ? 'opacity-50' : ''}`} |
|
|
> |
|
|
<div className='flex items-center justify-between mb-2'> |
|
|
<div className='flex items-center gap-2'> |
|
|
<Repeat size={16} className='text-gray-500' /> |
|
|
<Typography.Text strong className='text-sm'> |
|
|
Frequency Penalty |
|
|
</Typography.Text> |
|
|
<Tag size='small' shape='circle'> |
|
|
{inputs.frequency_penalty} |
|
|
</Tag> |
|
|
</div> |
|
|
<Button |
|
|
theme={parameterEnabled.frequency_penalty ? 'solid' : 'borderless'} |
|
|
type={parameterEnabled.frequency_penalty ? 'primary' : 'tertiary'} |
|
|
size='small' |
|
|
icon={ |
|
|
parameterEnabled.frequency_penalty ? ( |
|
|
<Check size={10} /> |
|
|
) : ( |
|
|
<X size={10} /> |
|
|
) |
|
|
} |
|
|
onClick={() => onParameterToggle('frequency_penalty')} |
|
|
className='!rounded-full !w-4 !h-4 !p-0 !min-w-0' |
|
|
disabled={disabled} |
|
|
/> |
|
|
</div> |
|
|
<Typography.Text className='text-xs text-gray-500 mb-2'> |
|
|
频率惩罚,减少重复词汇的出现 |
|
|
</Typography.Text> |
|
|
<Slider |
|
|
step={0.1} |
|
|
min={-2} |
|
|
max={2} |
|
|
value={inputs.frequency_penalty} |
|
|
onChange={(value) => onInputChange('frequency_penalty', value)} |
|
|
className='mt-2' |
|
|
disabled={!parameterEnabled.frequency_penalty || disabled} |
|
|
/> |
|
|
</div> |
|
|
|
|
|
{/* Presence Penalty */} |
|
|
<div |
|
|
className={`transition-opacity duration-200 mb-4 ${!parameterEnabled.presence_penalty || disabled ? 'opacity-50' : ''}`} |
|
|
> |
|
|
<div className='flex items-center justify-between mb-2'> |
|
|
<div className='flex items-center gap-2'> |
|
|
<Ban size={16} className='text-gray-500' /> |
|
|
<Typography.Text strong className='text-sm'> |
|
|
Presence Penalty |
|
|
</Typography.Text> |
|
|
<Tag size='small' shape='circle'> |
|
|
{inputs.presence_penalty} |
|
|
</Tag> |
|
|
</div> |
|
|
<Button |
|
|
theme={parameterEnabled.presence_penalty ? 'solid' : 'borderless'} |
|
|
type={parameterEnabled.presence_penalty ? 'primary' : 'tertiary'} |
|
|
size='small' |
|
|
icon={ |
|
|
parameterEnabled.presence_penalty ? ( |
|
|
<Check size={10} /> |
|
|
) : ( |
|
|
<X size={10} /> |
|
|
) |
|
|
} |
|
|
onClick={() => onParameterToggle('presence_penalty')} |
|
|
className='!rounded-full !w-4 !h-4 !p-0 !min-w-0' |
|
|
disabled={disabled} |
|
|
/> |
|
|
</div> |
|
|
<Typography.Text className='text-xs text-gray-500 mb-2'> |
|
|
存在惩罚,鼓励讨论新话题 |
|
|
</Typography.Text> |
|
|
<Slider |
|
|
step={0.1} |
|
|
min={-2} |
|
|
max={2} |
|
|
value={inputs.presence_penalty} |
|
|
onChange={(value) => onInputChange('presence_penalty', value)} |
|
|
className='mt-2' |
|
|
disabled={!parameterEnabled.presence_penalty || disabled} |
|
|
/> |
|
|
</div> |
|
|
|
|
|
{/* MaxTokens */} |
|
|
<div |
|
|
className={`transition-opacity duration-200 mb-4 ${!parameterEnabled.max_tokens || disabled ? 'opacity-50' : ''}`} |
|
|
> |
|
|
<div className='flex items-center justify-between mb-2'> |
|
|
<div className='flex items-center gap-2'> |
|
|
<Hash size={16} className='text-gray-500' /> |
|
|
<Typography.Text strong className='text-sm'> |
|
|
Max Tokens |
|
|
</Typography.Text> |
|
|
</div> |
|
|
<Button |
|
|
theme={parameterEnabled.max_tokens ? 'solid' : 'borderless'} |
|
|
type={parameterEnabled.max_tokens ? 'primary' : 'tertiary'} |
|
|
size='small' |
|
|
icon={ |
|
|
parameterEnabled.max_tokens ? ( |
|
|
<Check size={10} /> |
|
|
) : ( |
|
|
<X size={10} /> |
|
|
) |
|
|
} |
|
|
onClick={() => onParameterToggle('max_tokens')} |
|
|
className='!rounded-full !w-4 !h-4 !p-0 !min-w-0' |
|
|
disabled={disabled} |
|
|
/> |
|
|
</div> |
|
|
<Input |
|
|
placeholder='MaxTokens' |
|
|
name='max_tokens' |
|
|
required |
|
|
autoComplete='new-password' |
|
|
defaultValue={0} |
|
|
value={inputs.max_tokens} |
|
|
onChange={(value) => onInputChange('max_tokens', value)} |
|
|
className='!rounded-lg' |
|
|
disabled={!parameterEnabled.max_tokens || disabled} |
|
|
/> |
|
|
</div> |
|
|
|
|
|
{/* Seed */} |
|
|
<div |
|
|
className={`transition-opacity duration-200 mb-4 ${!parameterEnabled.seed || disabled ? 'opacity-50' : ''}`} |
|
|
> |
|
|
<div className='flex items-center justify-between mb-2'> |
|
|
<div className='flex items-center gap-2'> |
|
|
<Shuffle size={16} className='text-gray-500' /> |
|
|
<Typography.Text strong className='text-sm'> |
|
|
Seed |
|
|
</Typography.Text> |
|
|
<Typography.Text className='text-xs text-gray-400'> |
|
|
(可选,用于复现结果) |
|
|
</Typography.Text> |
|
|
</div> |
|
|
<Button |
|
|
theme={parameterEnabled.seed ? 'solid' : 'borderless'} |
|
|
type={parameterEnabled.seed ? 'primary' : 'tertiary'} |
|
|
size='small' |
|
|
icon={parameterEnabled.seed ? <Check size={10} /> : <X size={10} />} |
|
|
onClick={() => onParameterToggle('seed')} |
|
|
className='!rounded-full !w-4 !h-4 !p-0 !min-w-0' |
|
|
disabled={disabled} |
|
|
/> |
|
|
</div> |
|
|
<Input |
|
|
placeholder='随机种子 (留空为随机)' |
|
|
name='seed' |
|
|
autoComplete='new-password' |
|
|
value={inputs.seed || ''} |
|
|
onChange={(value) => |
|
|
onInputChange('seed', value === '' ? null : value) |
|
|
} |
|
|
className='!rounded-lg' |
|
|
disabled={!parameterEnabled.seed || disabled} |
|
|
/> |
|
|
</div> |
|
|
</> |
|
|
); |
|
|
}; |
|
|
|
|
|
export default ParameterControl; |
|
|
|