ayb-bh1146 commited on
Commit
d6b8eff
ยท
verified ยท
1 Parent(s): 7376ece
Files changed (1) hide show
  1. app.py +138 -0
app.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Piper TTS โ€” Hugging Face Space (CPU Free Tier)
3
+ ูŠุนู…ู„ ุนู„ู‰ CPU ุงู„ู…ุฌุงู†ูŠ ุจุฏูˆู† GPU
4
+ """
5
+ import os
6
+ import subprocess
7
+ import tempfile
8
+ import gradio as gr
9
+
10
+ # โ”€โ”€ ุชุญู…ูŠู„ ุงู„ุฃุตูˆุงุช ุนู†ุฏ ุจุฏุก ุงู„ุชุดุบูŠู„ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
11
+ os.makedirs("voices", exist_ok=True)
12
+
13
+ VOICES = {
14
+ "ุนุฑุจูŠ ๐Ÿ‡ฏ๐Ÿ‡ด (ูƒุฑูŠู…)": {
15
+ "model": "voices/ar.onnx",
16
+ "url_onnx": "https://huggingface.co/rhasspy/piper-voices/resolve/main/ar/ar_JO/kareem/medium/ar_JO-kareem-medium.onnx",
17
+ "url_json": "https://huggingface.co/rhasspy/piper-voices/resolve/main/ar/ar_JO/kareem/medium/ar_JO-kareem-medium.onnx.json",
18
+ },
19
+ "English ๐Ÿ‡บ๐Ÿ‡ธ (Lessac)": {
20
+ "model": "voices/en.onnx",
21
+ "url_onnx": "https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/lessac/medium/en_US-lessac-medium.onnx",
22
+ "url_json": "https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/lessac/medium/en_US-lessac-medium.onnx.json",
23
+ },
24
+ "English ๐Ÿ‡ฌ๐Ÿ‡ง (Alan)": {
25
+ "model": "voices/en_gb.onnx",
26
+ "url_onnx": "https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_GB/alan/medium/en_GB-alan-medium.onnx",
27
+ "url_json": "https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_GB/alan/medium/en_GB-alan-medium.onnx.json",
28
+ },
29
+ }
30
+
31
+ def download_voice(info: dict):
32
+ onnx = info["model"]
33
+ json = onnx + ".json"
34
+ if not os.path.exists(onnx):
35
+ print(f"โณ Downloading {onnx}...")
36
+ subprocess.run(["wget", "-q", "-O", onnx, info["url_onnx"]], check=True)
37
+ subprocess.run(["wget", "-q", "-O", json, info["url_json"]], check=True)
38
+ print(f"โœ… {onnx} ready!")
39
+
40
+ # ุชุญู…ูŠู„ ูƒู„ ุงู„ุฃุตูˆุงุช ุนู†ุฏ ุงู„ุจุฏุงูŠุฉ
41
+ for name, info in VOICES.items():
42
+ try:
43
+ download_voice(info)
44
+ except Exception as e:
45
+ print(f"โš ๏ธ Could not download {name}: {e}")
46
+
47
+
48
+ # โ”€โ”€ ุฏุงู„ุฉ ุงู„ุชูˆู„ูŠุฏ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
49
+ def synthesize(text: str, voice_name: str):
50
+ if not text.strip():
51
+ raise gr.Error("โš ๏ธ ู…ู† ูุถู„ูƒ ุงูƒุชุจ ู†ุตุงู‹ ุฃูˆู„ุงู‹!")
52
+
53
+ info = VOICES[voice_name]
54
+ model_path = info["model"]
55
+
56
+ if not os.path.exists(model_path):
57
+ raise gr.Error(f"โš ๏ธ ุงู„ุตูˆุช ุบูŠุฑ ู…ุชุงุญุŒ ุญุงูˆู„ ู…ุฑุฉ ุฃุฎุฑู‰ ุจุนุฏ ู‚ู„ูŠู„.")
58
+
59
+ with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
60
+ output_path = tmp.name
61
+
62
+ result = subprocess.run(
63
+ f'echo "{text}" | python -m piper --model {model_path} --output_file {output_path}',
64
+ shell=True,
65
+ capture_output=True,
66
+ text=True,
67
+ )
68
+
69
+ if result.returncode != 0 or not os.path.exists(output_path):
70
+ raise gr.Error(f"ุฎุทุฃ ููŠ ุงู„ุชูˆู„ูŠุฏ: {result.stderr[:200]}")
71
+
72
+ return output_path
73
+
74
+
75
+ # โ”€โ”€ ูˆุงุฌู‡ุฉ Gradio โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
76
+ css = """
77
+ .gradio-container { max-width: 750px !important; margin: 0 auto !important; }
78
+ """
79
+
80
+ EXAMPLES = [
81
+ ["ู…ุฑุญุจุงู‹ ุจูƒ ููŠ ุนุงู„ู… ุงู„ุฐูƒุงุก ุงู„ุงุตุทู†ุงุนูŠ!", "ุนุฑุจูŠ ๐Ÿ‡ฏ๐Ÿ‡ด (ูƒุฑูŠู…)"],
82
+ ["ุงู„ูŠูˆู… ุทู‚ุณ ุฌู…ูŠู„ ูˆุงู„ุณู…ุงุก ุตุงููŠุฉ ูˆุฒุฑู‚ุงุก.", "ุนุฑุจูŠ ๐Ÿ‡ฏ๐Ÿ‡ด (ูƒุฑูŠู…)"],
83
+ ["Hello! Welcome to Piper text to speech.", "English ๐Ÿ‡บ๐Ÿ‡ธ (Lessac)"],
84
+ ["The quick brown fox jumps over the lazy dog.", "English ๐Ÿ‡ฌ๐Ÿ‡ง (Alan)"],
85
+ ]
86
+
87
+ with gr.Blocks(css=css, title="Piper TTS") as demo:
88
+ gr.Markdown("# ๐Ÿ”Š Piper TTS โ€” ู†ุต ุฅู„ู‰ ุตูˆุช")
89
+ gr.Markdown(
90
+ "ุญูˆู‘ู„ ุฃูŠ ู†ุต ุนุฑุจูŠ ุฃูˆ ุฅู†ุฌู„ูŠุฒูŠ ุฅู„ู‰ ูƒู„ุงู… ููˆุฑุงู‹ โ€” "
91
+ "ูŠุนู…ู„ ู…ุญู„ูŠุงู‹ ุจุฏูˆู† ุฅู†ุชุฑู†ุช ูˆุจุณุฑุนุฉ ูุงุฆู‚ุฉ! โšก"
92
+ )
93
+
94
+ with gr.Row():
95
+ with gr.Column():
96
+ voice_dd = gr.Dropdown(
97
+ choices=list(VOICES.keys()),
98
+ value="ุนุฑุจูŠ ๐Ÿ‡ฏ๐Ÿ‡ด (ูƒุฑูŠู…)",
99
+ label="ุงู„ุตูˆุช",
100
+ )
101
+ text_in = gr.Textbox(
102
+ label="ุงู„ู†ุต",
103
+ placeholder="ุงูƒุชุจ ู‡ู†ุง...",
104
+ lines=5,
105
+ value="ู…ุฑุญุจุงู‹ุŒ ู‡ุฐุง ุงุฎุชุจุงุฑ ู„ู…ูƒุชุจุฉ ุจุงูŠุจุฑ ู„ุชุญูˆูŠู„ ุงู„ู†ุต ุฅู„ู‰ ูƒู„ุงู….",
106
+ )
107
+ btn = gr.Button("๐Ÿ”Š ุชูˆู„ูŠุฏ ุงู„ุตูˆุช", variant="primary", size="lg")
108
+
109
+ with gr.Column():
110
+ audio_out = gr.Audio(
111
+ label="ุงู„ุตูˆุช ุงู„ู…ูˆู„ูŽู‘ุฏ",
112
+ type="filepath",
113
+ autoplay=True,
114
+ )
115
+
116
+ btn.click(
117
+ fn=synthesize,
118
+ inputs=[text_in, voice_dd],
119
+ outputs=audio_out,
120
+ )
121
+
122
+ gr.Examples(
123
+ examples=EXAMPLES,
124
+ inputs=[text_in, voice_dd],
125
+ outputs=audio_out,
126
+ fn=synthesize,
127
+ cache_examples=True,
128
+ )
129
+
130
+ gr.Markdown(
131
+ "### ๐Ÿ’ก ู†ุตุงุฆุญ\n"
132
+ "- ุงู„ุตูˆุช ูŠููˆู„ูŽู‘ุฏ ููŠ **ุฃู‚ู„ ู…ู† ุซุงู†ูŠุฉ** โšก\n"
133
+ "- ูŠุฏุนู… ุงู„ู†ุตูˆุต ุงู„ุทูˆูŠู„ุฉ\n"
134
+ "- ูŠู…ูƒู†ูƒ ุชุญู…ูŠู„ ุงู„ุตูˆุช ุจุงู„ุถุบุท ุนู„ู‰ โฌ‡๏ธ"
135
+ )
136
+
137
+ if __name__ == "__main__":
138
+ demo.queue(max_size=5).launch()