Skip to content

Commit 52af438

Browse files
committed
fix: retry backend connection, freeze_support, collect all chromadb modules
1 parent 1b22cb7 commit 52af438

3 files changed

Lines changed: 38 additions & 17 deletions

File tree

pyinstaller.spec

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,16 @@ After build, copy:
1616
import platform
1717
import subprocess
1818

19+
from PyInstaller.utils.hooks import collect_all, collect_submodules
20+
1921
block_cipher = None
2022

23+
# ChromaDB uses dynamic imports heavily — collect everything
24+
chromadb_datas, chromadb_binaries, chromadb_hiddenimports = collect_all("chromadb")
25+
26+
# Also collect all onnxruntime submodules (used by chromadb embeddings)
27+
onnxruntime_hiddenimports = collect_submodules("onnxruntime")
28+
2129
# Determine the Rust target triple (Tauri sidecar naming convention)
2230
def get_target_triple():
2331
try:
@@ -43,14 +51,15 @@ TARGET_TRIPLE = get_target_triple()
4351
a = Analysis(
4452
["server.py"],
4553
pathex=["."],
46-
binaries=[],
54+
binaries=chromadb_binaries,
4755
datas=[
4856
("src/web/static", "src/web/static"),
4957
("templates", "templates"),
5058
("forms", "forms"),
5159
(".env.example", "."),
52-
],
60+
] + chromadb_datas,
5361
hiddenimports=[
62+
# DoctorFill modules
5463
"src",
5564
"src.config",
5665
"src.config.settings",
@@ -80,9 +89,10 @@ a = Analysis(
8089
"src.templates.loader",
8190
"src.web",
8291
"src.web.app",
92+
# Third-party
8393
"flask",
94+
"flask_cors",
8495
"dotenv",
85-
"chromadb",
8696
"tiktoken",
8797
"tiktoken_ext",
8898
"tiktoken_ext.openai_public",
@@ -95,7 +105,7 @@ a = Analysis(
95105
"json_repair",
96106
"tqdm",
97107
"requests",
98-
],
108+
] + chromadb_hiddenimports + onnxruntime_hiddenimports,
99109
hookspath=[],
100110
hooksconfig={},
101111
runtime_hooks=[],

server.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77

88
import sys
99
import os
10+
import multiprocessing
11+
12+
# Fix for macOS/Windows PyInstaller + multiprocessing
13+
multiprocessing.freeze_support()
1014

1115
# Ensure the project root is in sys.path for absolute imports
1216
# when running as a PyInstaller bundle.
1317
if getattr(sys, '_MEIPASS', None):
1418
sys.path.insert(0, sys._MEIPASS)
1519

16-
from src.web.app import app, main
17-
1820
if __name__ == "__main__":
21+
from src.web.app import main
1922
main()

src/web/static/index.html

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -494,18 +494,26 @@ <h1>DoctorFill</h1>
494494
});
495495

496496
// ──────────────────────────────────────────────────
497-
// Init: check if configured
497+
// Init: wait for backend then check config
498498
// ──────────────────────────────────────────────────
499-
fetch(API_BASE + '/config')
500-
.then(r => r.json())
501-
.then(data => {
502-
if (data.configured) {
503-
showMain();
504-
} else {
505-
showSetup();
506-
}
507-
})
508-
.catch(() => showSetup());
499+
async function waitForBackend(retries = 15, delay = 500) {
500+
for (let i = 0; i < retries; i++) {
501+
try {
502+
const r = await fetch(API_BASE + '/config');
503+
if (r.ok) return await r.json();
504+
} catch (_) { /* server not ready yet */ }
505+
await new Promise(res => setTimeout(res, delay));
506+
}
507+
return null;
508+
}
509+
510+
waitForBackend().then(data => {
511+
if (data && data.configured) {
512+
showMain();
513+
} else {
514+
showSetup();
515+
}
516+
});
509517

510518
// ──────────────────────────────────────────────────
511519
// Main screen: form loading

0 commit comments

Comments
 (0)