From 16c2208ac8319918087cb3fbb39268d4ad348951 Mon Sep 17 00:00:00 2001 From: Krzysztof Rudnicki Date: Sat, 20 Dec 2025 21:49:52 +0100 Subject: [PATCH] feat: more descriptive transbtion installation --- .../__pycache__/transcribe_fw.cpython-313.pyc | Bin 0 -> 28157 bytes .../transcribe_helpers.cpython-313.pyc | Bin 0 -> 9366 bytes .../testsAndMisc-bash/tools/transcribe_fw.py | 131 +++++++++++- .../tools/transcribe_helpers.py | 194 ++++++++++++++++++ scripts/misc/testsAndMisc-bash/transcribe.sh | 50 ++--- 5 files changed, 340 insertions(+), 35 deletions(-) create mode 100644 scripts/misc/testsAndMisc-bash/tools/__pycache__/transcribe_fw.cpython-313.pyc create mode 100644 scripts/misc/testsAndMisc-bash/tools/__pycache__/transcribe_helpers.cpython-313.pyc create mode 100644 scripts/misc/testsAndMisc-bash/tools/transcribe_helpers.py diff --git a/scripts/misc/testsAndMisc-bash/tools/__pycache__/transcribe_fw.cpython-313.pyc b/scripts/misc/testsAndMisc-bash/tools/__pycache__/transcribe_fw.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7f94d78fbe13fdd5cd3cfdba425bb2dd3be87ebf GIT binary patch literal 28157 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 literal 0 HcmV?d00001 diff --git a/scripts/misc/testsAndMisc-bash/tools/transcribe_fw.py b/scripts/misc/testsAndMisc-bash/tools/transcribe_fw.py index 48eff05..72fdc4f 100644 --- a/scripts/misc/testsAndMisc-bash/tools/transcribe_fw.py +++ b/scripts/misc/testsAndMisc-bash/tools/transcribe_fw.py @@ -7,6 +7,121 @@ import sys import time from datetime import timedelta from typing import List, Optional + + +def format_bytes(size: int) -> str: + """Format bytes as human-readable string.""" + for unit in ['B', 'KB', 'MB', 'GB']: + if size < 1024: + return f"{size:.1f}{unit}" + size /= 1024 + return f"{size:.1f}TB" + + +def download_model_with_progress(model_name: str) -> str: + """Download model files from HuggingFace with a visible progress bar. + + Returns the local path to the downloaded model. + """ + try: + from huggingface_hub import snapshot_download, hf_hub_download + from huggingface_hub.utils import EntryNotFoundError + except ImportError: + print("[WARN] huggingface_hub not available, falling back to default download", file=sys.stderr) + return model_name + + # Map common model names to HF repo IDs + model_map = { + "tiny": "Systran/faster-whisper-tiny", + "tiny.en": "Systran/faster-whisper-tiny.en", + "base": "Systran/faster-whisper-base", + "base.en": "Systran/faster-whisper-base.en", + "small": "Systran/faster-whisper-small", + "small.en": "Systran/faster-whisper-small.en", + "medium": "Systran/faster-whisper-medium", + "medium.en": "Systran/faster-whisper-medium.en", + "large-v1": "Systran/faster-whisper-large-v1", + "large-v2": "Systran/faster-whisper-large-v2", + "large-v3": "Systran/faster-whisper-large-v3", + "large": "Systran/faster-whisper-large-v3", + "distil-large-v2": "Systran/faster-distil-whisper-large-v2", + "distil-large-v3": "Systran/faster-distil-whisper-large-v3", + "distil-medium.en": "Systran/faster-distil-whisper-medium.en", + "distil-small.en": "Systran/faster-distil-whisper-small.en", + } + + repo_id = model_map.get(model_name, model_name) + + # Check if it looks like a repo ID + if "/" not in repo_id and model_name not in model_map: + # Assume it's a Systran model + repo_id = f"Systran/faster-whisper-{model_name}" + + print(f"[INFO] Checking model: {repo_id}", flush=True) + + # Files we need to download (model.bin is the large one) + required_files = ["config.json", "model.bin", "tokenizer.json", "vocabulary.txt"] + + try: + # Use snapshot_download which handles caching and shows what's happening + # First, let's check if model.bin needs downloading by checking cache + from huggingface_hub import try_to_load_from_cache, HfFileSystem + + cache_path = try_to_load_from_cache(repo_id, "model.bin") + if cache_path is not None: + print(f"[INFO] Model already cached, loading from: {os.path.dirname(cache_path)}", flush=True) + # Return the directory containing the cached files + return os.path.dirname(cache_path) + + # Model not cached, need to download + print(f"[INFO] Downloading model files from {repo_id}...", flush=True) + print("[INFO] This may take several minutes for large models (~3GB for large-v3)", flush=True) + + # Get file sizes to show progress + try: + fs = HfFileSystem() + files_info = fs.ls(repo_id, detail=True) + total_size = sum(f.get('size', 0) for f in files_info if f.get('name', '').split('/')[-1] in required_files) + print(f"[INFO] Total download size: ~{format_bytes(total_size)}", flush=True) + except Exception: + pass # Size info is optional + + # Download with progress + downloaded = 0 + start_time = time.time() + + for filename in required_files: + file_start = time.time() + print(f"[DOWNLOAD] {filename}...", end=" ", flush=True) + try: + local_path = hf_hub_download( + repo_id=repo_id, + filename=filename, + resume_download=True, + ) + elapsed = time.time() - file_start + file_size = os.path.getsize(local_path) if os.path.exists(local_path) else 0 + print(f"done ({format_bytes(file_size)}, {elapsed:.1f}s)", flush=True) + downloaded += 1 + + # Return directory on first successful download + if downloaded == 1: + model_dir = os.path.dirname(local_path) + except EntryNotFoundError: + print("not found (optional)", flush=True) + except Exception as e: + print(f"error: {e}", flush=True) + + total_time = time.time() - start_time + print(f"[INFO] Download complete in {total_time:.1f}s", flush=True) + + return model_dir + + except Exception as e: + print(f"[WARN] Custom download failed ({e}), falling back to default", file=sys.stderr) + return model_name + + def format_timestamp(seconds: float) -> str: td = timedelta(seconds=seconds) # Ensure SRT format HH:MM:SS,mmm @@ -324,7 +439,21 @@ def main(): compute_type = "float16" if device == "cuda" else "float32" print(f"[INFO] Loading model='{args.model}', device='{device}', compute_type='{compute_type}'") - model = WhisperModel(args.model, device=device, compute_type=compute_type) + + # Pre-download model files with explicit progress if not already cached + model_path = args.model + if not os.path.isdir(args.model): # Not a local path, need to download from HF + model_path = download_model_with_progress(args.model) + + # Show CTranslate2 conversion progress + import logging + logging.basicConfig(level=logging.INFO, format='[%(levelname)s] %(message)s') + ct2_logger = logging.getLogger("faster_whisper") + ct2_logger.setLevel(logging.INFO) + + print("[INFO] Initializing model...", flush=True) + model = WhisperModel(model_path, device=device, compute_type=compute_type) + print("[INFO] Model loaded successfully.", flush=True) # Transcription with live progress total_duration = get_media_duration(inp) diff --git a/scripts/misc/testsAndMisc-bash/tools/transcribe_helpers.py b/scripts/misc/testsAndMisc-bash/tools/transcribe_helpers.py new file mode 100644 index 0000000..a39756b --- /dev/null +++ b/scripts/misc/testsAndMisc-bash/tools/transcribe_helpers.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python3 +"""Helper utilities for transcribe.sh - replaces inline Python snippets.""" + +import argparse +import math +import os +import sys +import array +import wave + + +def get_python_version() -> str: + """Return Python major.minor version string.""" + return f"{sys.version_info.major}.{sys.version_info.minor}" + + +def check_faster_whisper() -> bool: + """Check if faster_whisper is importable. Exit 7 if not.""" + try: + import faster_whisper # noqa: F401 + return True + except ImportError: + return False + + +def check_diarization_deps() -> bool: + """Check if diarization dependencies are available. Returns False with warning if missing.""" + try: + import soundfile # noqa: F401 + import speechbrain # noqa: F401 + import torch # noqa: F401 + return True + except Exception as e: + print(f"[WARN] Diarization deps missing offline ({e}); speaker labels will be skipped.") + return False + + +def check_ctranslate2() -> bool: + """Check if ctranslate2 is importable.""" + try: + import ctranslate2 # noqa: F401 + return True + except ImportError: + return False + + +def print_deps_installed(): + """Print confirmation that Python dependencies are installed.""" + print(f"[PY] Python {sys.version.split()[0]} dependencies installed.") + + +def generate_sine_wav(outfile: str, frequency: float = 1000.0, duration: int = 3, + sample_rate: int = 16000, amplitude: float = 0.3) -> bool: + """Generate a sine wave WAV file using only Python stdlib. + + Args: + outfile: Output WAV file path + frequency: Tone frequency in Hz (default: 1000) + duration: Duration in seconds (default: 3) + sample_rate: Sample rate in Hz (default: 16000) + amplitude: Amplitude 0.0-1.0 (default: 0.3) + + Returns: + True on success, False on failure + """ + try: + n_samples = sample_rate * duration + data = array.array("h", [ + int(max(-1.0, min(1.0, amplitude * math.sin(2 * math.pi * frequency * (i / sample_rate)))) * 32767) + for i in range(n_samples) + ]) + with wave.open(outfile, "w") as wf: + wf.setnchannels(1) + wf.setsampwidth(2) + wf.setframerate(sample_rate) + wf.writeframes(data.tobytes()) + return True + except Exception as e: + print(f"[ERROR] Failed to generate WAV: {e}", file=sys.stderr) + return False + + +def prepare_model(model_name: str, model_dir: str) -> bool: + """Download a whisper model for offline use. + + Args: + model_name: Model name (tiny, base, small, medium, large-v3, etc.) + model_dir: Directory to store the model + + Returns: + True on success, False on failure + """ + try: + from faster_whisper import WhisperModel + + # Enable HuggingFace Hub progress bars for model download + try: + from huggingface_hub import logging as hf_logging + hf_logging.set_verbosity_info() + import huggingface_hub + huggingface_hub.constants.HF_HUB_DISABLE_PROGRESS_BARS = False + os.environ["HF_HUB_DISABLE_PROGRESS_BARS"] = "0" + except ImportError: + pass + + print(f"[PY] Preparing model '{model_name}' into {model_dir}") + print("[INFO] Downloading model files (progress bar should appear below)...", flush=True) + WhisperModel(model_name, device="cpu", compute_type="int8", download_root=model_dir) + print("[PY] Model prepared.") + return True + except Exception as e: + print(f"[ERROR] Failed to prepare model: {e}", file=sys.stderr) + return False + + +def test_cuda() -> bool: + """Test CUDA initialization with faster-whisper. + + Returns: + True if CUDA works, False otherwise + """ + try: + from faster_whisper import WhisperModel + WhisperModel("tiny", device="cuda", compute_type="float16") + print("[PY] CUDA test init succeeded.") + return True + except Exception as e: + print(f"[ERROR] CUDA test failed: {e}", file=sys.stderr) + return False + + +def main(): + parser = argparse.ArgumentParser( + description="Helper utilities for transcribe.sh", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Commands: + python-version Print Python major.minor version + check-faster-whisper Check if faster_whisper is installed (exit 7 if not) + check-diarization Check diarization deps (warn if missing) + check-ctranslate2 Check if ctranslate2 is installed (exit 1 if not) + deps-installed Print deps installed confirmation message + generate-wav FILE Generate a 3s 1kHz sine wave WAV file + prepare-model Download model for offline use (requires --model and --model-dir) + test-cuda Test CUDA initialization +""") + parser.add_argument("command", choices=[ + "python-version", + "check-faster-whisper", + "check-diarization", + "check-ctranslate2", + "deps-installed", + "generate-wav", + "prepare-model", + "test-cuda", + ], help="Command to run") + parser.add_argument("--file", help="Output file path (for generate-wav)") + parser.add_argument("--model", help="Model name (for prepare-model)") + parser.add_argument("--model-dir", help="Model directory (for prepare-model)") + + args = parser.parse_args() + + if args.command == "python-version": + print(get_python_version()) + elif args.command == "check-faster-whisper": + if not check_faster_whisper(): + print("Python dependency 'faster_whisper' not found in offline mode. Run with --online to install.", file=sys.stderr) + sys.exit(7) + elif args.command == "check-diarization": + check_diarization_deps() + elif args.command == "check-ctranslate2": + if not check_ctranslate2(): + sys.exit(1) + elif args.command == "deps-installed": + print_deps_installed() + elif args.command == "generate-wav": + if not args.file: + print("--file is required for generate-wav", file=sys.stderr) + sys.exit(2) + if not generate_sine_wav(args.file): + sys.exit(1) + elif args.command == "prepare-model": + if not args.model or not args.model_dir: + print("--model and --model-dir are required for prepare-model", file=sys.stderr) + sys.exit(2) + if not prepare_model(args.model, args.model_dir): + sys.exit(1) + elif args.command == "test-cuda": + if not test_cuda(): + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/scripts/misc/testsAndMisc-bash/transcribe.sh b/scripts/misc/testsAndMisc-bash/transcribe.sh index f7e0049..42e0465 100755 --- a/scripts/misc/testsAndMisc-bash/transcribe.sh +++ b/scripts/misc/testsAndMisc-bash/transcribe.sh @@ -11,6 +11,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$SCRIPT_DIR" TOOLS_DIR="$PROJECT_DIR/tools" PY_RUNNER="$TOOLS_DIR/transcribe_fw.py" +PY_HELPERS="$TOOLS_DIR/transcribe_helpers.py" VENV_DIR="$PROJECT_DIR/.venv" usage() { @@ -73,7 +74,7 @@ has_libcublas12() { # venv-provided NVIDIA CUDA libs if [[ -x "$VENV_DIR/bin/python" ]]; then local pyver - pyver="$("$VENV_DIR"/bin/python -c 'import sys;print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null || true)" + pyver="$("$VENV_DIR"/bin/python "$PY_HELPERS" python-version 2>/dev/null || true)" if [[ -n $pyver ]]; then for d in "$VENV_DIR/lib/python$pyver/site-packages/nvidia/cublas/lib" \ "$VENV_DIR/lib/python$pyver/site-packages/nvidia/cudnn/lib" \ @@ -234,46 +235,37 @@ install_python_deps() { export PIP_DEFAULT_TIMEOUT=${PIP_DEFAULT_TIMEOUT:-20} if [[ $OFFLINE -eq 1 ]]; then # Offline: do not install, just verify modules - if ! python -c 'import faster_whisper' >/dev/null 2>&1; then - echo "Python dependency 'faster_whisper' not found in offline mode. Run with --online to install." >&2 + if ! python "$PY_HELPERS" check-faster-whisper; then exit 7 fi # If diarization requested offline, check for its deps too (warn-only) if [[ ${FW_DIARIZE:-} == "1" ]]; then - python - <<'PY' || true -try: - import soundfile, speechbrain, torch # noqa: F401 -except Exception as e: - print(f"[WARN] Diarization deps missing offline ({e}); speaker labels will be skipped.") -PY + python "$PY_HELPERS" check-diarization || true fi return 0 fi if [[ $has_nvidia_flag -eq 1 ]]; then - # If ctranslate2 is not installed, attempt CUDA-enabled wheel (quiet, with fallback) - if ! "$VENV_DIR/bin/python" -c 'import ctranslate2' >/dev/null 2>&1; then + # If ctranslate2 is not installed, attempt CUDA-enabled wheel (with fallback) + if ! "$VENV_DIR/bin/python" "$PY_HELPERS" check-ctranslate2 2>/dev/null; then log "Installing CUDA-enabled CTranslate2 (cu12 wheel)" - python -m pip install -q --retries 1 --upgrade "ctranslate2<5,>=4.0" --extra-index-url https://download.opennmt.net/ctranslate2/cu12 || + python -m pip install --progress-bar on --retries 1 --upgrade "ctranslate2<5,>=4.0" --extra-index-url https://download.opennmt.net/ctranslate2/cu12 || log "Warning: could not reach cu12 wheel index; will proceed with available ctranslate2" fi # Ensure NVIDIA CUDA 12 runtime libs are available inside the venv - python -m pip install -q --retries 1 --upgrade nvidia-cublas-cu12 nvidia-cuda-runtime-cu12 nvidia-cudnn-cu12 || + python -m pip install --progress-bar on --retries 1 --upgrade nvidia-cublas-cu12 nvidia-cuda-runtime-cu12 nvidia-cudnn-cu12 || log "Warning: failed to install NVIDIA cu12 runtime libs via pip" fi - python -m pip install -q --retries 1 --upgrade faster-whisper ffmpeg-python + python -m pip install --progress-bar on --retries 1 --upgrade faster-whisper ffmpeg-python # If diarization requested and online, install its Python deps best-effort if [[ ${FW_DIARIZE:-} == "1" ]]; then - python -m pip install -q --retries 1 --upgrade soundfile speechbrain || + python -m pip install --progress-bar on --retries 1 --upgrade soundfile speechbrain || log "Warning: failed to install soundfile/speechbrain" # Torch and torchaudio CPU wheels (force to avoid mismatched CUDA builds) - python -m pip install -q --retries 1 --upgrade --force-reinstall --index-url https://download.pytorch.org/whl/cpu torch torchaudio || + python -m pip install --progress-bar on --retries 1 --upgrade --force-reinstall --index-url https://download.pytorch.org/whl/cpu torch torchaudio || log "Warning: failed to install torch/torchaudio CPU wheels" fi - python - <<'PY' -import sys -print(f"[PY] Python {sys.version.split()[0]} dependencies installed.") -PY + python "$PY_HELPERS" deps-installed } ensure_runner() { @@ -298,7 +290,7 @@ generate_test_audio() { # Fallback: generate tone via Python stdlib (no external deps) if [[ ! -s $tmpwav ]]; then log "Generating 3s 1kHz WAV via Python stdlib -> $tmpwav" >&2 - python3 -c 'import sys,wave,math,array;outfile=sys.argv[1];fr=16000;dur=3;freq=1000.0;ampl=0.3;n=fr*dur;data=array.array("h",[int(max(-1.0,min(1.0,ampl*math.sin(2*math.pi*freq*(i/fr))))*32767) for i in range(n)]);wf=wave.open(outfile,"w");wf.setnchannels(1);wf.setsampwidth(2);wf.setframerate(fr);wf.writeframes(data.tobytes());wf.close()' "$tmpwav" || true + python3 "$PY_HELPERS" generate-wav --file "$tmpwav" || true fi # Final fallback: tone via ffmpeg if [[ ! -s $tmpwav ]]; then @@ -315,15 +307,7 @@ prepare_model() { # shellcheck disable=SC1091 source "$VENV_DIR/bin/activate" log "Preparing model '$name' into $MODEL_DIR" - python - </dev/null || true)" + pyver="$("$VENV_DIR"/bin/python "$PY_HELPERS" python-version 2>/dev/null || true)" if [[ -n $pyver ]]; then venv_cuda_paths="$VENV_DIR/lib/python$pyver/site-packages/nvidia/cublas/lib:$VENV_DIR/lib/python$pyver/site-packages/nvidia/cudnn/lib:$VENV_DIR/lib/python$pyver/site-packages/nvidia/cuda_runtime/lib" fi @@ -454,7 +436,7 @@ main() { export PATH="${PATH}:${CUDA_HOME}/bin" # shellcheck disable=SC1091 source "$VENV_DIR/bin/activate" - python -c 'from faster_whisper import WhisperModel; WhisperModel("tiny", device="cuda", compute_type="float16"); print("[PY] CUDA test init succeeded.")' || { + python "$PY_HELPERS" test-cuda || { echo "CUDA environment check failed. Aborting as requested." >&2 exit 6 }