#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$ROOT_DIR" WITH_WHISPER="${WITH_WHISPER:-1}" WHISPER_CUDA="${WHISPER_CUDA:-0}" JOBS="${JOBS:-$(nproc)}" WHISPER_DIR="./vendor/whisper.cpp" MODEL_PATH="./models/ggml-base.en.bin" need_cmd() { if ! command -v "$1" >/dev/null 2>&1; then echo "[build] error: required command '$1' not found" >&2 exit 2 fi } have_cmd() { command -v "$1" >/dev/null 2>&1 } CFLAGS_COMMON=( -std=c99 -Wall -Wextra -Wpedantic -O2 -g -D_POSIX_C_SOURCE=200809L ) LDFLAGS_COMMON=( -lpulse-simple -lpulse -lX11 -lXtst -lpthread ) echo "[build] root: $ROOT_DIR" echo "[build] WITH_WHISPER=$WITH_WHISPER WHISPER_CUDA=$WHISPER_CUDA JOBS=$JOBS" need_cmd gcc need_cmd pkg-config if ! pkg-config --exists gtk+-3.0; then echo "[build] error: gtk+-3.0 dev files not found" >&2 exit 2 fi GTK_CFLAGS_STR="$(pkg-config --cflags gtk+-3.0 2>/dev/null || true)" if [[ -z "$GTK_CFLAGS_STR" ]]; then echo "[build] error: gtk+-3.0 cflags are unavailable" >&2 exit 2 fi if ! printf '#include \n' | gcc -x c -fsyntax-only $GTK_CFLAGS_STR - >/dev/null 2>&1; then echo "[build] error: gtk headers are not usable (gtk/gtk.h check failed)" >&2 exit 2 fi if [[ "$WITH_WHISPER" == "1" ]]; then if ! have_cmd cmake; then echo "[build] warning: cmake not found; forcing WITH_WHISPER=0" >&2 WITH_WHISPER=0 fi fi if [[ "$WITH_WHISPER" == "1" ]]; then if [[ ! -d "$WHISPER_DIR" ]] && ! have_cmd git; then echo "[build] warning: git not found and whisper.cpp is missing; forcing WITH_WHISPER=0" >&2 WITH_WHISPER=0 fi fi if [[ "$WITH_WHISPER" == "1" ]]; then if [[ ! -f "$MODEL_PATH" ]] && ! have_cmd wget; then echo "[build] warning: wget not found and model is missing; forcing WITH_WHISPER=0" >&2 WITH_WHISPER=0 fi fi echo "[build] effective: WITH_WHISPER=$WITH_WHISPER" if [[ "$WITH_WHISPER" == "1" ]]; then if [[ ! -d "$WHISPER_DIR" ]]; then echo "[build] cloning whisper.cpp..." mkdir -p ./vendor git clone https://github.com/ggerganov/whisper.cpp.git "$WHISPER_DIR" fi echo "[build] configuring whisper.cpp..." if [[ "$WHISPER_CUDA" == "1" ]]; then cmake -S "$WHISPER_DIR" -B "$WHISPER_DIR/build" -DGGML_CUDA=ON else cmake -S "$WHISPER_DIR" -B "$WHISPER_DIR/build" fi echo "[build] building whisper.cpp..." cmake --build "$WHISPER_DIR/build" -j"$JOBS" mkdir -p ./models if [[ -x ./scripts/download_models.sh ]]; then echo "[build] ensuring whisper models are downloaded..." bash ./scripts/download_models.sh elif [[ ! -f "$MODEL_PATH" ]]; then echo "[build] downloading model $MODEL_PATH..." wget -O "$MODEL_PATH" \ https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin fi fi echo "[build] building GTK3 app binary..." read -r -a GTK_CFLAGS <<< "$(pkg-config --cflags gtk+-3.0)" read -r -a GTK_LIBS <<< "$(pkg-config --libs gtk+-3.0)" APP_CFLAGS=("${CFLAGS_COMMON[@]}" "${GTK_CFLAGS[@]}") APP_LDFLAGS=("${LDFLAGS_COMMON[@]}" "${GTK_LIBS[@]}") if [[ "$WITH_WHISPER" == "1" ]]; then APP_CFLAGS+=( -DWITH_WHISPER=1 -isystem "$WHISPER_DIR/include" -isystem "$WHISPER_DIR/ggml/include" ) APP_LDFLAGS+=( -L"$WHISPER_DIR/build/src" -L"$WHISPER_DIR/build/ggml/src" -Wl,-rpath,"$WHISPER_DIR/build/src" -Wl,-rpath,"$WHISPER_DIR/build/ggml/src" -lwhisper -lggml ) fi gcc "${APP_CFLAGS[@]}" \ ./src/gui_main.c ./src/config.c ./src/audio.c ./src/transcribe.c ./src/typer.c ./src/voice_cmd.c \ -o ./voice_linux \ "${APP_LDFLAGS[@]}" echo "[build] done: ./voice_linux" echo "[build] run: ./voice_linux"