Commit Graph
61 Commits
Author SHA1 Message Date
yusufipkandMuzaffer Emre d04efe235a Put the three providers in a table, and test the request rather than the list
Reworked on top of master. The Groq request itself needed nothing beyond a key,
a base URL and a model id, but two providers fit in an if and an else where
three do not, and each one was written out four times: in transcribe_target(),
in the key rows of the settings window, in save and in load.

config.TRANSCRIBERS holds them now, one row each: the name the user sees and
the three settings that keep its key, its endpoint and its model. The variable
an empty key falls back to is the name of its setting, shouted. The provider
box, save, load, `dikte models --provider` and `dikte test-key` all read that
table, so a fourth provider is a row and a default rather than a branch in five
files. The key field, its Test button and its answer line are built once and
the three signals became one that carries which key was asked about.

The tests moved into the files of the modules they cover and check what a
provider actually changes: that the request goes to api.groq.com with the right
model and fields, that the glossary now reaches everything except OpenRouter,
that a Groq error says Groq, and that the settings window carries the key and
the model there and back. GROQ_API_KEY is cleared for the test run like the
other two, so a developer who has one does not send a test to the network.

Co-authored-by: Muzaffer Emre <[email protected]>
2026-08-01 22:09:41 +07:00
yusufipk 22edd2f247 Merge master into feature/groq-transcription 2026-08-01 22:09:01 +07:00
yusufipkandfirat 3bd8c1ad27 Add a Mac as the third system, beside Wayland and X11
Dikte already chose its clipboard programs once instead of in every
function; macOS joins that table rather than adding a branch to each one.
A Mac copies through pbcopy and presses Cmd+V straight into CoreGraphics,
records through AVFoundation, and asks Carbon for its global shortcuts.

The three tables are paste.Desktop, audio.Sound, and the pair of
predicates in hotkey.py. Each reads sys.platform inside the chooser, so a
test can stand somewhere else: 697 of the 737 tests now run on any
machine, the Wayland and X11 halves included, and the suite passes whole
whichever system it is run on.

Two things a Mac does not have needed saying rather than pretending:
there is no shortcut registry to install into, so Settings offers no
Install button and the listener is the mechanism instead of a fallback;
and nothing is offered as the sound the speakers are playing, so a
meeting needs BlackHole or Loopback and says so. The KDE-only labels
around them were already wrong on GNOME, and now name whichever desktop
is there.

Co-authored-by: firat <[email protected]>
2026-08-01 21:28:58 +07:00
yusufipk 5c429ab077 Ask parec for sound as it arrives, not two seconds of it at a time
Left alone, parec buffers about two seconds and then hands the lot over at
once. Measured against the chunk the level meter reads:

    parec, as it was          longest gap  2005 ms
    parec --latency-msec=64   longest gap    86 ms
    pw-record                 longest gap   129 ms

On a machine that has parec, which is every PulseAudio one and every PipeWire
one with the compatibility service, the waveform stood still and then jumped,
looking like a microphone that was not picking anything up. The recording
itself was fine, but the tail of one can be lost that way too: stop() ends the
process, and whatever is still held back goes with it.

The number asked for is the meter's own chunk, which is the unit the rest of
this file is measured in.
2026-08-01 20:52:43 +07:00
yusufipk 45a064e545 Tell a recorder that died from one that was asked to stop
The pump now says when the capture ended with nothing captured, which is worth
saying: parec refusing the device looks like silence otherwise. But stop() ends
it the same way, so a recording shorter than 0.3 s raised that alarm first and
"Recording too short" second, sending the user after a sound server that is
fine. It follows the flag MeetingRecorder already carries for this.

test_desktop_compat.py moves into the files for the modules it covers, so a
test is where the next person looking at that module will find it.
2026-08-01 20:34:15 +07:00
yusufipk 1544cca15c Install the GNOME shortcut this already knew how to install
install_shortcut(), remove_shortcut(), shortcut_status() and desktop_name()
were added and nothing called them: the settings window and the command line
both still went straight to the KDE ones. On GNOME, pressing Install ran
kwriteconfig6, which is not there, and the three interface strings written for
this never appeared. README said the settings window installs a GNOME or KDE
shortcut, and it installed neither.

Both callers go through the chooser now, and the status line names whichever
desktop answered.
2026-08-01 20:32:07 +07:00
yusufipk 0e6ec3aea9 Choose the clipboard's programs once, instead of in every function
Which pair of tools a session uses was being asked inside copy(), read(),
copy_bytes() and press(), four times, in a conditional each. A third desktop
means a third branch in each of them, and macOS is already open as a pull
request doing exactly that in a different style.

Wayland and X11 are two entries at the top of the file now, each naming its
programs and how to build a key press from them. The functions below take
whichever entry the session gets. Adding a desktop is an entry and a line in
desktop(), and it touches nothing else.

Two things fall out of it. The key press is checked against the same table on
both: xdotool was being handed the shortcut as typed, so ctrl+f13 was refused
on Wayland and passed through on X11. And a missing tool names the package to
install again, which the shared message had dropped.

The tests say the promises once and run them against both desktops, so a third
one inherits the list rather than needing a copy of it.
2026-08-01 20:32:07 +07:00
yusufipk 3d4c29c853 Merge branch 'test-suite' into feature/ubuntu-x11-gnome 2026-08-01 20:15:22 +07:00
yusufipk 80a4832818 Test what the application does, and run it on every pull request
570 tests over the standard library's unittest, so there is nothing to
install beyond the PyQt6 the application already needs. They reach neither
the network, the microphone, nor the real ~/.config/dikte: urllib is faked at
one function, the tools are faked at shutil.which, and every test is handed
its own config and data directory.

What they hold onto is what a change is most likely to move without meaning
to. The request each provider is sent, field by field. A settings window that
loads a value into a widget and writes it back, which is where a setting
added to one half and not the other is silently reset. The dictation chain
end to end: what is transcribed, what is pasted, what lands in the history,
and what happens to the audio afterwards. A config file written by an older
version. A meeting whose two channels heard the same sentence.

59 of them carry @linux_only, because they cover what Dikte is on this
desktop rather than what it does: PipeWire, wl-clipboard, ydotool, KDE's
shortcut file. The other 511 pass on any platform, and that line is worth
holding as the ports arrive.

CONTRIBUTING.md says how to run them, what support.py offers, and the three
things about this codebase that trip up a new test.
2026-08-01 20:06:47 +07:00
Muzaffer Emre dd73735617 Add Groq transcription support 2026-07-31 18:48:21 +03:00
Muzaffer Emre d64ed8968a Add GNOME X11 and PulseAudio support 2026-07-31 18:47:49 +03:00