Files
new-api/web/src/components/playground/SettingsPanel.js
Apple\Apple eeb9fe9b7f feat: enhance debug panel with real-time preview and collapsible tabs
- Add real-time request body preview that updates when parameters change
- Implement pre-constructed payload generation for debugging without sending requests
- Add support for image URLs in preview payload construction
- Upgrade debug panel to card-style tabs with custom arrow navigation
- Add collapsible functionality and dropdown menu for tab selection
- Integrate image-enabled messages with proper multimodal content structure
- Refactor tab state management with internal useState and external sync
- Remove redundant status labels and clean up component structure
- Set preview tab as default active tab for better UX
- Maintain backward compatibility with existing debug functionality

This enhancement significantly improves the debugging experience by allowing
developers to see exactly what request will be sent before actually sending it,
with real-time updates as they adjust parameters, models, or image settings.
2025-05-30 21:34:13 +08:00

197 lines
5.5 KiB
JavaScript

import React from 'react';
import {
Card,
Select,
TextArea,
Typography,
Button,
Switch,
Divider,
} from '@douyinfe/semi-ui';
import {
Sparkles,
Users,
Type,
ToggleLeft,
X,
} from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { renderGroupOption } from '../../helpers/render.js';
import ParameterControl from './ParameterControl';
import ImageUrlInput from './ImageUrlInput';
import ConfigManager from './ConfigManager';
const SettingsPanel = ({
inputs,
parameterEnabled,
models,
groups,
systemPrompt,
styleState,
showDebugPanel,
onInputChange,
onParameterToggle,
onSystemPromptChange,
onCloseSettings,
onConfigImport,
onConfigReset,
}) => {
const { t } = useTranslation();
const currentConfig = {
inputs,
parameterEnabled,
systemPrompt,
showDebugPanel,
};
return (
<Card
className={`!rounded-2xl h-full flex flex-col ${styleState.isMobile ? 'rounded-none border-none shadow-none' : ''}`}
bodyStyle={{
padding: styleState.isMobile ? '24px' : '24px 24px 16px 24px',
height: '100%',
display: 'flex',
flexDirection: 'column'
}}
>
{styleState.isMobile && (
<div className="flex items-center justify-between mb-4">
{/* 移动端显示配置管理下拉菜单和关闭按钮 */}
<ConfigManager
currentConfig={currentConfig}
onConfigImport={onConfigImport}
onConfigReset={onConfigReset}
styleState={styleState}
/>
<Button
icon={<X size={16} />}
onClick={onCloseSettings}
theme="borderless"
type="tertiary"
size="small"
className="!rounded-lg !text-gray-600 hover:!text-red-600 hover:!bg-red-50"
/>
</div>
)}
<div className="space-y-6 overflow-y-auto flex-1 pr-2 model-settings-scroll">
{/* 分组选择 */}
<div>
<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>
</div>
<Select
placeholder={t('请选择分组')}
name='group'
required
selection
onChange={(value) => onInputChange('group', value)}
value={inputs.group}
autoComplete='new-password'
optionList={groups}
renderOptionItem={renderGroupOption}
style={{ width: '100%' }}
className="!rounded-lg"
/>
</div>
{/* 模型选择 */}
<div>
<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>
</div>
<Select
placeholder={t('请选择模型')}
name='model'
required
selection
searchPosition='dropdown'
filter
onChange={(value) => onInputChange('model', value)}
value={inputs.model}
autoComplete='new-password'
optionList={models}
className="!rounded-lg"
/>
</div>
{/* 图片URL输入 */}
<ImageUrlInput
imageUrls={inputs.imageUrls}
imageEnabled={inputs.imageEnabled}
onImageUrlsChange={(urls) => onInputChange('imageUrls', urls)}
onImageEnabledChange={(enabled) => onInputChange('imageEnabled', enabled)}
/>
{/* 参数控制组件 */}
<ParameterControl
inputs={inputs}
parameterEnabled={parameterEnabled}
onInputChange={onInputChange}
onParameterToggle={onParameterToggle}
/>
{/* 流式输出开关 */}
<div>
<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>
</div>
<Switch
checked={inputs.stream}
onChange={(checked) => onInputChange('stream', checked)}
checkedText="开"
uncheckedText="关"
size="small"
/>
</div>
</div>
{/* System Prompt */}
<div>
<div className="flex items-center gap-2 mb-2">
<Type size={16} className="text-gray-500" />
<Typography.Text strong className="text-sm">
System Prompt
</Typography.Text>
</div>
<TextArea
placeholder='System Prompt'
name='system'
required
autoComplete='new-password'
autosize
defaultValue={systemPrompt}
onChange={onSystemPromptChange}
className="!rounded-lg"
maxHeight={200}
/>
</div>
</div>
{/* 桌面端的配置管理放在底部 */}
{!styleState.isMobile && (
<div className="flex-shrink-0 pt-3">
<ConfigManager
currentConfig={currentConfig}
onConfigImport={onConfigImport}
onConfigReset={onConfigReset}
styleState={styleState}
/>
</div>
)}
</Card>
);
};
export default SettingsPanel;