TGPro1 commited on
Commit
6a4b0e8
Β·
verified Β·
1 Parent(s): d87ca63

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +95 -59
app.py CHANGED
@@ -5,19 +5,25 @@ import base64
5
  import torch
6
  import tempfile
7
  import traceback
 
8
  from fastapi import FastAPI, Request
9
  from fastapi.middleware.cors import CORSMiddleware
10
  from fastapi.responses import HTMLResponse
11
  import uvicorn
12
- import scipy.io.wavfile
13
 
14
- # --- [v147] πŸš€ HYBRID ENGINE: GPU-STT + CPU-TTS ---
15
- print(f"--- [v147] πŸ“‘ BOOTING HYBRID ENGINE ---")
16
 
17
- from transformers import pipeline, SpeechT5Processor, SpeechT5ForTextToSpeech, SpeechT5HifiGan
18
- from datasets import load_dataset
19
  from deep_translator import GoogleTranslator
20
 
 
 
 
 
 
 
21
  try:
22
  import spaces
23
  HAS_SPACES = True
@@ -30,110 +36,140 @@ except ImportError:
30
  return func
31
  return decorator
32
 
 
33
  os.environ["COQUI_TOS_AGREED"] = "1"
34
  os.environ["PYTHONWARNINGS"] = "ignore"
 
 
35
 
36
  app = FastAPI()
37
  app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
38
 
39
- MODELS = {"stt": None, "tts_processor": None, "tts_model": None, "tts_vocoder": None, "tts_speaker": None}
40
-
41
- # Load TTS at startup (CPU)
42
- print("--- [v147] πŸ“₯ LOADING TTS (SpeechT5) ON CPU ---")
43
- MODELS["tts_processor"] = SpeechT5Processor.from_pretrained("microsoft/speecht5_tts")
44
- MODELS["tts_model"] = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts")
45
- MODELS["tts_vocoder"] = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")
46
- embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation")
47
- MODELS["tts_speaker"] = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0)
48
- print("--- [v147] βœ… TTS READY (CPU) ---")
49
 
50
- @spaces.GPU(duration=60)
51
- def process_stt(audio_b64, lang):
52
- """Speech-to-Text on GPU (Whisper)"""
53
  global MODELS
54
-
55
  if MODELS.get("stt") is None:
56
- print("--- [v147] πŸ“₯ LOADING WHISPER ON GPU ---")
 
 
 
 
 
 
57
  MODELS["stt"] = pipeline(
58
  "automatic-speech-recognition",
59
- model="openai/whisper-base",
 
 
 
60
  device="cuda",
61
- torch_dtype=torch.float32
62
  )
63
- print("--- [v147] βœ… WHISPER READY (GPU) ---")
64
-
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  audio_bytes = base64.b64decode(audio_b64)
66
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
67
- f.write(audio_bytes)
68
- temp_path = f.name
69
  try:
70
- result = MODELS["stt"](temp_path, generate_kwargs={"language": lang if lang and len(lang) <= 3 else None})
 
71
  return result["text"].strip()
72
  finally:
73
- if os.path.exists(temp_path):
74
- os.unlink(temp_path)
75
-
76
- def process_tts(text):
77
- """Text-to-Speech on CPU (SpeechT5)"""
78
- inputs = MODELS["tts_processor"](text=text, return_tensors="pt")
79
- speech = MODELS["tts_model"].generate_speech(inputs["input_ids"], MODELS["tts_speaker"], vocoder=MODELS["tts_vocoder"])
 
80
 
81
- with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as out_f:
82
- out_p = out_f.name
83
- scipy.io.wavfile.write(out_p, rate=16000, data=speech.numpy())
 
 
 
84
 
85
- with open(out_p, "rb") as f:
86
- audio_b64 = base64.b64encode(f.read()).decode()
87
- os.unlink(out_p)
88
- return audio_b64
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  @app.post("/process")
91
  async def api_process(request: Request):
92
  try:
93
  data = await request.json()
94
  action = data.get("action")
95
- if action == "health":
96
- return {"status": "awake", "v": "147", "mode": "HYBRID_GPU_STT_CPU_TTS"}
97
 
98
- print(f"--- [v147] πŸ› οΈ PROCESSING: {action} ---")
99
  t1 = time.time()
100
 
 
101
  stt_text = None
102
  if action in ["stt", "s2st"]:
103
- stt_text = process_stt(data.get("file"), data.get("lang"))
104
- if action == "stt":
105
- return {"text": stt_text}
106
 
 
107
  if action in ["tts", "s2st"]:
108
  text = (data.get("text") if action == "tts" else stt_text).strip()
109
  trans_text = text
 
110
  if action == "s2st":
111
  target = data.get("target_lang") or "en"
112
  trans_text = GoogleTranslator(source='auto', target=target).translate(stt_text)
113
  text = trans_text
114
 
115
- if len(text) < 2:
116
- return {"audio": ""} if action == "tts" else {"text": stt_text, "translated": "", "audio": ""}
117
 
118
- audio_b64 = process_tts(text)
119
 
120
- if action == "tts":
121
- return {"audio": audio_b64}
122
- return {"text": stt_text, "translated": trans_text, "audio": audio_b64}
123
 
124
  except Exception as e:
125
- print(f"❌ [v147] ERROR: {traceback.format_exc()}")
126
  return {"error": str(e)}
127
  finally:
128
- print(f"--- [v147] ✨ DONE ({time.time()-t1:.1f}s) ---")
 
129
 
130
  @app.get("/health")
131
- def health():
132
- return {"status": "ok", "v": "147", "mode": "HYBRID_GPU_STT_CPU_TTS", "spaces": HAS_SPACES}
133
 
134
  @app.get("/", response_class=HTMLResponse)
135
- def root():
136
- return f"<html><body><h1>πŸš€ AI Engine v147 (HYBRID)</h1><p>STT: GPU Whisper | TTS: CPU SpeechT5</p></body></html>"
137
 
138
  if __name__ == "__main__":
139
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
5
  import torch
6
  import tempfile
7
  import traceback
8
+ import gc
9
  from fastapi import FastAPI, Request
10
  from fastapi.middleware.cors import CORSMiddleware
11
  from fastapi.responses import HTMLResponse
12
  import uvicorn
 
13
 
14
+ # --- [v148] πŸš€ FULL FEATURE H200 ENGINE (STT + TRANS + TTS + FALLBACK) ---
15
+ print(f"--- [v148] πŸ“‘ BOOTING FULL ENGINE ---")
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
24
+ except ImportError:
25
+ HAS_CHATTERBOX = False
26
+
27
  try:
28
  import spaces
29
  HAS_SPACES = True
 
36
  return func
37
  return decorator
38
 
39
+ # --- System Config & Stability Flags ---
40
  os.environ["COQUI_TOS_AGREED"] = "1"
41
  os.environ["PYTHONWARNINGS"] = "ignore"
42
+ # Disable libraries that might conflict with MIG partitions
43
+ os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8"
44
 
45
  app = FastAPI()
46
  app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
47
 
48
+ MODELS = {"stt": None, "tts": None}
 
 
 
 
 
 
 
 
 
49
 
50
+ def load_stt_gpu():
51
+ """Load Whisper on GPU with stability flags."""
 
52
  global MODELS
 
53
  if MODELS.get("stt") is None:
54
+ print("--- [v148] πŸ“₯ LOADING WHISPER (Large-v3-Turbo) ---")
55
+ model_id = "openai/whisper-large-v3-turbo"
56
+ # Force FP32 and Eager attention to combat CUBLAS errors on H200 drivers
57
+ model = AutoModelForSpeechSeq2Seq.from_pretrained(
58
+ model_id, torch_dtype=torch.float32, low_cpu_mem_usage=True, use_safetensors=True
59
+ ).to("cuda")
60
+ processor = AutoProcessor.from_pretrained(model_id)
61
  MODELS["stt"] = pipeline(
62
  "automatic-speech-recognition",
63
+ model=model,
64
+ tokenizer=processor.tokenizer,
65
+ feature_extractor=processor.feature_extractor,
66
+ torch_dtype=torch.float32,
67
  device="cuda",
68
+ model_kwargs={"attn_implementation": "eager"}
69
  )
70
+ print("--- [v148] βœ… WHISPER LOADED (FP32/EAGER) ---")
71
+
72
+ def load_tts_gpu():
73
+ """Load XTTS on GPU."""
74
+ global MODELS
75
+ if MODELS.get("tts") is None:
76
+ print("--- [v148] πŸ“₯ LOADING XTTS v2 ---")
77
+ MODELS["tts"] = TTS("tts_models/multilingual/multi-dataset/xtts_v2").to("cuda")
78
+ # Explicit stability cast
79
+ MODELS["tts"].to(torch.float32)
80
+ print("--- [v148] βœ… XTTS LOADED (FP32) ---")
81
+
82
+ @spaces.GPU(duration=120)
83
+ def core_stt(audio_b64, lang):
84
+ load_stt_gpu()
85
  audio_bytes = base64.b64decode(audio_b64)
86
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
87
+ f.write(audio_bytes); temp_path = f.name
 
88
  try:
89
+ # Use batch_size=1 for kernel stability
90
+ result = MODELS["stt"](temp_path, batch_size=1, generate_kwargs={"language": lang if lang and len(lang) <= 3 else None})
91
  return result["text"].strip()
92
  finally:
93
+ if os.path.exists(temp_path): os.unlink(temp_path)
94
+
95
+ @spaces.GPU(duration=120)
96
+ def core_tts(text, target_lang, speaker_wav_b64=None):
97
+ load_tts_gpu()
98
+ 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"}
99
+ clean_lang = target_lang.split('-')[0].lower()
100
+ mapped_lang = XTTS_MAP.get(clean_lang) or ("zh-cn" if clean_lang == "zh" else None)
101
 
102
+ if not mapped_lang:
103
+ if HAS_CHATTERBOX:
104
+ print(f"--- [v148] πŸ“¦ FALLBACK: CHATTERBOX FOR {clean_lang} ---")
105
+ audio_bytes = chatterbox_utils.run_chatterbox_inference(text, clean_lang)
106
+ return base64.b64encode(audio_bytes).decode()
107
+ return {"error": f"Language {clean_lang} not supported."}
108
 
109
+ speaker_wav_path = "default_speaker.wav"
110
+ if speaker_wav_b64:
111
+ sb = base64.b64decode(speaker_wav_b64)
112
+ with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
113
+ f.write(sb); speaker_wav_path = f.name
114
+ elif not os.path.exists(speaker_wav_path):
115
+ speaker_wav_path = None
116
+
117
+ try:
118
+ with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as out_f: out_p = out_f.name
119
+ # XTTS inference
120
+ MODELS["tts"].tts_to_file(text=text, language=mapped_lang, file_path=out_p, speaker_wav=speaker_wav_path)
121
+ with open(out_p, "rb") as f: audio_b64 = base64.b64encode(f.read()).decode()
122
+ return audio_b64
123
+ finally:
124
+ if speaker_wav_b64 and os.path.exists(speaker_wav_path): os.unlink(speaker_wav_path)
125
+ if 'out_p' in locals() and os.path.exists(out_p): os.unlink(out_p)
126
 
127
  @app.post("/process")
128
  async def api_process(request: Request):
129
  try:
130
  data = await request.json()
131
  action = data.get("action")
132
+ if action == "health": return {"status": "awake", "v": "148", "mode": "FULL_FEATURE"}
 
133
 
134
+ print(f"--- [v148] πŸ› οΈ ENGINE ACTION: {action} ---")
135
  t1 = time.time()
136
 
137
+ # πŸŽ™οΈ STT
138
  stt_text = None
139
  if action in ["stt", "s2st"]:
140
+ stt_text = core_stt(data.get("file"), data.get("lang"))
141
+ if action == "stt": return {"text": stt_text}
 
142
 
143
+ # πŸ”Š TTS
144
  if action in ["tts", "s2st"]:
145
  text = (data.get("text") if action == "tts" else stt_text).strip()
146
  trans_text = text
147
+
148
  if action == "s2st":
149
  target = data.get("target_lang") or "en"
150
  trans_text = GoogleTranslator(source='auto', target=target).translate(stt_text)
151
  text = trans_text
152
 
153
+ if len(text) < 2: return {"audio": ""} if action == "tts" else {"text": stt_text, "translated": "", "audio": ""}
 
154
 
155
+ audio_res = core_tts(text, (data.get("lang") if action == "tts" else target), data.get("speaker_wav"))
156
 
157
+ if isinstance(audio_res, dict) and "error" in audio_res: return audio_res
158
+ if action == "tts": return {"audio": audio_res}
159
+ return {"text": stt_text, "translated": trans_text, "audio": audio_res}
160
 
161
  except Exception as e:
162
+ print(f"❌ [v148] ERROR: {traceback.format_exc()}")
163
  return {"error": str(e)}
164
  finally:
165
+ print(f"--- [v148] ✨ DONE ({time.time()-t1:.1f}s) ---")
166
+ torch.cuda.empty_cache()
167
 
168
  @app.get("/health")
169
+ def health(): return {"status": "ok", "v": "148", "mode": "FULL_H200", "gpu": HAS_SPACES}
 
170
 
171
  @app.get("/", response_class=HTMLResponse)
172
+ def root(): return "<html><body><h1>πŸš€ AI Engine v148 (FULL FEATURE H200)</h1></body></html>"
 
173
 
174
  if __name__ == "__main__":
175
  uvicorn.run(app, host="0.0.0.0", port=7860)