Merge master: the shortcut table, local models, and a Mac still in them

Four files disagreed, and all four the same way: master had turned things the
Mac branch wrote out by hand into one list to read from.

Shortcuts are the whole of it. master gave every binding a row in
hotkey.SHORTCUTS, so the Mac's DESKTOP_IDS is gone and CarbonHotkey reads the
desktop id off that row, which also gives the new cancel key a status line on a
Mac. Settings builds its four rows through master's _shortcut_row, and that one
now asks _install_buttons for Install and Remove, so macOS gets a combination
box and nothing to press, and everywhere else the button says the desktop's own
name. dikte.py starts the listener from the same table, on macOS whatever the
setting says: there is nothing installed for it to be a fallback to.

The rest is two imports and a paste list that lives in paste.Desktop now.
This commit is contained in:
yusufipk
2026-08-02 09:36:22 +03:00
41 changed files with 4888 additions and 470 deletions
+100 -3
View File
@@ -12,7 +12,9 @@ import unittest
from unittest import mock
import api
import cleanup
import config as cfg
import ggml
import i18n
import paste
from tests.support import DikteTest
@@ -126,10 +128,23 @@ class Keys(DikteTest):
def test_no_key_anywhere(self):
self.assertEqual(cfg.Config().openai_key(), "")
def test_every_provider_falls_back_to_the_variable_of_its_own_name(self):
with mock.patch.dict(os.environ, {"GROQ_API_KEY": "gsk-env"}):
self.assertEqual(cfg.Config().groq_key(), "gsk-env")
class TranscribeTarget(DikteTest):
def test_openai_by_default(self):
target = self.config(openai_api_key="sk-test").transcribe_target()
def test_this_machine_by_default(self):
target = cfg.Config().transcribe_target()
self.assertEqual(target.provider, "local")
self.assertEqual(target.api_key, "")
# Empty on purpose: the server picks a port when it starts, and reading
# a setting must not be what starts it.
self.assertEqual(target.base_url, "")
def test_openai_when_it_is_picked(self):
target = self.config(transcribe_provider="openai",
openai_api_key="sk-test").transcribe_target()
self.assertEqual(target.provider, "openai")
self.assertEqual(target.service, "OpenAI")
self.assertEqual(target.api_key, "sk-test")
@@ -146,8 +161,24 @@ class TranscribeTarget(DikteTest):
self.assertEqual(target.api_key, "sk-or-test")
self.assertEqual(target.model, "openai/whisper-1")
def test_groq_when_it_is_picked(self):
conf = self.config(transcribe_provider="groq", groq_api_key="gsk-test",
groq_transcribe_model="whisper-large-v3")
target = conf.transcribe_target()
self.assertEqual(target.provider, "groq")
self.assertEqual(target.service, "Groq")
self.assertEqual(target.api_key, "gsk-test")
self.assertEqual(target.base_url, api.GROQ_URL)
self.assertEqual(target.model, "whisper-large-v3")
def test_a_provider_this_version_has_never_heard_of(self):
"""A config written by a fork, or by a version that dropped one."""
target = self.config(transcribe_provider="deepgram").transcribe_target()
self.assertEqual(target.provider, "openai")
def test_a_self_hosted_endpoint(self):
conf = self.config(openai_base_url="http://localhost:8080/v1")
conf = self.config(transcribe_provider="openai",
openai_base_url="http://localhost:8080/v1")
self.assertEqual(conf.transcribe_target().base_url, "http://localhost:8080/v1")
@@ -459,3 +490,69 @@ class Directories(unittest.TestCase):
if __name__ == "__main__":
unittest.main()
class LocalCleanup(DikteTest):
def test_the_local_model_is_what_the_history_records(self):
conf = self.config(cleanup_provider="local",
local_llm_model="gemma-3-4b-it-Q4_K_M.gguf")
self.assertEqual(cleanup.provider(conf), "local")
self.assertEqual(cleanup.model(conf), "gemma-3-4b-it-Q4_K_M.gguf")
def test_it_needs_no_program_on_the_path(self):
# whisper.cpp and llama.cpp are fetched rather than installed, so unlike
# Claude Code and Codex there is no executable to look for.
self.assertEqual(cleanup.executable("local"), "")
def test_the_minutes_do_not_follow_the_cleanup_provider(self):
# A 4B model here will strip the filler words out of a dictation and
# will not write up an hour long meeting.
conf = self.config(cleanup_provider="local")
self.assertEqual(conf["meeting_model"], cfg.DEFAULTS["meeting_model"])
def test_only_the_cleanup_setting_asks_for_the_local_model(self):
self.assertFalse(cfg.Config().uses_local_llm())
self.assertTrue(self.config(cleanup_provider="local").uses_local_llm())
class ReadyToRun(DikteTest):
def setUp(self):
super().setUp()
self.patch_attr(ggml, "MODELS_DIR", self.path("models"))
def install(self, name):
path = ggml.whisper_model_path(name)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(b"model")
def test_a_missing_program_is_not_ready(self):
with mock.patch("shutil.which", return_value=None):
self.install("ggml-base.bin")
conf = self.config(local_model="ggml-base.bin")
self.assertFalse(conf.transcribe_ready())
def test_a_missing_model_is_not_ready_either(self):
with mock.patch("shutil.which", return_value="/usr/bin/whisper-server"):
conf = self.config(local_model="ggml-base.bin")
self.assertFalse(conf.transcribe_ready())
def test_both_halves_in_place(self):
with mock.patch("shutil.which", return_value="/usr/bin/whisper-server"):
self.install("ggml-base.bin")
conf = self.config(local_model="ggml-base.bin")
self.assertTrue(conf.transcribe_ready())
def test_a_hosted_provider_is_ready_when_it_has_a_key(self):
conf = self.config(transcribe_provider="openai", openai_api_key="sk-test")
self.assertTrue(conf.transcribe_ready())
def test_the_settings_reach_the_servers(self):
conf = self.config(local_model="ggml-base.bin", local_threads=4,
local_gpu=False, local_llm_model="gemma.gguf",
local_llm_context=4096)
conf.apply_local()
self.addCleanup(ggml.whisper.configure, model="", threads=0, gpu=True)
self.assertEqual(ggml.whisper.settings()["model"], "ggml-base.bin")
self.assertEqual(ggml.whisper.settings()["threads"], 4)
self.assertFalse(ggml.whisper.settings()["gpu"])
self.assertEqual(ggml.llm.settings()["context"], 4096)