docs: fix spec issues from review
This commit is contained in:
parent
ebfd751e8d
commit
82ef96ea09
|
|
@ -52,7 +52,8 @@ def _app_dir() -> str:
|
||||||
return os.path.dirname(sys.executable)
|
return os.path.dirname(sys.executable)
|
||||||
else:
|
else:
|
||||||
# Dev mode: use script directory (git repo root)
|
# Dev mode: use script directory (git repo root)
|
||||||
return os.path.dirname(os.path.abspath(__file__ + "/../../"))
|
# config.py lives at whisper_app/config.py → two levels up = repo root
|
||||||
|
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
```
|
```
|
||||||
|
|
||||||
Machine-local config (`config_local.json`) continues to use `%LOCALAPPDATA%\WhisperDictation` (Windows) or `~/.local/share/WhisperDictation` (Linux) — unchanged.
|
Machine-local config (`config_local.json`) continues to use `%LOCALAPPDATA%\WhisperDictation` (Windows) or `~/.local/share/WhisperDictation` (Linux) — unchanged.
|
||||||
|
|
@ -62,21 +63,25 @@ Machine-local config (`config_local.json`) continues to use `%LOCALAPPDATA%\Whis
|
||||||
`app.py` owns a `queue.Queue[str]` and a pre-queue buffer list.
|
`app.py` owns a `queue.Queue[str]` and a pre-queue buffer list.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
_log_buffer: list[str] = [] # before queue is ready
|
_log_buffer: list[str] = [] # before queue is ready, capped at 500 entries
|
||||||
_log_queue: queue.Queue | None = None
|
_log_queue: queue.Queue | None = None
|
||||||
|
_log_lock = threading.Lock()
|
||||||
|
|
||||||
def log(msg: str) -> None:
|
def log(msg: str) -> None:
|
||||||
if _log_queue is not None:
|
with _log_lock:
|
||||||
_log_queue.put(msg)
|
if _log_queue is not None:
|
||||||
else:
|
_log_queue.put(msg)
|
||||||
_log_buffer.append(msg)
|
else:
|
||||||
|
_log_buffer.append(msg)
|
||||||
|
|
||||||
def set_log_queue(q: queue.Queue) -> None:
|
def set_log_queue(q: queue.Queue) -> None:
|
||||||
global _log_queue
|
global _log_queue
|
||||||
_log_queue = q
|
with _log_lock:
|
||||||
for msg in _log_buffer:
|
_log_queue = q
|
||||||
q.put(msg)
|
buffered = list(_log_buffer)
|
||||||
_log_buffer.clear()
|
_log_buffer.clear()
|
||||||
|
for msg in buffered: # flush outside the lock to avoid deadlock
|
||||||
|
q.put_nowait(msg)
|
||||||
```
|
```
|
||||||
|
|
||||||
All `print()` calls in all modules are replaced with `app.log()`.
|
All `print()` calls in all modules are replaced with `app.log()`.
|
||||||
|
|
@ -106,6 +111,7 @@ Opened via tray icon left-click or "Anzeigen" menu item. Implemented in `log_win
|
||||||
- Close button → `withdraw()` (does not quit the app)
|
- Close button → `withdraw()` (does not quit the app)
|
||||||
- 🗑 button → clears the text widget
|
- 🗑 button → clears the text widget
|
||||||
- Queue polled via `root.after(100, _poll_log_queue)`
|
- Queue polled via `root.after(100, _poll_log_queue)`
|
||||||
|
- The tkinter `root` (hidden) is always alive as long as the tray runs — `withdraw()` on the log window does not trigger mainloop exit. The app exits only via the tray "Beenden" menu item.
|
||||||
|
|
||||||
## Settings Window — Installation Section
|
## Settings Window — Installation Section
|
||||||
|
|
||||||
|
|
@ -117,9 +123,10 @@ Each integration shows status ("eingerichtet" / "nicht eingerichtet") and two bu
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Autostart beim Login | `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` | `~/.config/autostart/whisper-dictation.desktop` |
|
| Autostart beim Login | `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` | `~/.config/autostart/whisper-dictation.desktop` |
|
||||||
| Startmenü-Eintrag | `%APPDATA%\Microsoft\Windows\Start Menu\Programs\Whisper Dictation.lnk` | `~/.local/share/applications/whisper-dictation.desktop` |
|
| Startmenü-Eintrag | `%APPDATA%\Microsoft\Windows\Start Menu\Programs\Whisper Dictation.lnk` | `~/.local/share/applications/whisper-dictation.desktop` |
|
||||||
| Desktop-Verknüpfung | `%USERPROFILE%\Desktop\Whisper Dictation.lnk` | `~/Desktop/whisper-dictation.desktop` |
|
| Desktop-Verknüpfung | `%USERPROFILE%\Desktop\Whisper Dictation.lnk` | XDG: `xdg-user-dir DESKTOP` (fallback: `~/Desktop`) |
|
||||||
|
|
||||||
Windows `.lnk` files are created via `pywin32` (`win32com.client.Dispatch("WScript.Shell")`).
|
Windows `.lnk` files are created via `pywin32` (`win32com.client.Dispatch("WScript.Shell")`).
|
||||||
|
`import win32com` must be guarded: `if sys.platform == "win32"` — top-level import is forbidden to avoid import errors on Linux.
|
||||||
|
|
||||||
**Only available when running as a frozen binary.** In dev mode, the buttons are disabled with a tooltip "Nur im gebauten Binary verfügbar".
|
**Only available when running as a frozen binary.** In dev mode, the buttons are disabled with a tooltip "Nur im gebauten Binary verfügbar".
|
||||||
|
|
||||||
|
|
@ -141,22 +148,25 @@ a = Analysis(
|
||||||
'ctranslate2',
|
'ctranslate2',
|
||||||
'faster_whisper',
|
'faster_whisper',
|
||||||
'sounddevice',
|
'sounddevice',
|
||||||
'pynput.keyboard._win32', # Windows
|
'pynput.keyboard._win32', # Windows
|
||||||
'pynput.keyboard._xorg', # Linux
|
'pynput.keyboard._xorg', # Linux X11
|
||||||
],
|
'pynput.keyboard._uinput', # Linux Wayland
|
||||||
datas=[
|
|
||||||
('config.json', '.'),
|
|
||||||
('vocabulary.json', '.'),
|
|
||||||
],
|
],
|
||||||
|
datas=[], # config.json / vocabulary.json NOT bundled — see below
|
||||||
)
|
)
|
||||||
exe = EXE(a.pure, ..., console=False, icon='icon.ico')
|
pyz = PYZ(a.pure)
|
||||||
|
exe = EXE(pyz, a.scripts, ..., console=False, icon='icon.ico')
|
||||||
|
coll = COLLECT(exe, a.binaries, a.datas, name='whisper-dictation')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**config.json / vocabulary.json are NOT bundled via `datas`.**
|
||||||
|
They are user-editable files that live next to the binary. `build.py` copies them from the repo root into `dist/whisper-dictation/` after the PyInstaller run. This is the single authoritative location in frozen mode (`os.path.dirname(sys.executable)`).
|
||||||
|
|
||||||
### `build.py`
|
### `build.py`
|
||||||
|
|
||||||
1. Generates `icon.ico` from PIL
|
1. Generates `icon.ico` from PIL (must run before PyInstaller — `.spec` references it)
|
||||||
2. Runs PyInstaller with the `.spec` file
|
2. Runs PyInstaller with the `.spec` file
|
||||||
3. Copies `config.json` and `vocabulary.json` into `dist/whisper-dictation/`
|
3. Copies `config.json` and `vocabulary.json` into `dist/whisper-dictation/` **only if they don't already exist there** (to avoid overwriting user edits)
|
||||||
|
|
||||||
### Platform requirement
|
### Platform requirement
|
||||||
|
|
||||||
|
|
@ -172,6 +182,16 @@ PyInstaller cannot cross-compile. **Build must be run separately on each platfor
|
||||||
|
|
||||||
Added to `requirements-windows.txt`. Not required on Linux.
|
Added to `requirements-windows.txt`. Not required on Linux.
|
||||||
|
|
||||||
|
## UI Language
|
||||||
|
|
||||||
|
All UI labels are in German. "WHISPER DICTATION" in the log panel header is the product name and stays as-is. All other UI text (buttons, section headers, tooltips) is German.
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
- **Startup crash visibility:** With `console=False`, crashes before the tray appears produce no visible output. Implementer should wrap `main()` in a try/except that writes to a logfile (e.g., `%LOCALAPPDATA%\WhisperDictation\error.log`) as a last resort.
|
||||||
|
- **pynput hidden imports:** Only keyboard backends are needed (`_win32`, `_xorg`, `_uinput`). No mouse backends required — hotkeys are keyboard-only.
|
||||||
|
- **`_log_buffer` cap:** Enforce max 500 entries; if buffer exceeds cap, drop oldest entry before appending.
|
||||||
|
|
||||||
## Out of Scope
|
## Out of Scope
|
||||||
|
|
||||||
- Code signing / notarization
|
- Code signing / notarization
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue