Add OpenWhispr easy setup installer and companion files

Single-file bash installer (setup-openwhispr.sh) with distro detection,
dependency installation, STT/AI cleanup provider selection, API key
management, and first-run launch. Includes README, LICENSE (MIT),
CHANGELOG, .gitignore, ShellCheck CI, issue templates, PR template,
and GitHub setup guide.

https://claude.ai/code/session_01XKYC1basxdwtHy71tky7xm
This commit is contained in:
Claude
2026-03-25 12:57:53 +00:00
parent abf5062779
commit da73b43b1d
10 changed files with 996 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
---
name: Bug report
about: Report a problem with the installer
title: "[Bug] "
labels: bug
assignees: ""
---
## Describe the bug
A clear and concise description of what went wrong.
## Steps to reproduce
1. Run `bash setup-openwhispr.sh`
2. Choose option ...
3. See error ...
## Expected behaviour
What you expected to happen.
## Environment
- **Distro**: (e.g., Ubuntu 24.04)
- **Architecture**: (e.g., x86_64 / aarch64)
- **Session type**: (X11 / Wayland)
- **Desktop**: (GNOME / KDE / other)
- **OpenWhispr version**: (if already installed)
- **Script version**: (run `head -5 setup-openwhispr.sh`)
## Terminal output
```
Paste relevant output here
```
## Additional context
Anything else that might help.
+33
View File
@@ -0,0 +1,33 @@
---
name: Distro compatibility report
about: Report whether the installer works on your distro
title: "[Distro] "
labels: distro-report
assignees: ""
---
## Distribution details
- **Distro**: (e.g., Pop!_OS 24.04)
- **Based on**: (e.g., Ubuntu / Debian / Arch / independent)
- **Architecture**: (x86_64 / aarch64)
- **Session type**: (X11 / Wayland)
- **Desktop environment**: (GNOME / KDE / Sway / other)
## Result
- [ ] Script detected distro correctly
- [ ] OpenWhispr installed successfully
- [ ] Paste dependencies installed correctly
- [ ] API keys stored correctly
- [ ] OpenWhispr launched after install
## Notes
Any issues, workarounds, or suggestions for this distro.
## Terminal output
```
Paste full script output here
```
+19
View File
@@ -0,0 +1,19 @@
## What does this PR do?
Brief description of the change.
## Checklist
- [ ] `bash -n setup-openwhispr.sh` passes (no syntax errors)
- [ ] ShellCheck passes with no new warnings
- [ ] Tested on at least one supported distro
- [ ] Updated CHANGELOG.md if user-facing
- [ ] No hardcoded paths or usernames (uses YOUR_USERNAME placeholder or is generic)
## Testing
Describe how you tested this change.
## Related issues
Closes #
+23
View File
@@ -0,0 +1,23 @@
name: ShellCheck
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
shellcheck:
name: ShellCheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install ShellCheck
run: sudo apt-get install -y shellcheck
- name: Run ShellCheck
run: shellcheck -x setup-openwhispr.sh
+15
View File
@@ -0,0 +1,15 @@
# OS
.DS_Store
Thumbs.db
# Editor
*.swp
*.swo
*~
.vscode/
.idea/
# Temp
/tmp/
*.bak
*.tmp
+24
View File
@@ -0,0 +1,24 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/),
and this project adheres to [Semantic Versioning](https://semver.org/).
## [1.0.0] — 2026-03-25
### Added
- Single-file bash installer `setup-openwhispr.sh`
- Automatic distro detection (Ubuntu, Debian, Mint, Fedora, openSUSE, Arch)
- Architecture detection (amd64, arm64)
- GitHub releases integration — fetches latest OpenWhispr automatically
- Paste dependency detection (xdotool / kdotool / wtype / D-Bus)
- STT provider selection: local Whisper/Parakeet, Groq, OpenAI Realtime
- AI cleanup provider selection: OpenAI, Anthropic, Groq, Ollama, skip
- Safe API key storage in `~/.bashrc` (never overwrites existing keys)
- Idempotent — safe to re-run, skips already-installed versions
- ShellCheck CI via GitHub Actions
- README with cost table, privacy table, and one-command install
- Issue templates for bug reports and distro compatibility reports
- Pull request template
+88
View File
@@ -0,0 +1,88 @@
# GitHub Repository Setup Guide
Step-by-step instructions to publish this project on GitHub.
## 1. Create a new GitHub repository
Go to [github.com/new](https://github.com/new) and create a repository:
- **Name**: `openwhispr-easy-setup`
- **Description**: `One-command installer for OpenWhispr on Linux — distro detection, dependencies, API keys, first-run setup`
- **Visibility**: Public
- **Do NOT** initialize with README, .gitignore, or license (we already have them)
## 2. Push local files
```bash
cd openwhispr-easy-setup
git init
git add .
git commit -m "Initial release v1.0.0"
git branch -M main
git remote add origin https://github.com/YOUR_USERNAME/openwhispr-easy-setup.git
git push -u origin main
```
## 3. Replace YOUR_USERNAME placeholder
Replace `YOUR_USERNAME` with your actual GitHub username in all files:
```bash
sed -i 's/YOUR_USERNAME/your-actual-username/g' setup-openwhispr.sh README.md GITHUB_SETUP.md LICENSE
```
Then commit:
```bash
git add -A
git commit -m "Replace YOUR_USERNAME with actual username"
git push
```
## 4. Tag the v1.0.0 release
```bash
git tag -a v1.0.0 -m "v1.0.0 — Initial release"
git push origin v1.0.0
```
Then go to **Releases → Draft a new release**:
- **Tag**: `v1.0.0`
- **Title**: `v1.0.0 — Initial release`
- **Description**: Copy the [CHANGELOG.md](CHANGELOG.md) entries for v1.0.0
- Click **Publish release**
## 5. Add GitHub topics
Go to your repository page → click the gear icon next to **About** → add these topics:
```
linux
voice-dictation
openwhispr
speech-to-text
whisper
easy-install
```
## 6. Set repository description
In the same **About** section, set the description to:
> One-command installer for OpenWhispr on Linux — distro detection, dependencies, API keys, first-run setup
## 7. Verify
- [ ] README renders correctly with badges
- [ ] ShellCheck CI runs on push (check **Actions** tab)
- [ ] Issue templates appear when creating new issues
- [ ] PR template appears when opening a pull request
- [ ] `bash <(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/openwhispr-easy-setup/main/setup-openwhispr.sh)` works
## Done!
Share the one-liner with anyone who wants to install OpenWhispr:
```bash
bash <(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/openwhispr-easy-setup/main/setup-openwhispr.sh)
```
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 YOUR_USERNAME
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+114
View File
@@ -0,0 +1,114 @@
# OpenWhispr Easy Setup
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![ShellCheck](https://github.com/YOUR_USERNAME/openwhispr-easy-setup/actions/workflows/lint.yml/badge.svg)](https://github.com/YOUR_USERNAME/openwhispr-easy-setup/actions/workflows/lint.yml)
**One-command installer for [OpenWhispr](https://github.com/OpenWhispr/openwhispr) on Linux** — distro detection, dependencies, API keys, first-run setup.
> *Your voice stays on your machine. Always. The only question is whether you want AI to clean up the text after transcription.*
## Quick install
```bash
bash <(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/openwhispr-easy-setup/main/setup-openwhispr.sh)
```
Or clone and run:
```bash
git clone https://github.com/YOUR_USERNAME/openwhispr-easy-setup.git
cd openwhispr-easy-setup
bash setup-openwhispr.sh
```
## What it does
| Step | Action | Details |
|------|--------|---------|
| 1/8 | **Intro** | Explains OpenWhispr and the privacy model |
| 2/8 | **Detect distro + arch** | Ubuntu, Debian, Mint, Fedora, openSUSE, Arch — amd64/arm64 |
| 3/8 | **Install OpenWhispr** | Fetches latest release from GitHub, picks correct package |
| 4/8 | **Paste dependencies** | xdotool (X11), wtype (Wayland), kdotool (KDE), or D-Bus (GNOME) |
| 5/8 | **STT provider** | Local Whisper/Parakeet, Groq, or OpenAI Realtime |
| 6/8 | **AI cleanup** | OpenAI, Anthropic, Groq, Ollama, or skip |
| 7/8 | **First launch** | Opens OpenWhispr for model download and hotkey setup |
| 8/8 | **Summary** | Prints config, useful commands, and next steps |
## STT options
| Option | Method | Streaming | Cost | Audio sent to |
|--------|--------|-----------|------|---------------|
| 1 (default) | Local Whisper/Parakeet | No | Free | Nobody, ever |
| 2 | Groq whisper-large-v3-turbo | No | $0.04/hr* | Groq servers |
| 3 | OpenAI Realtime API | Yes | $0.06/min | OpenAI servers |
\*Groq free tier: ~2,000 audio seconds/day.
## AI cleanup options
| Provider | Model | Per use | 50/day/mo | 200/day/mo |
|----------|-------|---------|-----------|------------|
| OpenAI | gpt-4o-mini-2024-07-18 | $0.000058 | $0.09 | $0.35 |
| Anthropic | claude-haiku-4-5 | $0.000450 | $0.68 | $2.70 |
| Groq | llama-3.3-70b-versatile | Free* | Free* | Free* |
| Ollama | Local (fully offline) | Free | Free | Free |
| Skip | Raw transcription only | Free | Free | Free |
\*Groq free: 1,000 req/day, 100K tokens/day.
## Privacy
| Data | Where it goes | Condition |
|------|---------------|-----------|
| **Audio** | Stays on your machine | Default (local Whisper/Parakeet) |
| **Audio** | Groq or OpenAI servers | Only if you choose cloud STT |
| **Text** | AI cleanup provider | Only if you choose AI cleanup |
| **API keys** | `~/.bashrc` on your machine | Never sent anywhere by this script |
No provider uses your data for training. Cloud data is deleted within 30 days.
## Useful commands
```bash
openwhispr # Launch the app
openwhispr --help # Show options
source ~/.bashrc # Reload API keys in current shell
```
In the app:
- **Settings → Hotkey** — change your hotkey (default: backtick `` ` ``)
- **Settings → Models** — download better speech models
- **Settings → Processing** — change STT or AI provider
## Supported distros
| Distro | Package format | Status |
|--------|---------------|--------|
| Ubuntu / Debian / Mint | `.deb` | Supported |
| Fedora | `.rpm` (dnf) | Supported |
| openSUSE | `.rpm` (zypper) | Supported |
| Arch / Manjaro / EndeavourOS | `.tar.gz` | Supported |
Architecture: `x86_64` (amd64) and `aarch64` (arm64).
## Requirements
- **bash 4+**
- **curl** — for downloading
- **jq** — for parsing GitHub API (script offers to install if missing)
## Safe to re-run
The script is idempotent:
- Skips OpenWhispr install if the latest version is already present
- Never overwrites existing API keys in `~/.bashrc`
- Detects already-installed paste dependencies
## Troubleshooting
- [OpenWhispr Troubleshooting Guide](https://github.com/OpenWhispr/openwhispr/blob/main/TROUBLESHOOTING.md)
- [Open an issue](https://github.com/YOUR_USERNAME/openwhispr-easy-setup/issues/new/choose)
## License
[MIT](LICENSE)
+619
View File
@@ -0,0 +1,619 @@
#!/usr/bin/env bash
# setup-openwhispr.sh — One-command installer for OpenWhispr on Linux
# https://github.com/YOUR_USERNAME/openwhispr-easy-setup
# License: MIT
# Do NOT use set -e — we handle errors explicitly
readonly SCRIPT_VERSION="1.0.0"
readonly BASHRC="$HOME/.bashrc"
readonly MARKER="# Added by openwhispr-easy-setup"
readonly GITHUB_API="https://api.github.com/repos/OpenWhispr/openwhispr/releases/latest"
readonly TMP_DIR="/tmp/openwhispr-install"
# ── Colours & formatting ─────────────────────────────────────────────────────
if [[ -t 1 ]]; then
BOLD='\033[1m'
DIM='\033[2m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
CYAN='\033[0;36m'
RESET='\033[0m'
else
BOLD='' DIM='' GREEN='' YELLOW='' RED='' CYAN='' RESET=''
fi
# ── Helper functions ──────────────────────────────────────────────────────────
# shellcheck disable=SC2059
info() { printf "${GREEN}[✓]${RESET} %s\n" "$*"; }
# shellcheck disable=SC2059
warn() { printf "${YELLOW}[!]${RESET} %s\n" "$*"; }
# shellcheck disable=SC2059
err() { printf "${RED}[✗]${RESET} %s\n" "$*" >&2; }
# shellcheck disable=SC2059
step() { printf "\n${BOLD}${CYAN}[%s]${RESET} ${BOLD}%s${RESET}\n" "$1" "$2"; }
# shellcheck disable=SC2059
divider() { printf "${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n"; }
prompt_default() {
# Usage: prompt_default "prompt text" "default" VARNAME
local prompt="$1" default="$2" varname="$3" reply
printf "%s [default: %s]: " "$prompt" "$default"
read -r reply
reply="${reply:-$default}"
printf -v "$varname" '%s' "$reply"
}
prompt_hidden() {
# Usage: prompt_hidden "prompt text" VARNAME
local prompt="$1" varname="$2" reply
printf "%s: " "$prompt"
read -rs reply
printf "\n"
printf -v "$varname" '%s' "$reply"
}
store_api_key() {
# Usage: store_api_key VARNAME value
local keyname="$1" keyval="$2"
if [[ -z "$keyval" ]]; then
warn "Empty value for $keyname — skipping."
return 1
fi
# Check if already present in bashrc
if grep -q "^export ${keyname}=" "$BASHRC" 2>/dev/null; then
info "$keyname already set in $BASHRC — not overwriting."
else
printf '\n%s\nexport %s="%s"\n' "$MARKER" "$keyname" "$keyval" >> "$BASHRC"
info "$keyname stored in $BASHRC"
fi
# Also export for current session
export "$keyname=$keyval"
}
command_exists() { command -v "$1" >/dev/null 2>&1; }
# ── Variables set during the run ──────────────────────────────────────────────
DISTRO="" # debian, ubuntu, mint, fedora, arch, opensuse
DISTRO_FAMILY="" # deb, rpm-dnf, rpm-zypper, arch
ARCH="" # amd64, arm64
SESSION_TYPE="" # x11, wayland
DESKTOP="" # GNOME, KDE, etc.
STT_CHOICE=""
CLEANUP_CHOICE=""
STT_LABEL=""
CLEANUP_LABEL=""
INSTALLED_VERSION=""
LATEST_VERSION=""
# ══════════════════════════════════════════════════════════════════════════════
# [1/8] Intro
# ══════════════════════════════════════════════════════════════════════════════
step "1/8" "Welcome to OpenWhispr Easy Setup v${SCRIPT_VERSION}"
divider
cat <<'INTRO'
OpenWhispr is an Electron-based voice dictation app for Linux.
Press a hotkey, speak, and your words appear wherever the cursor is.
Your voice stays on your machine. Always.
The only question is whether you want AI to clean up
the text after transcription.
Speech-to-text (STT) is local Whisper/Parakeet by default.
Audio never leaves your machine unless YOU explicitly choose a cloud option.
This script will:
1. Detect your distro and architecture
2. Install OpenWhispr (latest release)
3. Install paste/typing dependencies
4. Configure STT provider
5. Configure AI text cleanup
6. Launch OpenWhispr for first-run setup
INTRO
divider
printf "\nPress Enter to continue or Ctrl-C to cancel... "
read -r
# ══════════════════════════════════════════════════════════════════════════════
# [2/8] Detect distro + arch
# ══════════════════════════════════════════════════════════════════════════════
step "2/8" "Detecting distribution and architecture"
detect_distro() {
if [[ -f /etc/os-release ]]; then
# shellcheck source=/dev/null
. /etc/os-release
case "${ID,,}" in
ubuntu) DISTRO="ubuntu"; DISTRO_FAMILY="deb" ;;
debian) DISTRO="debian"; DISTRO_FAMILY="deb" ;;
linuxmint) DISTRO="mint"; DISTRO_FAMILY="deb" ;;
fedora) DISTRO="fedora"; DISTRO_FAMILY="rpm-dnf" ;;
opensuse*|sles) DISTRO="opensuse"; DISTRO_FAMILY="rpm-zypper" ;;
arch|manjaro|endeavouros) DISTRO="arch"; DISTRO_FAMILY="arch" ;;
*)
err "Unsupported distribution: ${ID} (${PRETTY_NAME:-unknown})"
err "Supported: Ubuntu, Debian, Mint, Fedora, openSUSE, Arch"
exit 1
;;
esac
else
err "Cannot detect distribution (/etc/os-release not found)."
exit 1
fi
}
detect_arch() {
local machine
machine="$(uname -m)"
case "$machine" in
x86_64) ARCH="amd64" ;;
aarch64) ARCH="arm64" ;;
*)
err "Unsupported architecture: $machine"
err "Supported: x86_64 (amd64), aarch64 (arm64)"
exit 1
;;
esac
}
detect_distro
detect_arch
info "Distro: ${DISTRO} (${DISTRO_FAMILY}) | Arch: ${ARCH}"
# ── Check base dependencies ───────────────────────────────────────────────────
if ! command_exists curl; then
err "curl is required but not installed."
err "Install it with your package manager and re-run this script."
exit 1
fi
if ! command_exists jq; then
warn "jq is required but not installed."
printf "Install jq now? [Y/n]: "
read -r jq_reply
jq_reply="${jq_reply:-Y}"
if [[ "${jq_reply,,}" == "y" ]]; then
case "$DISTRO_FAMILY" in
deb) sudo apt update && sudo apt install -y jq ;;
rpm-dnf) sudo dnf install -y jq ;;
rpm-zypper) sudo zypper install -y jq ;;
arch) sudo pacman -S --noconfirm jq ;;
esac
if ! command_exists jq; then
err "Failed to install jq. Please install it manually and re-run."
exit 1
fi
info "jq installed."
else
err "jq is required. Please install it and re-run."
exit 1
fi
fi
# ══════════════════════════════════════════════════════════════════════════════
# [3/8] Install OpenWhispr
# ══════════════════════════════════════════════════════════════════════════════
step "3/8" "Installing OpenWhispr"
# Check currently installed version
get_installed_version() {
if command_exists openwhispr; then
openwhispr --version 2>/dev/null || true
elif command_exists open-whispr; then
open-whispr --version 2>/dev/null || true
fi
}
INSTALLED_VERSION="$(get_installed_version)"
# Fetch latest release info
info "Fetching latest release info..."
RELEASE_JSON="$(curl -sf "$GITHUB_API")" || {
err "Failed to fetch release info from GitHub."
err "Check your internet connection and try again."
exit 1
}
LATEST_VERSION="$(printf '%s' "$RELEASE_JSON" | jq -r '.tag_name // empty')"
if [[ -z "$LATEST_VERSION" ]]; then
err "Could not determine latest version from GitHub."
exit 1
fi
info "Latest version: ${LATEST_VERSION}"
# Strip leading 'v' for comparison
LATEST_CLEAN="${LATEST_VERSION#v}"
INSTALLED_CLEAN="${INSTALLED_VERSION#v}"
if [[ -n "$INSTALLED_VERSION" && "$INSTALLED_CLEAN" == "$LATEST_CLEAN" ]]; then
info "OpenWhispr ${LATEST_VERSION} is already installed — skipping."
else
if [[ -n "$INSTALLED_VERSION" ]]; then
info "Upgrading from ${INSTALLED_VERSION} to ${LATEST_VERSION}..."
fi
# Determine asset pattern
case "$DISTRO_FAMILY" in
deb) ASSET_EXT=".deb" ;;
rpm-dnf|rpm-zypper) ASSET_EXT=".rpm" ;;
arch) ASSET_EXT=".tar.gz" ;;
esac
# Map arch names (assets may use different conventions)
case "$ARCH" in
amd64) ARCH_PATTERNS=("amd64" "x86_64" "x64") ;;
arm64) ARCH_PATTERNS=("arm64" "aarch64") ;;
esac
# Find matching asset URL
ASSET_URL=""
for arch_pat in "${ARCH_PATTERNS[@]}"; do
ASSET_URL="$(printf '%s' "$RELEASE_JSON" | jq -r \
--arg ext "$ASSET_EXT" --arg arch "$arch_pat" \
'.assets[] | select(.name | (endswith($ext) and contains($arch))) | .browser_download_url' \
| head -1)"
[[ -n "$ASSET_URL" ]] && break
done
if [[ -z "$ASSET_URL" ]]; then
err "No ${ASSET_EXT} asset found for ${ARCH} in release ${LATEST_VERSION}."
err "Check: https://github.com/OpenWhispr/openwhispr/releases/latest"
exit 1
fi
ASSET_NAME="$(basename "$ASSET_URL")"
info "Downloading ${ASSET_NAME}..."
mkdir -p "$TMP_DIR"
curl --progress-bar -fL -o "${TMP_DIR}/${ASSET_NAME}" "$ASSET_URL" || {
err "Download failed."
exit 1
}
info "Installing..."
case "$DISTRO_FAMILY" in
deb)
sudo apt install -y "${TMP_DIR}/${ASSET_NAME}" || {
err "Installation failed. Try: sudo dpkg -i ${TMP_DIR}/${ASSET_NAME}"
exit 1
}
;;
rpm-dnf)
sudo dnf install -y "${TMP_DIR}/${ASSET_NAME}" || {
err "Installation failed."
exit 1
}
;;
rpm-zypper)
sudo zypper install -y "${TMP_DIR}/${ASSET_NAME}" || {
err "Installation failed."
exit 1
}
;;
arch)
sudo mkdir -p /opt/openwhispr
sudo tar -xzf "${TMP_DIR}/${ASSET_NAME}" -C /opt/openwhispr || {
err "Extraction failed."
exit 1
}
# Find the binary and symlink
local_bin="$(find /opt/openwhispr -maxdepth 2 -name 'openwhispr' -o -name 'open-whispr' 2>/dev/null | head -1)"
if [[ -n "$local_bin" ]]; then
sudo ln -sf "$local_bin" /usr/local/bin/openwhispr
fi
;;
esac
# Clean up
rm -rf "$TMP_DIR"
info "OpenWhispr ${LATEST_VERSION} installed successfully."
fi
# ══════════════════════════════════════════════════════════════════════════════
# [4/8] Install paste dependencies
# ══════════════════════════════════════════════════════════════════════════════
step "4/8" "Installing paste/typing dependencies"
SESSION_TYPE="${XDG_SESSION_TYPE:-}"
DESKTOP="${XDG_CURRENT_DESKTOP:-}"
if [[ -z "$SESSION_TYPE" ]]; then
# Try to detect
if [[ -n "${WAYLAND_DISPLAY:-}" ]]; then
SESSION_TYPE="wayland"
elif [[ -n "${DISPLAY:-}" ]]; then
SESSION_TYPE="x11"
else
warn "Cannot detect session type (X11/Wayland). Skipping paste deps."
fi
fi
info "Session: ${SESSION_TYPE:-unknown} | Desktop: ${DESKTOP:-unknown}"
install_paste_dep() {
local pkg="$1"
if command_exists "$pkg"; then
info "$pkg is already installed."
return 0
fi
info "Installing $pkg..."
case "$DISTRO_FAMILY" in
deb) sudo apt install -y "$pkg" ;;
rpm-dnf) sudo dnf install -y "$pkg" ;;
rpm-zypper) sudo zypper install -y "$pkg" ;;
arch) sudo pacman -S --noconfirm "$pkg" ;;
esac
}
case "$SESSION_TYPE" in
x11)
install_paste_dep "xdotool"
;;
wayland)
if [[ "$DESKTOP" == *"GNOME"* ]]; then
info "GNOME on Wayland — OpenWhispr uses D-Bus natively. No extra deps."
elif [[ "$DESKTOP" == *"KDE"* ]]; then
install_paste_dep "kdotool"
else
install_paste_dep "wtype"
fi
;;
*)
warn "Skipping paste dependency install (unknown session type)."
;;
esac
# ══════════════════════════════════════════════════════════════════════════════
# [5/8] STT provider
# ══════════════════════════════════════════════════════════════════════════════
step "5/8" "Speech-to-text (STT) provider"
cat <<'STT_MENU'
How should OpenWhispr transcribe your voice?
Option Method Streaming Cost Audio sent to
─────────────────────────────────────────────────────────────────────────────
1) Local Whisper/Parakeet (default) no free nobody, ever
2) Groq whisper-large-v3-turbo no $0.04/hr* Groq servers
3) OpenAI Realtime API YES $0.06/min OpenAI servers
*Groq free tier: ~2,000 audio seconds/day (~600 dictations/day free).
NOT used for training. 30-day retention max.
Verify: https://console.groq.com/docs/your-data
Streaming (option 3) = text appears word-by-word as you speak.
Options 1 and 2 transcribe after you stop speaking.
All cloud options send audio to a server (like Siri/Google Assistant)
but unlike Siri/Google: NOT tied to your identity, NOT used for
training, deleted within 30 days.
Best free combo: option 1 (local) + Groq cleanup [step 6]
Best free cloud combo: option 2 (Groq STT) + Groq cleanup [same key]
Best streaming: option 3 (OpenAI Realtime) + any cleanup
STT_MENU
prompt_default "Enter 1-3" "1" STT_CHOICE
case "$STT_CHOICE" in
1)
STT_LABEL="Local Whisper/Parakeet (offline)"
info "STT: Local — audio never leaves your machine."
;;
2)
STT_LABEL="Groq whisper-large-v3-turbo (cloud)"
info "STT: Groq cloud transcription."
if [[ -n "${GROQ_API_KEY:-}" ]]; then
info "GROQ_API_KEY already set — reusing."
else
prompt_hidden "Enter your Groq API key (from https://console.groq.com)" GROQ_KEY_INPUT
store_api_key "GROQ_API_KEY" "$GROQ_KEY_INPUT"
fi
;;
3)
STT_LABEL="OpenAI Realtime API (cloud, streaming)"
info "STT: OpenAI Realtime (streaming)."
if [[ -n "${OPENAI_API_KEY:-}" ]]; then
info "OPENAI_API_KEY already set — reusing."
else
prompt_hidden "Enter your OpenAI API key (from https://platform.openai.com/api-keys)" OPENAI_KEY_INPUT
store_api_key "OPENAI_API_KEY" "$OPENAI_KEY_INPUT"
fi
;;
*)
warn "Invalid choice '$STT_CHOICE' — defaulting to local."
STT_CHOICE="1"
STT_LABEL="Local Whisper/Parakeet (offline)"
;;
esac
# ══════════════════════════════════════════════════════════════════════════════
# [6/8] AI cleanup provider
# ══════════════════════════════════════════════════════════════════════════════
step "6/8" "AI text cleanup provider"
cat <<'CLEANUP_MENU'
After transcription, AI can fix grammar, spelling, and filler words.
Only transcribed TEXT is sent — your voice stays local regardless.
None of these providers use your text for training.
Provider Model Per use 50/day/mo 200/day/mo
──────────────────────────────────────────────────────────────────────────
1) OpenAI gpt-4o-mini-2024-07-18 $0.000058 $0.09 $0.35
2) Anthropic claude-haiku-4-5 $0.000450 $0.68 $2.70
3) Groq llama-3.3-70b-versatile free* free* free*
4) Local Ollama (fully offline) free free free
5) Skip raw transcription only free free free
*Groq free: 1,000 req/day, 100K tokens/day. NOT used for training.
Verify: https://console.groq.com/docs/your-data
Pricing based on ~50 words per dictation (~125 input + 65 output tokens).
Verify current pricing:
OpenAI: https://openai.com/api/pricing
Anthropic: https://www.anthropic.com/pricing
Groq: https://groq.com/pricing
CLEANUP_MENU
prompt_default "Enter 1-5" "1" CLEANUP_CHOICE
case "$CLEANUP_CHOICE" in
1)
CLEANUP_LABEL="OpenAI gpt-4o-mini"
info "Cleanup: OpenAI gpt-4o-mini."
if [[ -n "${OPENAI_API_KEY:-}" ]]; then
info "OPENAI_API_KEY already set — reusing."
else
prompt_hidden "Enter your OpenAI API key (from https://platform.openai.com/api-keys)" OPENAI_KEY_INPUT
store_api_key "OPENAI_API_KEY" "$OPENAI_KEY_INPUT"
fi
;;
2)
CLEANUP_LABEL="Anthropic claude-haiku-4-5"
info "Cleanup: Anthropic claude-haiku-4-5."
if [[ -n "${ANTHROPIC_API_KEY:-}" ]]; then
info "ANTHROPIC_API_KEY already set — reusing."
else
prompt_hidden "Enter your Anthropic API key (from https://console.anthropic.com)" ANTHROPIC_KEY_INPUT
store_api_key "ANTHROPIC_API_KEY" "$ANTHROPIC_KEY_INPUT"
fi
;;
3)
CLEANUP_LABEL="Groq llama-3.3-70b (free)"
info "Cleanup: Groq llama-3.3-70b."
if [[ -n "${GROQ_API_KEY:-}" ]]; then
info "GROQ_API_KEY already set — reusing."
else
prompt_hidden "Enter your Groq API key (from https://console.groq.com)" GROQ_KEY_INPUT
store_api_key "GROQ_API_KEY" "$GROQ_KEY_INPUT"
fi
;;
4)
CLEANUP_LABEL="Local Ollama (offline)"
info "Cleanup: Local Ollama."
if command_exists ollama; then
info "Ollama is already installed."
else
warn "Ollama is not installed."
cat <<'OLLAMA_INFO'
To install Ollama:
curl -fsSL https://ollama.ai/install.sh | sh
Then pull a model:
ollama pull llama3.1
OLLAMA_INFO
printf "Install Ollama now? [Y/n]: "
read -r ollama_reply
ollama_reply="${ollama_reply:-Y}"
if [[ "${ollama_reply,,}" == "y" ]]; then
curl -fsSL https://ollama.ai/install.sh | sh || {
warn "Ollama install failed. Install manually later."
}
else
warn "Skipping Ollama install — you can install it later."
fi
fi
;;
5)
CLEANUP_LABEL="None (raw transcription)"
info "Cleanup: Skipped — raw transcription only."
;;
*)
warn "Invalid choice '$CLEANUP_CHOICE' — defaulting to OpenAI."
CLEANUP_CHOICE="1"
CLEANUP_LABEL="OpenAI gpt-4o-mini"
if [[ -n "${OPENAI_API_KEY:-}" ]]; then
info "OPENAI_API_KEY already set — reusing."
else
prompt_hidden "Enter your OpenAI API key (from https://platform.openai.com/api-keys)" OPENAI_KEY_INPUT
store_api_key "OPENAI_API_KEY" "$OPENAI_KEY_INPUT"
fi
;;
esac
# ══════════════════════════════════════════════════════════════════════════════
# [7/8] First launch
# ══════════════════════════════════════════════════════════════════════════════
step "7/8" "First launch"
cat <<'LAUNCH_INFO'
OpenWhispr will open now for first-run setup.
- It will download speech models (~75-500 MB depending on choice).
- Set your hotkey in Settings (default: backtick `).
- The app manages its own autostart.
LAUNCH_INFO
LAUNCHED=false
if command_exists openwhispr; then
openwhispr &>/dev/null &
LAUNCHED=true
elif command_exists open-whispr; then
open-whispr &>/dev/null &
LAUNCHED=true
fi
if [[ "$LAUNCHED" == true ]]; then
info "OpenWhispr launched in the background."
else
warn "Could not find openwhispr in PATH."
warn "Try launching manually:"
warn " openwhispr"
warn " open-whispr"
warn " /opt/openwhispr/openwhispr"
fi
# ══════════════════════════════════════════════════════════════════════════════
# [8/8] Summary
# ══════════════════════════════════════════════════════════════════════════════
step "8/8" "Done!"
printf "\n"
divider
# shellcheck disable=SC2059
printf "${BOLD} OpenWhispr is ready${RESET}\n"
divider
cat <<EOF
Hotkey: backtick (\`) — change in Settings
STT: ${STT_LABEL}
AI cleanup: ${CLEANUP_LABEL}
API keys stored in: ${BASHRC}
Apply now: source ${BASHRC}
Useful commands:
openwhispr launch the app
openwhispr --help show options
Settings → Hotkey change your hotkey
Settings → Models download better speech models
Settings → Processing change STT or AI provider
Troubleshoot: https://github.com/OpenWhispr/openwhispr/blob/main/TROUBLESHOOTING.md
This installer: https://github.com/YOUR_USERNAME/openwhispr-easy-setup
EOF
divider
printf "\n"