trinitytf commited on
Commit
be09fe1
·
verified ·
1 Parent(s): e81cacd

Upload 6 files

Browse files
Files changed (2) hide show
  1. app.py +72 -0
  2. requirements.txt +4 -0
app.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+
4
+ import gradio as gr
5
+ import numpy as np
6
+ import spaces
7
+ import torch
8
+ from qwen_tts import Qwen3TTSModel
9
+
10
+ # 0.6B matches the voices' origin; switch to Qwen/Qwen3-TTS-12Hz-1.7B-Base for
11
+ # higher quality at ~2.5x the GPU time per clip.
12
+ MODEL_ID = "Qwen/Qwen3-TTS-12Hz-0.6B-Base"
13
+ MAX_CHARS = 1500
14
+
15
+ VOICES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "voices")
16
+ with open(os.path.join(VOICES_DIR, "transcripts.json"), encoding="utf-8") as f:
17
+ TRANSCRIPTS = json.load(f)
18
+ VOICES = sorted(TRANSCRIPTS.keys())
19
+ LANGUAGES = ["English", "Chinese", "Japanese", "Korean", "German",
20
+ "French", "Russian", "Portuguese", "Spanish", "Italian"]
21
+
22
+ model = Qwen3TTSModel.from_pretrained(
23
+ MODEL_ID,
24
+ device_map="cuda",
25
+ dtype=torch.bfloat16,
26
+ )
27
+
28
+ _prompt_cache = {}
29
+
30
+
31
+ def _get_voice_prompt(voice: str):
32
+ if voice not in _prompt_cache:
33
+ _prompt_cache[voice] = model.create_voice_clone_prompt(
34
+ ref_audio=os.path.join(VOICES_DIR, f"{voice}.wav"),
35
+ ref_text=TRANSCRIPTS[voice],
36
+ )
37
+ return _prompt_cache[voice]
38
+
39
+
40
+ @spaces.GPU(duration=90)
41
+ def tts(text: str, voice: str, language: str):
42
+ text = (text or "").strip()
43
+ if not text:
44
+ raise gr.Error("Enter some text to speak.")
45
+ if len(text) > MAX_CHARS:
46
+ raise gr.Error(f"Text too long ({len(text)} chars, max {MAX_CHARS}).")
47
+ if voice not in TRANSCRIPTS:
48
+ raise gr.Error(f"Unknown voice '{voice}'. Available: {', '.join(VOICES)}")
49
+
50
+ wavs, sr = model.generate_voice_clone(
51
+ text=text,
52
+ language=language,
53
+ voice_clone_prompt=_get_voice_prompt(voice),
54
+ )
55
+ audio = np.asarray(wavs[0], dtype=np.float32)
56
+ return sr, audio
57
+
58
+
59
+ demo = gr.Interface(
60
+ fn=tts,
61
+ inputs=[
62
+ gr.Textbox(label="Text", lines=4, placeholder="What should the voice say?"),
63
+ gr.Dropdown(VOICES, value=VOICES[0], label="Voice"),
64
+ gr.Dropdown(LANGUAGES, value="English", label="Language"),
65
+ ],
66
+ outputs=gr.Audio(label="Generated speech"),
67
+ title="EsfandTTS — Qwen3-TTS voice clone",
68
+ description="Cloned voices via Qwen3-TTS 0.6B Base. Also callable as an API (see the 'Use via API' link below).",
69
+ flagging_mode="never",
70
+ )
71
+
72
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ qwen-tts==0.1.1
2
+ transformers==4.57.3
3
+ accelerate==1.12.0
4
+ huggingface-hub<1.0