Files
whisper-local/whisper_local/tray/_download_progress.py
T
info bead04ff09 feat(tray): Modell-Lade-Wartebalken plattformübergreifend anzeigen
Entfernt den Windows-only-Guard in App.__init__, damit der Dialog mit
indeterminatem ttk.Progressbar auch unter Linux erscheint, wenn das Laden
länger als 500 ms dauert. Ersetzt das literale \u2026 im Label durch das
Zeichen … und passt Spec/Plan an den tatsächlichen Umsetzungsstand an
(Timeout-basierter Wartebalken statt tqdm-Monkey-Patch, da die Xet-Engine
Python-tqdm bypasst).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 20:58:21 +02:00

120 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Download-Fortschrittsdialog für den ersten Whisper-Modell-Download (Windows)."""
from __future__ import annotations
import queue
import sys
import threading
from typing import Any
import tqdm as tqdm_module
class TkProgressTqdm(tqdm_module.tqdm):
"""tqdm-Ersatz, der Fortschritts-Updates thread-safe in eine Queue schreibt."""
_queue: queue.Queue | None = None
def __init__(self, *args: Any, **kwargs: Any) -> None:
self._desc = kwargs.get("desc", "")
self._accumulated_n = 0
super().__init__(*args, **kwargs)
def update(self, n: int | float | None = 1) -> bool | None:
if n is None:
n = 0
self._accumulated_n += n
result = super().update(n)
if self._queue is not None:
self._queue.put({
"file": self._desc,
"n": self._accumulated_n,
"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 längerem Laden einen Wartebalken.
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
from tkinter import messagebox, ttk
from faster_whisper import WhisperModel
from whisper_local.tray._theme import apply_system_theme
result: list[Any] = [None]
error: list[BaseException | None] = [None]
done_event = threading.Event()
def worker() -> None:
try:
result[0] = WhisperModel(
model_name,
compute_type=compute_type,
download_root=download_root,
)
except Exception as exc:
error[0] = exc
finally:
done_event.set()
thread = threading.Thread(target=worker, daemon=True)
thread.start()
# 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.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)
ttk.Label(frame, text="Bitte warten…", foreground="gray").pack(
anchor=tk.W, pady=(4, 8)
)
pb = ttk.Progressbar(frame, length=320, mode="indeterminate")
pb.pack(fill=tk.X)
pb.start(10)
def poll() -> None:
if done_event.is_set():
root.quit()
return
root.after(100, poll)
root.after(100, poll)
root.mainloop()
if error[0] is not None:
root.withdraw()
messagebox.showerror("Fehler beim Modell-Laden", str(error[0]))
root.destroy()
sys.exit(1)
root.destroy()
return result[0]