From 6f60d49c7b5103e871817afda0638fd0affe2fea Mon Sep 17 00:00:00 2001 From: Adolfo Reyna Date: Sat, 28 Feb 2026 19:00:56 -0500 Subject: [PATCH] feat: implement streaming mode (-s) and 4-bit quantization (-q) for performance --- README.md | 2 ++ transcribe.py | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/README.md b/README.md index 32c134d..2cd2512 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,8 @@ Run the script using `python3 transcribe.py` with optional flags. - `-i`, `--ingest`: Enable data transmission to the remote server. - `-l`, `--list-devices`: Show available audio devices and exit. - `-d`, `--device [ID]`: Input device index (bypasses selection prompt). +- `-q`, `--quantize`: Use 4-bit quantized Whisper model for faster transcription (Strategy 3). +- `-s`, `--stream`: Enable real-time streaming transcription/draft mode (Strategy 1). --- diff --git a/transcribe.py b/transcribe.py index 78f6468..d42876d 100644 --- a/transcribe.py +++ b/transcribe.py @@ -83,6 +83,7 @@ def ingest_worker(): ingest_queue.task_done() def main(): + global WHISPER_MODEL parser = argparse.ArgumentParser(description="Live transcription and translation with Whisper.") parser.add_argument("-es", action="store_true", help="Enable Spanish translation") parser.add_argument("-en", action="store_true", help="Enable English (detected or bridged)") @@ -91,9 +92,14 @@ def main(): parser.add_argument("-i", "--ingest", action="store_true", help="Enable data transmission to server") parser.add_argument("-l", "--list-devices", action="store_true", help="Show available audio devices and exit") parser.add_argument("-d", "--device", type=int, help="Input device index") + parser.add_argument("-q", "--quantize", action="store_true", help="Use 4-bit quantized Whisper model for speed") + parser.add_argument("-s", "--stream", action="store_true", help="Enable real-time streaming transcription (Draft mode)") args = parser.parse_args() + if args.quantize: + WHISPER_MODEL = "mlx-community/whisper-small-mlx-4bit" + if args.list_devices: print("\nAvailable Audio Devices:") print(sd.query_devices()) @@ -140,6 +146,7 @@ def main(): audio_buffer = [] speech_started = False + last_stream_time = time.time() try: with sd.InputStream(samplerate=SAMPLERATE, channels=CHANNELS, callback=callback, blocksize=BLOCK_SIZE, device=device_index): @@ -167,6 +174,11 @@ def main(): if (buffer_len_samples - last_end) > (SAMPLERATE * MIN_SILENCE_DURATION_MS / 1000) or buffer_len_samples > BUFFER_LIMIT: + # Clear draft line if it was used + if args.stream: + sys.stdout.write("\r\033[K") + sys.stdout.flush() + # 1. Transcribe & Detect Language transcription_result = mlx_whisper.transcribe(current_audio, path_or_hf_repo=WHISPER_MODEL) original_text = transcription_result['text'].strip() @@ -220,6 +232,16 @@ def main(): audio_buffer = [] speech_started = False + last_stream_time = time.time() + + elif args.stream and (time.time() - last_stream_time) > 1.0: + # Draft transcription + draft_result = mlx_whisper.transcribe(current_audio, path_or_hf_repo=WHISPER_MODEL) + draft_text = draft_result['text'].strip() + if draft_text: + sys.stdout.write(f"\r\033[K[DRAFT]: {draft_text}") + sys.stdout.flush() + last_stream_time = time.time() elif not speech_started and len(current_audio) > SAMPLERATE * 2: audio_buffer = []