diff --git a/whisper_local/tray/_download_progress.py b/whisper_local/tray/_download_progress.py index bd5918a..44fb6eb 100644 --- a/whisper_local/tray/_download_progress.py +++ b/whisper_local/tray/_download_progress.py @@ -39,10 +39,11 @@ def load_model_with_progress( compute_type: str, download_root: str | None, ) -> Any: - """Lädt WhisperModel — zeigt bei Bedarf einen Download-Fortschrittsdialog. + """Lädt WhisperModel — zeigt bei längerem Laden einen Wartebalken. - Wenn das Modell bereits gecacht ist (kein tqdm-Update kommt), erscheint - kein Dialog. Auf Download-Fehler wird ein Fehlerdialog gezeigt und sys.exit(1) + Wenn das Modell in unter 500 ms bereit ist (vollständiger Cache), erscheint + kein Dialog. Bei Download oder langsamer Initialisierung wird ein indeterminater + Wartebalken angezeigt. Auf Fehler wird ein Fehlerdialog gezeigt und sys.exit(1) aufgerufen. """ import tkinter as tk @@ -52,14 +53,11 @@ def load_model_with_progress( from whisper_local.tray._theme import apply_system_theme - q: queue.Queue[dict[str, Any] | None] = queue.Queue() - result: list[WhisperModel | None] = [None] + result: list[Any] = [None] error: list[BaseException | None] = [None] - original_tqdm = tqdm_module.tqdm + done_event = threading.Event() def worker() -> None: - TkProgressTqdm._queue = q - tqdm_module.tqdm = TkProgressTqdm try: result[0] = WhisperModel( model_name, @@ -69,16 +67,23 @@ def load_model_with_progress( except Exception as exc: error[0] = exc finally: - tqdm_module.tqdm = original_tqdm - TkProgressTqdm._queue = None - q.put(None) # Sentinel: signalisiert Fertigstellung + done_event.set() thread = threading.Thread(target=worker, daemon=True) thread.start() - # --- tkinter-Dialog (lazy: erscheint nur bei echtem Download) --- + # Kurz warten – wenn Modell sofort bereit (vollständiger Cache), kein Dialog + if done_event.wait(timeout=0.5): + if error[0] is not None: + root = tk.Tk() + root.withdraw() + messagebox.showerror("Fehler beim Modell-Laden", str(error[0])) + root.destroy() + sys.exit(1) + return result[0] + + # Modell braucht länger (Download oder Initialisierung) → Dialog anzeigen root = tk.Tk() - root.withdraw() # zunächst versteckt root.title("whisper-local – Modell wird geladen") root.resizable(False, False) apply_system_theme(root) @@ -87,48 +92,26 @@ def load_model_with_progress( frame.pack(fill=tk.BOTH, expand=True) ttk.Label(frame, text=f"Lade Whisper-Modell '{model_name}'...").pack(anchor=tk.W) + ttk.Label(frame, text="Bitte warten\u2026", foreground="gray").pack( + anchor=tk.W, pady=(4, 8) + ) - file_var = tk.StringVar(value="") - ttk.Label(frame, textvariable=file_var, foreground="gray").pack(anchor=tk.W, pady=(4, 8)) - - progress_var = tk.DoubleVar(value=0.0) - ttk.Progressbar( - frame, variable=progress_var, maximum=100, length=320, mode="determinate" - ).pack(fill=tk.X) - - pct_var = tk.StringVar(value="0 %") - ttk.Label(frame, textvariable=pct_var).pack(anchor=tk.E, pady=(2, 0)) - - _dialog_shown = False + pb = ttk.Progressbar(frame, length=320, mode="indeterminate") + pb.pack(fill=tk.X) + pb.start(10) def poll() -> None: - nonlocal _dialog_shown - try: - while True: - msg = q.get_nowait() - if msg is None: # Sentinel → fertig - root.quit() - return - # Erste echte Meldung → Dialog anzeigen - if not _dialog_shown: - root.deiconify() - _dialog_shown = True - # UI aktualisieren - file_var.set(msg["file"]) - if msg["total"] > 0: - pct = 100.0 * msg["n"] / msg["total"] - progress_var.set(pct) - pct_var.set(f"{pct:.0f} %") - except queue.Empty: - pass - root.after(50, poll) + if done_event.is_set(): + root.quit() + return + root.after(100, poll) - root.after(50, poll) + root.after(100, poll) root.mainloop() if error[0] is not None: root.withdraw() - messagebox.showerror("Fehler beim Modell-Download", str(error[0])) + messagebox.showerror("Fehler beim Modell-Laden", str(error[0])) root.destroy() sys.exit(1)