Docs: Configuration · Troubleshooting · Desktop packaging · Implementation
Produces a standalone .exe — no Python install required on the target machine.
Prerequisites: Python 3.10+, PyInstaller.
pip install pyinstaller
powershell -ExecutionPolicy Bypass -File build\build.ps1Output:
dist\LogNotes\LogNotes.exe— run directly without an installer.build\Output\LogNotes-Setup-<version>.exe— installer with Start Menu entry and optional desktop shortcut. Requires Inno Setup onPATH; skipped automatically if missing.
Debug build (adds a console window so you can see stderr on silent failures):
powershell -ExecutionPolicy Bypass -File build\build.ps1 -Debug
dist\LogNotes-debug\LogNotes-debug.exeUpdating: close any running LogNotes.exe first (locked DLLs will block the build), then rebuild and re-run the installer. User config (%APPDATA%\LogNotes\config.json) and model cache (%LOCALAPPDATA%\LogNotes\cache) persist across upgrades.
SmartScreen: the unsigned build triggers "Windows protected your PC" on first launch — click More info → Run anyway.
Ollama is not bundled. Install it from ollama.com, then ollama pull llama3.2:1b. The app connects to http://localhost:11434 by default; change via ollama_host in %APPDATA%\LogNotes\config.json.
Produces a standalone .app bundle — no Python install required on the target machine.
Prerequisites: Python 3.10+, PyInstaller.
pip install pyinstaller
pyinstaller --noconsole --onedir --name LogNotes \
--add-data "src/ui/assets:src/ui/assets" \
main.pyOutput: dist/LogNotes/LogNotes.app — double-click to run.
Note: the build/ directory contains Windows-specific tooling (build.ps1, installer.iss) and is not used on Mac. There is no Mac equivalent of the Inno Setup installer; distributing the .app folder directly (e.g. zipped) is the standard approach for unsigned apps.
Accessibility permissions: pynput requires Accessibility access to capture global hotkeys. On first run macOS will prompt you — grant access in System Settings → Privacy & Security → Accessibility. Without it the hotkey will not fire.
Ollama is not bundled. Install it from ollama.com and pull the model once:
ollama pull llama3.2:1bStart Ollama before launching the app (ollama serve) if grammar cleanup is enabled.
| Location | Contents |
|---|---|
%APPDATA%\LogNotes\config.json |
User settings. Shared between dev and packaged runs. See configuration.md. |
%LOCALAPPDATA%\LogNotes\cache\hf |
HuggingFace model cache (Whisper). First-run download lands here. |
%LOCALAPPDATA%\LogNotes\cache\torch |
torch.hub cache (Silero VAD). |
%LOCALAPPDATA%\LogNotes\cache\logo.ico |
Generated window icon (bundle is read-only under _MEIPASS). |
{autopf}\LogNotes\ |
Installer target — Program Files, no admin required. |
User data and model cache are intentionally preserved on uninstall.
All in service of "runs correctly from both source and a frozen bundle."
src/paths.py (new)
resource_path(rel)— resolves bundled assets viasys._MEIPASSwhen frozen, project-root-relative in dev.user_data_dir()—%APPDATA%\LogNotes.user_cache_dir()—%LOCALAPPDATA%\LogNotes\cache.
- stdout/stderr guards. Under
--noconsole,sys.stdoutandsys.stderrareNone. Any library that calls.write()(torch.hub, tqdm, etc.) would crash. Replaced withio.StringIOsinks at the top of the file — output discarded, API preserved. This fix was required for Silero VAD (torch.hub.load) to load in the frozen build. - Cache redirect.
HF_HOMEandTORCH_HOMEset touser_cache_dir()before any torch/whisper import. - SIGINT guard. Only registers the signal handler when
sys.stdin is not None and sys.stdin.isatty()— pointless and sometimes failing under--noconsole.
CONFIG_FILEnow resolves touser_data_dir() / "config.json".- Added
ollama_hostconfig key (defaulthttp://localhost:11434) withhttp(s)://URL validation in_validate_config. - Asset lookups use
resource_path("src/ui/assets/logo.png"). - The generated
.icois cached inuser_cache_dir()(the bundle is read-only when frozen).
GrammarProcessor.__init__takes optionalhost. Passed through from config in main.py.
- Pre-existing bug surfaced during testing:
update_hotkeywrote toself._modifiers/self._keybut_check_hotkeyreadsself._required_modifiers/self._required_key, so hotkey changes were silently ignored. Fixed.
Layout under build/:
| File | Purpose |
|---|---|
LogNotes.spec |
PyInstaller release spec, console=False. |
LogNotes.debug.spec |
Same with console=True for diagnosing silent failures. |
build.ps1 |
Clean → PyInstaller → Inno Setup. Supports -Debug and -SkipInstaller. ASCII-only (Windows PowerShell 5.1 mis-parses UTF-8 without a BOM). |
installer.iss |
Inno Setup script. |
- Uses
collect_all("faster_whisper" / "ctranslate2" / "torch" / "torchaudio")rather than hand-curatinghiddenimports+collect-binaries. This was essential — manual curation would have taken many iterations for the native-DLL-heavy stack. datas=[('src/ui/assets', 'src/ui/assets')]— bundles the logo.excludes=["tkinter.test"]only. Do not excludetestorunittest—torch.utils._config_moduleimportsunittestat runtime; excluding it crashed the frozen build withModuleNotFoundError: No module named 'unittest'.console=Falsefor release; icon set tosrc/ui/assets/logo.ico.COLLECT(onedir), neveronefile— onefile extracts to temp on every launch, which is slow and triggers antivirus.
Note: -ExecutionPolicy Bypass is per-invocation only and does not change the user/machine policy. Alternative: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned once, then drop the flag.
Output: dist\LogNotes\LogNotes.exe (~800 MB, dominated by torch).
build/installer.iss — Inno Setup:
DefaultDirName={autopf}\LogNotesPrivilegesRequired=lowest— runs without admin. Admin would break writes to%APPDATA%/%LOCALAPPDATA%when the app runs as the installing user.- Start Menu shortcut always created; desktop shortcut optional (unchecked by default).
- Shortcuts use
logo.icofrom the bundled assets. - Uninstaller removes program files but leaves user data + model cache in place. Standard practice.
- In-place upgrades over prior versions.
Build (requires Inno Setup with iscc.exe
on PATH):
iscc build\installer.issOr rely on build/build.ps1, which invokes iscc
automatically when present and skips gracefully when not.
Output: build\Output\LogNotes-Setup-<version>.exe.
All code paths are additive. python main.py still works — resource_path
returns the dev-tree path when sys.frozen is false, and both dev and
packaged builds read/write the same %APPDATA%\LogNotes\config.json.
That shared config is usually what you want; if you ever need to isolate
dev, key user_data_dir() off sys.frozen.
Ollama is not bundled. It runs as a separate local service on
http://localhost:11434 by default. The packaged app is just an HTTP client.
User must:
- Install Ollama from ollama.com.
ollama pull llama3.2:1b(or whichever model is configured).- Have Ollama running before launching the app.
The endpoint is configurable via ollama_host in
%APPDATA%\LogNotes\config.json.
Whisper models download on first use into the user cache dir. No bundling — keeps the installer smaller, single code path, Activity-tab retry UX already handles the first-run wait gracefully.
Small local app, small surface:
- Spec
datas=is explicit — no.envor secrets bundled. - Ollama traffic stays on localhost.
- Installer and app run without admin.
- Silero VAD is pinned (
SILERO_VAD_VERSION = "v5.1"in src/audio/vad.py) — a compromised upstream repo can't silently swap the model. - Unsigned binaries will trigger SmartScreen ("More info → Run anyway") and may produce 1–3 heuristic VirusTotal false positives. Normal for unsigned PyInstaller output. Code signing (~$100/yr OV cert) would eliminate both; only worth it for public distribution.
Here are some issues encountered during previous builds for reference:
excludes=["test", "unittest"]breaks torch. Torch importsunittestat runtime viatorch.utils._config_module. Keep onlytkinter.test.sys.stdout/sys.stderrareNoneunder--noconsole.torch.huband any progress-printing library will crash. Replace withio.StringIOsinks at the top ofmain.py.- UTF-8 without BOM confuses Windows PowerShell 5.1. Non-ASCII characters
(em-dashes etc.) in
.ps1files cause string-termination parser errors. Keepbuild.ps1ASCII-only. - Running
LogNotes.exelocks bundled DLLs. Rebuilding fails with "Access to the path is denied" if the app is still running. Close it (ortaskkill) before rebuilding.
| Artifact | Path |
|---|---|
| Resource/path helpers | src/paths.py |
| stdout/stderr + env-var bootstrap | main.py |
| Config path + ollama_host + asset paths | src/ui/app.py |
| Ollama host plumbing | src/processing/grammar.py |
| Hotkey update fix | src/input/hotkey.py |
| PyInstaller release spec | build/LogNotes.spec |
| PyInstaller debug spec | build/LogNotes.debug.spec |
| Build script | build/build.ps1 |
| Inno Setup script | build/installer.iss |
| User-facing docs | README.md "Desktop App" section |