hey-declare / models.py
raianand's picture
Upload 9 files
10c24a4 verified
Raw
History Blame Contribute Delete
5.1 kB
"""
models.py -- loads and runs the three ASR conditions under blind test:
BASELINE (zero-shot pretrained), VANILLA_FT, and DECLARE.
*** YOU MUST SUPPLY YOUR OWN CHECKPOINTS ***
This sandbox has no access to your NeMo checkpoints, NGC, or a GPU, so the
model-loading code below is written against the standard NeMo API used
throughout your existing notebooks (`ASRModel.from_pretrained` /
`ASRModel.restore_from`) but has not been executed end-to-end. Before
deploying, do one of:
1. Upload your three .nemo files into this Space's repo (e.g. under
checkpoints/) and point CHECKPOINT_PATHS at them, or
2. Push each checkpoint to its own private HF model repo and set the
corresponding entry in CHECKPOINT_PATHS to that repo id, or
3. Point BASELINE at the public NGC pretrained model name (as in your
other notebooks) since that one needs no fine-tuned weights at all.
If a checkpoint is missing, that condition falls back to a clearly-labelled
MOCK transcription so the rest of the app (routing, NLU, logging) can still
be tested and demoed without real model weights.
"""
import os
import random
MODEL_ID = os.environ.get("BASELINE_MODEL_ID", "stt_en_conformer_ctc_small_ls")
# Fill these in with real paths / HF repo ids before deploying.
CHECKPOINT_PATHS = {
"BASELINE": None, # loaded via from_pretrained(MODEL_ID) below -- no path needed
"VANILLA_FT": os.environ.get("VANILLA_FT_CKPT", "checkpoints/vanilla_ft.nemo"),
"DECLARE": os.environ.get("DECLARE_CKPT", "checkpoints/declare.nemo"),
}
_loaded_models = {}
_nemo_available = False
try:
import nemo.collections.asr as nemo_asr # noqa: F401
_nemo_available = True
except Exception:
_nemo_available = False
def _load_model(condition: str):
"""Lazily loads and caches one of the three ASR models."""
if condition in _loaded_models:
return _loaded_models[condition]
if not _nemo_available:
_loaded_models[condition] = None
return None
import nemo.collections.asr as nemo_asr
try:
if condition == "BASELINE":
model = nemo_asr.models.ASRModel.from_pretrained(model_name=MODEL_ID)
else:
ckpt = CHECKPOINT_PATHS[condition]
if not ckpt or not os.path.exists(ckpt):
print(f"[models.py] Checkpoint not found for {condition}: {ckpt}")
_loaded_models[condition] = None
return None
model = nemo_asr.models.ASRModel.restore_from(ckpt)
model.eval()
_loaded_models[condition] = model
return model
except Exception as e:
print(f"[models.py] Failed to load {condition}: {e}")
_loaded_models[condition] = None
return None
_MOCK_NOISE = [
lambda s: s, # occasionally perfect
lambda s: s.replace("the", "da").replace("to", "too"),
lambda s: " ".join(w[::-1] if len(w) > 4 else w for w in s.split()[:3]) + " " + " ".join(s.split()[3:]),
]
def _mock_transcribe(reference_text: str, condition: str) -> str:
"""Used only when no real checkpoint/NeMo install is available, so the
rest of the pipeline (routing, NLU, logging, UI) remains demoable.
Clearly NOT a substitute for real model inference."""
random.seed(hash((reference_text, condition)) % (2**32))
noiser = random.choice(_MOCK_NOISE)
return f"[MOCK-{condition}] " + noiser(reference_text)
def transcribe(condition: str, audio_path: str, reference_text: str = "") -> str:
"""Runs ASR for the given blind condition ('BASELINE' | 'VANILLA_FT' | 'DECLARE').
Falls back to a labelled mock transcription if no real model is loaded,
so the app remains runnable before checkpoints are supplied.
The audio file at `audio_path` is deleted immediately after this function
returns (see the `finally` block) -- only the resulting transcript is ever
logged or retained. This is a hard participant-facing commitment, not just
a UI statement, so it is enforced here rather than left to the caller.
"""
model = _load_model(condition)
try:
if model is None:
return _mock_transcribe(reference_text, condition)
try:
out = model.transcribe([audio_path], verbose=False)[0]
return out.text if hasattr(out, "text") else out
except Exception as e:
print(f"[models.py] Inference failed for {condition}: {e}")
return _mock_transcribe(reference_text, condition)
finally:
try:
if audio_path and os.path.exists(audio_path):
os.remove(audio_path)
except Exception as e:
print(f"[models.py] Warning: could not delete audio file {audio_path}: {e}")
def status_report() -> dict:
"""For an admin/debug panel: which conditions have real models loaded."""
return {
"nemo_available": _nemo_available,
"baseline_loaded": _load_model("BASELINE") is not None,
"vanilla_ft_loaded": _load_model("VANILLA_FT") is not None,
"declare_loaded": _load_model("DECLARE") is not None,
}