Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
729cfd5
Will make CUDA optional to reduce bundle sizes
raivisdejus Mar 13, 2026
5edb158
Fix for running installation locally
raivisdejus Mar 15, 2026
5bab7b4
Forcing Torch CPU on Linux
raivisdejus Mar 27, 2026
d13bec5
Fixed issues in SNAPs
raivisdejus Mar 28, 2026
9c695c5
Fixes for windows
raivisdejus Mar 28, 2026
3d89dd0
Adding translations
raivisdejus Mar 28, 2026
eff4bb1
Adding translations
raivisdejus Mar 29, 2026
8edbe9f
Version bump
raivisdejus Mar 29, 2026
6f0fb9a
Snap fix
raivisdejus Mar 29, 2026
b57e0dc
Snap fix
raivisdejus Mar 29, 2026
140dcb6
Snap fix
raivisdejus Mar 29, 2026
c50d3ce
Rearranging whisper types
raivisdejus Mar 29, 2026
145e9b6
Test fixes
raivisdejus Mar 29, 2026
9376dad
Test fixes
raivisdejus Mar 29, 2026
6de9e60
Adding more tests
raivisdejus Mar 29, 2026
e558307
Adjusting mac dependencies
raivisdejus Mar 29, 2026
ebf78bd
Teest fix
raivisdejus Mar 29, 2026
946a062
Teest fix
raivisdejus Mar 29, 2026
9da497d
uv.lock upate
raivisdejus May 4, 2026
d7f7f96
Fix for finding local CUDA
raivisdejus May 4, 2026
90a2f89
Ensuring pip
raivisdejus May 4, 2026
aa1fbe3
CUDA installer UI adjustments
raivisdejus May 4, 2026
3715952
Fixed tests
raivisdejus May 4, 2026
ab9cb65
Regenerate uv.lock after rebase onto main
raivisdejus Sep 5, 2026
e6d2754
Updating cuda dependencies to match project main
raivisdejus Sep 5, 2026
4db628c
Version mismatch fix
raivisdejus Sep 5, 2026
b13597b
Adding note on CUDA installation to the Readme
raivisdejus Sep 12, 2026
3b0e232
Will install cuda in venv
raivisdejus Sep 12, 2026
20bfd2f
Appimage fix and translations
raivisdejus Sep 12, 2026
97ce55c
Appimage fix
raivisdejus Sep 12, 2026
13e9b29
Adding debug to whisper.cpp
raivisdejus Sep 12, 2026
9625eae
Adding popup for cida to appimages
raivisdejus Sep 12, 2026
28cc0ed
Fix for windows
raivisdejus Sep 12, 2026
bd380bb
Will simplify cuda detection
raivisdejus Sep 12, 2026
a0ffa31
Adding checkmark to install button
raivisdejus Sep 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,6 @@ jobs:
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
uv pip install msvc-runtime
uv pip install -U torch==2.8.0+cu129 torchaudio==2.8.0+cu129 --index-url https://download.pytorch.org/whl/cu129
uv pip install nvidia-cublas-cu12==12.9.1.4 nvidia-cuda-cupti-cu12==12.9.79 nvidia-cuda-runtime-cu12==12.9.79 --extra-index-url https://pypi.nvidia.com

uv cache clean
uv run pip cache purge
fi
shell: bash

Expand Down Expand Up @@ -288,7 +283,6 @@ jobs:
name: Buzz-${{ runner.os }}-${{ runner.arch }}
path: |
dist/Buzz*-windows.exe
dist/Buzz*-windows-*.bin
dist/Buzz*-mac.dmg
dist/Buzz*.AppImage

Expand Down Expand Up @@ -402,6 +396,5 @@ jobs:
files: |
Buzz*-unix.tar.gz
Buzz*.exe
Buzz*.bin
Buzz*.dmg
Buzz*.AppImage
26 changes: 26 additions & 0 deletions Buzz.spec
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,32 @@ else:

binaries.append(("buzz/whisper_cpp/*", "buzz/whisper_cpp"))

# Bundle a standalone Python interpreter for runtime pip installs (e.g. CUDA).
# We copy python.exe, DLLs, and the stdlib from the uv-managed base interpreter.
# The version is derived from the build interpreter so it tracks requires-python.
if platform.system() == "Windows":
import sys as _sys
_base = _sys.base_prefix # e.g. .../uv/python/cpython-3.13.12-windows-x86_64-none
_py_dll = f"python{_sys.version_info.major}{_sys.version_info.minor}.dll"
_py_dest = "python"
if os.path.isfile(os.path.join(_base, "python.exe")):
binaries.append((os.path.join(_base, "python.exe"), _py_dest))
binaries.append((os.path.join(_base, "python3.dll"), _py_dest))
binaries.append((os.path.join(_base, _py_dll), _py_dest))
for _vcrt in ("vcruntime140.dll", "vcruntime140_1.dll"):
_vcrt_path = os.path.join(_base, _vcrt)
if os.path.isfile(_vcrt_path):
binaries.append((_vcrt_path, _py_dest))
# Bundle DLLs directory (C extensions like _ssl, _socket, etc.)
_dlls_dir = os.path.join(_base, "DLLs")
if os.path.isdir(_dlls_dir):
for _f in os.listdir(_dlls_dir):
binaries.append((os.path.join(_dlls_dir, _f), os.path.join(_py_dest, "DLLs")))
# Bundle standard library
datas.append((os.path.join(_base, "Lib"), os.path.join(_py_dest, "Lib")))
else:
print(f"WARNING: Could not find bundleable Python at {_base}")

if platform.system() == "Windows":
datas += [("dll_backup", "dll_backup")]
datas += collect_data_files("msvc-runtime")
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ pip3 install nvidia-cublas-cu12==12.9.1.4 nvidia-cuda-cupti-cu12==12.9.79 nvidia

For info on how to get latest development version with latest features and bug fixes see [FAQ](https://chidiwilliams.github.io/buzz/docs/faq#9-where-can-i-get-latest-development-version).

### Nvidia CUDA GPU acceleration

If you are on Buzz version `1.4.6` or later and have a Nvidia GPU, go to `Help -> About Buzz` and install CUDA Acceleration.

### Support Buzz

You can help the Buzz by starring 🌟 the repo and sharing it with your friends.
Expand Down
48 changes: 45 additions & 3 deletions appimage/build-appimage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,27 @@ mkdir -p "$APPDIR/usr/bin" \
# Copy entire PyInstaller output into usr/bin/
cp -a "$PROJECT_DIR/dist/Buzz/." "$APPDIR/usr/bin/"

# Strip the executable-stack flag from bundled shared objects. uv's
# python-build-standalone marks libpython PT_GNU_STACK=RWE, and kernels from
# Linux 7.0 (Ubuntu 26.04) on refuse that at dlopen time, so the app dies with
# "cannot enable executable stack as shared object requires: Invalid argument".
# Patch the AppDir copy, never the shared uv Python cache.
echo "==> Clearing executable-stack flags..."
uv run --no-project "$SCRIPT_DIR/clear-execstack.py" "$APPDIR/usr/bin"

# Bundle uv: the in-app CUDA installer needs it to build the private CUDA venv.
# The AppImage ships no standalone interpreter, and the host's python3 is
# whatever the distro installed — on Ubuntu 26.04 that is 3.14, which has no
# torch wheels. uv downloads a CPython matching the one Buzz is frozen with.
echo "==> Bundling uv..."
UV_BIN="$(command -v uv)"
if [ -z "$UV_BIN" ]; then
echo "ERROR: uv not found in PATH; it is required for in-app CUDA installation." >&2
exit 1
fi
cp "$(readlink -f "$UV_BIN")" "$APPDIR/usr/bin/uv"
chmod +x "$APPDIR/usr/bin/uv"

# ── Step 3: Desktop integration ─────────────────────────────────────────────
# Desktop file — Exec must be just the binary name for AppImage spec
cat > "$APPDIR/Buzz.desktop" << 'EOF'
Expand Down Expand Up @@ -82,6 +103,11 @@ cat > "$APPDIR/AppRun" << 'APPRUN'
SELF="$(readlink -f "$0")"
APPDIR="$(dirname "$SELF")"

# The type-2 runtime already exports this; re-exporting keeps it correct for
# an extracted AppDir too, so buzz/cuda_manager.py's is_appimage() can tell
# that Buzz itself is the running bundle.
export APPDIR

export PATH="$APPDIR/usr/bin:$PATH"
export LD_LIBRARY_PATH="$APPDIR/usr/bin:${LD_LIBRARY_PATH:-}"
export QT_MEDIA_BACKEND=ffmpeg
Expand Down Expand Up @@ -111,10 +137,26 @@ if [ ! -f "$RUNTIME" ]; then
"https://github.com/AppImage/type2-runtime/releases/download/continuous/runtime-${ARCH}"
fi

# Use APPIMAGETOOL_EXTRACT_AND_RUN when FUSE is unavailable (CI, containers)
# Fall back to extract-and-run when FUSE is unavailable (CI, containers) or
# unusable. Presence of `fusermount` is not enough: distros that ship only FUSE 3
# (Ubuntu 25.10+, where /usr/bin/fusermount is a symlink to fusermount3) still
# fail to mount appimagetool's FUSE 2 runtime. Probe it instead of guessing.
#
# The variable is APPIMAGE_EXTRACT_AND_RUN: it is read by the AppImage type-2
# runtime, which is what appimagetool (itself an AppImage) boots through. There
# is no APPIMAGETOOL_-prefixed variant -- setting one is silently ignored and
# the build dies with "Cannot mount AppImage, please check your FUSE setup."
EXTRA_ARGS=(--runtime-file "$RUNTIME" --no-appstream)
if [ "${CI:-}" = "true" ] || ! command -v fusermount &>/dev/null; then
export APPIMAGETOOL_EXTRACT_AND_RUN=1
if [ "${CI:-}" = "true" ] || ! "$APPIMAGETOOL" --version >/dev/null 2>&1; then
echo "==> FUSE unusable for appimagetool; falling back to extract-and-run"
export APPIMAGE_EXTRACT_AND_RUN=1
fi

# If it still cannot start, neither mounting nor extraction works -- fail here
# with a clear message instead of midway through packaging.
if ! "$APPIMAGETOOL" --version >/dev/null 2>&1; then
echo "ERROR: cannot run $APPIMAGETOOL (neither FUSE mount nor extract-and-run works)." >&2
exit 1
fi

# Validate AppStream metadata ourselves in offline mode. appimagetool's internal
Expand Down
87 changes: 87 additions & 0 deletions appimage/clear-execstack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
"""Clear the executable-stack flag from bundled ELF shared objects.

uv's python-build-standalone ships libpython marked PT_GNU_STACK = RWE, and
PyInstaller copies it verbatim. Recent kernels (Ubuntu 26.04 / Linux 7.0)
refuse to make the stack executable at dlopen time, so loading the library
dies with:

cannot enable executable stack as shared object requires: Invalid argument

Nothing in CPython actually needs an executable stack -- the flag is a build
artifact -- so clearing PF_X on the PT_GNU_STACK header is the accepted fix.
This is the same edit `execstack -c` / `patchelf --clear-execstack` perform,
done here so the build needs no extra tooling.
"""

import os
import struct
import sys

PT_GNU_STACK = 0x6474E551
PF_X = 0x1


def clear_execstack(path):
"""Return True if the file was modified."""
with open(path, "rb") as fh:
header = fh.read(64)

# ELF64, little-endian only -- the only shape we ship on Linux.
if len(header) < 64 or header[:4] != b"\x7fELF":
return False
if header[4] != 2 or header[5] != 1:
return False

e_phoff = struct.unpack_from("<Q", header, 0x20)[0]
e_phentsize = struct.unpack_from("<H", header, 0x36)[0]
e_phnum = struct.unpack_from("<H", header, 0x38)[0]
if not e_phoff or e_phentsize < 8:
return False

with open(path, "r+b") as fh:
for i in range(e_phnum):
entry = e_phoff + i * e_phentsize
fh.seek(entry)
chunk = fh.read(8)
if len(chunk) < 8:
break
p_type, p_flags = struct.unpack("<II", chunk)
if p_type != PT_GNU_STACK or not (p_flags & PF_X):
continue
fh.seek(entry + 4)
fh.write(struct.pack("<I", p_flags & ~PF_X))
return True
return False


def main(argv):
if len(argv) < 2:
print("usage: clear-execstack.py <dir-or-file>...", file=sys.stderr)
return 2

targets = []
for arg in argv[1:]:
if os.path.isdir(arg):
for root, _dirs, files in os.walk(arg):
targets.extend(os.path.join(root, f) for f in files)
else:
targets.append(arg)

patched = 0
for target in targets:
if os.path.islink(target) or not os.path.isfile(target):
continue
try:
if clear_execstack(target):
print(f" cleared execstack: {target}")
patched += 1
except OSError as exc:
print(f" warning: {target}: {exc}", file=sys.stderr)

print(f" {patched} file(s) patched")
return 0


if __name__ == "__main__":
sys.exit(main(sys.argv))
Loading