Spaces:
Sleeping
Sleeping
Upload app.py
Browse files
app.py
CHANGED
|
@@ -56,8 +56,13 @@ LLM_REPO_ID = os.environ.get("LLM_REPO_ID", "aijadugar/wisprflow-clone-llm")
|
|
| 56 |
# Under ZeroGPU, torch.cuda.is_available() is unreliable/False in the main
|
| 57 |
# process anyway; actual device placement happens lazily inside the
|
| 58 |
# @spaces.GPU-decorated functions below.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
LOAD_DEVICE = "cpu"
|
| 60 |
-
LOAD_DTYPE = torch.
|
| 61 |
|
| 62 |
MODE_PROMPTS = {
|
| 63 |
"Email": (
|
|
@@ -98,6 +103,7 @@ whisper_processor = WhisperProcessor.from_pretrained(WHISPER_REPO_ID)
|
|
| 98 |
whisper_model = WhisperForConditionalGeneration.from_pretrained(
|
| 99 |
WHISPER_REPO_ID,
|
| 100 |
torch_dtype=LOAD_DTYPE,
|
|
|
|
| 101 |
)
|
| 102 |
whisper_model.eval()
|
| 103 |
|
|
@@ -106,6 +112,7 @@ llm_tokenizer = AutoTokenizer.from_pretrained(LLM_REPO_ID)
|
|
| 106 |
llm_model = AutoModelForCausalLM.from_pretrained(
|
| 107 |
LLM_REPO_ID,
|
| 108 |
torch_dtype=LOAD_DTYPE,
|
|
|
|
| 109 |
)
|
| 110 |
llm_model.eval()
|
| 111 |
|
|
@@ -191,31 +198,41 @@ def _clean_up_on_gpu(raw_text, mode):
|
|
| 191 |
|
| 192 |
def transcribe(audio_path):
|
| 193 |
if audio_path is None:
|
| 194 |
-
return "", 0.0
|
| 195 |
start = time.time()
|
| 196 |
-
|
|
|
|
|
|
|
|
|
|
| 197 |
elapsed = time.time() - start
|
| 198 |
-
return text, elapsed
|
| 199 |
|
| 200 |
|
| 201 |
def clean_up(raw_text, mode):
|
| 202 |
if not raw_text.strip():
|
| 203 |
-
return "", 0.0
|
| 204 |
start = time.time()
|
| 205 |
-
|
|
|
|
|
|
|
|
|
|
| 206 |
elapsed = time.time() - start
|
| 207 |
-
return cleaned, elapsed
|
| 208 |
|
| 209 |
|
| 210 |
def run_pipeline(audio_path, mode):
|
| 211 |
if audio_path is None:
|
| 212 |
return "", "", "Record or upload audio first."
|
| 213 |
|
| 214 |
-
raw_text, asr_seconds = transcribe(audio_path)
|
|
|
|
|
|
|
| 215 |
if not raw_text:
|
| 216 |
return "", "", "Couldn't transcribe that clip — try again."
|
| 217 |
|
| 218 |
-
cleaned_text, llm_seconds = clean_up(raw_text, mode)
|
|
|
|
|
|
|
| 219 |
|
| 220 |
total = asr_seconds + llm_seconds
|
| 221 |
stats = (
|
|
|
|
| 56 |
# Under ZeroGPU, torch.cuda.is_available() is unreliable/False in the main
|
| 57 |
# process anyway; actual device placement happens lazily inside the
|
| 58 |
# @spaces.GPU-decorated functions below.
|
| 59 |
+
#
|
| 60 |
+
# bfloat16 (not float32) on CPU: halves RAM for both models. Modern PyTorch
|
| 61 |
+
# has native CPU kernels for bf16 matmul/linear (unlike float16, which is
|
| 62 |
+
# poorly supported on CPU), so this is safe and meaningfully cuts memory
|
| 63 |
+
# pressure — important since the LLM checkpoint here is ~15GB.
|
| 64 |
LOAD_DEVICE = "cpu"
|
| 65 |
+
LOAD_DTYPE = torch.bfloat16
|
| 66 |
|
| 67 |
MODE_PROMPTS = {
|
| 68 |
"Email": (
|
|
|
|
| 103 |
whisper_model = WhisperForConditionalGeneration.from_pretrained(
|
| 104 |
WHISPER_REPO_ID,
|
| 105 |
torch_dtype=LOAD_DTYPE,
|
| 106 |
+
low_cpu_mem_usage=True,
|
| 107 |
)
|
| 108 |
whisper_model.eval()
|
| 109 |
|
|
|
|
| 112 |
llm_model = AutoModelForCausalLM.from_pretrained(
|
| 113 |
LLM_REPO_ID,
|
| 114 |
torch_dtype=LOAD_DTYPE,
|
| 115 |
+
low_cpu_mem_usage=True,
|
| 116 |
)
|
| 117 |
llm_model.eval()
|
| 118 |
|
|
|
|
| 198 |
|
| 199 |
def transcribe(audio_path):
|
| 200 |
if audio_path is None:
|
| 201 |
+
return "", 0.0, None
|
| 202 |
start = time.time()
|
| 203 |
+
try:
|
| 204 |
+
text = _transcribe_on_gpu(audio_path)
|
| 205 |
+
except Exception as e:
|
| 206 |
+
return "", time.time() - start, f"Transcription failed: {e}"
|
| 207 |
elapsed = time.time() - start
|
| 208 |
+
return text, elapsed, None
|
| 209 |
|
| 210 |
|
| 211 |
def clean_up(raw_text, mode):
|
| 212 |
if not raw_text.strip():
|
| 213 |
+
return "", 0.0, None
|
| 214 |
start = time.time()
|
| 215 |
+
try:
|
| 216 |
+
cleaned = _clean_up_on_gpu(raw_text, mode)
|
| 217 |
+
except Exception as e:
|
| 218 |
+
return "", time.time() - start, f"Cleanup failed: {e}"
|
| 219 |
elapsed = time.time() - start
|
| 220 |
+
return cleaned, elapsed, None
|
| 221 |
|
| 222 |
|
| 223 |
def run_pipeline(audio_path, mode):
|
| 224 |
if audio_path is None:
|
| 225 |
return "", "", "Record or upload audio first."
|
| 226 |
|
| 227 |
+
raw_text, asr_seconds, asr_error = transcribe(audio_path)
|
| 228 |
+
if asr_error:
|
| 229 |
+
return "", "", asr_error
|
| 230 |
if not raw_text:
|
| 231 |
return "", "", "Couldn't transcribe that clip — try again."
|
| 232 |
|
| 233 |
+
cleaned_text, llm_seconds, llm_error = clean_up(raw_text, mode)
|
| 234 |
+
if llm_error:
|
| 235 |
+
return raw_text, "", llm_error
|
| 236 |
|
| 237 |
total = asr_seconds + llm_seconds
|
| 238 |
stats = (
|