Say when the processor build landed instead of the Vulkan one

The install falls back to upstream's CPU archive whenever Dikte's own
release, the file in it, or its reviewed digest is not there, and until
the package is published by hand that is every download. It happened
without a word: the window said "Downloaded, version v1.9.3." either
way, and a graphics card sitting idle looks exactly like one being used.

The install record now carries which of the two builds landed, written
only where both were on offer, and the settings window says so on the
line that already reports the version.
This commit is contained in:
2026-09-05 09:16:59 +03:00
parent 956c3eaf3c
commit 59180b8eff
5 changed files with 94 additions and 6 deletions
+36 -6
View File
@@ -284,6 +284,17 @@ def _wanted_assets(program):
return (f"bin-ubuntu-{arch}.tar.gz",)
def _managed_whisper(program, tag=""):
"""Whether this machine is one Dikte publishes its own whisper-server for.
Linux x86_64 with a Vulkan loader on it, and no version asked for by hand:
a pinned version is upstream's to answer.
"""
return (not tag and program is WHISPER and sys.platform == "linux"
and platform.machine().lower() in ("x86_64", "amd64")
and _has_vulkan())
def _install_record(program):
return BIN_DIR / program.name / "installed.json"
@@ -307,6 +318,21 @@ def installed_version(program):
return _read_record(program).get("tag") or ""
def vulkan_missing(program):
"""Whether what Dikte installed is the processor build on a machine the
Vulkan one was fetched for.
The Vulkan whisper-server is a release of Dikte's own, published by hand
once the reviewed archive is built, and the install falls back to the
upstream processor build whenever that release, the file in it, or its
reviewed digest is not there. Nothing is wrong with the fallback except
that it is invisible: a graphics card sitting idle looks exactly like a
graphics card being used.
"""
return (bool(installed_program(program))
and _read_record(program).get("backend") == "processor")
def program_path(program, custom=""):
"""Which copy of the program to run, or "" when there is none.
@@ -382,10 +408,8 @@ def install_program(program, tag="", on_progress=None, should_stop=None,
"""
repo = program.repo
release_tag = tag or "latest"
managed = (not tag and program is WHISPER and sys.platform == "linux"
and platform.machine().lower() in ("x86_64", "amd64")
and _has_vulkan())
item = None
managed = _managed_whisper(program, tag)
item, vulkan = None, False
if managed:
repo = DIKTE_REPO
release_tag = MANAGED_WHISPER_RELEASE
@@ -398,6 +422,7 @@ def install_program(program, tag="", on_progress=None, should_stop=None,
item = next((a for a in assets
if a.name.endswith(MANAGED_WHISPER_VULKAN)
and a.sha256 == MANAGED_WHISPER_SHA256), None)
vulkan = item is not None
if item:
tag = MANAGED_WHISPER_VERSION
@@ -476,8 +501,13 @@ def install_program(program, tag="", on_progress=None, should_stop=None,
# Found under the sibling, run from the final directory.
binary = into / binary.relative_to(fresh)
# Written last, so the record never points at anything half-made.
_install_record(program).write_text(
json.dumps({"tag": tag, "binary": str(binary)}), encoding="utf-8")
record = {"tag": tag, "binary": str(binary)}
if managed:
# Which of the two builds this machine ended up with. Only written
# where both were on offer, so an install that never had the
# choice is not made to look like a fallback.
record["backend"] = "vulkan" if vulkan else "processor"
_install_record(program).write_text(json.dumps(record), encoding="utf-8")
except OSError as exc:
raise LocalError(t("Could not install {name}: {error}",
name=program.name, error=exc)) from exc
+3
View File
@@ -780,6 +780,9 @@ TR = {
"Not installed.": "Kurulu değil.",
"Installed on the system: {path}": "Sistemde kurulu: {path}",
"Downloaded, version {version}.": "İndirildi, sürüm {version}.",
"Downloaded, version {version}. There was no Vulkan build, "
"so this one runs on the processor.":
"İndirildi, sürüm {version}. Vulkan sürümü yoktu, bu sürüm işlemcide çalışıyor.",
"Fetching the model list…": "Model listesi çekiliyor…",
"Downloading…": "İndiriliyor…",
"Downloading: {done} of {total}{share}": "İndiriliyor: {done} / {total}{share}",
+7
View File
@@ -358,6 +358,13 @@ class LocalModelBox(QGroupBox):
# for this machine and may reach the graphics card, while the
# released binaries carry processor backends only.
self.program_label.setText(t("Installed on the system: {path}", path=path))
elif ggml.vulkan_missing(self.program):
# The download landed the processor build where the graphics card
# one belongs, and nothing else on this window would say so.
self.program_label.setText(
t("Downloaded, version {version}. There was no Vulkan build, "
"so this one runs on the processor.",
version=ggml.installed_version(self.program) or "?"))
else:
self.program_label.setText(
t("Downloaded, version {version}.",
+19
View File
@@ -259,6 +259,7 @@ class InstallProgram(Local):
"whisper-bin-ubuntu-vulkan-x64.tar.gz"))
self.assertTrue(os.path.isfile(path))
self.assertEqual("v1.9.3", ggml.installed_version(ggml.WHISPER))
self.assertFalse(ggml.vulkan_missing(ggml.WHISPER))
def test_an_explicit_whisper_version_still_comes_from_upstream(self):
self.patch_attr(ggml, "_arch", lambda: "x64")
@@ -339,6 +340,24 @@ class InstallProgram(Local):
"whisper-bin-ubuntu-x64.tar.gz"))
self.assertTrue(os.path.isfile(path))
def test_a_fallback_to_the_processor_build_is_there_to_be_shown(self):
"""Until the Vulkan package is published every download lands the
processor build, and a graphics card sitting idle looks exactly like
one being used. The window asks this and says so."""
self.patch_attr(ggml, "_arch", lambda: "x64")
self.patch_attr(ggml, "_has_vulkan", lambda: True)
managed = self.release("Dikte-1.1.0-x86_64.AppImage")
managed["tag_name"] = "whisper.cpp-v1.9.3"
upstream = self.release("whisper-bin-ubuntu-x64.tar.gz")
with fake_urlopen(managed, upstream, body(self.archive)):
ggml.install_program(ggml.WHISPER)
self.assertTrue(ggml.vulkan_missing(ggml.WHISPER))
def test_a_machine_with_no_vulkan_is_not_told_it_is_missing_one(self):
# Nothing was on offer to fall back from, so there is nothing to say.
self.install("whisper-bin-ubuntu-x64.tar.gz")
self.assertFalse(ggml.vulkan_missing(ggml.WHISPER))
def test_a_release_with_nothing_for_this_machine_says_so(self):
self.patch_attr(ggml, "_arch", lambda: "x64")
with fake_urlopen(self.release("whisper-bin-Win32.zip")):
+29
View File
@@ -6,6 +6,7 @@ save, so a setting added to one half and not the other is silently reset the
next time anybody presses Save. That is the failure this catches.
"""
import json
import os
import sys
import unittest
@@ -1214,6 +1215,34 @@ class LocalModels(DikteTest):
for row in range(box.repo.count()))
self.assertGreaterEqual(view.minimumWidth(), widest)
def test_a_processor_build_where_the_vulkan_one_belongs_says_so(self):
# The Vulkan whisper-server is published by hand, and until it is
# there the download lands upstream's processor build. Said nowhere,
# an idle graphics card looks exactly like one that is being used.
binary = self.path("bin/whisper/v1.9.3/whisper-server")
binary.parent.mkdir(parents=True)
binary.write_text("")
binary.chmod(0o755)
self.path("bin/whisper/installed.json").write_text(json.dumps(
{"tag": "v1.9.3", "binary": str(binary), "backend": "processor"}))
# A whisper-server on this machine's PATH would win over the download.
self.patch_attr(ggml.shutil, "which", lambda name: None)
label = self.window(cfg.Config()).local_whisper.program_label.text()
self.assertIn("v1.9.3", label)
self.assertIn("Vulkan", label)
def test_an_ordinary_install_is_reported_without_a_word_about_vulkan(self):
binary = self.path("bin/whisper/v1.9.3/whisper-server")
binary.parent.mkdir(parents=True)
binary.write_text("")
binary.chmod(0o755)
self.path("bin/whisper/installed.json").write_text(json.dumps(
{"tag": "v1.9.3", "binary": str(binary)}))
self.patch_attr(ggml.shutil, "which", lambda name: None)
label = self.window(cfg.Config()).local_whisper.program_label.text()
self.assertIn("v1.9.3", label)
self.assertNotIn("Vulkan", label)
def test_only_the_chosen_transcriber_is_on_screen(self):
window = self.window(self.config(transcribe_provider="openai"))
self.assertTrue(window.stt_form.isRowVisible(window.transcribe_model_row))