mirror of
https://github.com/yusufipk/dikte.git
synced 2026-09-11 19:06:11 +00:00
Call the tab Agent, pick shortcuts from a list, and stop answering from memory
Four things the first use of it turned up. The tab was called Claude while the setting inside it chooses between three providers, two of which are not Claude. It is Agent now, and the messages that pointed at it by name point at the new one. The three global shortcuts were the only fields in the window you had to know the syntax of to fill in, next to a paste key that has been a dropdown all along. They are editable combo boxes now, sharing one shortlist of combinations that are usually free. Typing your own still works; it is just no longer the only way. The instruction was read as discouraging the tools, which is the opposite of the point. "Keep it short" is about the answer, and a model that reads it as "answer off the top of your head" hands back a caveat about its training data instead of the thing it was asked. Asked who won the 2026 World Cup it answered, twice, that the tournament had not been played, on the 28th of July. So shortness is now stated as being about the answer rather than the work, and writing a caveat is named as the moment to go and look instead. Same question, same model, only the prompt changed: no tool calls and a wrong answer before, a web search and the right one after. It also appended its sources, which a reply being pasted into someone's text field has no use for, so that is ruled out alongside the headings and the bullet lists. Clicking the tray icon during a Claude recording did nothing, because the icon was wired to the dictation toggle and that one leaves the other mode's recording alone on purpose. The shortcuts should stay tied to their own mode; the icon is one button and now ends whichever recording is running.
This commit is contained in:
@@ -46,7 +46,7 @@ set next to it.
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Start / stop recording | `Ctrl+Space`, or click the tray icon |
|
| Start / stop recording | `Ctrl+Space`, or click the tray icon |
|
||||||
| Cancel a recording | Tray menu → *Cancel recording*, or `dikte cancel` |
|
| Cancel a recording | Tray menu → *Cancel recording*, or `dikte cancel` |
|
||||||
| Speak a command to Claude | Tray menu → *Ask Claude*, or `dikte ask` |
|
| Speak a command to an agent | Tray menu → *Ask Claude*, or `dikte ask` |
|
||||||
| Start / end a meeting | Tray menu → *Record a meeting*, or `dikte meeting` |
|
| Start / end a meeting | Tray menu → *Record a meeting*, or `dikte meeting` |
|
||||||
| Settings | Tray menu → *Settings*, or `dikte settings` |
|
| Settings | Tray menu → *Settings*, or `dikte settings` |
|
||||||
| Reload after an update | Tray menu → *Restart*, or `dikte restart` |
|
| Reload after an update | Tray menu → *Restart*, or `dikte restart` |
|
||||||
@@ -90,7 +90,7 @@ elapsed time, then the stage it is on. It never takes focus. Pressing
|
|||||||
a thing you can say to a window that is not Claude. Codex (`codex exec`) runs
|
a thing you can say to a window that is not Claude. Codex (`codex exec`) runs
|
||||||
the same way, and OpenRouter is there as a plain question-and-answer fallback
|
the same way, and OpenRouter is there as a plain question-and-answer fallback
|
||||||
for a machine with neither CLI on it. Provider, model, permissions and working
|
for a machine with neither CLI on it. Provider, model, permissions and working
|
||||||
directory are under Settings → Claude, and commands close together stay in one
|
directory are under Settings → Agent, and commands close together stay in one
|
||||||
conversation.
|
conversation.
|
||||||
- **Meetings** are recorded from the microphone and the speaker output at the
|
- **Meetings** are recorded from the microphone and the speaker output at the
|
||||||
same time, which settles who said what by the channel a voice arrived on
|
same time, which settles who said what by the channel a voice arrived on
|
||||||
|
|||||||
+2
-2
@@ -46,7 +46,7 @@ yapıştırılır; modelin yanındaki kutudan düşünme seviyesini de seçebili
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Kaydı başlat / bitir | `Ctrl+Space`, ya da tepsi simgesine tıkla |
|
| Kaydı başlat / bitir | `Ctrl+Space`, ya da tepsi simgesine tıkla |
|
||||||
| Kaydı iptal et | Tepsi menüsü → *Kaydı iptal et*, ya da `dikte cancel` |
|
| Kaydı iptal et | Tepsi menüsü → *Kaydı iptal et*, ya da `dikte cancel` |
|
||||||
| Claude'a sesle komut ver | Tepsi menüsü → *Claude'a sor*, ya da `dikte ask` |
|
| Ajana sesle komut ver | Tepsi menüsü → *Claude'a sor*, ya da `dikte ask` |
|
||||||
| Toplantıyı başlat / bitir | Tepsi menüsü → *Toplantı kaydet*, ya da `dikte meeting` |
|
| Toplantıyı başlat / bitir | Tepsi menüsü → *Toplantı kaydet*, ya da `dikte meeting` |
|
||||||
| Ayarlar | Tepsi menüsü → *Ayarlar*, ya da `dikte settings` |
|
| Ayarlar | Tepsi menüsü → *Ayarlar*, ya da `dikte settings` |
|
||||||
| Güncelleme sonrası yeniden yükle | Tepsi menüsü → *Yeniden başlat*, ya da `dikte restart` |
|
| Güncelleme sonrası yeniden yükle | Tepsi menüsü → *Yeniden başlat*, ya da `dikte restart` |
|
||||||
@@ -88,7 +88,7 @@ süreyi, ardından hangi aşamada olduğunu gösterir. Odak almaz. Dikte çalı
|
|||||||
perşembe üçe takvime koy" cümlesini Claude olmayan bir pencerede söyleyebilir
|
perşembe üçe takvime koy" cümlesini Claude olmayan bir pencerede söyleyebilir
|
||||||
olmanı sağlayan da budur. Codex (`codex exec`) da aynı şekilde çalışır;
|
olmanı sağlayan da budur. Codex (`codex exec`) da aynı şekilde çalışır;
|
||||||
OpenRouter ise ikisi de kurulu olmayan bir makinede düz soru cevap için
|
OpenRouter ise ikisi de kurulu olmayan bir makinede düz soru cevap için
|
||||||
duruyor. Sağlayıcı, model, izinler ve çalışma dizini Ayarlar → Claude
|
duruyor. Sağlayıcı, model, izinler ve çalışma dizini Ayarlar → Ajan
|
||||||
sekmesinde; arka arkaya verilen komutlar tek bir konuşmada kalır.
|
sekmesinde; arka arkaya verilen komutlar tek bir konuşmada kalır.
|
||||||
- **Toplantılar** mikrofonla hoparlör çıkışından aynı anda kaydedilir; kimin ne
|
- **Toplantılar** mikrofonla hoparlör çıkışından aynı anda kaydedilir; kimin ne
|
||||||
dediği tahmin edilmez, sesin hangi kanaldan geldiğiyle belli olur. İki taraf
|
dediği tahmin edilmez, sesin hangi kanaldan geldiğiyle belli olur. İki taraf
|
||||||
|
|||||||
+1
-1
@@ -178,7 +178,7 @@ def ask(prompt, conf, on_stage=None, should_stop=None):
|
|||||||
if not shutil.which(binary):
|
if not shutil.which(binary):
|
||||||
raise AssistantError(t(
|
raise AssistantError(t(
|
||||||
"{binary} not found. Install it, or pick another provider under "
|
"{binary} not found. Install it, or pick another provider under "
|
||||||
"Settings → Claude.", binary=binary,
|
"Settings → Agent.", binary=binary,
|
||||||
))
|
))
|
||||||
|
|
||||||
run = _ask_claude if name == "claude" else _ask_codex
|
run = _ask_claude if name == "claude" else _ask_codex
|
||||||
|
|||||||
@@ -232,8 +232,18 @@ follow, and no way to answer a question you ask back.
|
|||||||
- Reply in the language you were spoken to in
|
- Reply in the language you were spoken to in
|
||||||
- Keep it short. A sentence or two when that covers it. No preamble, no "here
|
- Keep it short. A sentence or two when that covers it. No preamble, no "here
|
||||||
is what I found", no closing offer of further help
|
is what I found", no closing offer of further help
|
||||||
|
- Short is the answer, not the work. Being asked for one line is not being asked
|
||||||
|
to answer off the top of your head: when what was asked turns on something
|
||||||
|
current, specific or personal, go and look. Search the web, read the file,
|
||||||
|
open the calendar, run the command. Then answer in one line
|
||||||
|
- Never hand back a caveat in place of an answer. The moment you are about to
|
||||||
|
write that something falls after your training data, that you cannot be sure,
|
||||||
|
or that you have no way to know, is the moment to go and find out instead. You
|
||||||
|
have the tools. A guess and an apology are both worth less than the ten
|
||||||
|
seconds that checking costs
|
||||||
- Plain prose. No headings, no bullet lists, no bold, and no code fence unless
|
- Plain prose. No headings, no bullet lists, no bold, and no code fence unless
|
||||||
what was asked for is code
|
what was asked for is code. Nothing appended after the answer either: no list
|
||||||
|
of sources, no links, no note on how you found it
|
||||||
- When you did something rather than answered something, say what you did in
|
- When you did something rather than answered something, say what you did in
|
||||||
one sentence, carrying the detail that confirms it: the day and time an event
|
one sentence, carrying the detail that confirms it: the day and time an event
|
||||||
was saved for, the name of a file that was written
|
was saved for, the name of a file that was written
|
||||||
@@ -254,8 +264,17 @@ da senin soracağın soruya verilecek bir yanıt yok.
|
|||||||
- Sana hangi dilde konuşulduysa o dilde cevap ver
|
- Sana hangi dilde konuşulduysa o dilde cevap ver
|
||||||
- Kısa tut. Yetiyorsa bir iki cümle. Giriş cümlesi kurma, "işte buldukların"
|
- Kısa tut. Yetiyorsa bir iki cümle. Giriş cümlesi kurma, "işte buldukların"
|
||||||
deme, sonunda başka yardım teklif etme
|
deme, sonunda başka yardım teklif etme
|
||||||
|
- Kısa olması gereken cevap, iş değil. Tek satır istenmesi, aklından cevap ver
|
||||||
|
demek değildir: sorulan şey güncel, belirli ya da kişisel bir şeye bağlıysa
|
||||||
|
git bak. İnternette ara, dosyayı oku, takvime bak, komutu çalıştır. Sonra tek
|
||||||
|
satırla cevapla
|
||||||
|
- Cevabın yerine asla bir çekince koyma. Bir şeyin eğitim verinden sonrasına
|
||||||
|
denk geldiğini, emin olamayacağını ya da bilmene imkân olmadığını yazmak
|
||||||
|
üzereysen, tam o an gidip öğrenmenin zamanıdır. Araçların var. Bir tahmin de
|
||||||
|
bir özür de, bakmanın alacağı on saniyeden daha az değerlidir
|
||||||
- Düz metin yaz. Başlık, madde işareti, kalın yazı kullanma; istenen şey kodun
|
- Düz metin yaz. Başlık, madde işareti, kalın yazı kullanma; istenen şey kodun
|
||||||
kendisi değilse kod bloğu da açma
|
kendisi değilse kod bloğu da açma. Cevabın arkasına da bir şey ekleme: kaynak
|
||||||
|
listesi, bağlantı, nasıl bulduğuna dair not olmasın
|
||||||
- Bir şeyi cevaplamak yerine yaptıysan, ne yaptığını tek cümleyle söyle ve onu
|
- Bir şeyi cevaplamak yerine yaptıysan, ne yaptığını tek cümleyle söyle ve onu
|
||||||
doğrulayan ayrıntıyı da yaz: kaydın hangi güne ve saate düştüğü, yazdığın
|
doğrulayan ayrıntıyı da yaz: kaydın hangi güne ve saate düştüğü, yazdığın
|
||||||
dosyanın adı
|
dosyanın adı
|
||||||
|
|||||||
@@ -163,7 +163,15 @@ class Dikte:
|
|||||||
self._set_icon("audio-input-microphone")
|
self._set_icon("audio-input-microphone")
|
||||||
|
|
||||||
def _tray_clicked(self, reason):
|
def _tray_clicked(self, reason):
|
||||||
if reason == QSystemTrayIcon.ActivationReason.Trigger:
|
if reason != QSystemTrayIcon.ActivationReason.Trigger:
|
||||||
|
return
|
||||||
|
# The icon ends whatever is being recorded rather than only a dictation.
|
||||||
|
# The two shortcuts are each tied to their own mode, on purpose, but the
|
||||||
|
# icon is one button: having it refuse to stop a recording it can see is
|
||||||
|
# just a button that does nothing.
|
||||||
|
if self.state == RECORDING and self.ask_mode:
|
||||||
|
self._toggle_ask()
|
||||||
|
else:
|
||||||
self._toggle()
|
self._toggle()
|
||||||
|
|
||||||
def _set_icon(self, name):
|
def _set_icon(self, name):
|
||||||
|
|||||||
@@ -331,8 +331,8 @@ TR = {
|
|||||||
"Using {name}…": "{name} kullanıyor…",
|
"Using {name}…": "{name} kullanıyor…",
|
||||||
"Thinking…": "Düşünüyor…",
|
"Thinking…": "Düşünüyor…",
|
||||||
"{binary} not found. Install it, or pick another provider under "
|
"{binary} not found. Install it, or pick another provider under "
|
||||||
"Settings → Claude.":
|
"Settings → Agent.":
|
||||||
"{binary} bulunamadı. Kur ya da Ayarlar → Claude sekmesinden başka bir "
|
"{binary} bulunamadı. Kur ya da Ayarlar → Ajan sekmesinden başka bir "
|
||||||
"sağlayıcı seç.",
|
"sağlayıcı seç.",
|
||||||
"Could not run {binary}: {error}": "{binary} çalıştırılamadı: {error}",
|
"Could not run {binary}: {error}": "{binary} çalıştırılamadı: {error}",
|
||||||
"{service} exited with code {code}.": "{service} {code} koduyla çıktı.",
|
"{service} exited with code {code}.": "{service} {code} koduyla çıktı.",
|
||||||
@@ -344,8 +344,8 @@ TR = {
|
|||||||
"It was not allowed to use: {tools}": "Şunları kullanmasına izin yoktu: {tools}",
|
"It was not allowed to use: {tools}": "Şunları kullanmasına izin yoktu: {tools}",
|
||||||
"The model returned an empty reply.": "Model boş cevap döndürdü.",
|
"The model returned an empty reply.": "Model boş cevap döndürdü.",
|
||||||
|
|
||||||
# --- settings: Claude ---------------------------------------------------
|
# --- settings: the agent ------------------------------------------------
|
||||||
"Claude": "Claude",
|
"Agent": "Ajan",
|
||||||
"This shortcut records the same way dictation does, but the transcript is "
|
"This shortcut records the same way dictation does, but the transcript is "
|
||||||
"not what gets pasted. It goes to an agent as a command, and what comes "
|
"not what gets pasted. It goes to an agent as a command, and what comes "
|
||||||
"back is pasted instead: the answer to a question, or a sentence saying "
|
"back is pasted instead: the answer to a question, or a sentence saying "
|
||||||
@@ -386,7 +386,7 @@ TR = {
|
|||||||
"The conversation": "Konuşma",
|
"The conversation": "Konuşma",
|
||||||
"The answer": "Cevap",
|
"The answer": "Cevap",
|
||||||
"Found: {path}": "Bulundu: {path}",
|
"Found: {path}": "Bulundu: {path}",
|
||||||
"No KDE shortcut installed. The tray menu asks Claude too.":
|
"No KDE shortcut installed. The tray menu asks it too.":
|
||||||
"Kurulu KDE kısayolu yok. Tepsi menüsünden de sorulabilir.",
|
"Kurulu KDE kısayolu yok. Tepsi menüsünden de sorulabilir.",
|
||||||
"A name like “sonnet” always means the newest model of that line. Opus "
|
"A name like “sonnet” always means the newest model of that line. Opus "
|
||||||
"thinks harder and answers slower, which is felt here more than anywhere "
|
"thinks harder and answers slower, which is felt here more than anywhere "
|
||||||
|
|||||||
+34
-17
@@ -90,6 +90,15 @@ REASONING_LEVELS = [
|
|||||||
("Very high", "xhigh"), ("Maximum", "max"),
|
("Very high", "xhigh"), ("Maximum", "max"),
|
||||||
]
|
]
|
||||||
PASTE_SHORTCUTS = ["ctrl+v", "ctrl+shift+v", "shift+insert"]
|
PASTE_SHORTCUTS = ["ctrl+v", "ctrl+shift+v", "shift+insert"]
|
||||||
|
# Offered for all three global shortcuts, which keeps them one kind of field
|
||||||
|
# rather than three. The boxes stay editable: this is a shortlist of
|
||||||
|
# combinations that are usually free, not the set of ones that work.
|
||||||
|
SHORTCUTS = [
|
||||||
|
"Ctrl+Space", "Ctrl+Alt+Space", "Ctrl+Shift+Space", "Meta+Space",
|
||||||
|
"Ctrl+Alt+A", "Ctrl+Alt+D", "Ctrl+Alt+M", "Ctrl+Alt+Q",
|
||||||
|
"Meta+A", "Meta+D", "Meta+M",
|
||||||
|
"Ctrl+Alt+F1", "Ctrl+Alt+F2", "Ctrl+Alt+F3",
|
||||||
|
]
|
||||||
AUDIO_FILTER = ("*.mp3 *.wav *.m4a *.ogg *.opus *.flac *.aac *.wma "
|
AUDIO_FILTER = ("*.mp3 *.wav *.m4a *.ogg *.opus *.flac *.aac *.wma "
|
||||||
"*.mp4 *.mkv *.webm *.mov *.avi")
|
"*.mp4 *.mkv *.webm *.mov *.avi")
|
||||||
|
|
||||||
@@ -122,7 +131,7 @@ class SettingsWindow(QDialog):
|
|||||||
tabs.addTab(self._general_tab(), t("General"))
|
tabs.addTab(self._general_tab(), t("General"))
|
||||||
tabs.addTab(self._api_tab(), t("API and models"))
|
tabs.addTab(self._api_tab(), t("API and models"))
|
||||||
tabs.addTab(self._prompt_tab(), t("Cleanup rules"))
|
tabs.addTab(self._prompt_tab(), t("Cleanup rules"))
|
||||||
tabs.addTab(self._assistant_tab(), t("Claude"))
|
tabs.addTab(self._assistant_tab(), t("Agent"))
|
||||||
tabs.addTab(self._meeting_tab(), t("Meeting"))
|
tabs.addTab(self._meeting_tab(), t("Meeting"))
|
||||||
tabs.addTab(self._minutes_tab(), t("Minutes"))
|
tabs.addTab(self._minutes_tab(), t("Minutes"))
|
||||||
tabs.addTab(self._file_tab(), t("Audio file"))
|
tabs.addTab(self._file_tab(), t("Audio file"))
|
||||||
@@ -353,8 +362,7 @@ class SettingsWindow(QDialog):
|
|||||||
|
|
||||||
how = QGroupBox(t("How it runs"))
|
how = QGroupBox(t("How it runs"))
|
||||||
how_form = QFormLayout(how)
|
how_form = QFormLayout(how)
|
||||||
self.assistant_shortcut = QLineEdit()
|
self.assistant_shortcut = self._shortcut_box(t("none"))
|
||||||
self.assistant_shortcut.setPlaceholderText(t("none"))
|
|
||||||
install = QPushButton(t("Install as a KDE shortcut"))
|
install = QPushButton(t("Install as a KDE shortcut"))
|
||||||
install.clicked.connect(self._install_ask_shortcut)
|
install.clicked.connect(self._install_ask_shortcut)
|
||||||
remove = QPushButton(t("Remove"))
|
remove = QPushButton(t("Remove"))
|
||||||
@@ -604,8 +612,7 @@ class SettingsWindow(QDialog):
|
|||||||
))
|
))
|
||||||
recording_form.addRow("", self.meeting_keep_audio)
|
recording_form.addRow("", self.meeting_keep_audio)
|
||||||
|
|
||||||
self.meeting_shortcut = QLineEdit()
|
self.meeting_shortcut = self._shortcut_box(t("none"))
|
||||||
self.meeting_shortcut.setPlaceholderText(t("none"))
|
|
||||||
install = QPushButton(t("Install as a KDE shortcut"))
|
install = QPushButton(t("Install as a KDE shortcut"))
|
||||||
install.clicked.connect(self._install_meeting_shortcut)
|
install.clicked.connect(self._install_meeting_shortcut)
|
||||||
remove = QPushButton(t("Remove"))
|
remove = QPushButton(t("Remove"))
|
||||||
@@ -752,8 +759,7 @@ class SettingsWindow(QDialog):
|
|||||||
page = QWidget()
|
page = QWidget()
|
||||||
layout = QVBoxLayout(page)
|
layout = QVBoxLayout(page)
|
||||||
form = QFormLayout()
|
form = QFormLayout()
|
||||||
self.shortcut = QLineEdit()
|
self.shortcut = self._shortcut_box("Ctrl+Space")
|
||||||
self.shortcut.setPlaceholderText("Ctrl+Space")
|
|
||||||
form.addRow(t("Shortcut"), self.shortcut)
|
form.addRow(t("Shortcut"), self.shortcut)
|
||||||
layout.addLayout(form)
|
layout.addLayout(form)
|
||||||
|
|
||||||
@@ -837,6 +843,17 @@ class SettingsWindow(QDialog):
|
|||||||
layout.addLayout(row)
|
layout.addLayout(row)
|
||||||
return page
|
return page
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _shortcut_box(placeholder=""):
|
||||||
|
"""The field a global shortcut is typed or picked in."""
|
||||||
|
box = QComboBox()
|
||||||
|
box.setEditable(True)
|
||||||
|
box.addItems(SHORTCUTS)
|
||||||
|
box.setCurrentText("")
|
||||||
|
if placeholder:
|
||||||
|
box.lineEdit().setPlaceholderText(placeholder)
|
||||||
|
return box
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _row(*widgets):
|
def _row(*widgets):
|
||||||
"""Widgets side by side in one form row; the first one takes the space."""
|
"""Widgets side by side in one form row; the first one takes the space."""
|
||||||
@@ -878,7 +895,7 @@ class SettingsWindow(QDialog):
|
|||||||
self.cleanup_prompt.setPlainText(conf["cleanup_prompt"] or cfg.default_cleanup_prompt())
|
self.cleanup_prompt.setPlainText(conf["cleanup_prompt"] or cfg.default_cleanup_prompt())
|
||||||
self.transcribe_prompt.setPlainText(conf["transcribe_prompt"])
|
self.transcribe_prompt.setPlainText(conf["transcribe_prompt"])
|
||||||
|
|
||||||
self.assistant_shortcut.setText(conf["assistant_shortcut"])
|
self.assistant_shortcut.setCurrentText(conf["assistant_shortcut"])
|
||||||
self._select_data(self.assistant_provider, conf["assistant_provider"])
|
self._select_data(self.assistant_provider, conf["assistant_provider"])
|
||||||
self.assistant_model.setCurrentText(conf["assistant_model"])
|
self.assistant_model.setCurrentText(conf["assistant_model"])
|
||||||
self._select_data(self.assistant_permission, conf["assistant_permission_mode"])
|
self._select_data(self.assistant_permission, conf["assistant_permission_mode"])
|
||||||
@@ -906,7 +923,7 @@ class SettingsWindow(QDialog):
|
|||||||
self.meeting_cleanup.setChecked(conf["meeting_cleanup"])
|
self.meeting_cleanup.setChecked(conf["meeting_cleanup"])
|
||||||
self.meeting_max_minutes.setValue(max(5, int(conf["meeting_max_seconds"]) // 60))
|
self.meeting_max_minutes.setValue(max(5, int(conf["meeting_max_seconds"]) // 60))
|
||||||
self.meeting_keep_audio.setChecked(conf["meeting_keep_audio"])
|
self.meeting_keep_audio.setChecked(conf["meeting_keep_audio"])
|
||||||
self.meeting_shortcut.setText(conf["meeting_shortcut"])
|
self.meeting_shortcut.setCurrentText(conf["meeting_shortcut"])
|
||||||
self.meeting_prompt.setPlainText(
|
self.meeting_prompt.setPlainText(
|
||||||
conf["meeting_prompt"] or cfg.default_meeting_prompt()
|
conf["meeting_prompt"] or cfg.default_meeting_prompt()
|
||||||
)
|
)
|
||||||
@@ -915,7 +932,7 @@ class SettingsWindow(QDialog):
|
|||||||
self.file_cleanup.setChecked(conf["file_cleanup"])
|
self.file_cleanup.setChecked(conf["file_cleanup"])
|
||||||
self.file_path = ""
|
self.file_path = ""
|
||||||
|
|
||||||
self.shortcut.setText(conf["shortcut"])
|
self.shortcut.setCurrentText(conf["shortcut"])
|
||||||
self.evdev_enabled.setChecked(conf["evdev_hotkey"])
|
self.evdev_enabled.setChecked(conf["evdev_hotkey"])
|
||||||
|
|
||||||
self.history_limit.setValue(max(0, int(conf["history_limit"])))
|
self.history_limit.setValue(max(0, int(conf["history_limit"])))
|
||||||
@@ -962,7 +979,7 @@ class SettingsWindow(QDialog):
|
|||||||
conf["cleanup_prompt"] = "" if prompt == cfg.default_cleanup_prompt() else prompt
|
conf["cleanup_prompt"] = "" if prompt == cfg.default_cleanup_prompt() else prompt
|
||||||
conf["transcribe_prompt"] = self.transcribe_prompt.toPlainText().strip()
|
conf["transcribe_prompt"] = self.transcribe_prompt.toPlainText().strip()
|
||||||
|
|
||||||
conf["assistant_shortcut"] = self.assistant_shortcut.text().strip()
|
conf["assistant_shortcut"] = self.assistant_shortcut.currentText().strip()
|
||||||
conf["assistant_provider"] = self.assistant_provider.currentData() or "claude"
|
conf["assistant_provider"] = self.assistant_provider.currentData() or "claude"
|
||||||
conf["assistant_model"] = (self.assistant_model.currentText().strip()
|
conf["assistant_model"] = (self.assistant_model.currentText().strip()
|
||||||
or cfg.DEFAULTS["assistant_model"])
|
or cfg.DEFAULTS["assistant_model"])
|
||||||
@@ -1001,7 +1018,7 @@ class SettingsWindow(QDialog):
|
|||||||
conf["meeting_cleanup"] = self.meeting_cleanup.isChecked()
|
conf["meeting_cleanup"] = self.meeting_cleanup.isChecked()
|
||||||
conf["meeting_max_seconds"] = self.meeting_max_minutes.value() * 60
|
conf["meeting_max_seconds"] = self.meeting_max_minutes.value() * 60
|
||||||
conf["meeting_keep_audio"] = self.meeting_keep_audio.isChecked()
|
conf["meeting_keep_audio"] = self.meeting_keep_audio.isChecked()
|
||||||
conf["meeting_shortcut"] = self.meeting_shortcut.text().strip()
|
conf["meeting_shortcut"] = self.meeting_shortcut.currentText().strip()
|
||||||
meeting_prompt = self.meeting_prompt.toPlainText().strip()
|
meeting_prompt = self.meeting_prompt.toPlainText().strip()
|
||||||
conf["meeting_prompt"] = ("" if meeting_prompt == cfg.default_meeting_prompt()
|
conf["meeting_prompt"] = ("" if meeting_prompt == cfg.default_meeting_prompt()
|
||||||
else meeting_prompt)
|
else meeting_prompt)
|
||||||
@@ -1009,7 +1026,7 @@ class SettingsWindow(QDialog):
|
|||||||
conf["file_timestamps"] = self.file_timestamps.isChecked()
|
conf["file_timestamps"] = self.file_timestamps.isChecked()
|
||||||
conf["file_cleanup"] = self.file_cleanup.isChecked()
|
conf["file_cleanup"] = self.file_cleanup.isChecked()
|
||||||
|
|
||||||
conf["shortcut"] = self.shortcut.text().strip() or "Ctrl+Space"
|
conf["shortcut"] = self.shortcut.currentText().strip() or "Ctrl+Space"
|
||||||
conf["evdev_hotkey"] = self.evdev_enabled.isChecked()
|
conf["evdev_hotkey"] = self.evdev_enabled.isChecked()
|
||||||
conf["history_limit"] = self.history_limit.value()
|
conf["history_limit"] = self.history_limit.value()
|
||||||
conf.save()
|
conf.save()
|
||||||
@@ -1217,7 +1234,7 @@ class SettingsWindow(QDialog):
|
|||||||
# ---- shortcut --------------------------------------------------------
|
# ---- shortcut --------------------------------------------------------
|
||||||
|
|
||||||
def _install_shortcut(self):
|
def _install_shortcut(self):
|
||||||
combo = self.shortcut.text().strip() or "Ctrl+Space"
|
combo = self.shortcut.currentText().strip() or "Ctrl+Space"
|
||||||
clashes = hotkey.conflicting_shortcuts(combo)
|
clashes = hotkey.conflicting_shortcuts(combo)
|
||||||
if clashes:
|
if clashes:
|
||||||
answer = QMessageBox.question(
|
answer = QMessageBox.question(
|
||||||
@@ -1246,7 +1263,7 @@ class SettingsWindow(QDialog):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _install_meeting_shortcut(self):
|
def _install_meeting_shortcut(self):
|
||||||
combo = self.meeting_shortcut.text().strip()
|
combo = self.meeting_shortcut.currentText().strip()
|
||||||
if not combo:
|
if not combo:
|
||||||
QMessageBox.information(self, t("Shortcut"),
|
QMessageBox.information(self, t("Shortcut"),
|
||||||
t("Type a key combination first."))
|
t("Type a key combination first."))
|
||||||
@@ -1284,7 +1301,7 @@ class SettingsWindow(QDialog):
|
|||||||
# ---- Claude ----------------------------------------------------------
|
# ---- Claude ----------------------------------------------------------
|
||||||
|
|
||||||
def _install_ask_shortcut(self):
|
def _install_ask_shortcut(self):
|
||||||
combo = self.assistant_shortcut.text().strip()
|
combo = self.assistant_shortcut.currentText().strip()
|
||||||
if not combo:
|
if not combo:
|
||||||
QMessageBox.information(self, t("Shortcut"),
|
QMessageBox.information(self, t("Shortcut"),
|
||||||
t("Type a key combination first."))
|
t("Type a key combination first."))
|
||||||
@@ -1316,7 +1333,7 @@ class SettingsWindow(QDialog):
|
|||||||
current = hotkey.kde_shortcut_status(hotkey.ASK_DESKTOP_ID)
|
current = hotkey.kde_shortcut_status(hotkey.ASK_DESKTOP_ID)
|
||||||
self.assistant_shortcut_status.setText(
|
self.assistant_shortcut_status.setText(
|
||||||
t("Registered in KDE: {shortcut}", shortcut=current) if current
|
t("Registered in KDE: {shortcut}", shortcut=current) if current
|
||||||
else t("No KDE shortcut installed. The tray menu asks Claude too.")
|
else t("No KDE shortcut installed. The tray menu asks it too.")
|
||||||
)
|
)
|
||||||
|
|
||||||
def _assistant_provider_changed(self):
|
def _assistant_provider_changed(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user