Created
February 17, 2025 06:08
-
-
Save bfollington/08211733948ad941d7e1c9772eba13b6 to your computer and use it in GitHub Desktop.
Transcribe from microphone
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Function to check if a command exists | |
command_exists() { | |
command -v "$1" >/dev/null 2>&1 | |
} | |
# Function to install mlx_whisper using uv | |
install_mlx_whisper() { | |
if command_exists uv; then | |
echo "Installing mlx_whisper using uv..." >&2 | |
uv pip install mlx-whisper >&2 | |
else | |
echo "Error: uv is not installed." >&2 | |
echo "Please visit https://github.com/astral-sh/uv to install uv first" >&2 | |
echo "Then run this script again." >&2 | |
exit 1 | |
fi | |
} | |
# Function to check dependencies | |
check_dependencies() { | |
local missing_deps=false | |
if ! command_exists mlx_whisper; then | |
echo "mlx_whisper is not installed." >&2 | |
read -p "Would you like to install it now? (y/n) " -n 1 -r | |
echo >&2 | |
if [[ $REPLY =~ ^[Yy]$ ]]; then | |
install_mlx_whisper | |
else | |
missing_deps=true | |
fi | |
fi | |
if ! command_exists ffmpeg; then | |
echo "ffmpeg is not installed." >&2 | |
echo "Please install ffmpeg using your package manager:" >&2 | |
echo " macOS: brew install ffmpeg" >&2 | |
echo " Ubuntu/Debian: sudo apt install ffmpeg" >&2 | |
echo " Other: https://ffmpeg.org/download.html" >&2 | |
missing_deps=true | |
fi | |
if [ "$missing_deps" = true ]; then | |
exit 1 | |
fi | |
} | |
# Function to display usage information | |
usage() { | |
echo "Usage: $0 [input_file]" >&2 | |
echo "If no input file is provided, will record audio until Ctrl+C is pressed" >&2 | |
exit 1 | |
} | |
format="txt" # default format | |
while getopts "f:" opt; do | |
case $opt in | |
f) format="$OPTARG" ;; | |
*) usage ;; | |
esac | |
done | |
shift $((OPTIND-1)) | |
# Check dependencies first | |
check_dependencies | |
# Create temporary directory | |
temp_dir=$(mktemp -d) | |
temp_audio="${temp_dir}/recording.wav" | |
# Function to clean up temporary files | |
cleanup() { | |
rm -rf "$temp_dir" | |
} | |
trap cleanup EXIT | |
if [ $# -eq 0 ]; then | |
# No input file - record audio | |
echo "Recording audio... Press Ctrl+C to stop" >&2 | |
# Trap Ctrl+C (SIGINT) to gracefully stop recording | |
trap 'kill $FF_PID; wait $FF_PID' INT | |
ffmpeg -f avfoundation -i ":2" -acodec pcm_s16le "$temp_audio" >/dev/null 2>&1 & | |
FF_PID=$! | |
# Wait for ffmpeg to be killed by Ctrl+C | |
wait $FF_PID || true | |
# Reset the trap | |
trap - INT | |
# Check if we actually recorded something | |
if [ -f "$temp_audio" ] && [ -s "$temp_audio" ]; then | |
echo -e "\nRecording stopped. Transcribing..." >&2 | |
input_file="$temp_audio" | |
else | |
echo -e "\nNo recording created. Exiting." >&2 | |
exit 1 | |
fi | |
else | |
input_file=$(realpath "$1") | |
fi | |
clean_output() { | |
local format=$1 | |
if [ "$format" = "srt" ]; then | |
# Remove frontmatter and keep SRT format | |
awk '/\[.*\]/{p=1}p' | grep '^\[' 2>/dev/null | |
else | |
# Convert to plain text by removing timestamps and joining lines | |
awk '/\[.*\]/{p=1}p' | \ | |
grep '^\[' | \ | |
sed -E 's/\[.*\]//g' | \ | |
awk 'NF' | \ | |
tr -d '\n' | \ | |
sed 's/ / /g' 2>/dev/null | |
echo 2>/dev/null # Add final newline | |
fi | |
} | |
# Run mlx_whisper and output plain text | |
mlx_whisper "$input_file" \ | |
--language en \ | |
--output-format ${format:-txt} | clean_output "${format:-txt}" | pbcopy |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment