summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvin <git@vineetk.net>2025-08-22 16:53:10 -0400
committervin <git@vineetk.net>2025-08-22 16:53:10 -0400
commitcc2d05f027ef2672a96d1b780e5af44b03375af8 (patch)
treeab831dd53b618ee3119df635166967eb0f3d9302
parent968414d2d38f3cb30ac4e1af3151a0842c113366 (diff)
improve asr.py
-rw-r--r--asr.py119
1 files changed, 65 insertions, 54 deletions
diff --git a/asr.py b/asr.py
index 110629f..e598e4b 100644
--- a/asr.py
+++ b/asr.py
@@ -1,68 +1,79 @@
1import librosa 1import librosa
2import soundfile as sf
3import onnx_asr 2import onnx_asr
4import os 3import os
5import sys 4import sys
6#import numpy as np 5import json
6import numpy as np
7from tqdm import tqdm 7from tqdm import tqdm
8 8
9print("Loading ASR model...") 9# converts TimestampedResult to JSON-serializable dictionary
10providers = [ 10def result_to_dict(result, offset_seconds):
11 "ROCMExecutionProvider", 11 return {
12 #"CUDAExecutionProvider", 12 "text": result.text,
13 "CPUExecutionProvider", 13 "tokens": result.tokens,
14] 14 "timestamps": [ts + offset_seconds for ts in result.timestamps]
15model = onnx_asr.load_model( 15 }
16 "nemo-parakeet-tdt-0.6b-v3",
17 providers=providers,
18 #quantization="int8"
19).with_timestamps()
20 16
21# parakeet needs 16khz mono wav as input 17def main(input_file, output_file):
22input_file = "input.wav" 18 print("Loading ASR model...")
23chunk_duration_seconds = 20 19 providers = [
24sample_rate = 16000 20 "ROCMExecutionProvider",
25 21 "CPUExecutionProvider",
26print(f"Loading and resampling {input_file}...") 22 ]
27try: 23 try:
28 audio, sr = librosa.load(input_file, sr=sample_rate, mono=True) 24 model = onnx_asr.load_model(
29except Exception as e: 25 "nemo-parakeet-tdt-0.6b-v3",
30 print(f"Error loading audio file: {e}") 26 providers=providers,
31 exit() 27 ).with_timestamps()
32 28 except Exception as e:
33# process audio in chunks 29 print(f"Failed to load the ASR model. Ensure ONNX Runtime for ROCm is installed correctly. Error: {e}")
34chunk_size_samples = int(chunk_duration_seconds * sample_rate) 30 sys.exit(1)
35full_transcript = []
36temp_dir = "temp_chunks"
37os.makedirs(temp_dir, exist_ok=True)
38 31
39print("Starting transcription process in chunks...") 32 chunk_duration_seconds = 20
40num_chunks = (len(audio) + chunk_size_samples - 1) // chunk_size_samples 33 sample_rate = 16000
41 34
42for i in tqdm(range(num_chunks), desc="Transcribing"): 35 print(f"Loading and resampling {input_file}...")
43 start_sample = i * chunk_size_samples
44 end_sample = start_sample + chunk_size_samples
45 chunk = audio[start_sample:end_sample]
46
47 temp_chunk_file = os.path.join(temp_dir, f"chunk_{i}.wav")
48 sf.write(temp_chunk_file, chunk, sample_rate)
49
50 try: 36 try:
51 transcript = model.recognize(temp_chunk_file) 37 audio, sr = librosa.load(input_file, sr=sample_rate, mono=True)
52 if transcript:
53 full_transcript.append(transcript)
54 except Exception as e: 38 except Exception as e:
55 print(f" Error processing chunk {i + 1}: {e}") 39 print(f"Error loading audio file: {e}")
56 finally: 40 sys.exit(1)
57 os.remove(temp_chunk_file) 41
42 chunk_size_samples = int(chunk_duration_seconds * sample_rate)
43 full_transcript_data = []
44
45 print("Starting transcription process in chunks...")
46 num_chunks = (len(audio) + chunk_size_samples - 1) // chunk_size_samples
58 47
59os.rmdir(temp_dir) 48 for i in tqdm(range(num_chunks), desc="Transcribing"):
49 start_sample = i * chunk_size_samples
50 end_sample = start_sample + chunk_size_samples
51 chunk = audio[start_sample:end_sample]
52
53 chunk_offset_seconds = start_sample / sample_rate
54
55 try:
56 transcript_results = model.recognize(np.copy(chunk))
57
58 if transcript_results:
59 for result in transcript_results:
60 full_transcript_data.append(result_to_dict(result, chunk_offset_seconds))
61 except Exception as e:
62 print(f" Error processing chunk {i + 1}: {e}")
60 63
61print("\n" + "="*30) 64 print(f"\nTranscription complete. Saving results to {output_file}...")
62print(" FINAL TRANSCRIPT") 65 with open(output_file, "w") as f:
63print("="*30) 66 json.dump(full_transcript_data, f, indent=2)
64print(full_transcript)
65 67
66# onnxruntime has some bug where it doesn't exit properly, aborting instead 68 print("Done.")
67# so hard exit instead (sys.exit does graceful exit) 69 # os._exit(0) workaround for ONNX Runtime bug
68os._exit(0) 70 os._exit(0)
71
72if __name__ == "__main__":
73 if len(sys.argv) < 3:
74 print("Usage: python asr.py <input_audio_file> <output_json_file>")
75 sys.exit(1)
76
77 input_path = sys.argv[1]
78 output_path = sys.argv[2]
79 main(input_path, output_path)