mirror of
https://github.com/yusufipk/dikte.git
synced 2026-09-12 03:16:19 +00:00
Let the cleanup model be told how hard to think
This commit is contained in:
@@ -37,7 +37,8 @@ runs on either one (`gpt-4o-transcribe` by default), cleanup always on
|
|||||||
OpenRouter (`google/gemini-3.5-flash-lite`), so a single OpenRouter key can
|
OpenRouter (`google/gemini-3.5-flash-lite`), so a single OpenRouter key can
|
||||||
cover both. They fall back to `OPENAI_API_KEY` and `OPENROUTER_API_KEY`, and are
|
cover both. They fall back to `OPENAI_API_KEY` and `OPENROUTER_API_KEY`, and are
|
||||||
stored in `~/.config/dikte/config.json`, mode 600. Cleanup can be switched off,
|
stored in `~/.config/dikte/config.json`, mode 600. Cleanup can be switched off,
|
||||||
in which case the raw transcript is pasted.
|
in which case the raw transcript is pasted, and a thinking model's effort can be
|
||||||
|
set next to it.
|
||||||
|
|
||||||
## Using it
|
## Using it
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -38,7 +38,7 @@ temizleme her zaman OpenRouter'da (`google/gemini-3.5-flash-lite`), yani tek bir
|
|||||||
OpenRouter anahtarı ikisine de yeter. Boş bırakırsan `OPENAI_API_KEY` ve
|
OpenRouter anahtarı ikisine de yeter. Boş bırakırsan `OPENAI_API_KEY` ve
|
||||||
`OPENROUTER_API_KEY` kullanılır; anahtarlar `~/.config/dikte/config.json`
|
`OPENROUTER_API_KEY` kullanılır; anahtarlar `~/.config/dikte/config.json`
|
||||||
içinde, izinler 600. Temizlemeyi tamamen kapatabilirsin, o zaman ham transkript
|
içinde, izinler 600. Temizlemeyi tamamen kapatabilirsin, o zaman ham transkript
|
||||||
yapıştırılır.
|
yapıştırılır; modelin yanındaki kutudan düşünme seviyesini de seçebilirsin.
|
||||||
|
|
||||||
## Kullanım
|
## Kullanım
|
||||||
|
|
||||||
|
|||||||
@@ -173,7 +173,8 @@ def transcribe_segments(target, wav_path, language="", prompt="", timeout=300):
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def cleanup(text, api_key, model, system_prompt, base_url=OPENROUTER_URL, timeout=180):
|
def cleanup(text, api_key, model, system_prompt, reasoning="",
|
||||||
|
base_url=OPENROUTER_URL, timeout=180):
|
||||||
if not api_key:
|
if not api_key:
|
||||||
raise ApiError(t("{service} API key is empty. Add it in Settings.",
|
raise ApiError(t("{service} API key is empty. Add it in Settings.",
|
||||||
service="OpenRouter"))
|
service="OpenRouter"))
|
||||||
@@ -185,6 +186,11 @@ def cleanup(text, api_key, model, system_prompt, base_url=OPENROUTER_URL, timeou
|
|||||||
{"role": "user", "content": f"<transcript>\n{text}\n</transcript>"},
|
{"role": "user", "content": f"<transcript>\n{text}\n</transcript>"},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
# An empty level means "whatever the model does on its own"; anything else is
|
||||||
|
# one of OpenRouter's efforts. The thinking itself is never shown, so ask for
|
||||||
|
# it to be left out of the reply.
|
||||||
|
if reasoning:
|
||||||
|
payload["reasoning"] = {"effort": reasoning, "exclude": True}
|
||||||
try:
|
try:
|
||||||
data = _request(
|
data = _request(
|
||||||
f"{base_url.rstrip('/')}/chat/completions",
|
f"{base_url.rstrip('/')}/chat/completions",
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ DEFAULTS = {
|
|||||||
"transcribe_prompt": "",
|
"transcribe_prompt": "",
|
||||||
"cleanup_enabled": True,
|
"cleanup_enabled": True,
|
||||||
"cleanup_model": "google/gemini-3.5-flash-lite",
|
"cleanup_model": "google/gemini-3.5-flash-lite",
|
||||||
|
"cleanup_reasoning": "", # empty -> whatever the model does by default
|
||||||
"cleanup_prompt": "", # empty -> language-specific default
|
"cleanup_prompt": "", # empty -> language-specific default
|
||||||
"auto_paste": True,
|
"auto_paste": True,
|
||||||
"paste_shortcut": "ctrl+v",
|
"paste_shortcut": "ctrl+v",
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ class FileTranscriber(QObject):
|
|||||||
conf.openrouter_key(),
|
conf.openrouter_key(),
|
||||||
conf["cleanup_model"],
|
conf["cleanup_model"],
|
||||||
prompt,
|
prompt,
|
||||||
|
reasoning=conf["cleanup_reasoning"],
|
||||||
base_url=conf["openrouter_base_url"],
|
base_url=conf["openrouter_base_url"],
|
||||||
))
|
))
|
||||||
return ("\n" if timestamps else "\n\n").join(out)
|
return ("\n" if timestamps else "\n\n").join(out)
|
||||||
|
|||||||
@@ -158,6 +158,21 @@ TR = {
|
|||||||
"Connection works. {count} audio models visible.":
|
"Connection works. {count} audio models visible.":
|
||||||
"Bağlantı tamam. {count} ses modeli görünüyor.",
|
"Bağlantı tamam. {count} ses modeli görünüyor.",
|
||||||
"Clean the transcript with a model": "Transkripti bir modelle temizle",
|
"Clean the transcript with a model": "Transkripti bir modelle temizle",
|
||||||
|
"Thinking": "Düşünme",
|
||||||
|
"Model's own default": "Modelin kendi varsayılanı",
|
||||||
|
"Off": "Kapalı",
|
||||||
|
"Minimal": "En az",
|
||||||
|
"Low": "Düşük",
|
||||||
|
"Medium": "Orta",
|
||||||
|
"High": "Yüksek",
|
||||||
|
"Very high": "Çok yüksek",
|
||||||
|
"Maximum": "En yüksek",
|
||||||
|
"How long a thinking model may reason before it answers. Cleanup is a light "
|
||||||
|
"job, so more thinking mostly costs time and tokens. Models that cannot "
|
||||||
|
"think ignore this.":
|
||||||
|
"Düşünebilen bir modelin yanıtlamadan önce ne kadar düşüneceği. Temizleme "
|
||||||
|
"hafif bir iş, fazla düşünmenin çoğunlukla getirisi süre ve token. "
|
||||||
|
"Düşünemeyen modeller bunu yok sayar.",
|
||||||
"Fetch model list": "Model listesini çek",
|
"Fetch model list": "Model listesini çek",
|
||||||
"Fetching model list…": "Model listesi çekiliyor…",
|
"Fetching model list…": "Model listesi çekiliyor…",
|
||||||
"Could not fetch the list: {error}": "Liste alınamadı: {error}",
|
"Could not fetch the list: {error}": "Liste alınamadı: {error}",
|
||||||
|
|||||||
@@ -43,6 +43,13 @@ CLEANUP_MODELS = [
|
|||||||
"google/gemini-2.5-flash-lite", "anthropic/claude-haiku-4.5",
|
"google/gemini-2.5-flash-lite", "anthropic/claude-haiku-4.5",
|
||||||
"openai/gpt-5-mini", "meta-llama/llama-3.3-70b-instruct",
|
"openai/gpt-5-mini", "meta-llama/llama-3.3-70b-instruct",
|
||||||
]
|
]
|
||||||
|
# How hard the cleanup model may think before it answers, in OpenRouter's own
|
||||||
|
# effort levels. A model that ignores the field simply answers as it always did.
|
||||||
|
REASONING_LEVELS = [
|
||||||
|
("Model's own default", ""), ("Off", "none"), ("Minimal", "minimal"),
|
||||||
|
("Low", "low"), ("Medium", "medium"), ("High", "high"),
|
||||||
|
("Very high", "xhigh"), ("Maximum", "max"),
|
||||||
|
]
|
||||||
PASTE_SHORTCUTS = ["ctrl+v", "ctrl+shift+v", "shift+insert"]
|
PASTE_SHORTCUTS = ["ctrl+v", "ctrl+shift+v", "shift+insert"]
|
||||||
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")
|
||||||
@@ -231,6 +238,17 @@ class SettingsWindow(QDialog):
|
|||||||
self.refresh_models = QPushButton(t("Fetch model list"))
|
self.refresh_models = QPushButton(t("Fetch model list"))
|
||||||
self.refresh_models.clicked.connect(self._load_models)
|
self.refresh_models.clicked.connect(self._load_models)
|
||||||
orr_form.addRow(t("Model"), self._row(self.cleanup_model, self.refresh_models))
|
orr_form.addRow(t("Model"), self._row(self.cleanup_model, self.refresh_models))
|
||||||
|
|
||||||
|
self.cleanup_reasoning = QComboBox()
|
||||||
|
for label, value in REASONING_LEVELS:
|
||||||
|
self.cleanup_reasoning.addItem(t(label), value)
|
||||||
|
self.cleanup_reasoning.setToolTip(
|
||||||
|
t("How long a thinking model may reason before it answers. Cleanup is "
|
||||||
|
"a light job, so more thinking mostly costs time and tokens. Models "
|
||||||
|
"that cannot think ignore this.")
|
||||||
|
)
|
||||||
|
orr_form.addRow(t("Thinking"), self.cleanup_reasoning)
|
||||||
|
|
||||||
self.models_label = QLabel(t("Runs on OpenRouter."))
|
self.models_label = QLabel(t("Runs on OpenRouter."))
|
||||||
self.models_label.setWordWrap(True)
|
self.models_label.setWordWrap(True)
|
||||||
orr_form.addRow(self.models_label)
|
orr_form.addRow(self.models_label)
|
||||||
@@ -456,6 +474,7 @@ class SettingsWindow(QDialog):
|
|||||||
self._provider_changed() # selecting index 0 fires no signal
|
self._provider_changed() # selecting index 0 fires no signal
|
||||||
self.cleanup_enabled.setChecked(conf["cleanup_enabled"])
|
self.cleanup_enabled.setChecked(conf["cleanup_enabled"])
|
||||||
self.cleanup_model.setCurrentText(conf["cleanup_model"])
|
self.cleanup_model.setCurrentText(conf["cleanup_model"])
|
||||||
|
self._select_data(self.cleanup_reasoning, conf["cleanup_reasoning"])
|
||||||
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"])
|
||||||
|
|
||||||
@@ -498,6 +517,7 @@ class SettingsWindow(QDialog):
|
|||||||
|
|
||||||
conf["cleanup_enabled"] = self.cleanup_enabled.isChecked()
|
conf["cleanup_enabled"] = self.cleanup_enabled.isChecked()
|
||||||
conf["cleanup_model"] = self.cleanup_model.currentText().strip()
|
conf["cleanup_model"] = self.cleanup_model.currentText().strip()
|
||||||
|
conf["cleanup_reasoning"] = self.cleanup_reasoning.currentData() or ""
|
||||||
|
|
||||||
# Store an empty prompt when it matches the default, so switching the
|
# Store an empty prompt when it matches the default, so switching the
|
||||||
# interface language also switches the prompt language.
|
# interface language also switches the prompt language.
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ class Pipeline(QObject):
|
|||||||
conf.openrouter_key(),
|
conf.openrouter_key(),
|
||||||
conf["cleanup_model"],
|
conf["cleanup_model"],
|
||||||
conf.cleanup_prompt(),
|
conf.cleanup_prompt(),
|
||||||
|
reasoning=conf["cleanup_reasoning"],
|
||||||
base_url=conf["openrouter_base_url"],
|
base_url=conf["openrouter_base_url"],
|
||||||
)
|
)
|
||||||
except api.ApiError as exc:
|
except api.ApiError as exc:
|
||||||
|
|||||||
Reference in New Issue
Block a user