| |
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| import os |
| from pathlib import Path |
| from typing import Any |
|
|
| from asr_onnx_runtime import OnnxAsrEngine, OnnxCacheAsrEngine |
|
|
|
|
| APP_DIR = Path(__file__).resolve().parent |
| BUNDLE_CANDIDATES = ( |
| "model_bundle", |
| ) |
|
|
|
|
| def default_bundle_dir() -> Path: |
| env_value = os.environ.get("AUDIO8_ASR_BUNDLE") |
| if env_value: |
| return Path(env_value).expanduser() |
| for name in BUNDLE_CANDIDATES: |
| candidate = APP_DIR / name |
| if (candidate / "metadata.json").exists(): |
| return candidate |
| return APP_DIR / "model_bundle" |
|
|
|
|
| def transcribe_file( |
| audio_path: str | Path, |
| *, |
| bundle_dir: str | Path | None = None, |
| backend: str = "onnx_cache", |
| cache_precision: str = "int8", |
| audio_precision: str = "int8", |
| language: str | None = None, |
| max_new_tokens: int = 128, |
| provider: str = "CPUExecutionProvider", |
| threads: int | None = None, |
| hotwords: str | list[str] | None = None, |
| hotword_topk: int = 50, |
| hotword_start_boost: float = 6.0, |
| hotword_continuation_boost: float = 8.0, |
| ) -> dict[str, Any]: |
| bundle_path = Path(bundle_dir).expanduser() if bundle_dir is not None else default_bundle_dir() |
| audio_file = Path(audio_path).expanduser() |
| if backend == "onnx": |
| engine = OnnxAsrEngine( |
| bundle_path, |
| provider=provider, |
| intra_op_num_threads=threads, |
| audio_precision=audio_precision, |
| ) |
| elif backend == "onnx_cache": |
| engine = OnnxCacheAsrEngine( |
| bundle_path, |
| provider=provider, |
| intra_op_num_threads=threads, |
| cache_precision=cache_precision, |
| audio_precision=audio_precision, |
| ) |
| else: |
| raise ValueError(f"Unsupported backend: {backend}") |
| return engine.transcribe( |
| audio_file.read_bytes(), |
| language=language, |
| max_new_tokens=max_new_tokens, |
| hotwords=hotwords, |
| hotword_topk=hotword_topk, |
| hotword_start_boost=hotword_start_boost, |
| hotword_continuation_boost=hotword_continuation_boost, |
| ) |
|
|
|
|
| def parse_args() -> argparse.Namespace: |
| parser = argparse.ArgumentParser(description="Transcribe one audio file with the Audio8 ASR ONNX runtime.") |
| parser.add_argument("audio", type=Path, help="Audio file path. WAV is recommended; librosa/soundfile handle common formats.") |
| parser.add_argument("--bundle_dir", type=Path, default=default_bundle_dir()) |
| parser.add_argument("--backend", choices=["onnx_cache", "onnx"], default=os.environ.get("ASR_BACKEND", "onnx_cache")) |
| parser.add_argument("--cache_precision", choices=["fp32", "int8", "int4", "auto"], default=os.environ.get("ASR_CACHE_PRECISION", "int8")) |
| parser.add_argument("--audio_precision", choices=["fp32", "int8", "auto"], default=os.environ.get("ASR_AUDIO_PRECISION", "int8")) |
| parser.add_argument( |
| "--language", |
| default=None, |
| help="Compatibility field; the current ONNX runtime ignores it and infers language from audio.", |
| ) |
| parser.add_argument("--max_new_tokens", type=int, default=128) |
| parser.add_argument("--provider", default=os.environ.get("ORT_PROVIDER", "CPUExecutionProvider")) |
| parser.add_argument("--threads", type=int, default=int(os.environ.get("ORT_THREADS", "0"))) |
| parser.add_argument("--hotwords", default=None, help="Comma separated hotwords, disabled when omitted.") |
| parser.add_argument("--hotword_topk", type=int, default=50) |
| parser.add_argument("--hotword_start_boost", type=float, default=6.0) |
| parser.add_argument("--hotword_continuation_boost", type=float, default=8.0) |
| parser.add_argument("--json", action="store_true", help="Print the full result JSON instead of only transcript text.") |
| return parser.parse_args() |
|
|
|
|
| def main() -> None: |
| args = parse_args() |
| result = transcribe_file( |
| args.audio, |
| bundle_dir=args.bundle_dir, |
| backend=args.backend, |
| cache_precision=args.cache_precision, |
| audio_precision=args.audio_precision, |
| language=args.language or None, |
| max_new_tokens=args.max_new_tokens, |
| provider=args.provider, |
| threads=args.threads if args.threads > 0 else None, |
| hotwords=args.hotwords or None, |
| hotword_topk=args.hotword_topk, |
| hotword_start_boost=args.hotword_start_boost, |
| hotword_continuation_boost=args.hotword_continuation_boost, |
| ) |
| if args.json: |
| print(json.dumps(result, ensure_ascii=False, indent=2)) |
| else: |
| print(result.get("text", "")) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|