Update App.py
Browse files
App.py
CHANGED
|
@@ -9,29 +9,42 @@ from pydantic import BaseModel
|
|
| 9 |
torch.set_num_threads(int(os.environ.get("TORCH_THREADS", "2")))
|
| 10 |
|
| 11 |
HERE = os.path.dirname(os.path.abspath(__file__))
|
| 12 |
-
SECRET = os.environ.get("TTS_SECRET_KEY", "")
|
| 13 |
-
|
|
|
|
| 14 |
VOICE_FILE = os.path.join(HERE, "voice.wav")
|
| 15 |
FALLBACK_VOICE = "hf://kyutai/tts-voices/alba-mackenna/casual.wav"
|
| 16 |
-
QUANTIZE = os.environ.get("TTS_QUANTIZE", "0") == "1"
|
| 17 |
MAX_CHARS = int(os.environ.get("MAX_CHARS", "6000"))
|
| 18 |
-
GAP_SECONDS = 0.22
|
| 19 |
|
| 20 |
model = None
|
| 21 |
voice_state = None
|
| 22 |
SR = 24000
|
| 23 |
state_msg = "loading"
|
|
|
|
| 24 |
gen_lock = threading.Lock()
|
| 25 |
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
def load_everything():
|
| 28 |
-
global model, voice_state, SR, state_msg
|
| 29 |
try:
|
| 30 |
from pocket_tts import TTSModel
|
|
|
|
|
|
|
| 31 |
try:
|
| 32 |
-
m = TTSModel.load_model(
|
| 33 |
except TypeError:
|
| 34 |
-
m = TTSModel.load_model(
|
| 35 |
if QUANTIZE:
|
| 36 |
try:
|
| 37 |
m = torch.quantization.quantize_dynamic(m, {torch.nn.Linear}, dtype=torch.qint8)
|
|
@@ -45,8 +58,9 @@ def load_everything():
|
|
| 45 |
model = m
|
| 46 |
state_msg = "ready"
|
| 47 |
print("Model ready, sample rate", SR)
|
| 48 |
-
except Exception:
|
| 49 |
state_msg = "error"
|
|
|
|
| 50 |
traceback.print_exc()
|
| 51 |
|
| 52 |
|
|
@@ -81,12 +95,10 @@ def split_clean(text: str):
|
|
| 81 |
parts = re.split(r"[\u0964\u0965\.\?\!\n;:]+", text)
|
| 82 |
out = []
|
| 83 |
for p in parts:
|
| 84 |
-
# sirf Devanagari (danda chhodkar), digits aur space rakho
|
| 85 |
p = re.sub(r"[^\u0900-\u0963\u0966-\u097F0-9\s]", " ", p)
|
| 86 |
p = re.sub(r"\s+", " ", p).strip()
|
| 87 |
if len(p) < 3:
|
| 88 |
continue
|
| 89 |
-
# bahut lambe vakya ko ~200 chars ke tukdon me todo
|
| 90 |
while len(p) > 220:
|
| 91 |
cut = p.rfind(" ", 0, 200)
|
| 92 |
cut = cut if cut > 50 else 200
|
|
@@ -113,7 +125,7 @@ def to_pcm16(a) -> bytes:
|
|
| 113 |
|
| 114 |
def pcm_stream(sentences):
|
| 115 |
silence = np.zeros(int(GAP_SECONDS * SR), dtype="<i2").tobytes()
|
| 116 |
-
with gen_lock:
|
| 117 |
for s in sentences:
|
| 118 |
try:
|
| 119 |
for a in iter_audio(s):
|
|
@@ -135,7 +147,7 @@ def root():
|
|
| 135 |
|
| 136 |
@app.get("/health")
|
| 137 |
def health():
|
| 138 |
-
return {"state": state_msg}
|
| 139 |
|
| 140 |
|
| 141 |
@app.post("/tts")
|
|
@@ -145,7 +157,7 @@ def tts(req: TTSReq, request: Request):
|
|
| 145 |
if state_msg == "loading":
|
| 146 |
return JSONResponse({"error": "model abhi load ho raha he, 1 minute baad try karo"}, status_code=503)
|
| 147 |
if state_msg == "error" or model is None:
|
| 148 |
-
return JSONResponse({"error": "model load fail hua
|
| 149 |
if len(req.text) > MAX_CHARS:
|
| 150 |
return JSONResponse({"error": f"text bahut lamba he (max {MAX_CHARS} characters)"}, status_code=413)
|
| 151 |
sentences = split_clean(req.text)
|
|
|
|
| 9 |
torch.set_num_threads(int(os.environ.get("TORCH_THREADS", "2")))
|
| 10 |
|
| 11 |
HERE = os.path.dirname(os.path.abspath(__file__))
|
| 12 |
+
SECRET = os.environ.get("TTS_SECRET_KEY", "") # Space Settings -> Secrets me daalo
|
| 13 |
+
MODEL_REPO = "saryps-labs/pocket-tts-hindi"
|
| 14 |
+
LOCAL_DIR = "/home/user/hindi_model"
|
| 15 |
VOICE_FILE = os.path.join(HERE, "voice.wav")
|
| 16 |
FALLBACK_VOICE = "hf://kyutai/tts-voices/alba-mackenna/casual.wav"
|
| 17 |
+
QUANTIZE = os.environ.get("TTS_QUANTIZE", "0") == "1"
|
| 18 |
MAX_CHARS = int(os.environ.get("MAX_CHARS", "6000"))
|
| 19 |
+
GAP_SECONDS = 0.22
|
| 20 |
|
| 21 |
model = None
|
| 22 |
voice_state = None
|
| 23 |
SR = 24000
|
| 24 |
state_msg = "loading"
|
| 25 |
+
last_error = ""
|
| 26 |
gen_lock = threading.Lock()
|
| 27 |
|
| 28 |
|
| 29 |
+
def get_config_path() -> str:
|
| 30 |
+
cfg = os.environ.get("TTS_CONFIG") or os.path.join(LOCAL_DIR, "config.yaml")
|
| 31 |
+
if not os.path.exists(cfg):
|
| 32 |
+
from huggingface_hub import snapshot_download
|
| 33 |
+
snapshot_download(MODEL_REPO, local_dir=LOCAL_DIR)
|
| 34 |
+
cfg = os.path.join(LOCAL_DIR, "config.yaml")
|
| 35 |
+
return cfg
|
| 36 |
+
|
| 37 |
+
|
| 38 |
def load_everything():
|
| 39 |
+
global model, voice_state, SR, state_msg, last_error
|
| 40 |
try:
|
| 41 |
from pocket_tts import TTSModel
|
| 42 |
+
cfg = get_config_path()
|
| 43 |
+
print("Config:", cfg)
|
| 44 |
try:
|
| 45 |
+
m = TTSModel.load_model(cfg, temp=0.3, lsd_decode_steps=1, eos_threshold=-1.0)
|
| 46 |
except TypeError:
|
| 47 |
+
m = TTSModel.load_model(cfg)
|
| 48 |
if QUANTIZE:
|
| 49 |
try:
|
| 50 |
m = torch.quantization.quantize_dynamic(m, {torch.nn.Linear}, dtype=torch.qint8)
|
|
|
|
| 58 |
model = m
|
| 59 |
state_msg = "ready"
|
| 60 |
print("Model ready, sample rate", SR)
|
| 61 |
+
except Exception as e:
|
| 62 |
state_msg = "error"
|
| 63 |
+
last_error = f"{type(e).__name__}: {e}"
|
| 64 |
traceback.print_exc()
|
| 65 |
|
| 66 |
|
|
|
|
| 95 |
parts = re.split(r"[\u0964\u0965\.\?\!\n;:]+", text)
|
| 96 |
out = []
|
| 97 |
for p in parts:
|
|
|
|
| 98 |
p = re.sub(r"[^\u0900-\u0963\u0966-\u097F0-9\s]", " ", p)
|
| 99 |
p = re.sub(r"\s+", " ", p).strip()
|
| 100 |
if len(p) < 3:
|
| 101 |
continue
|
|
|
|
| 102 |
while len(p) > 220:
|
| 103 |
cut = p.rfind(" ", 0, 200)
|
| 104 |
cut = cut if cut > 50 else 200
|
|
|
|
| 125 |
|
| 126 |
def pcm_stream(sentences):
|
| 127 |
silence = np.zeros(int(GAP_SECONDS * SR), dtype="<i2").tobytes()
|
| 128 |
+
with gen_lock:
|
| 129 |
for s in sentences:
|
| 130 |
try:
|
| 131 |
for a in iter_audio(s):
|
|
|
|
| 147 |
|
| 148 |
@app.get("/health")
|
| 149 |
def health():
|
| 150 |
+
return {"state": state_msg, "error": last_error}
|
| 151 |
|
| 152 |
|
| 153 |
@app.post("/tts")
|
|
|
|
| 157 |
if state_msg == "loading":
|
| 158 |
return JSONResponse({"error": "model abhi load ho raha he, 1 minute baad try karo"}, status_code=503)
|
| 159 |
if state_msg == "error" or model is None:
|
| 160 |
+
return JSONResponse({"error": "model load fail hua: " + last_error}, status_code=500)
|
| 161 |
if len(req.text) > MAX_CHARS:
|
| 162 |
return JSONResponse({"error": f"text bahut lamba he (max {MAX_CHARS} characters)"}, status_code=413)
|
| 163 |
sentences = split_clean(req.text)
|