feat: validate tts form items
This commit is contained in:
@@ -175,5 +175,7 @@ export default {
|
||||
'Transcript of Reference Audio (for ICL mode)',
|
||||
'playground.params.refAudio.vectorMode':
|
||||
'Use Speaker Embedding Only (no ICL)',
|
||||
'playground.params.streamMode': 'Enable Streaming'
|
||||
'playground.params.streamMode': 'Enable Streaming',
|
||||
'playground.speech.rules.refAudio':
|
||||
'Either the reference audio transcript or speaker embedding must be set.'
|
||||
};
|
||||
|
||||
@@ -178,7 +178,9 @@ export default {
|
||||
'Transcript of Reference Audio (for ICL mode)',
|
||||
'playground.params.refAudio.vectorMode':
|
||||
'Use Speaker Embedding Only (no ICL)',
|
||||
'playground.params.streamMode': 'Enable Streaming'
|
||||
'playground.params.streamMode': 'Enable Streaming',
|
||||
'playground.speech.rules.refAudio':
|
||||
'Either the reference audio transcript or speaker embedding must be set.'
|
||||
};
|
||||
|
||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||
@@ -191,4 +193,5 @@ export default {
|
||||
// 7. 'playground.params.duration': 'Duration (seconds)',
|
||||
// 8. 'playground.params.resolution': 'Resolution'
|
||||
// 9. 'playground.params.streamMode': 'Enable Streaming'
|
||||
// 10. 'playground.speech.rules.refAudio': 'Either the reference audio transcript or speaker embedding must be set.'
|
||||
// ========== End of To-Do List ==========
|
||||
|
||||
@@ -172,7 +172,9 @@ export default {
|
||||
'Transcript of Reference Audio (for ICL mode)',
|
||||
'playground.params.refAudio.vectorMode':
|
||||
'Use Speaker Embedding Only (no ICL)',
|
||||
'playground.params.streamMode': 'Enable Streaming'
|
||||
'playground.params.streamMode': 'Enable Streaming',
|
||||
'playground.speech.rules.refAudio':
|
||||
'Either the reference audio transcript or speaker embedding must be set.'
|
||||
};
|
||||
|
||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||
@@ -181,5 +183,6 @@ export default {
|
||||
// 3. 'playground.uploadImage.url.button': 'Add Image from URL',
|
||||
// 4. 'playground.params.duration': 'Duration (seconds)',
|
||||
// 5. 'playground.params.resolution': 'Resolution',
|
||||
// 6. 'playground.params.streamMode': 'Enable Streaming'
|
||||
// 6. 'playground.params.streamMode': 'Enable Streaming',
|
||||
// 7. 'playground.speech.rules.refAudio': 'Either the reference audio transcript or speaker embedding must be set.'
|
||||
// ========== End of To-Do List ==========
|
||||
|
||||
@@ -132,7 +132,8 @@ export default {
|
||||
'Sınıflandırıcısız rehberlik ölçeği, görselin isteme bağlılığını etkiler.',
|
||||
'playground.image.strength.tip':
|
||||
'Değer ne kadar yüksek olursa, orijinal görsel üzerindeki değişiklik o kadar büyük olur.',
|
||||
'playground.image.edit.tips': 'Yüklemek için görseli tıklayın veya bu alana sürükleyin',
|
||||
'playground.image.edit.tips':
|
||||
'Yüklemek için görseli tıklayın veya bu alana sürükleyin',
|
||||
'playground.image.saveMask': 'Maskeyi Kaydet',
|
||||
'playground.image.negativeMask': 'Maskeyi Ters Çevir',
|
||||
'playground.image.brushSize': 'Fırça Boyutu',
|
||||
@@ -154,14 +155,13 @@ export default {
|
||||
'playground.model.noavailable.tips2':
|
||||
'Beklenen model görünmüyorsa, çalıştığından ve doğru kategoride olduğundan emin olun. Kategori yanlışsa, modelin ayarlarından manuel olarak düzeltebilirsiniz.',
|
||||
'playground.rerank.query.validate': 'Sorgu gereklidir.',
|
||||
'playground.image.generate.error':
|
||||
'Bir sorun oluştu. Görsel oluşturulamadı.',
|
||||
'playground.image.generate.error': 'Bir sorun oluştu. Görsel oluşturulamadı.',
|
||||
'playground.uploadfile.sizeError':
|
||||
'Dosya boyutu sınırı aşıyor. İzin verilen maksimum: {size}.',
|
||||
'playground.uploadImage.url.invalid':
|
||||
'Lütfen doğrudan bir görsel URL\'si girin (örn. https://.../image.png). İptal etmek için ESC tuşuna basın.',
|
||||
'playground.uploadImage.url.holder': 'Görsel URL\'si girin',
|
||||
'playground.uploadImage.url.button': 'URL\'den Görsel Ekle',
|
||||
"Lütfen doğrudan bir görsel URL'si girin (örn. https://.../image.png). İptal etmek için ESC tuşuna basın.",
|
||||
'playground.uploadImage.url.holder': "Görsel URL'si girin",
|
||||
'playground.uploadImage.url.button': "URL'den Görsel Ekle",
|
||||
'playground.params.duration': 'Süre (saniye)',
|
||||
'playground.params.resolution': 'Çözünürlük',
|
||||
'playground.params.taskType': 'Görev Türü',
|
||||
@@ -170,10 +170,15 @@ export default {
|
||||
'playground.params.maxTokens': 'Maksimum Yeni Token',
|
||||
'playground.params.refAudio': 'Referans Ses',
|
||||
'playground.params.refAudio.tips':
|
||||
'Referans ses URL\'si girin veya bir ses dosyası yükleyin.',
|
||||
'playground.params.refAudio.text':
|
||||
'Referans Ses Transkripti (ICL modu için)',
|
||||
"Referans ses URL'si girin veya bir ses dosyası yükleyin.",
|
||||
'playground.params.refAudio.text': 'Referans Ses Transkripti (ICL modu için)',
|
||||
'playground.params.refAudio.vectorMode':
|
||||
'Yalnızca Konuşmacı Gömme Kullan (ICL yok)',
|
||||
'playground.params.streamMode': 'Akışı Etkinleştir'
|
||||
'playground.params.streamMode': 'Akışı Etkinleştir',
|
||||
'playground.speech.rules.refAudio':
|
||||
'Either the reference audio transcript or speaker embedding must be set.'
|
||||
};
|
||||
|
||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||
// 1. 'playground.speech.rules.refAudio': 'Either the reference audio transcript or speaker embedding must be set.'
|
||||
// ========== End of To-Do List ==========
|
||||
|
||||
@@ -167,5 +167,7 @@ export default {
|
||||
'playground.params.refAudio.text': '参考音频文本(用于上下文学习模式)',
|
||||
'playground.params.refAudio.vectorMode':
|
||||
'仅使用说话人嵌入(不使用上下文学习)',
|
||||
'playground.params.streamMode': '启用流式输出'
|
||||
'playground.params.streamMode': '启用流式输出',
|
||||
'playground.speech.rules.refAudio':
|
||||
'设置参考音频文本或仅使用说话人嵌入的任意一项。'
|
||||
};
|
||||
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user