feat: load_model_with_progress mit tkinter-Fortschrittsdialog
This commit is contained in:
@@ -32,3 +32,99 @@ class TkProgressTqdm(tqdm_module.tqdm):
|
||||
"total": self.total or 0,
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
def load_model_with_progress(
|
||||
model_name: str,
|
||||
compute_type: str,
|
||||
download_root: str | None,
|
||||
) -> Any:
|
||||
"""Lädt WhisperModel — zeigt bei Bedarf einen Download-Fortschrittsdialog.
|
||||
|
||||
Wenn das Modell bereits gecacht ist (kein tqdm-Update kommt), erscheint
|
||||
kein Dialog. Auf Download-Fehler wird ein Fehlerdialog gezeigt und sys.exit(1)
|
||||
aufgerufen.
|
||||
"""
|
||||
import tkinter as tk
|
||||
from tkinter import messagebox, ttk
|
||||
|
||||
from faster_whisper import WhisperModel
|
||||
|
||||
from whisper_local.tray._theme import apply_system_theme
|
||||
|
||||
q: queue.Queue[dict[str, Any] | None] = queue.Queue()
|
||||
result: list[WhisperModel | None] = [None]
|
||||
error: list[BaseException | None] = [None]
|
||||
original_tqdm = tqdm_module.tqdm
|
||||
|
||||
def worker() -> None:
|
||||
TkProgressTqdm._queue = q
|
||||
tqdm_module.tqdm = TkProgressTqdm
|
||||
try:
|
||||
result[0] = WhisperModel(
|
||||
model_name,
|
||||
compute_type=compute_type,
|
||||
download_root=download_root,
|
||||
)
|
||||
except Exception as exc:
|
||||
error[0] = exc
|
||||
finally:
|
||||
tqdm_module.tqdm = original_tqdm
|
||||
TkProgressTqdm._queue = None
|
||||
q.put(None) # Sentinel: signalisiert Fertigstellung
|
||||
|
||||
thread = threading.Thread(target=worker, daemon=True)
|
||||
thread.start()
|
||||
|
||||
# --- tkinter-Dialog (lazy: erscheint nur bei echtem Download) ---
|
||||
root = tk.Tk()
|
||||
root.withdraw() # zunächst versteckt
|
||||
root.title("whisper-local – Modell wird geladen")
|
||||
root.resizable(False, False)
|
||||
apply_system_theme(root)
|
||||
|
||||
frame = ttk.Frame(root, padding=16)
|
||||
frame.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
ttk.Label(frame, text=f"Lade Whisper-Modell '{model_name}'...").pack(anchor=tk.W)
|
||||
|
||||
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))
|
||||
|
||||
def poll() -> None:
|
||||
try:
|
||||
while True:
|
||||
msg = q.get_nowait()
|
||||
if msg is None: # Sentinel → fertig
|
||||
root.quit()
|
||||
return
|
||||
# Erste echte Meldung → Dialog anzeigen
|
||||
if not root.winfo_viewable():
|
||||
root.deiconify()
|
||||
# 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)
|
||||
|
||||
root.after(50, poll)
|
||||
root.mainloop()
|
||||
root.destroy()
|
||||
|
||||
if error[0] is not None:
|
||||
messagebox.showerror("Fehler beim Modell-Download", str(error[0]))
|
||||
sys.exit(1)
|
||||
|
||||
return result[0]
|
||||
|
||||
Reference in New Issue
Block a user