|
Download GUI-ARCHITECTURE.md from smlflg/shared-gui: direct link, hf CLI and curl.
- Browser
- Download file 10.6 kB
-
https://huggingface.co/smlflg/shared-gui/resolve/main/GUI-ARCHITECTURE.md
- Command line
-
hf download hf://smlflg/shared-gui/GUI-ARCHITECTURE.md
-
curl -L -o GUI-ARCHITECTURE.md https://huggingface.co/smlflg/shared-gui/resolve/main/GUI-ARCHITECTURE.md
10.6 kB
| # GUI-Architektur β 3 Standalone GTK3 Apps | |
| Stand: 2026-03-04 | |
| ## 1. Shared Base Module (`~/Projekte/shared-gui/gui_base.py`) | |
| Gemeinsame Grundlage fuer alle drei GUIs. Importiert `theme.py` aus ClaudeCodePanel. | |
| ### BaseApp Klasse | |
| ```python | |
| class BaseApp(Gtk.Window): | |
| def __init__(self, title, width, height, icon_name=None) | |
| ``` | |
| Bereitgestellte Features: | |
| - **Window Setup**: Titel, Groesse, Icon, `destroy`-Signal | |
| - **HeaderBar**: Gtk.HeaderBar mit Titel + optionalem Subtitle | |
| - **StatusBar**: Unten, CSS-Klasse `.status-bar`, mit `set_status(text, css_class)` Methode | |
| - **Theme**: Automatisches Laden von Catppuccin CSS via `theme.py`, COSMIC dark/light Watcher | |
| - **CSS Provider**: Gemeinsam fuer alle Widgets, erweiterbar via `add_css(css_string)` | |
| - **Refresh Timer**: `start_refresh(interval_seconds, callback)` β GLib.timeout_add_seconds | |
| - **Main Box**: Vertikaler Gtk.Box (`self.content_box`) zwischen Header und StatusBar | |
| ### Theme-Modul Wiederverwendung | |
| `gui_base.py` importiert direkt aus ClaudeCodePanel: | |
| ```python | |
| sys.path.insert(0, str(Path.home() / "Projekte/ClaudeCodePanel")) | |
| from theme import build_css, setup_theme_watcher, get_palette, is_dark_mode | |
| ``` | |
| ### Gemeinsame CSS-Klassen (aus theme.py) | |
| Alle Apps erben automatisch: | |
| - `.panel-header`, `.stat-value`, `.stat-label` β Ueberschriften + Statistiken | |
| - `.section-frame`, `.section-title` β Karten/Sektionen | |
| - `.status-bar`, `.status-saved`, `.status-error` β Statusleiste | |
| - `.shortcut-btn` β Aktionsbuttons | |
| - `.monitor-value`, `.cost-value` β Monospace-Werte | |
| Zusaetzlich definiert gui_base.py: | |
| - `.base-card` β Standardkarte (border-radius 8px, card-bg, border) | |
| - `.base-toolbar` β Toolbar-Leiste (mantle-bg, border-radius 8px) | |
| - `.base-badge` β Kleine Status-Badges (border-radius 12px) | |
| --- | |
| ## 2. Design-Specs pro GUI | |
| ### 2.1 Sidecar-GUI (`~/Projekte/Sidecar/gui/`) | |
| **Zweck:** Visuelles Dashboard fuer den Sidecar Daemon β Rules, Sessions, Findings. | |
| **Layout:** | |
| ``` | |
| +-----------------------------------------------+ | |
| | [HeaderBar] Sidecar Control Panel [Reload] | | |
| +-----------------------------------------------+ | |
| | [Notebook] | | |
| | +-------------------------------------------+ | | |
| | | Tab: Status | Tab: Rules | Tab: Findings | | | |
| | +-------------------------------------------+ | | |
| | | | |
| | STATUS TAB: | | |
| | Daemon: running PID: 12345 Uptime: 2h 15m | | |
| | Rules: 22 Findings: 5 Plugins: 3 | | |
| | | | |
| | RULES TAB: | | |
| | [SearchEntry filter] | | |
| | +------------------------------------------+ | | |
| | | Name | Group | Enabled | Fires | | | |
| | | cli_first | enforce | [x] | 12 | | | |
| | | gate_rm_rf | gate | [x] | 3 | | | |
| | +------------------------------------------+ | | |
| | [Enable] [Disable] [Snooze 30m] | | |
| | | | |
| | FINDINGS TAB: | | |
| | [ScrolledWindow mit Finding-Cards] | | |
| | Time | Rule | Severity | Message | | |
| +-----------------------------------------------+ | |
| | [StatusBar] Connected via /tmp/claude-sidecar.sock | | |
| +-----------------------------------------------+ | |
| ``` | |
| **Widgets:** | |
| - `Gtk.Notebook` mit 3 Tabs | |
| - Status-Tab: Grid mit Labels (key-value), aktualisiert via Refresh | |
| - Rules-Tab: `Gtk.ListBox` mit Rows, SearchEntry fuer Filter, Toggle-Buttons | |
| - Findings-Tab: `Gtk.ListBox` mit farbcodierten Karten (Severity β Farbe) | |
| **Datenquellen:** | |
| - Primaer: Unix Socket `/tmp/claude-sidecar.sock` (JSON-Protokoll, wie sidecar-ctl) | |
| - Kommandos: `status`, `rules`, `findings`, `enable`, `disable`, `snooze`, `reload` | |
| - Socket-Kommunikation non-blocking via `GLib.io_add_watch` auf Socket-FD | |
| **Refresh:** 5 Sekunden (Status + Rules), Findings on-demand | |
| **Interaktion:** | |
| - Rules: Klick auf Row β Enable/Disable Toggle, Rechtsklick β Snooze | |
| - Findings: Nur Anzeige, scrollbar | |
| - Reload-Button in HeaderBar | |
| --- | |
| ### 2.2 Tools-GUI (`~/Projekte/ClaudeCodePanel/tools-gui/`) | |
| **Zweck:** Session-History + Kosten-Tracking fuer Claude Code. | |
| **Layout:** | |
| ``` | |
| +-----------------------------------------------+ | |
| | [HeaderBar] Claude Code Tools [Ref] | | |
| +-----------------------------------------------+ | |
| | [Notebook] | | |
| | +-------------------------------------------+ | | |
| | | Tab: Sessions | Tab: Costs | Tab: Tools | | | |
| | +-------------------------------------------+ | | |
| | | | |
| | SESSIONS TAB: | | |
| | [SearchEntry] [ComboBox: Sortierung] | | |
| | +------------------------------------------+ | | |
| | | Projekt | Letztes Msg | Kosten | Res | | | |
| | | Sidecar | vor 2h | $0.12 | [>] | | | |
| | | ClaudePanel | vor 1d | $0.45 | [>] | | | |
| | +------------------------------------------+ | | |
| | | | |
| | COSTS TAB: | | |
| | Heute: $1.23 Woche: $8.50 Monat: $32.10 | | |
| | [BarChart via DrawingArea β letzte 7 Tage] | | |
| | Top Tools: Read(45) Edit(23) Bash(18) | | |
| | | | |
| | TOOLS TAB: | | |
| | Tool-Usage Breakdown (ListBox) | | |
| | Skill-Usage + Missed Skills | | |
| +-----------------------------------------------+ | |
| | [StatusBar] 12 Sessions | $1.23 heute | | |
| +-----------------------------------------------+ | |
| ``` | |
| **Widgets:** | |
| - Sessions-Tab: `Gtk.ListBox` mit Session-Rows, SearchEntry, ComboBox fuer Sortierung | |
| - Costs-Tab: Stat-Labels oben, `Gtk.DrawingArea` fuer 7-Tage-Balkendiagramm (Cairo), Tool-Rankings | |
| - Tools-Tab: `Gtk.ListBox` mit Tool-Usage, Skill-Usage | |
| **Datenquellen:** | |
| - `monitor.py` Funktionen: `get_daily_cost()`, `get_top_tools()`, `get_recent_sessions()`, `get_usage_timeline()`, `get_provider_costs()`, `get_skill_usage()`, `get_missed_skills_summary()` | |
| - Import: `sys.path.insert(0, "~/Projekte/ClaudeCodePanel")` + `from monitor import ...` | |
| **Refresh:** 30 Sekunden (passend zum TTL-Cache in monitor.py) | |
| --- | |
| ### 2.3 Florian-GUI (`~/Projekte/MyAIGame/florian-gui/`) | |
| **Zweck:** TTS Control Panel β Voice-Auswahl, Test, Speed/Pitch, Audio-Playback. | |
| **Layout:** | |
| ``` | |
| +-----------------------------------------------+ | |
| | [HeaderBar] Florian TTS Control [Play] | | |
| +-----------------------------------------------+ | |
| | | | |
| | Voice: [ComboBox: florian|katja|conrad|...] | | |
| | | | |
| | Speed: [=====|========] 1.0x | | |
| | Pitch: [=====|========] +0Hz | | |
| | | | |
| | Format: ( ) mp3 ( ) wav ( ) opus ( ) flac | | |
| | | | |
| | Text: | | |
| | +------------------------------------------+ | | |
| | | Guten Tag, ich bin Florian und teste | | | |
| | | die Sprachausgabe. | | | |
| | +------------------------------------------+ | | |
| | | | |
| | [ Speak ] [Stop] | | |
| | | | |
| | +------------------------------------------+ | | |
| | | Audio-Wellenform / Fortschrittsbalken | | | |
| | +------------------------------------------+ | | |
| | | | |
| | Server: localhost:5050 [Health: OK] | | |
| +-----------------------------------------------+ | |
| | [StatusBar] Ready β Florian (de-DE) | | |
| +-----------------------------------------------+ | |
| ``` | |
| **Widgets:** | |
| - `Gtk.ComboBoxText` fuer Voice-Auswahl (aus `/v1/audio/voices` Endpoint) | |
| - `Gtk.Scale` fuer Speed (0.25 β 4.0, Step 0.25) und Pitch (-20Hz β +20Hz) | |
| - `Gtk.RadioButton` Gruppe fuer Format | |
| - `Gtk.TextView` fuer Text-Eingabe (mehrzeilig) | |
| - `Gtk.Button` Speak + Stop | |
| - `Gtk.ProgressBar` fuer Audio-Playback | |
| - Health-Indikator (Label mit Farbcode) | |
| **Datenquellen:** | |
| - HTTP API: `http://localhost:5050` | |
| - `GET /v1/audio/voices` β Voice-Liste | |
| - `POST /v1/audio/speech` β Audio-Bytes (body: `{input, voice, speed, response_format}`) | |
| - `GET /health` β Server-Status | |
| - HTTP via `Gio.InputStream` / subprocess `curl` + GLib.spawn_async (kein threading!) | |
| **Audio-Playback:** | |
| - Tempfile schreiben β `subprocess.Popen(["mpv", "--no-video", tmpfile])` via `GLib.spawn_async` | |
| - Stop = Kill des mpv-Prozesses | |
| **Refresh:** Health-Check alle 10 Sekunden | |
| --- | |
| ## 3. Dateistruktur pro Projekt | |
| ### shared-gui/ | |
| ``` | |
| ~/Projekte/shared-gui/ | |
| gui_base.py # BaseApp + Theme-Integration + gemeinsame CSS | |
| ``` | |
| ### Sidecar-GUI | |
| ``` | |
| ~/Projekte/Sidecar/gui/ | |
| main.py # Entry-Point, SidecarApp(BaseApp) | |
| socket_client.py # Non-blocking Unix Socket Client (GLib.io_add_watch) | |
| tabs/ | |
| status_tab.py # Daemon-Status Anzeige | |
| rules_tab.py # Rules ListBox + Filter + Enable/Disable | |
| findings_tab.py # Findings ListBox | |
| ``` | |
| ### Tools-GUI | |
| ``` | |
| ~/Projekte/ClaudeCodePanel/tools-gui/ | |
| main.py # Entry-Point, ToolsApp(BaseApp) | |
| tabs/ | |
| sessions_tab.py # Session-ListBox + Search + Sort | |
| costs_tab.py # Kosten-Stats + Cairo BarChart | |
| tools_tab.py # Tool-Usage + Skill-Usage | |
| ``` | |
| ### Florian-GUI | |
| ``` | |
| ~/Projekte/MyAIGame/florian-gui/ | |
| main.py # Entry-Point, FlorianApp(BaseApp) | |
| tts_client.py # HTTP Client (Gio/subprocess, non-blocking) | |
| audio_player.py # mpv-basierter Player (GLib.spawn_async) | |
| ``` | |
| --- | |
| ## 4. Constraints | |
| | Constraint | Detail | | |
| |-----------|--------| | |
| | **Toolkit** | GTK 3.0 via PyGObject (`gi.require_version("Gtk", "3.0")`) | | |
| | **Theme** | Catppuccin Mocha (dark) / Latte (light) via `theme.py` | | |
| | **Desktop** | COSMIC β `is_dark_mode()` liest `~/.config/cosmic/CosmicTheme.Mode/v1/is_dark` | | |
| | **Event Loop** | GLib Main Loop β KEIN threading, KEIN asyncio im GUI-Thread | | |
| | **Timer** | `GLib.timeout_add_seconds()` fuer Refresh, Return `True` fuer Repeat | | |
| | **Non-Blocking I/O** | Socket: `GLib.io_add_watch`, HTTP: `GLib.spawn_async` mit Callback | | |
| | **CSS** | Alle Styles via `Gtk.CssProvider`, keine inline-Styles | | |
| | **GLib.idle_add** | Nur als One-Shot (`return False`), NIE mit `return True` | | |
| | **Python** | 3.11+ (match/case erlaubt, aber nicht erforderlich) | | |
| | **Abhaengigkeiten** | PyGObject >= 3.42, gir1.2-gtk-3.0 (keine zusaetzlichen Pakete) | | |