Last active
June 21, 2026 09:26
-
-
Save leodutra/a0923f416b7cd19369d2fed207c179ac to your computer and use it in GitHub Desktop.
Install Fabric AI on Arch Linux
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
| # ------------------------------------------------------------ | |
| # Helpers | |
| # ------------------------------------------------------------ | |
| zshrc_append() { | |
| # Append a line to ~/.zshrc only if it isn't already there. | |
| local line="$1" | |
| grep -qxF "$line" ~/.zshrc 2>/dev/null || echo "$line" >> ~/.zshrc | |
| } | |
| # ------------------------------------------------------------ | |
| sudo pacman -S --needed base-devel git pkgconf cmake make gcc | |
| # Install Paru | |
| if ! command -v paru >/dev/null 2>&1; then | |
| git clone https://aur.archlinux.org/paru.git | |
| cd paru || exit | |
| makepkg -si | |
| fi | |
| # Install Fabric AI + dependencies | |
| paru -S --needed --noconfirm \ | |
| cmake \ | |
| fabric-ai \ | |
| ffmpeg \ | |
| python \ | |
| python-html2text \ | |
| python-readability-lxml \ | |
| python-requests \ | |
| xclip \ | |
| yt-dlp | |
| # Install Whisper.cpp | |
| cd $HOME | |
| git clone https://github.com/ggml-org/whisper.cpp.git | |
| cd whisper.cpp | |
| sh ./models/download-ggml-model.sh large-v2 | |
| # build the project | |
| cmake -B build -DGGML_CUDA=1 -DCMAKE_CUDA_ARCHITECTURES="86" -D WHISPER_FFMPEG=yes | |
| cmake --build build -j --config Release | |
| cd $HOME | |
| # Install Fabric completions | |
| curl -fsSL https://raw.githubusercontent.com/danielmiessler/Fabric/refs/heads/main/completions/setup-completions.sh | sh | |
| zshrc_append 'source ~/.config/zsh/aliases/fabric-ai-zsh-aliases.zsh' | |
| # Fabric Setup | |
| fabric --setup | |
| # Reload zsh config | |
| source ~/.zshrc |
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
| # ============================================================================= | |
| # Fabric AI | |
| # ============================================================================= | |
| # Main Fabric command. | |
| alias fabric=fabric-ai | |
| # Pattern aliases. | |
| # Creates aliases for all Fabric patterns so they can be invoked directly. | |
| for pattern_file in "$HOME/.config/fabric/patterns"/*; do | |
| pattern_name="$(basename "$pattern_file")" | |
| alias_name="${FABRIC_ALIAS_PREFIX:-}${pattern_name}" | |
| alias_command="alias $alias_name='fabric --pattern $pattern_name'" | |
| eval "$alias_command" | |
| done | |
| # ============================================================================= | |
| # Clipboard Utilities | |
| # ============================================================================= | |
| # Returns clipboard contents (Wayland first, X11 fallback). | |
| p() { | |
| wl-paste --primary 2>/dev/null || xclip -selection clipboard -o | |
| } | |
| # ============================================================================= | |
| # Web Utilities | |
| # ============================================================================= | |
| # Fetch a URL, extract the main readable content, and convert to Markdown. | |
| # | |
| # Usage: | |
| # html https://example.com | |
| html() { | |
| python - "$1" <<'PY' | |
| import sys, requests | |
| from readability import Document | |
| import html2text | |
| url = sys.argv[1] | |
| html = requests.get(url).text | |
| doc = Document(html) | |
| print(html2text.html2text(doc.summary())) | |
| PY | |
| } | |
| # ============================================================================= | |
| # Whisper.cpp transcription helper | |
| # ============================================================================= | |
| # Usage: | |
| # whisper <url-or-file> | |
| # | |
| # Supports local audio/video files and YouTube URLs. | |
| # | |
| # Environment: | |
| # WHISPER_MODEL model name (default: large-v2) | |
| # WHISPER_MODEL_FILE explicit ggml path (default: derived from WHISPER_MODEL) | |
| # WHISPER_CPP_DIR whisper.cpp root (default: ~/whisper.cpp) | |
| # WHISPER_CPP_BIN whisper-cli path (default: <dir>/build/bin/whisper-cli) | |
| # WHISPER_LANG spoken language (default: auto — set "pt"/"en"/... to force) | |
| # WHISPER_THREADS thread count (default: nproc) | |
| # WHISPER_VAD enable Silero VAD (0/1, default 1; needs model present) | |
| # WHISPER_VAD_MODEL Silero VAD ggml path (default: <dir>/models/ggml-silero-v6.2.0.bin) | |
| # WHISPER_SUPPRESS_NST suppress (applause)/(music) tokens (0/1, default 0) | |
| # WHISPER_MAX_LEN max line length (default: 0 = off; cosmetic line-wrap only) | |
| # WHISPER_EXTRA_ARGS extra flags string (passthrough, e.g. "--prompt 'tech jargon'") | |
| # WHISPER_QUIET silence stderr (0/1) | |
| # WHISPER_DEBUG print resolved config (0/1) | |
| # | |
| # Note: whisper.cpp defaults -l to "en", NOT auto-detect. This wrapper defaults to | |
| # "auto" so non-English audio isn't silently transcribed as English (the | |
| # "(speaking in foreign language)" loop). Force WHISPER_LANG when you know the | |
| # language and want to avoid mis-detection on silent/music intros. | |
| whisper() { | |
| local input="$1" | |
| local model="${WHISPER_MODEL:-large-v2}" | |
| local WHISPER_CPP_DIR="${WHISPER_CPP_DIR:-$HOME/whisper.cpp}" | |
| local WHISPER_BIN="${WHISPER_CPP_BIN:-$WHISPER_CPP_DIR/build/bin/whisper-cli}" | |
| local MODEL_FILE="${WHISPER_MODEL_FILE:-$WHISPER_CPP_DIR/models/ggml-${model}.bin}" | |
| local TRANSCRIBE_LANG="${WHISPER_LANG:-auto}" # NOT `LANG` — that shadows the locale env var | |
| local THREADS="${WHISPER_THREADS:-$(nproc)}" | |
| local MAX_LEN="${WHISPER_MAX_LEN:-0}" | |
| local VAD_MODEL="${WHISPER_VAD_MODEL:-$WHISPER_CPP_DIR/models/ggml-silero-v6.2.0.bin}" | |
| local quiet="${WHISPER_QUIET:-0}" | |
| [[ -z "$input" ]] && { | |
| echo "Usage: whisper <url-or-file>" >&2 | |
| return 1 | |
| } | |
| [[ ! -x "$WHISPER_BIN" ]] && { | |
| echo "whisper-cli not found at $WHISPER_BIN" >&2 | |
| echo "Build: cmake -B build -DGGML_CUDA=1 && cmake --build build -j --config Release" >&2 | |
| return 1 | |
| } | |
| [[ ! -f "$MODEL_FILE" ]] && { | |
| echo "Model not found: $MODEL_FILE" >&2 | |
| echo "Download: $WHISPER_CPP_DIR/models/download-ggml-model.sh $model" >&2 | |
| return 1 | |
| } | |
| command -v ffmpeg >/dev/null 2>&1 || { | |
| echo "ffmpeg not found in PATH" >&2 | |
| return 1 | |
| } | |
| if [[ "$input" =~ ^https?:// ]]; then | |
| command -v yt-dlp >/dev/null 2>&1 || { | |
| echo "yt-dlp not found in PATH (required for URLs)" >&2 | |
| return 1 | |
| } | |
| elif [[ ! -f "$input" ]]; then | |
| echo "File not found: $input" >&2 | |
| return 2 | |
| fi | |
| [[ "${WHISPER_DEBUG:-0}" == 1 ]] && { | |
| local vad_state="off" | |
| [[ "${WHISPER_VAD:-1}" == 1 && -f "$VAD_MODEL" ]] && vad_state="on ($VAD_MODEL)" | |
| echo "whisper: model=$MODEL_FILE lang=$TRANSCRIBE_LANG threads=$THREADS vad=$vad_state max_len=$MAX_LEN" >&2 | |
| } | |
| ( | |
| set -o pipefail | |
| [[ "$quiet" == 1 ]] && exec 2>/dev/null | |
| local tmpwav | |
| tmpwav=$(mktemp --suffix=.wav) || exit 1 | |
| trap 'rm -f "$tmpwav"' EXIT | |
| # 16 kHz mono PCM s16le — the format whisper-cli requires | |
| if [[ "$input" =~ ^https?:// ]]; then | |
| yt-dlp -f bestaudio -o - "$input" \ | |
| | ffmpeg -loglevel error -i pipe:0 -ar 16000 -ac 1 -c:a pcm_s16le -y "$tmpwav" </dev/null \ | |
| || { echo "Audio prep failed" >&2; exit 3; } | |
| else | |
| ffmpeg -loglevel error -i "$input" -ar 16000 -ac 1 -c:a pcm_s16le -y "$tmpwav" </dev/null \ | |
| || { echo "Audio prep failed" >&2; exit 3; } | |
| fi | |
| local args=( | |
| -m "$MODEL_FILE" | |
| -f "$tmpwav" | |
| -l "$TRANSCRIBE_LANG" # the one real fix: don't let it silently fall back to "en" | |
| -t "$THREADS" | |
| -nt -np | |
| ) | |
| # opt-in hardening | |
| [[ "${WHISPER_SUPPRESS_NST:-0}" == 1 ]] && args+=( --suppress-nst ) | |
| [[ "${WHISPER_VAD:-1}" == 1 && -f "$VAD_MODEL" ]] && args+=( --vad --vad-model "$VAD_MODEL" ) | |
| [[ "$MAX_LEN" != "0" ]] && args+=( --max-len "$MAX_LEN" --split-on-word ) | |
| # passthrough — quote-aware via xargs, no eval (no injection / no broken quoting). | |
| # Prefer a real array if you embed odd characters: WHISPER_EXTRA_ARGS_ARR=(--prompt "x y") | |
| if [[ -n "${WHISPER_EXTRA_ARGS:-}" ]]; then | |
| local extra=() | |
| mapfile -t extra < <(printf '%s' "$WHISPER_EXTRA_ARGS" | xargs printf '%s\n') | |
| args+=( "${extra[@]}" ) | |
| fi | |
| [[ -n "${WHISPER_EXTRA_ARGS_ARR:-}" ]] && args+=( "${WHISPER_EXTRA_ARGS_ARR[@]}" ) | |
| "$WHISPER_BIN" "${args[@]}" | |
| ) | |
| } | |
| # ============================================================================= | |
| # YouTube Helpers | |
| # ============================================================================= | |
| # Extract transcript using Fabric. | |
| # | |
| # Usage: | |
| # yt <youtube-url> | |
| # yt -t <youtube-url> | |
| # | |
| # Options: | |
| # -t, --timestamps | |
| # Include timestamps in transcript output. | |
| yt() { | |
| if [ "$#" -eq 0 ] || [ "$#" -gt 2 ]; then | |
| echo "Usage: yt [-t | --timestamps] youtube-link" | |
| echo "Use the '-t' flag to get the transcript with timestamps." | |
| return 1 | |
| fi | |
| transcript_flag="--transcript" | |
| if [ "$1" = "-t" ] || [ "$1" = "--timestamps" ]; then | |
| transcript_flag="--transcript-with-timestamps" | |
| shift | |
| fi | |
| local video_link="$1" | |
| fabric -y "$video_link" $transcript_flag | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment