()
| 30 | return [p for p in folder.iterdir() if p.is_file() and p.suffix.lower() in exts] |
| 31 | |
| 32 | def main(): |
| 33 | parser = argparse.ArgumentParser(description="Batch ASR using FunASR AutoModel") |
| 34 | parser.add_argument("--input-folder", "-i", type=Path, default=Path("examples/audio_samples"), |
| 35 | help="Folder with audio files (default: examples/audio_samples)") |
| 36 | parser.add_argument("--output-file", "-o", type=Path, default=Path("examples/batch_transcriptions.txt"), |
| 37 | help="Output text file (default: examples/batch_transcriptions.txt)") |
| 38 | parser.add_argument("--model", "-m", default="paraformer-zh", |
| 39 | help="Model name (default: paraformer-zh). Examples: paraformer-zh, paraformer-en, SenseVoiceSmall") |
| 40 | parser.add_argument("--device", "-d", default="cpu", help="Device for inference (default: cpu)") |
| 41 | parser.add_argument("--recursive", "-r", action="store_true", help="Recursively search input folder for audio files") |
| 42 | parser.add_argument("--extensions", "-e", nargs="+", default=[".wav", ".mp3"], help="Accepted audio extensions (default: .wav .mp3)") |
| 43 | parser.add_argument("--vad-model", default="fsmn-vad", help="VAD model to use. Set to 'none' to disable. (default: fsmn-vad)") |
| 44 | args = parser.parse_args() |
| 45 | |
| 46 | if not args.input_folder.exists(): |
| 47 | print(f"Input folder does not exist: {args.input_folder}", file=sys.stderr) |
| 48 | sys.exit(2) |
| 49 | |
| 50 | exts = [ext.lower() if ext.startswith('.') else f'.{ext.lower()}' for ext in args.extensions] |
| 51 | files = sorted(find_audio_files(args.input_folder, exts, args.recursive)) |
| 52 | if len(files) == 0: |
| 53 | print(f"No audio files found in {args.input_folder} with extensions {exts}") |
| 54 | sys.exit(0) |
| 55 | |
| 56 | vad_arg = args.vad_model if args.vad_model.lower() != 'none' else None |
| 57 | print(f"Loading model '{args.model}' on device '{args.device}'... (this may take a while)") |
| 58 | try: |
| 59 | model = AutoModel(model=args.model, vad_model=vad_arg, device=args.device) |
| 60 | except Exception as e: |
| 61 | print("Failed to load model:", e, file=sys.stderr) |
| 62 | raise |
| 63 | |
| 64 | results = {} |
| 65 | total = len(files) |
| 66 | for idx, fpath in enumerate(files, start=1): |
| 67 | rel_key = str(fpath.relative_to(args.input_folder)) |
| 68 | try: |
| 69 | print(f"[{idx}/{total}] Processing: {fpath}") |
| 70 | # `cache` was removed per review because it's not used by generate |
| 71 | res = model.generate(input=str(fpath), language="auto") |
| 72 | text = rich_transcription_postprocess(res[0]["text"]) if res and isinstance(res, list) and "text" in res[0] else "" |
| 73 | results[rel_key] = text |
| 74 | print(f" -> {text}") |
| 75 | except Exception as e: |
| 76 | print(f" Error processing {fpath}: {e}", file=sys.stderr) |
| 77 | results[rel_key] = f"<ERROR: {e}>" |
| 78 | |
| 79 | # Ensure output directory exists |
| 80 | args.output_file.parent.mkdir(parents=True, exist_ok=True) |
| 81 | with args.output_file.open("w", encoding="utf-8") as outf: |
| 82 | for fname, transcription in results.items(): |
| 83 | outf.write(f"{fname}: {transcription}\n") |
| 84 | |
| 85 | print(f"\nAll transcriptions saved to {args.output_file}") |
| 86 | |
| 87 | |
| 88 | if __name__ == "__main__": |
no test coverage detected
searching dependent graphs…