diff --git a/README.de.md b/README.de.md index 7eab48c..29a9b5e 100644 --- a/README.de.md +++ b/README.de.md @@ -155,7 +155,7 @@ Blitztext registriert globale Hotkeys via `evdev`. Mit diesen Kombinationen hast Die KI-Workflows helfen bei Formulierung, Ton und Emojis. Die passenden Einstellungen findest du unter **Einstellungen → KI-Workflows**:
- KI-Workflow-Einstellungen + KI-Workflow-Einstellungen

@@ -195,6 +195,12 @@ Für den Workflow **Blitztext+** (Text-Verbesserer) gibt es vorgefertigte Schrei Das **Compose-Fenster** (`✍ Compose…` im Tray-Kontextmenü) ermöglicht das Umschreiben beliebiger Texte mit der KI — ganz ohne Sprachaufnahme. Es eignet sich ideal zum Überarbeiten fertiger Entwürfe, E-Mails oder Notizen. +
+
+ Compose-Fenster +

+
+ **Öffnen:** Klick auf das Tray-Icon → **✍ Compose…** **Was du im Compose-Fenster tun kannst:** @@ -251,7 +257,7 @@ Das Tray-Kontextmenü gibt dir schnellen Zugriff auf alle Workflows, das Compose

- Tray-Kontextmenü + Tray-Kontextmenü

@@ -266,11 +272,12 @@ Das Hauptfenster ist dein grafisches Kontrollzentrum — nützlich, wenn Hotkeys

- Hauptfenster + Hauptfenster

- **Workflow-Dropdown:** Alle 5 Aufnahmemodi zur Auswahl. +- **Schreibstil-Vorlage:** Sichtbar wenn **Blitztext+** gewählt ist — Preset direkt im Hauptfenster wählen. Änderungen werden sofort mit dem Tray synchronisiert. - **Start/Stopp-Button:** Klick zum Starten oder Beenden einer Aufnahme. - **Abbruch:** Bricht die aktuelle Aufnahme ohne Transkription ab. - **Diktat / Verlauf:** Schnellzugriff auf den Diktat-Modus und den Transkript-Verlauf. @@ -286,8 +293,8 @@ Zusätzlich zu den Workflows bietet das Tool drei Komfort-Funktionen:

- Verlauf - Vorlesen + Verlauf + Vorlesen

@@ -320,11 +327,11 @@ Alles wird lokal und sicher unter `~/.config/blitztext-linux/config.json` gespei Der Einstellungs-Dialog hat drei Tabs:
- Einstellungen: Spracherkennung + Einstellungen: Spracherkennung
Spracherkennung — Whisper-Modell, Backend, Sprache, Hotkey-Modus und Aufnahmetaste.

- Einstellungen: KI-Workflows + Einstellungen: KI-Workflows
KI-Workflows — LLM-Anbieter, API-Key, Base-URL, Modell, Tonfall und Schreibstil-Vorlage.

- Einstellungen: Allgemein + Einstellungen: Allgemein
Allgemein — Auto-Paste, Diktat-Ordner, Verlaufsgröße, Sprache der Oberfläche und Signatur.

diff --git a/README.md b/README.md index e1ea984..09b2f34 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ Blitztext registers global hotkeys via `evdev`. With these combinations you have The AI workflows help with phrasing, tone, and emojis. You'll find the relevant settings under **Settings → AI Workflows**:
- AI workflow settings + AI workflow settings

@@ -197,6 +197,12 @@ For the **Blitztext+** workflow (text improver) there are ready-made writing-sty The **Compose window** (`✍ Compose…` in the tray menu) lets you rewrite any text using the AI — without recording your voice. It is ideal for editing existing drafts, emails, or notes. +
+
+ Compose window +

+
+ **How to open:** Click the tray icon → **✍ Compose…** **What you can do in the Compose window:** @@ -253,7 +259,7 @@ The tray context menu gives you quick access to all workflows, the compose windo

- Tray context menu + Tray context menu

@@ -268,11 +274,12 @@ The main window is your graphical control center — useful when hotkeys are blo

- Main window + Main window

- **Workflow dropdown:** Select from all 5 recording modes. +- **Writing-style preset:** Visible when **Blitztext+** is selected — pick your preset directly in the main window. Changes sync to the tray instantly. - **Start/Stop button:** Click to begin or end a recording. - **Discard:** Cancels the current recording without transcription. - **Dictation / History:** Quick access to dictation mode and the transcript history. @@ -288,8 +295,8 @@ In addition to the workflows, the tool offers three convenience functions:

- History - Read aloud + History + Read aloud

@@ -323,11 +330,11 @@ Everything is stored locally and securely under `~/.config/blitztext-linux/confi The settings dialog has three tabs:
- Settings: Speech Recognition + Settings: Speech Recognition
Speech Recognition — Whisper model, backend, language, hotkey mode, and recording key.

- Settings: AI Workflows + Settings: AI Workflows
AI Workflows — LLM provider, API key, base URL, model, tone, and writing-style preset.

- Settings: General + Settings: General
General — Auto-Paste, dictation folder, history size, interface language, and signature.

diff --git a/docs/screenshots/linux/Banner-de.png b/docs/screenshots/linux/Banner-de.png new file mode 100644 index 0000000..8506a2e Binary files /dev/null and b/docs/screenshots/linux/Banner-de.png differ diff --git a/docs/screenshots/linux/Banner-en.png b/docs/screenshots/linux/Banner-en.png new file mode 100644 index 0000000..72097fb Binary files /dev/null and b/docs/screenshots/linux/Banner-en.png differ diff --git a/docs/screenshots/linux/compose-de.png b/docs/screenshots/linux/compose-de.png new file mode 100644 index 0000000..b8b08ee Binary files /dev/null and b/docs/screenshots/linux/compose-de.png differ diff --git a/docs/screenshots/linux/compose-en.png b/docs/screenshots/linux/compose-en.png new file mode 100644 index 0000000..d7ccaa5 Binary files /dev/null and b/docs/screenshots/linux/compose-en.png differ diff --git a/docs/screenshots/linux/history-de.png b/docs/screenshots/linux/history-de.png new file mode 100644 index 0000000..673b661 Binary files /dev/null and b/docs/screenshots/linux/history-de.png differ diff --git a/docs/screenshots/linux/history-en.png b/docs/screenshots/linux/history-en.png new file mode 100644 index 0000000..c879f45 Binary files /dev/null and b/docs/screenshots/linux/history-en.png differ diff --git a/docs/screenshots/linux/main-window-de.png b/docs/screenshots/linux/main-window-de.png new file mode 100644 index 0000000..acb8504 Binary files /dev/null and b/docs/screenshots/linux/main-window-de.png differ diff --git a/docs/screenshots/linux/main-window-en.png b/docs/screenshots/linux/main-window-en.png new file mode 100644 index 0000000..403ae42 Binary files /dev/null and b/docs/screenshots/linux/main-window-en.png differ diff --git a/docs/screenshots/linux/main-window-recording-de.png b/docs/screenshots/linux/main-window-recording-de.png new file mode 100644 index 0000000..6d2e96f Binary files /dev/null and b/docs/screenshots/linux/main-window-recording-de.png differ diff --git a/docs/screenshots/linux/main-window-recording-en.png b/docs/screenshots/linux/main-window-recording-en.png new file mode 100644 index 0000000..7d58a58 Binary files /dev/null and b/docs/screenshots/linux/main-window-recording-en.png differ diff --git a/docs/screenshots/linux/settings-ai-workflows-compose-en.png b/docs/screenshots/linux/settings-ai-workflows-compose-en.png new file mode 100644 index 0000000..7e9d9bd Binary files /dev/null and b/docs/screenshots/linux/settings-ai-workflows-compose-en.png differ diff --git a/docs/screenshots/linux/settings-ai-workflows-de.png b/docs/screenshots/linux/settings-ai-workflows-de.png new file mode 100644 index 0000000..e8c0d1e Binary files /dev/null and b/docs/screenshots/linux/settings-ai-workflows-de.png differ diff --git a/docs/screenshots/linux/settings-ai-workflows-en.png b/docs/screenshots/linux/settings-ai-workflows-en.png new file mode 100644 index 0000000..cca4a19 Binary files /dev/null and b/docs/screenshots/linux/settings-ai-workflows-en.png differ diff --git a/docs/screenshots/linux/settings-general-de.png b/docs/screenshots/linux/settings-general-de.png new file mode 100644 index 0000000..ae362b2 Binary files /dev/null and b/docs/screenshots/linux/settings-general-de.png differ diff --git a/docs/screenshots/linux/settings-general-en.png b/docs/screenshots/linux/settings-general-en.png new file mode 100644 index 0000000..bf04760 Binary files /dev/null and b/docs/screenshots/linux/settings-general-en.png differ diff --git a/docs/screenshots/linux/settings-speech-de.png b/docs/screenshots/linux/settings-speech-de.png new file mode 100644 index 0000000..4d2b468 Binary files /dev/null and b/docs/screenshots/linux/settings-speech-de.png differ diff --git a/docs/screenshots/linux/settings-speech-en.png b/docs/screenshots/linux/settings-speech-en.png new file mode 100644 index 0000000..feef9a2 Binary files /dev/null and b/docs/screenshots/linux/settings-speech-en.png differ diff --git a/docs/screenshots/linux/tray-menu-de.png b/docs/screenshots/linux/tray-menu-de.png new file mode 100644 index 0000000..e98ed19 Binary files /dev/null and b/docs/screenshots/linux/tray-menu-de.png differ diff --git a/docs/screenshots/linux/tray-menu-en.png b/docs/screenshots/linux/tray-menu-en.png new file mode 100644 index 0000000..0a26a7f Binary files /dev/null and b/docs/screenshots/linux/tray-menu-en.png differ diff --git a/docs/screenshots/linux/tts-de.png b/docs/screenshots/linux/tts-de.png new file mode 100644 index 0000000..2c04cfe Binary files /dev/null and b/docs/screenshots/linux/tts-de.png differ diff --git a/docs/screenshots/linux/tts-en.png b/docs/screenshots/linux/tts-en.png new file mode 100644 index 0000000..dbd15fb Binary files /dev/null and b/docs/screenshots/linux/tts-en.png differ diff --git a/scripts/_make_screenshots.py b/scripts/_make_screenshots.py index 0f89caf..b83c395 100644 --- a/scripts/_make_screenshots.py +++ b/scripts/_make_screenshots.py @@ -22,12 +22,15 @@ from PyQt6.QtCore import Qt from PyQt6.QtWidgets import QApplication +from app.blitztext_linux import BlitztextApp, Config, SettingsDialog +from app.compose_window import ComposeWindow from app.config import BlitztextConfig from app.history_panel import HistoryPanel from app.i18n import set_language, t +from app.llm_service import LLMService, WorkflowType from app.main_window import MainWindow +from app.paste_service import PasteService from app.tts_window import TtsWindow -from app.blitztext_linux import BlitztextApp, Config, SettingsDialog SCREENSHOT_DIR = Path("docs/screenshots/linux") CANVAS_SIZE = (1280, 640) @@ -47,20 +50,22 @@ "hero": "Your local AI voice assistant for KDE Plasma & Wayland", "sub": "Record speech, transcribe locally or online, optionally rewrite it with AI, and paste it directly into the active app.", "flow": "Record • Transcribe • Rewrite • Paste", - "feature_title": "What is new in v0.4.0", + "feature_title": "What is new in v0.8.0", "tag_new": "NEW", "chips": [ - ("Multilingual UI", "Switch the whole app between English and German."), - ("Writing-style presets", "Ready-made Blitztext+ presets for common writing tasks."), - ("Offline-ready", "Local Whisper and privacy-friendly workflows stay available."), - ("Global hotkeys", "Capture dictation from anywhere in KDE Plasma."), + ("Compose window", "Draft, refine and compare AI-rewritten text before pasting it anywhere."), + ("Preset in main window", "Pick your writing style in the main window — changes sync to the tray instantly."), + ("Tone & template control", "Choose tone and writing template directly inside the Compose window."), + ("Prompt transparency", "Inspect and edit the AI system prompt before running a rewrite."), ], "labels": { "main": "Main window", - "general": "Settings → General", + "compose": "Compose window", "workflows": "Settings → AI Workflows", "tray": "Tray presets", }, + "compose_input": "Please help me write a concise follow-up email for our product meeting earlier today.", + "compose_output": "Hi team,\n\nThank you for the productive discussion today. Here are the key action items we agreed on:\n\n• Finalise the API contract by Friday\n• Schedule a follow-up review for next Tuesday\n• Share the updated roadmap with stakeholders\n\nLet me know if I missed anything.\n\nBest,", "history_entries": [ ("Please move tomorrow's team sync to 10:00.", False), ("Could you send me the updated rollout plan afterwards?", True), @@ -74,20 +79,22 @@ "hero": "Dein lokaler KI-Sprachassistent für KDE Plasma & Wayland", "sub": "Sprache aufnehmen, lokal oder online transkribieren, optional mit KI umformulieren und direkt in die aktive Anwendung einfügen.", "flow": "Aufnehmen • Transkribieren • Umformulieren • Direkt einfügen", - "feature_title": "Neu im Stand v0.4.0", + "feature_title": "Neu in v0.8.0", "tag_new": "NEU", "chips": [ - ("Mehrsprachige Oberfläche", "Die komplette App lässt sich zwischen Deutsch und Englisch umschalten."), - ("Schreibstil-Vorlagen", "Vorgefertigte Blitztext+-Presets für typische Schreibaufgaben."), - ("Offline-fähig", "Lokale Whisper-Workflows bleiben für datensparsame Nutzung verfügbar."), - ("Globale Hotkeys", "Diktat direkt aus jeder Anwendung unter KDE Plasma starten."), + ("Entwurfsfenster", "Text entwerfen, verfeinern und KI-Varianten vergleichen, bevor du einfügst."), + ("Preset im Hauptfenster", "Schreibstil direkt im Hauptfenster wählen – Änderungen bleiben mit dem Tray synchron."), + ("Tonfall & Vorlage", "Tonfall und Schreibvorlage direkt im Entwurfsfenster steuern."), + ("Prompt-Transparenz", "KI-Systemprompt vor der Ausführung einsehen und anpassen."), ], "labels": { "main": "Hauptfenster", - "general": "Einstellungen → Allgemein", + "compose": "Entwurfsfenster", "workflows": "Einstellungen → KI-Workflows", "tray": "Tray-Presets", }, + "compose_input": "Bitte hilf mir, eine knappe Nachfass-E-Mail zu unserem heutigen Produktmeeting zu schreiben.", + "compose_output": "Hallo zusammen,\n\nvielen Dank für die produktive Diskussion heute. Hier die vereinbarten Aufgaben:\n\n• API-Vertrag bis Freitag finalisieren\n• Review-Termin für nächsten Dienstag eintragen\n• Aktualisierte Roadmap an Stakeholder verteilen\n\nBitte meldet euch, falls ich etwas vergessen habe.\n\nViele Grüße,", "history_entries": [ ("Bitte verschiebe das Team-Meeting morgen auf 10 Uhr.", False), ("Kannst du mir danach den aktualisierten Rollout-Plan schicken?", True), @@ -277,14 +284,14 @@ def _make_banner(lang: str, out_dir: Path) -> None: screenshots = { "main": out_dir / f"main-window-{lang}.png", - "general": out_dir / f"settings-general-{lang}.png", + "compose": out_dir / f"compose-{lang}.png", "workflows": out_dir / f"settings-ai-workflows-{lang}.png", "tray": out_dir / f"tray-menu-{lang}.png", } placements = [ (screenshots["main"], (824, 74), (220, 260), copy["labels"]["main"]), - (screenshots["general"], (1046, 74), (194, 260), copy["labels"]["general"]), + (screenshots["compose"], (1046, 74), (194, 260), copy["labels"]["compose"]), (screenshots["workflows"], (790, 350), (250, 236), copy["labels"]["workflows"]), (screenshots["tray"], (1054, 332), (186, 254), copy["labels"]["tray"]), ] @@ -307,6 +314,36 @@ def _make_banner(lang: str, out_dir: Path) -> None: print(f" ✓ {social_path.name}") +class _FakeLLMService(LLMService): + """Minimal LLMService stub for offscreen rendering — never calls any API.""" + + def __init__(self) -> None: + self.api_key = "SCREENSHOT_DUMMY_TOKEN" + self.writing_preset = "standard" + + def is_configured(self) -> bool: + return True + + def rewrite_text(self, *args, **kwargs) -> str: # type: ignore[override] + return "" + + def build_system_prompt(self, *args, **kwargs) -> str: # type: ignore[override] + return "" + + def rewrite_raw(self, *args, **kwargs) -> str: # type: ignore[override] + return "" + + +class _FakePasteService(PasteService): + """Minimal PasteService stub — suppresses all clipboard / xdotool calls.""" + + def __init__(self) -> None: + pass + + def paste(self, text: str, force_autopaste=None) -> None: + pass + + def _tab_index(tabs, key: str) -> int: """Resolve a settings tab by its i18n key, independent of tab order or language.""" target = t(key) @@ -336,9 +373,16 @@ def _render_language_set(out_dir: Path, lang: str) -> None: show_history_panel=lambda *a, **k: None, show_settings_dialog=lambda *a, **k: None, show_tts_window=lambda *a, **k: None, + main_window_preset_changed=lambda *a, **k: None, ) main_window = MainWindow(controller) + # Switch to TEXT_IMPROVER so the writing-style preset combo is visible + for i in range(main_window._workflow_combo.count()): + if main_window._workflow_combo.itemData(i) == WorkflowType.TEXT_IMPROVER: + main_window._workflow_combo.setCurrentIndex(i) + _process_events() + break _grab(main_window, out_dir / f"main-window-{lang}.png") main_window.update_state("RECORDING", None, None) _grab(main_window, out_dir / f"main-window-recording-{lang}.png") @@ -347,6 +391,8 @@ def _render_language_set(out_dir: Path, lang: str) -> None: settings = SettingsDialog(config) settings.tabs.setCurrentIndex(_tab_index(settings.tabs, "settings.tab.general")) _grab(settings, out_dir / f"settings-general-{lang}.png") + settings.tabs.setCurrentIndex(_tab_index(settings.tabs, "settings.tab.speech")) + _grab(settings, out_dir / f"settings-speech-{lang}.png") settings.tabs.setCurrentIndex(_tab_index(settings.tabs, "settings.tab.workflows")) _grab(settings, out_dir / f"settings-ai-workflows-{lang}.png") settings.close() @@ -366,6 +412,12 @@ def _render_language_set(out_dir: Path, lang: str) -> None: _grab(tts, out_dir / f"tts-{lang}.png") tts.close() + compose = ComposeWindow(_FakeLLMService(), _FakePasteService(), config) + compose.set_input_text(copy["compose_input"]) + compose.txtOutput.setPlainText(copy["compose_output"]) + _grab(compose, out_dir / f"compose-{lang}.png") + compose.close() + _capture_tray_menu(config, lang, out_dir / f"tray-menu-{lang}.png") _make_banner(lang, out_dir)