randusertry commited on
Commit
c2b7e8e
·
verified ·
1 Parent(s): b7b963f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -12
app.py CHANGED
@@ -3,6 +3,7 @@ from fastapi.responses import StreamingResponse
3
  from piper import PiperVoice
4
  import io
5
  import os
 
6
 
7
  app = FastAPI()
8
 
@@ -10,6 +11,34 @@ app = FastAPI()
10
  MODEL_DIR = "./models"
11
  os.makedirs(MODEL_DIR, exist_ok=True)
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  # Cache for loaded models to avoid re-loading from disk every request
14
  loaded_voices = {}
15
 
@@ -25,20 +54,42 @@ def get_voice(model_name: str):
25
  loaded_voices[model_name] = PiperVoice.load(model_path, config_path)
26
  return loaded_voices[model_name]
27
 
28
- @app.get("/tts")
29
- async def tts(text: str, model: str = "en_US-lessac-medium"):
 
 
 
 
 
30
  try:
31
- voice = get_voice(model)
32
-
33
- # Create an in-memory buffer for the WAV file
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  wav_buffer = io.BytesIO()
35
- with io.BytesIO() as f:
36
- voice.synthesize(text, f)
37
- audio_data = f.getvalue()
38
-
39
- return Response(content=audio_data, media_type="audio/wav")
40
  except Exception as e:
41
- return {"error": str(e)}
42
 
43
  @app.get("/health")
44
  def home():
@@ -46,4 +97,4 @@ def home():
46
 
47
  @app.get("/")
48
  def home():
49
- return {"status": "Piper TTS is running"}
 
3
  from piper import PiperVoice
4
  import io
5
  import os
6
+ from pydantic import BaseModel
7
 
8
  app = FastAPI()
9
 
 
11
  MODEL_DIR = "./models"
12
  os.makedirs(MODEL_DIR, exist_ok=True)
13
 
14
+ VOICE_MAP = {
15
+ # Gendered Languages (Male and Female models available)
16
+ "en": {"gendered": True, "male": "en_GB-alan-medium", "female": "en_GB-semaine-medium"},
17
+ "es": {"gendered": True, "male": "es_ES-sharvard-medium", "female": "es_ES-carlota-low"},
18
+ "fr": {"gendered": True, "male": "fr_FR-upmc-medium", "female": "fr_FR-siwis-low"},
19
+ "de": {"gendered": True, "male": "de_DE-thorsten-medium", "female": "de_DE-kerstin-low"},
20
+ "it": {"gendered": True, "male": "it_IT-riccardo-x_low", "female": "it_IT-paola-medium"},
21
+ "pl": {"gendered": True, "male": "pl_PL-dark_ness-medium", "female": "pl_PL-gosia-medium"},
22
+ "uk": {"gendered": True, "male": "uk_UA-ukrainian_tts-medium", "female": "uk_UA-lada-medium"},
23
+ "nl": {"gendered": True, "male": "nl_NL-ronnie-medium", "female": "nl_NL-mls-medium"},
24
+
25
+ # Non-Gendered / Single-Voice Languages (Default model used)
26
+ "bg": {"gendered": False, "default": "bg_BG-dimitar-medium"},
27
+ "ca": {"gendered": False, "default": "ca_ES-upc_ona-medium"},
28
+ "cs": {"gendered": False, "default": "cs_CZ-jirka-medium"},
29
+ "da": {"gendered": False, "default": "da_DK-talesyntese-medium"},
30
+ "fi": {"gendered": False, "default": "fi_FI-harri-medium"},
31
+ "el": {"gendered": False, "default": "el_GR-rapotakis-low"},
32
+ "hu": {"gendered": False, "default": "hu_HU-mls-medium"},
33
+ "is": {"gendered": False, "default": "is_IS-ugla-medium"},
34
+ "lv": {"gendered": False, "default": "lv_LV-sanda-medium"},
35
+ "ro": {"gendered": False, "default": "ro_RO-mls-medium"},
36
+ "sk": {"gendered": False, "default": "sk_SK-lili-medium"},
37
+ "sl": {"gendered": False, "default": "sl_SI-artificer-medium"},
38
+ "sv": {"gendered": False, "default": "sv_SE-extf0-medium"},
39
+ "cy": {"gendered": False, "default": "cy_GB-bu-tts-medium"}
40
+ }
41
+
42
  # Cache for loaded models to avoid re-loading from disk every request
43
  loaded_voices = {}
44
 
 
54
  loaded_voices[model_name] = PiperVoice.load(model_path, config_path)
55
  return loaded_voices[model_name]
56
 
57
+ class TTSRequest(BaseModel):
58
+ text: str
59
+ language: str
60
+ gender: str
61
+
62
+ @app.post("/tts")
63
+ async def tts_post(request: TTSRequest):
64
  try:
65
+ lang_code = request.language.lower()
66
+ gender_req = request.gender.lower()
67
+
68
+ # 1. Get the language entry
69
+ lang_entry = VOICE_MAP.get(lang_code)
70
+ if not lang_entry:
71
+ raise HTTPException(status_code=400, detail=f"Language '{lang_code}' not supported.")
72
+
73
+ # 2. Determine which model file to use
74
+ if lang_entry["gendered"]:
75
+ # If gendered, try to get the requested gender
76
+ model_name = lang_entry.get(gender_req)
77
+ if not model_name:
78
+ # Fallback to male if requested gender isn't found in a gendered set
79
+ model_name = lang_entry["male"]
80
+ else:
81
+ # If not gendered, use the default key
82
+ model_name = lang_entry["default"]
83
+
84
+ # 3. Load and Synthesize
85
+ voice = get_voice(model_name)
86
  wav_buffer = io.BytesIO()
87
+ voice.synthesize(request.text, wav_buffer)
88
+
89
+ return Response(content=wav_buffer.getvalue(), media_type="audio/wav")
90
+
 
91
  except Exception as e:
92
+ raise HTTPException(status_code=500, detail=str(e))
93
 
94
  @app.get("/health")
95
  def home():
 
97
 
98
  @app.get("/")
99
  def home():
100
+ return {"languages": VOICE_MAP}