R-TA commited on
Commit
2f04210
·
verified ·
1 Parent(s): 6046bd0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -4
app.py CHANGED
@@ -1,10 +1,14 @@
1
  import os
2
  import html
 
3
  import subprocess
4
  import tempfile
5
- from typing import Optional
6
 
7
  import gradio as gr
 
 
 
8
 
9
 
10
  DESCRIPTION = """
@@ -89,13 +93,20 @@ def _parse_voices(output: str):
89
  return mapping
90
 
91
 
92
- def load_voices():
93
  try:
94
  proc = subprocess.run(["mimic3", "--voices"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
95
  if proc.returncode != 0:
96
  err = proc.stderr.decode(errors="ignore")
97
  raise gr.Error(f"Failed to list voices.\n\n{err}")
98
- mapping = _parse_voices(proc.stdout.decode(errors="ignore"))
 
 
 
 
 
 
 
99
  if not mapping:
100
  raise gr.Error("No voices found. Try again after models are available.")
101
  languages = sorted(mapping.keys())
@@ -191,6 +202,74 @@ with gr.Blocks(title="Mimic 3 TTS") as demo:
191
  outputs=[audio],
192
  )
193
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  if __name__ == "__main__":
195
- demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
196
 
 
 
1
  import os
2
  import html
3
+ import base64
4
  import subprocess
5
  import tempfile
6
+ from typing import Optional, Dict, List, Tuple
7
 
8
  import gradio as gr
9
+ from fastapi import FastAPI, HTTPException
10
+ from fastapi.middleware.cors import CORSMiddleware
11
+ from pydantic import BaseModel
12
 
13
 
14
  DESCRIPTION = """
 
93
  return mapping
94
 
95
 
96
+ def _get_voice_mapping() -> Dict[str, List[str]]:
97
  try:
98
  proc = subprocess.run(["mimic3", "--voices"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
99
  if proc.returncode != 0:
100
  err = proc.stderr.decode(errors="ignore")
101
  raise gr.Error(f"Failed to list voices.\n\n{err}")
102
+ return _parse_voices(proc.stdout.decode(errors="ignore"))
103
+ except FileNotFoundError:
104
+ raise gr.Error("mimic3 CLI not found. Ensure 'mycroft-mimic3-tts' is installed.")
105
+
106
+
107
+ def load_voices():
108
+ try:
109
+ mapping = _get_voice_mapping()
110
  if not mapping:
111
  raise gr.Error("No voices found. Try again after models are available.")
112
  languages = sorted(mapping.keys())
 
202
  outputs=[audio],
203
  )
204
 
205
+ # --- FastAPI app and API endpoints ---
206
+
207
+ app = FastAPI(title="Mimic 3 TTS API")
208
+ app.add_middleware(
209
+ CORSMiddleware,
210
+ allow_origins=["*"],
211
+ allow_credentials=True,
212
+ allow_methods=["*"],
213
+ allow_headers=["*"],
214
+ )
215
+
216
+ # Mount Gradio UI at root path
217
+ from gradio.routes import mount_gradio_app # type: ignore
218
+ mount_gradio_app(app, demo, path="/")
219
+
220
+
221
+ class TtsRequest(BaseModel):
222
+ text: str
223
+ voice: Optional[str] = None
224
+ use_ssml: bool = False
225
+ rate: Optional[str] = None
226
+ pitch: Optional[str] = None
227
+
228
+
229
+ @app.get("/api/languages")
230
+ def api_languages():
231
+ mapping = _get_voice_mapping()
232
+ languages = sorted(mapping.keys())
233
+ return {"languages": languages}
234
+
235
+
236
+ @app.get("/api/voices")
237
+ def api_voices(language: Optional[str] = None):
238
+ mapping = _get_voice_mapping()
239
+ if language:
240
+ return {"voices": mapping.get(language, [])}
241
+ # Flattened list
242
+ all_voices: List[Tuple[str, str]] = []
243
+ for lang, voices in mapping.items():
244
+ all_voices.extend([(lang, v) for v in voices])
245
+ return {"voices_by_language": mapping, "all_voices": all_voices}
246
+
247
+
248
+ @app.post("/api/tts")
249
+ def api_tts(req: TtsRequest):
250
+ if not req.text or not req.text.strip():
251
+ raise HTTPException(status_code=400, detail="Text is required")
252
+ try:
253
+ out_path = synthesize(req.text, (req.voice or ""), req.use_ssml, (req.rate or ""), (req.pitch or ""))
254
+ if not out_path or not os.path.exists(out_path):
255
+ raise HTTPException(status_code=500, detail="TTS synthesis failed")
256
+ with open(out_path, "rb") as f:
257
+ wav_bytes = f.read()
258
+ audio_b64 = base64.b64encode(wav_bytes).decode()
259
+ return {
260
+ "mime_type": "audio/wav",
261
+ "audio_base64": audio_b64,
262
+ "voice": req.voice,
263
+ }
264
+ finally:
265
+ try:
266
+ if out_path and os.path.exists(out_path):
267
+ os.remove(out_path)
268
+ except Exception:
269
+ pass
270
+
271
+
272
  if __name__ == "__main__":
273
+ import uvicorn
274
 
275
+ uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 7860)))