| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import React, { useState, useEffect } from 'react'; |
| import { |
| TextArea, |
| Typography, |
| Button, |
| Switch, |
| Banner, |
| } from '@douyinfe/semi-ui'; |
| import { Code, Edit, Check, X, AlertTriangle } from 'lucide-react'; |
| import { useTranslation } from 'react-i18next'; |
|
|
| const CustomRequestEditor = ({ |
| customRequestMode, |
| customRequestBody, |
| onCustomRequestModeChange, |
| onCustomRequestBodyChange, |
| defaultPayload, |
| }) => { |
| const { t } = useTranslation(); |
| const [isValid, setIsValid] = useState(true); |
| const [errorMessage, setErrorMessage] = useState(''); |
| const [localValue, setLocalValue] = useState(customRequestBody || ''); |
|
|
| |
| useEffect(() => { |
| if ( |
| customRequestMode && |
| (!customRequestBody || customRequestBody.trim() === '') |
| ) { |
| const defaultJson = defaultPayload |
| ? JSON.stringify(defaultPayload, null, 2) |
| : ''; |
| setLocalValue(defaultJson); |
| onCustomRequestBodyChange(defaultJson); |
| } |
| }, [ |
| customRequestMode, |
| defaultPayload, |
| customRequestBody, |
| onCustomRequestBodyChange, |
| ]); |
|
|
| |
| useEffect(() => { |
| if (customRequestBody !== localValue) { |
| setLocalValue(customRequestBody || ''); |
| validateJson(customRequestBody || ''); |
| } |
| }, [customRequestBody]); |
|
|
| |
| const validateJson = (value) => { |
| if (!value.trim()) { |
| setIsValid(true); |
| setErrorMessage(''); |
| return true; |
| } |
|
|
| try { |
| JSON.parse(value); |
| setIsValid(true); |
| setErrorMessage(''); |
| return true; |
| } catch (error) { |
| setIsValid(false); |
| setErrorMessage(`JSON格式错误: ${error.message}`); |
| return false; |
| } |
| }; |
|
|
| const handleValueChange = (value) => { |
| setLocalValue(value); |
| validateJson(value); |
| |
| onCustomRequestBodyChange(value); |
| }; |
|
|
| const handleModeToggle = (enabled) => { |
| onCustomRequestModeChange(enabled); |
| if (enabled && defaultPayload) { |
| const defaultJson = JSON.stringify(defaultPayload, null, 2); |
| setLocalValue(defaultJson); |
| onCustomRequestBodyChange(defaultJson); |
| } |
| }; |
|
|
| const formatJson = () => { |
| try { |
| const parsed = JSON.parse(localValue); |
| const formatted = JSON.stringify(parsed, null, 2); |
| setLocalValue(formatted); |
| onCustomRequestBodyChange(formatted); |
| setIsValid(true); |
| setErrorMessage(''); |
| } catch (error) { |
| |
| } |
| }; |
|
|
| return ( |
| <div className='space-y-4'> |
| {/* 自定义模式开关 */} |
| <div className='flex items-center justify-between'> |
| <div className='flex items-center gap-2'> |
| <Code size={16} className='text-gray-500' /> |
| <Typography.Text strong className='text-sm'> |
| 自定义请求体模式 |
| </Typography.Text> |
| </div> |
| <Switch |
| checked={customRequestMode} |
| onChange={handleModeToggle} |
| checkedText='开' |
| uncheckedText='关' |
| size='small' |
| /> |
| </div> |
| |
| {customRequestMode && ( |
| <> |
| {/* 提示信息 */} |
| <Banner |
| type='warning' |
| description='启用此模式后,将使用您自定义的请求体发送API请求,模型配置面板的参数设置将被忽略。' |
| icon={<AlertTriangle size={16} />} |
| className='!rounded-lg' |
| closeIcon={null} |
| /> |
| |
| {/* JSON编辑器 */} |
| <div> |
| <div className='flex items-center justify-between mb-2'> |
| <Typography.Text strong className='text-sm'> |
| 请求体 JSON |
| </Typography.Text> |
| <div className='flex items-center gap-2'> |
| {isValid ? ( |
| <div className='flex items-center gap-1 text-green-600'> |
| <Check size={14} /> |
| <Typography.Text className='text-xs'> |
| 格式正确 |
| </Typography.Text> |
| </div> |
| ) : ( |
| <div className='flex items-center gap-1 text-red-600'> |
| <X size={14} /> |
| <Typography.Text className='text-xs'> |
| 格式错误 |
| </Typography.Text> |
| </div> |
| )} |
| <Button |
| theme='borderless' |
| type='tertiary' |
| size='small' |
| icon={<Edit size={14} />} |
| onClick={formatJson} |
| disabled={!isValid} |
| className='!rounded-lg' |
| > |
| 格式化 |
| </Button> |
| </div> |
| </div> |
| |
| <TextArea |
| value={localValue} |
| onChange={handleValueChange} |
| placeholder='{"model": "gpt-4o", "messages": [...], ...}' |
| autosize={{ minRows: 8, maxRows: 20 }} |
| className={`custom-request-textarea !rounded-lg font-mono text-sm ${!isValid ? '!border-red-500' : ''}`} |
| style={{ |
| fontFamily: 'Consolas, Monaco, "Courier New", monospace', |
| lineHeight: '1.5', |
| }} |
| /> |
| |
| {!isValid && errorMessage && ( |
| <Typography.Text type='danger' className='text-xs mt-1 block'> |
| {errorMessage} |
| </Typography.Text> |
| )} |
| |
| <Typography.Text className='text-xs text-gray-500 mt-2 block'> |
| 请输入有效的JSON格式的请求体。您可以参考预览面板中的默认请求体格式。 |
| </Typography.Text> |
| </div> |
| </> |
| )} |
| </div> |
| ); |
| }; |
|
|
| export default CustomRequestEditor; |
|
|