feat: validate tts form items

This commit is contained in:
jialin
2026-04-09 12:14:36 +08:00
committed by jialin
parent 78bf76e965
commit ae3148a86f
12 changed files with 107 additions and 90 deletions
@@ -35,6 +35,7 @@ const ModelSelect: React.FC<{
]}
>
<SealSelect
required
description={intl.formatMessage({
id: 'playground.model.noavailable.tips2'
})}
@@ -1,4 +1,5 @@
import CheckboxField from '@/components/seal-form/checkbox-field';
import InputNumber from '@/components/seal-form/input-number';
import SealInput from '@/components/seal-form/seal-input';
import UploadAudio from '@/components/upload-audio';
import useAppUtils from '@/hooks/use-app-utils';
@@ -6,7 +7,7 @@ import { convertFileToBase64 } from '@/utils/load-audio-file';
import { CloseCircleFilled } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import React from 'react';
import React, { useEffect } from 'react';
import styled from 'styled-components';
import { useFormContext } from '../../config/form-context';
@@ -70,24 +71,74 @@ const TTSAdvanceConfig: React.FC = () => {
);
};
const atLeastOneValidator = (relateField: string) => () => ({
validator(rule: any, value: string) {
const type = form.getFieldValue('task_type');
const relateFieldValue = form.getFieldValue(relateField);
if (type !== 'Base') return Promise.resolve();
if (value || relateFieldValue) return Promise.resolve();
return Promise.reject(
new Error(
intl.formatMessage({ id: 'playground.speech.rules.refAudio' })
)
);
}
});
useEffect(() => {
if (taskType === 'Base') {
form.setFieldsValue({
x_vector_only_mode: true
});
onValuesChange?.(
{ x_vector_only_mode: true },
{ ...form.getFieldsValue(), x_vector_only_mode: true }
);
}
}, [taskType]);
return (
<>
<Form.Item
name="instructions"
rules={[
{
required: taskType === 'VoiceDesign',
message: getRuleMessage('input', 'playground.params.instructions')
}
]}
>
<SealInput.Input
allowClear
required={taskType === 'VoiceDesign'}
description={intl.formatMessage({
id: 'playground.params.instructions.tips'
})}
label={intl.formatMessage({ id: 'playground.params.instructions' })}
></SealInput.Input>
</Form.Item>
<Form.Item
name="max_new_tokens"
getValueProps={(value) => ({ value: value || null })}
>
<InputNumber
min={0}
step={1}
max={4096}
label={intl.formatMessage({ id: 'playground.params.maxTokens' })}
></InputNumber>
</Form.Item>
<Container>
<Form.Item
name="ref_audio"
getValueProps={(value) => ({ value: fileName ? fileName : value })}
rules={[
{
required: taskType === 'Base',
message: getRuleMessage('input', 'playground.params.refAudio')
}
]}
dependencies={['task_type']}
>
<SealInput.Input
allowClear
readOnly={!!fileName}
required={taskType === 'Base'}
suffix={
<SuffixWrapper>
{fileName ? (
@@ -110,7 +161,12 @@ const TTSAdvanceConfig: React.FC = () => {
></SealInput.Input>
</Form.Item>
</Container>
<Form.Item name="ref_text">
<Form.Item
name="ref_text"
style={{ marginBottom: 12 }}
dependencies={['task_type', 'x_vector_only_mode']}
rules={[atLeastOneValidator('x_vector_only_mode')]}
>
<SealInput.TextArea
allowClear
scaleSize={true}
@@ -118,9 +174,11 @@ const TTSAdvanceConfig: React.FC = () => {
></SealInput.TextArea>
</Form.Item>
<Form.Item
dependencies={['task_type', 'ref_text']}
style={{ marginBottom: 12 }}
name="x_vector_only_mode"
valuePropName="checked"
style={{ marginBottom: 8 }}
rules={[atLeastOneValidator('ref_text')]}
>
<CheckboxField
label={intl.formatMessage({
@@ -43,58 +43,5 @@ export const TTSAdvancedParamsConfig: ParamsSchema[] = [
required: false
}
]
},
{
type: 'Input',
name: 'instructions',
label: {
text: 'playground.params.instructions',
isLocalized: true
},
description: {
text: 'playground.params.instructions.tips',
isLocalized: true
},
attrs: {
allowClear: true
},
initAttrs: (meta: any) => {
return {
options: _.map(meta?.voices || [], (item: string) => ({
label: item,
value: item
}))
};
},
rules: [
{
required: false
}
]
},
{
type: 'InputNumber',
name: 'max_new_tokens',
label: {
text: 'playground.params.maxTokens',
isLocalized: true
},
attrs: {
step: 1,
min: 0,
max: 4096
},
formItemAttrs: {
getValueProps: (value: number) => {
return {
value: value || null
};
}
},
rules: [
{
required: false
}
]
}
];
+2 -6
View File
@@ -189,9 +189,6 @@ const GroundTTS: React.FC<MessageProps> = forwardRef((props, ref) => {
const submitMessage = async (current?: { role: string; content: string }) => {
try {
await formRef.current?.form.validateFields();
if (!parameters.model) return;
setLoading(true);
setMessageId();
setTokenResult(null);
@@ -207,7 +204,6 @@ const GroundTTS: React.FC<MessageProps> = forwardRef((props, ref) => {
};
setParams(params);
console.log('submitMessage params:', streamTTS.isPlaying);
// Choose stream or non-stream based on parameters
if (parameters.stream) {
@@ -230,7 +226,6 @@ const GroundTTS: React.FC<MessageProps> = forwardRef((props, ref) => {
await nonStreamTTS.generate(params);
}
} catch (error: any) {
console.log('error:', error);
setPlayingStream(false);
setTokenResult({
error: true,
@@ -248,7 +243,7 @@ const GroundTTS: React.FC<MessageProps> = forwardRef((props, ref) => {
};
const handleSendMessage = (message: Omit<MessageItem, 'uid'>) => {
submitMessage(message);
formRef.current?.form.submit();
};
const handleCloseViewCode = () => {
@@ -353,6 +348,7 @@ const GroundTTS: React.FC<MessageProps> = forwardRef((props, ref) => {
<TTSDataForm
ref={formRef}
modelList={modelList}
onFinish={submitMessage}
updatateParams={updatateParams}
/>
</RightContainer>
+1 -1
View File
@@ -10,7 +10,7 @@
flex-direction: column;
position: relative;
height: calc(
100vh - @HEADER_HEIGHT - var(--page-content-padding) -
100vh - @HEADER_HEIGHT - 4px - var(--page-content-padding) -
var(--page-content-padding) - var(--page-header-height)
);
width: calc(100% - 390px);
@@ -6,8 +6,8 @@
border-left: 1px solid var(--ant-color-split);
transition: width 0.3s ease;
height: calc(
100vh - @HEADER_HEIGHT - var(--page-content-padding) -
var(--page-header-height)
100vh - @HEADER_HEIGHT - 2px - var(--page-content-padding) -
var(--page-content-padding) - var(--page-header-height)
);
padding-top: 16px;
display: flex;
+3 -3
View File
@@ -41,7 +41,7 @@
overflow: hidden;
height: calc(
100vh - var(--page-header-height) - var(--page-content-padding) -
@HEADER_HEIGHT
var(--page-content-padding) - @HEADER_HEIGHT
);
.collapse {
@@ -74,8 +74,8 @@
.ant-divider {
margin: 0;
height: calc(
100vh - var(--page-header-height) - var(--page-content-padding) -
@HEADER_HEIGHT
100vh - var(--page-header-height) - 2px - var(--page-content-padding) -
var(--page-content-padding) - @HEADER_HEIGHT
);
}
}