mirror of
https://github.com/yusufipk/dikte.git
synced 2026-09-11 10:56:10 +00:00
Transcribe and clean up on this machine, without installing anything first
whisper-server is started on --inference-path /v1/audio/transcriptions, which is exactly the path api.py already builds for the hosted providers, and llama-server answers /chat/completions the way OpenRouter does. So the local half is one more base URL rather than a second code path: worker.py, filetranscribe.py and meeting.py are untouched, and dictation, subtitles and meetings all work here on the first try. Three findings worth naming, none of them in the new code: whisper.cpp cuts segments on tokens, which in Turkish lands inside a word about as often as between two. Pasted raw that gives "akraba değ\niller."; in a subtitle it gives a cue reading "değ". Whisper marks the start of a word with a leading space, so a piece that does not begin with one continues the word above it. A small model will repeat the transcript until the context is full, and every one of those tokens is a second of somebody waiting: measured at 206 seconds, and 25 with a ceiling on the reply. Hosted models are left alone, where the same runaway is rare and a ceiling would cut the minutes short. A server outlives SIGTERM and SIGKILL holding its model in memory. Signals are now turned into an event Qt delivers, since Qt blocks in C where a Python handler never runs, and a pid file lets the next start sweep up what a SIGKILL left behind. The minutes keep their own provider rather than following cleanup's. The two jobs are not the same size: a 4B model here will strip the filler words out of a dictation and will not write up an hour long meeting. The suite runs offline now: a test that reaches the network says so instead of quietly going there.
This commit is contained in:
@@ -41,8 +41,18 @@ CHANGED = {
|
||||
"transcribe_model": "whisper-1",
|
||||
"openrouter_transcribe_model": "openai/whisper-1",
|
||||
"cleanup_enabled": False,
|
||||
"cleanup_provider": "local",
|
||||
"cleanup_model": "some/other-model",
|
||||
"cleanup_reasoning": "high",
|
||||
"local_model": "ggml-small.bin",
|
||||
"local_gpu": False,
|
||||
"local_preload": False,
|
||||
"local_threads": 6,
|
||||
"local_llm_model": "gemma-3-4b-it-Q4_K_M.gguf",
|
||||
"local_llm_repo": "ggml-org/gemma-4-E2B-it-GGUF",
|
||||
"local_llm_gpu": False,
|
||||
"local_llm_preload": True,
|
||||
"local_llm_reasoning": "low",
|
||||
"cleanup_prompt": "Only fix the punctuation.",
|
||||
"file_cleanup_prompt": "Keep the stamps where they are.",
|
||||
"transcribe_prompt": "Paraşüt, OpenFrame",
|
||||
@@ -259,3 +269,53 @@ class Overlay(DikteTest):
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
|
||||
class LocalModels(DikteTest):
|
||||
"""The download boxes, without a network and without either program."""
|
||||
|
||||
def window(self, conf):
|
||||
window = settings_ui.SettingsWindow(conf, "dikte toggle")
|
||||
self.addCleanup(window.deleteLater)
|
||||
self.addCleanup(window.close)
|
||||
return window
|
||||
|
||||
def test_it_opens_where_the_missing_model_is_fixed(self):
|
||||
# Nothing can transcribe on a fresh install, which is why this window
|
||||
# was opened at all.
|
||||
window = self.window(cfg.Config())
|
||||
self.assertEqual(window.tabs.currentIndex(), window.api_tab_index)
|
||||
|
||||
def test_it_opens_where_it_was_left_when_everything_works(self):
|
||||
conf = self.config(transcribe_provider="openai", openai_api_key="sk-test")
|
||||
self.assertEqual(self.window(conf).tabs.currentIndex(), 0)
|
||||
|
||||
def test_a_model_that_is_not_here_yet_survives_a_save(self):
|
||||
# The box is filled from what is on this disk, so a model that was
|
||||
# deleted from underneath is not in the list. Dropping it on save would
|
||||
# quietly empty the setting instead of asking for the download again.
|
||||
conf = self.config(local_model="ggml-large-v3-turbo-q5_0.bin")
|
||||
with mock.patch.object(QMessageBox, "information"):
|
||||
self.window(conf)._save()
|
||||
self.assertEqual(conf["local_model"], "ggml-large-v3-turbo-q5_0.bin")
|
||||
|
||||
def test_nothing_is_fetched_for_a_window_nobody_opened(self):
|
||||
# DikteTest closes the network, so a request would fail the test. The
|
||||
# lists are asked for when the box is shown, not when it is built.
|
||||
window = self.window(cfg.Config())
|
||||
self.assertTrue(window.local_whisper._pending)
|
||||
|
||||
def test_the_hosted_boxes_go_away_when_the_work_happens_here(self):
|
||||
window = self.window(self.config(transcribe_provider="openai"))
|
||||
self.assertTrue(window.hosted_stt.isVisibleTo(window))
|
||||
self.assertFalse(window.local_whisper.isVisibleTo(window))
|
||||
window._select_data(window.transcribe_provider, "local")
|
||||
self.assertFalse(window.hosted_stt.isVisibleTo(window))
|
||||
self.assertTrue(window.local_whisper.isVisibleTo(window))
|
||||
|
||||
def test_the_same_for_cleanup(self):
|
||||
window = self.window(cfg.Config())
|
||||
self.assertTrue(window.hosted_cleanup.isVisibleTo(window))
|
||||
window._select_data(window.cleanup_provider, "local")
|
||||
self.assertTrue(window.local_llm.isVisibleTo(window))
|
||||
self.assertFalse(window.hosted_cleanup.isVisibleTo(window))
|
||||
|
||||
Reference in New Issue
Block a user