Compare commits

..

3 Commits

3 changed files with 63 additions and 24 deletions

View File

@@ -475,8 +475,10 @@ class IndexTTS2Backend:
emo_vector = None emo_vector = None
if emo_text and len(emo_text.strip()) > 0: if emo_text and len(emo_text.strip()) > 0:
emo_vector = self._emo_text_to_vector(emo_text) raw_vector = self._emo_text_to_vector(emo_text)
logger.info(f"IndexTTS2 emo_text={repr(emo_text)} → emo_vector={emo_vector}") if raw_vector is not None:
emo_vector = [v * emo_alpha for v in raw_vector]
logger.info(f"IndexTTS2 emo_text={repr(emo_text)} emo_alpha={emo_alpha} → emo_vector={emo_vector}")
async with IndexTTS2Backend._gpu_lock: async with IndexTTS2Backend._gpu_lock:
await loop.run_in_executor( await loop.run_in_executor(

View File

@@ -63,8 +63,21 @@ const CustomVoiceForm = forwardRef<CustomVoiceFormHandle>((_props, ref) => {
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [advancedOpen, setAdvancedOpen] = useState(false) const [advancedOpen, setAdvancedOpen] = useState(false)
const [indexTTS2Open, setIndexTTS2Open] = useState(false) const [indexTTS2Open, setIndexTTS2Open] = useState(false)
const [selectedEmotion, setSelectedEmotion] = useState('none')
const [emoText, setEmoText] = useState('') const [emoText, setEmoText] = useState('')
const [emoAlpha, setEmoAlpha] = useState(0.6) const [emoAlpha, setEmoAlpha] = useState(0.6)
const EMOTION_PRESETS = [
{ value: 'none', label: '不使用情感控制', emo_text: '', emo_alpha: 0.5 },
{ value: 'happy', label: '开心', emo_text: '开心', emo_alpha: 0.6 },
{ value: 'angry', label: '愤怒', emo_text: '愤怒', emo_alpha: 0.15 },
{ value: 'sad', label: '悲伤', emo_text: '悲伤', emo_alpha: 0.4 },
{ value: 'fear', label: '恐惧', emo_text: '恐惧', emo_alpha: 0.4 },
{ value: 'hate', label: '厌恶', emo_text: '厌恶', emo_alpha: 0.6 },
{ value: 'low', label: '低沉', emo_text: '低沉', emo_alpha: 0.6 },
{ value: 'surprise', label: '惊讶', emo_text: '惊讶', emo_alpha: 0.3 },
{ value: 'neutral', label: '中性', emo_text: '中性', emo_alpha: 0.5 },
]
const [isIndexTTS2Loading, setIsIndexTTS2Loading] = useState(false) const [isIndexTTS2Loading, setIsIndexTTS2Loading] = useState(false)
const [tempAdvancedParams, setTempAdvancedParams] = useState({ const [tempAdvancedParams, setTempAdvancedParams] = useState({
max_new_tokens: 2048, max_new_tokens: 2048,
@@ -555,35 +568,59 @@ const CustomVoiceForm = forwardRef<CustomVoiceFormHandle>((_props, ref) => {
<DialogTrigger asChild> <DialogTrigger asChild>
<Button type="button" variant="outline" className="w-full"> <Button type="button" variant="outline" className="w-full">
<Zap className="mr-2 h-4 w-4" /> <Zap className="mr-2 h-4 w-4" />
IndexTTS2
</Button> </Button>
</DialogTrigger> </DialogTrigger>
<DialogContent className="sm:max-w-[480px]"> <DialogContent className="sm:max-w-[480px]">
<DialogHeader> <DialogHeader>
<DialogTitle>IndexTTS2</DialogTitle> <DialogTitle></DialogTitle>
<DialogDescription>使 IndexTTS2 </DialogDescription> <DialogDescription>使 IndexTTS2 </DialogDescription>
</DialogHeader> </DialogHeader>
<div className="space-y-4 py-4"> <div className="space-y-4 py-4">
<div className="space-y-2"> <div className="space-y-2">
<Label>emo_text</Label> <Label></Label>
<Textarea <Select
placeholder="输入情感参考句,如:你吓死我了!(留空则不使用情感控制)" value={selectedEmotion}
value={emoText} onValueChange={(value) => {
onChange={e => setEmoText(e.target.value)} const preset = EMOTION_PRESETS.find(p => p.value === value)
className="min-h-[60px]" if (preset) {
/> setSelectedEmotion(value)
</div> setEmoText(preset.emo_text)
<div className="space-y-2"> setEmoAlpha(preset.emo_alpha)
<Label>emo_alpha{emoAlpha.toFixed(2)}</Label> }
<Input }}
type="range" >
min={0} <SelectTrigger>
max={1} <SelectValue />
step={0.05} </SelectTrigger>
value={emoAlpha} <SelectContent>
onChange={e => setEmoAlpha(parseFloat(e.target.value))} {EMOTION_PRESETS.map(p => (
/> <SelectItem key={p.value} value={p.value}>
{p.label}
{p.value !== 'none' && (
<span className="ml-2 text-xs text-muted-foreground"> {p.emo_alpha}</span>
)}
</SelectItem>
))}
</SelectContent>
</Select>
</div> </div>
{selectedEmotion !== 'none' && (
<div className="space-y-2">
<Label>{emoAlpha.toFixed(2)}</Label>
<Input
type="range"
min={0}
max={1}
step={0.05}
value={emoAlpha}
onChange={e => setEmoAlpha(parseFloat(e.target.value))}
/>
{(selectedEmotion === 'angry') && (
<p className="text-xs text-muted-foreground"> 0.2</p>
)}
</div>
)}
</div> </div>
<DialogFooter> <DialogFooter>
<Button type="button" variant="outline" onClick={() => setIndexTTS2Open(false)}></Button> <Button type="button" variant="outline" onClick={() => setIndexTTS2Open(false)}></Button>

View File

@@ -73,7 +73,7 @@ const SelectContent = React.forwardRef<
<SelectPrimitive.Content <SelectPrimitive.Content
ref={ref} ref={ref}
className={cn( className={cn(
"relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]", "relative z-[200] max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",
position === "popper" && position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className className