122 lines
3.8 KiB
Bash
Executable File
122 lines
3.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# One-off "high-quality" transcription that overrides the cached transcript
|
|
# in the most recent run directory for the given video, then re-runs the
|
|
# merger so the enhanced transcript is regenerated using the existing frames.
|
|
#
|
|
# Usage:
|
|
# ./transcribe_oneoff.sh <video> [language]
|
|
# language: optional ISO code (es, en). Omit for auto-detect.
|
|
#
|
|
# What this does differently from the main pipeline:
|
|
# 1. Reuses the existing run directory (frames cache stays put).
|
|
# 2. Preprocesses audio: loudnorm + light denoise + speech-band filter.
|
|
# 3. Uses whisperx large-v3 with int8 quantization (fits in ~3-4 GB GPU).
|
|
# 4. Stricter no-speech / logprob thresholds to suppress hallucinations on
|
|
# silent stretches (the source of the random Arabic/etc. drift).
|
|
# 5. Backs up the old <stem>.json before overwriting, so it is recoverable.
|
|
# 6. Re-runs process_meeting.py without --run-whisper/--diarize so the new
|
|
# transcript is picked up from cache and merged with the cached frames.
|
|
|
|
set -euo pipefail
|
|
|
|
VIDEO="${1:?usage: $0 <video> [language]}"
|
|
LANG="${2:-}"
|
|
|
|
VENV_DIR="/home/mariano/wdir/venv/def"
|
|
if [[ ! -f "$VENV_DIR/bin/activate" ]]; then
|
|
echo "ERROR: venv not found at $VENV_DIR" >&2
|
|
exit 1
|
|
fi
|
|
# shellcheck disable=SC1091
|
|
source "$VENV_DIR/bin/activate"
|
|
|
|
WHISPERX="whisperx"
|
|
PYTHON="python"
|
|
|
|
if [[ ! -f "$VIDEO" ]]; then
|
|
echo "ERROR: video not found: $VIDEO" >&2
|
|
exit 1
|
|
fi
|
|
|
|
STEM="$(basename "${VIDEO%.*}")"
|
|
|
|
# Locate the most recent run dir for this video stem.
|
|
RUN_DIR="$(ls -1dt output/*-"$STEM" 2>/dev/null | head -n1 || true)"
|
|
if [[ -z "$RUN_DIR" || ! -d "$RUN_DIR" ]]; then
|
|
echo "ERROR: no existing run dir found under output/ for stem '$STEM'." >&2
|
|
echo " Run process_meeting.py at least once first to extract frames." >&2
|
|
exit 1
|
|
fi
|
|
echo "==> Using run dir: $RUN_DIR"
|
|
|
|
TRANSCRIPT_JSON="$RUN_DIR/${STEM}.json"
|
|
|
|
# Back up the old transcript before overwrite.
|
|
if [[ -f "$TRANSCRIPT_JSON" ]]; then
|
|
BACKUP="$TRANSCRIPT_JSON.bak.$(date +%Y%m%d-%H%M%S)"
|
|
cp "$TRANSCRIPT_JSON" "$BACKUP"
|
|
echo "==> Backed up old transcript → $BACKUP"
|
|
fi
|
|
|
|
# No audio preprocessing: previous attempts with afftdn/loudnorm caused VAD
|
|
# to drop the bulk of the meeting after ~20min. Feed the raw video directly;
|
|
# whisperx will extract audio internally.
|
|
INPUT_AUDIO="$VIDEO"
|
|
|
|
# cuDNN libs for whisperx (mirrors what process_meeting.py does).
|
|
SITE_PKGS="$(python -c 'import site; print(site.getsitepackages()[0])')"
|
|
CUDNN_LIB="$SITE_PKGS/nvidia/cudnn/lib"
|
|
if [[ -d "$CUDNN_LIB" ]]; then
|
|
export LD_LIBRARY_PATH="$CUDNN_LIB:${LD_LIBRARY_PATH:-}"
|
|
fi
|
|
|
|
# whisperx writes <input_basename>.json into --output_dir.
|
|
# Our input basename is "${STEM}_clean", so we redirect to a temp dir and
|
|
# move the result into place under the canonical name.
|
|
TX_TMP="$(mktemp -d)"
|
|
trap 'rm -rf "$TX_TMP"' EXIT
|
|
|
|
CMD=(
|
|
"$WHISPERX" "$INPUT_AUDIO"
|
|
--model large-v3
|
|
--compute_type int8
|
|
--batch_size 4
|
|
--output_format json
|
|
--output_dir "$TX_TMP"
|
|
--diarize
|
|
)
|
|
|
|
if [[ -n "$LANG" ]]; then
|
|
echo "==> Forcing language: $LANG"
|
|
CMD+=(--language "$LANG")
|
|
else
|
|
echo "==> Auto-detecting language"
|
|
fi
|
|
|
|
if [[ -n "${HF_TOKEN:-}" ]]; then
|
|
CMD+=(--hf_token "$HF_TOKEN")
|
|
fi
|
|
|
|
echo "==> Running: ${CMD[*]}"
|
|
"${CMD[@]}"
|
|
|
|
# Move whisperx output into place under the canonical name expected by the cache.
|
|
# whisperx names output by the input basename (without extension).
|
|
NEW_JSON="$TX_TMP/${STEM}.json"
|
|
if [[ ! -f "$NEW_JSON" ]]; then
|
|
echo "ERROR: expected whisperx output not found: $NEW_JSON" >&2
|
|
exit 1
|
|
fi
|
|
mv "$NEW_JSON" "$TRANSCRIPT_JSON"
|
|
echo "==> Wrote new transcript → $TRANSCRIPT_JSON"
|
|
|
|
echo
|
|
echo "==> Re-running merger to regenerate enhanced transcript with cached frames"
|
|
"$PYTHON" process_meeting.py "$VIDEO" \
|
|
--embed-images \
|
|
--scene-detection \
|
|
--scene-threshold 10
|
|
|
|
echo
|
|
echo "==> Done."
|