aniketqxp's picture
feat: add processing service runtime
f1ef7e2
Raw
History Blame Contribute Delete
3.54 kB
"""
Batch transcription over the NA test set using per-channel isolation.
Each call has separate agent and customer WAV files — we transcribe each
channel independently so channel identity IS the speaker label.
No RMS attribution guessing, no cross-speaker leakage.
Usage:
python run_batch.py --model small.en
python run_batch.py --model small.en --accent en-CA
python run_batch.py --model small.en --domains health telecom
"""
import os
import sys
import json
import time
import argparse
from pathlib import Path
from faster_whisper import WhisperModel
sys.path.insert(0, str(Path(__file__).parent))
sys.path.insert(0, str(Path(__file__).parent.parent / "evaluation"))
sys.path.insert(0, str(Path(__file__).parent.parent / "pipeline"))
from transcribe_channels import transcribe_call
from prompts_domain import prompt_for
import paths
DATA_DIR = str(paths.NA_TESTSET)
MANIFEST = str(paths.MANIFEST)
RESULTS = os.path.join(DATA_DIR, "results")
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--model", default="small.en")
ap.add_argument("--accent", default=None)
ap.add_argument("--domains", nargs="+", default=None)
args = ap.parse_args()
with open(MANIFEST, encoding="utf-8") as f:
manifest = json.load(f)
if args.accent:
manifest = [m for m in manifest if m["accent"] == args.accent]
if args.domains:
manifest = [m for m in manifest if m.get("domain", "").lower() in args.domains]
todo = []
for m in manifest:
out = os.path.join(RESULTS, m["accent"], m["call_id"] + ".json")
if not (os.path.exists(out) and os.path.getsize(out) > 0):
todo.append(m)
print(f"Total calls: {len(manifest)} | done: {len(manifest)-len(todo)} | to do: {len(todo)}")
if not todo:
print("Nothing to do.")
return
print(f"Loading faster-whisper {args.model}/int8 (once)...")
model = WhisperModel(args.model, device="cpu", compute_type="int8")
t_start = time.time()
for i, m in enumerate(todo, 1):
a_wav = os.path.join(DATA_DIR, m["agent_wav"])
c_wav = os.path.join(DATA_DIR, m["customer_wav"])
out_dir = os.path.join(RESULTS, m["accent"])
os.makedirs(out_dir, exist_ok=True)
out = os.path.join(out_dir, m["call_id"] + ".json")
prompt = prompt_for(m.get("domain", ""))
t0 = time.time()
try:
agent_words, customer_words, _, duration = transcribe_call(
model, a_wav, c_wav,
decode={"initial_prompt": prompt},
)
except Exception as e:
print(f" [{i}/{len(todo)}] {m['call_id']} ERROR: {e}")
continue
with open(out, "w", encoding="utf-8") as f:
json.dump({
"model": f"faster-whisper {args.model}/int8 + per-channel",
"call_id": m["call_id"],
"accent": m["accent"],
"domain": m["domain"],
"agent": agent_words,
"customer": customer_words,
}, f, indent=2)
elapsed = time.time() - t0
avg = (time.time() - t_start) / i
eta = avg * (len(todo) - i)
print(f" [{i}/{len(todo)}] {m['accent']:<14} {m['call_id']:<36} "
f"{duration:5.0f}s | {elapsed:5.1f}s | A:{len(agent_words)} C:{len(customer_words)} | "
f"ETA {eta/60:5.1f}m")
print(f"\nDone. {len(todo)} calls in {(time.time()-t_start)/60:.1f} min.")
if __name__ == "__main__":
main()