TGPro1 commited on
Commit
376aa42
Β·
verified Β·
1 Parent(s): 10dd7ed

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +38 -48
app.py CHANGED
@@ -11,13 +11,13 @@ from fastapi.middleware.cors import CORSMiddleware
11
  from fastapi.responses import HTMLResponse
12
  import uvicorn
13
 
14
- # --- [v142] πŸš€ REFINED HYBRID ENGINE (CPU STT + GPU TTS) ---
15
- print(f"--- [v142] πŸ“‘ BOOTING REFINED HYBRID ---")
16
 
17
- # Top-level imports for stability
18
  from transformers import pipeline, AutoModelForSpeechSeq2Seq, AutoProcessor
19
  from TTS.api import TTS
20
  from deep_translator import GoogleTranslator
 
21
  try:
22
  import chatterbox_utils
23
  HAS_CHATTERBOX = True
@@ -35,7 +35,6 @@ except ImportError:
35
  if f is None: return lambda x: x
36
  return f
37
 
38
- # --- Global Sync ---
39
  os.environ["COQUI_TOS_AGREED"] = "1"
40
  os.environ["PYTHONWARNINGS"] = "ignore"
41
 
@@ -45,54 +44,34 @@ app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], all
45
  MODELS = {"stt": None, "tts": None}
46
 
47
  def load_cpu_stt():
48
- """Loads Whisper on CPU for maximum stability."""
49
  global MODELS
50
  if MODELS.get("stt") is None:
51
- print("--- [v142] πŸ“₯ LOADING WHISPER ON CPU ---")
52
  model_id = "openai/whisper-large-v3-turbo"
53
- model = AutoModelForSpeechSeq2Seq.from_pretrained(
54
- model_id, torch_dtype=torch.float32, low_cpu_mem_usage=True
55
- ) # CPU handles FP32 best
56
  processor = AutoProcessor.from_pretrained(model_id)
57
- MODELS["stt"] = pipeline(
58
- "automatic-speech-recognition",
59
- model=model,
60
- tokenizer=processor.tokenizer,
61
- feature_extractor=processor.feature_extractor,
62
- device="cpu"
63
- )
64
- print("--- [v142] βœ… WHISPER LOADED (CPU) ---")
65
 
66
- @spaces.GPU(duration=120)
67
- def load_gpu_tts():
68
- """Loads XTTS on GPU for maximum speed."""
69
  global MODELS
70
  if MODELS.get("tts") is None:
71
- print("--- [v142] πŸ“₯ LOADING XTTS ON GPU ---")
72
  MODELS["tts"] = TTS("tts_models/multilingual/multi-dataset/xtts_v2").to("cuda")
73
- print("--- [v142] βœ… XTTS LOADED (GPU) ---")
74
-
75
- def stt_process_internal(audio_b64, lang):
76
- load_cpu_stt()
77
- audio_bytes = base64.b64decode(audio_b64)
78
- with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
79
- f.write(audio_bytes); temp_path = f.name
80
- try:
81
- result = MODELS["stt"](temp_path, generate_kwargs={"language": lang if lang and len(lang) <= 3 else None})
82
- return result["text"].strip()
83
- finally:
84
- if os.path.exists(temp_path): os.unlink(temp_path)
85
 
86
  @spaces.GPU(duration=120)
87
- def tts_process_internal(text, target_lang, speaker_wav_b64=None):
88
- load_gpu_tts()
 
89
  XTTS_MAP = {"en": "en", "de": "de", "fr": "fr", "es": "es", "it": "it", "pl": "pl", "pt": "pt", "tr": "tr", "ru": "ru", "nl": "nl", "cs": "cs", "ar": "ar", "hu": "hu", "ko": "ko", "hi": "hi", "zh": "zh-cn"}
90
  clean_lang = target_lang.split('-')[0].lower()
91
  mapped_lang = XTTS_MAP.get(clean_lang) or ("zh-cn" if clean_lang == "zh" else None)
92
 
93
  if not mapped_lang:
94
  if HAS_CHATTERBOX:
95
- print(f"--- [v142] πŸ“¦ USING CHATTERBOX FOR {clean_lang} ---")
96
  audio_bytes = chatterbox_utils.run_chatterbox_inference(text, clean_lang)
97
  return base64.b64encode(audio_bytes).decode()
98
  return {"error": f"Language {clean_lang} not supported."}
@@ -114,27 +93,37 @@ def tts_process_internal(text, target_lang, speaker_wav_b64=None):
114
  if speaker_wav_b64 and os.path.exists(speaker_wav_path): os.unlink(speaker_wav_path)
115
  if 'out_p' in locals() and os.path.exists(out_p): os.unlink(out_p)
116
 
 
 
 
 
 
 
 
 
 
 
 
117
  @app.post("/process")
118
  async def api_process(request: Request):
119
  try:
120
  data = await request.json()
121
  action = data.get("action")
122
- if action == "health": return {"status": "awake", "v": "142", "gpu": HAS_SPACES}
123
 
124
- print(f"--- [v142] πŸ› οΈ HYBRID ENGINE: {action} ---")
125
  t1 = time.time()
126
 
127
- # πŸŽ™οΈ STT (CPU Segment)
128
  stt_text = None
129
  if action in ["stt", "s2st"]:
130
- stt_text = stt_process_internal(data.get("file"), data.get("lang"))
131
  if action == "stt": return {"text": stt_text}
132
 
133
- # πŸ”Š TTS (GPU Segment)
134
  if action in ["tts", "s2st"]:
135
  text = (data.get("text") if action == "tts" else stt_text).strip()
136
  trans_text = text
137
-
138
  if action == "s2st":
139
  target = data.get("target_lang") or "en"
140
  trans_text = GoogleTranslator(source='auto', target=target).translate(stt_text)
@@ -142,23 +131,24 @@ async def api_process(request: Request):
142
 
143
  if len(text) < 2: return {"audio": ""} if action == "tts" else {"text": stt_text, "translated": "", "audio": ""}
144
 
145
- audio_res = tts_process_internal(text, (data.get("lang") if action == "tts" else target), data.get("speaker_wav"))
146
- if isinstance(audio_res, dict) and "error" in audio_res: return audio_res
147
 
 
148
  if action == "tts": return {"audio": audio_res}
149
  return {"text": stt_text, "translated": trans_text, "audio": audio_res}
150
 
151
  except Exception as e:
152
- print(f"❌ [v142] ERROR: {traceback.format_exc()}")
153
  return {"error": str(e)}
154
  finally:
155
- print(f"--- [v142] ✨ DONE ({time.time()-t1:.1f}s) ---")
156
 
157
  @app.get("/health")
158
- def health(): return {"status": "ok", "v": "142", "mode": "HYBRID", "gpu": HAS_SPACES}
159
 
160
  @app.get("/", response_class=HTMLResponse)
161
- def root(): return "<html><body><h1>πŸš€ AI Engine v142 (PRODUCTION HYBRID)</h1></body></html>"
162
 
163
  if __name__ == "__main__":
164
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
11
  from fastapi.responses import HTMLResponse
12
  import uvicorn
13
 
14
+ # --- [v143] πŸš€ SEAMLESS HYBRID ENGINE (CPU STT + GPU TTS / FIX NESTING) ---
15
+ print(f"--- [v143] πŸ“‘ BOOTING SEAMLESS HYBRID ---")
16
 
 
17
  from transformers import pipeline, AutoModelForSpeechSeq2Seq, AutoProcessor
18
  from TTS.api import TTS
19
  from deep_translator import GoogleTranslator
20
+
21
  try:
22
  import chatterbox_utils
23
  HAS_CHATTERBOX = True
 
35
  if f is None: return lambda x: x
36
  return f
37
 
 
38
  os.environ["COQUI_TOS_AGREED"] = "1"
39
  os.environ["PYTHONWARNINGS"] = "ignore"
40
 
 
44
  MODELS = {"stt": None, "tts": None}
45
 
46
  def load_cpu_stt():
47
+ """Loads Whisper on CPU."""
48
  global MODELS
49
  if MODELS.get("stt") is None:
50
+ print("--- [v143] πŸ“₯ LOADING WHISPER ON CPU ---")
51
  model_id = "openai/whisper-large-v3-turbo"
52
+ model = AutoModelForSpeechSeq2Seq.from_pretrained(model_id, torch_dtype=torch.float32, low_cpu_mem_usage=True)
 
 
53
  processor = AutoProcessor.from_pretrained(model_id)
54
+ MODELS["stt"] = pipeline("automatic-speech-recognition", model=model, tokenizer=processor.tokenizer, feature_extractor=processor.feature_extractor, device="cpu")
55
+ print("--- [v143] βœ… WHISPER LOADED (CPU) ---")
 
 
 
 
 
 
56
 
57
+ def load_gpu_tts_internal():
58
+ """Loads XTTS on GPU (called within @spaces.GPU). No decorator here to avoid nesting."""
 
59
  global MODELS
60
  if MODELS.get("tts") is None:
61
+ print("--- [v143] πŸ“₯ LOADING XTTS ON GPU ---")
62
  MODELS["tts"] = TTS("tts_models/multilingual/multi-dataset/xtts_v2").to("cuda")
63
+ print("--- [v143] βœ… XTTS LOADED (GPU) ---")
 
 
 
 
 
 
 
 
 
 
 
64
 
65
  @spaces.GPU(duration=120)
66
+ def tts_process_gpu(text, target_lang, speaker_wav_b64=None):
67
+ """The ONLY @spaces.GPU entry point for TTS."""
68
+ load_gpu_tts_internal()
69
  XTTS_MAP = {"en": "en", "de": "de", "fr": "fr", "es": "es", "it": "it", "pl": "pl", "pt": "pt", "tr": "tr", "ru": "ru", "nl": "nl", "cs": "cs", "ar": "ar", "hu": "hu", "ko": "ko", "hi": "hi", "zh": "zh-cn"}
70
  clean_lang = target_lang.split('-')[0].lower()
71
  mapped_lang = XTTS_MAP.get(clean_lang) or ("zh-cn" if clean_lang == "zh" else None)
72
 
73
  if not mapped_lang:
74
  if HAS_CHATTERBOX:
 
75
  audio_bytes = chatterbox_utils.run_chatterbox_inference(text, clean_lang)
76
  return base64.b64encode(audio_bytes).decode()
77
  return {"error": f"Language {clean_lang} not supported."}
 
93
  if speaker_wav_b64 and os.path.exists(speaker_wav_path): os.unlink(speaker_wav_path)
94
  if 'out_p' in locals() and os.path.exists(out_p): os.unlink(out_p)
95
 
96
+ def stt_process_cpu(audio_b64, lang):
97
+ load_cpu_stt()
98
+ audio_bytes = base64.b64decode(audio_b64)
99
+ with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
100
+ f.write(audio_bytes); temp_path = f.name
101
+ try:
102
+ result = MODELS["stt"](temp_path, generate_kwargs={"language": lang if lang and len(lang) <= 3 else None})
103
+ return result["text"].strip()
104
+ finally:
105
+ if os.path.exists(temp_path): os.unlink(temp_path)
106
+
107
  @app.post("/process")
108
  async def api_process(request: Request):
109
  try:
110
  data = await request.json()
111
  action = data.get("action")
112
+ if action == "health": return {"status": "awake", "v": "143"}
113
 
114
+ print(f"--- [v143] πŸ› οΈ HYBRID ACTION: {action} ---")
115
  t1 = time.time()
116
 
117
+ # πŸŽ™οΈ STT Segment (CPU)
118
  stt_text = None
119
  if action in ["stt", "s2st"]:
120
+ stt_text = stt_process_cpu(data.get("file"), data.get("lang"))
121
  if action == "stt": return {"text": stt_text}
122
 
123
+ # πŸ”Š TTS Segment (GPU)
124
  if action in ["tts", "s2st"]:
125
  text = (data.get("text") if action == "tts" else stt_text).strip()
126
  trans_text = text
 
127
  if action == "s2st":
128
  target = data.get("target_lang") or "en"
129
  trans_text = GoogleTranslator(source='auto', target=target).translate(stt_text)
 
131
 
132
  if len(text) < 2: return {"audio": ""} if action == "tts" else {"text": stt_text, "translated": "", "audio": ""}
133
 
134
+ # This is the single @spaces.GPU gated call
135
+ audio_res = tts_process_gpu(text, (data.get("lang") if action == "tts" else target), data.get("speaker_wav"))
136
 
137
+ if isinstance(audio_res, dict) and "error" in audio_res: return audio_res
138
  if action == "tts": return {"audio": audio_res}
139
  return {"text": stt_text, "translated": trans_text, "audio": audio_res}
140
 
141
  except Exception as e:
142
+ print(f"❌ [v143] ERROR: {traceback.format_exc()}")
143
  return {"error": str(e)}
144
  finally:
145
+ print(f"--- [v143] ✨ DONE ({time.time()-t1:.1f}s) ---")
146
 
147
  @app.get("/health")
148
+ def health(): return {"status": "ok", "v": "143", "mode": "HYBRID"}
149
 
150
  @app.get("/", response_class=HTMLResponse)
151
+ def root(): return "<html><body><h1>πŸš€ AI Engine v143 (SEAMLESS HYBRID)</h1></body></html>"
152
 
153
  if __name__ == "__main__":
154
  uvicorn.run(app, host="0.0.0.0", port=7860)