120 lines
3.8 KiB
Python
120 lines
3.8 KiB
Python
# whisper_app/log_window.py
|
|
import os
|
|
import queue
|
|
import tkinter as tk
|
|
from whisper_app import app
|
|
|
|
BG = "#18181f"
|
|
BG2 = "#22222c"
|
|
BG3 = "#2c2c38"
|
|
BORDER = "#38384a"
|
|
FG = "#e8e8f0"
|
|
FG2 = "#7878a0"
|
|
AMBER = "#f5a623"
|
|
GREEN = "#4ade80"
|
|
RED = "#f87171"
|
|
YELLOW = "#facc15"
|
|
_sans = "Segoe UI" if os.name == "nt" else "sans-serif"
|
|
_mono = "Consolas" if os.name == "nt" else "monospace"
|
|
|
|
_window: tk.Toplevel | None = None
|
|
_text: tk.Text | None = None
|
|
_log_q: queue.Queue | None = None
|
|
_MAX_LINES = 200
|
|
|
|
def create(root: tk.Tk, log_queue: queue.Queue,
|
|
on_settings, on_vocab) -> tk.Toplevel:
|
|
global _window, _text, _log_q
|
|
_log_q = log_queue
|
|
|
|
win = tk.Toplevel(root)
|
|
win.title("Whisper Dictation")
|
|
win.configure(bg=BG)
|
|
win.resizable(True, True)
|
|
win.minsize(400, 300)
|
|
win.protocol("WM_DELETE_WINDOW", win.withdraw)
|
|
|
|
# ── Header ──
|
|
hdr = tk.Frame(win, bg=BG2)
|
|
hdr.pack(fill="x")
|
|
tk.Frame(hdr, bg=AMBER, height=2).pack(fill="x")
|
|
hdr_inner = tk.Frame(hdr, bg=BG2, padx=12, pady=6)
|
|
hdr_inner.pack(fill="x")
|
|
tk.Label(hdr_inner, text="WHISPER DICTATION",
|
|
font=(_sans, 11, "bold"), bg=BG2, fg=FG).pack(side="left")
|
|
tk.Button(hdr_inner, text="✕", command=win.withdraw,
|
|
bg=BG2, fg=FG2, relief="flat", bd=0,
|
|
font=(_sans, 11), cursor="hand2").pack(side="right")
|
|
|
|
# ── Log text ──
|
|
txt = tk.Text(win, bg=BG, fg=FG, font=(_mono, 10),
|
|
relief="flat", bd=0, padx=10, pady=6,
|
|
state="disabled", wrap="none",
|
|
width=48, height=10,
|
|
highlightthickness=0)
|
|
txt.pack(fill="both", expand=True)
|
|
txt.tag_config("green", foreground=GREEN)
|
|
txt.tag_config("red", foreground=RED)
|
|
txt.tag_config("yellow", foreground=YELLOW)
|
|
txt.tag_config("grey", foreground=FG2)
|
|
_text = txt
|
|
|
|
# ── Button bar ──
|
|
bar = tk.Frame(win, bg=BG2, pady=6, padx=10)
|
|
bar.pack(fill="x")
|
|
for label, cmd in [("⚙ Einstellungen", on_settings), ("📚 Vokabular", on_vocab)]:
|
|
b = tk.Button(bar, text=label, command=cmd,
|
|
bg=BG3, fg=FG, relief="flat", bd=0,
|
|
font=(_sans, 10), padx=10, pady=4, cursor="hand2")
|
|
b.pack(side="left", padx=(0, 4))
|
|
tk.Button(bar, text="🗑", command=_clear_log,
|
|
bg=BG3, fg=FG2, relief="flat", bd=0,
|
|
font=(_sans, 10), padx=8, pady=4, cursor="hand2").pack(side="right")
|
|
|
|
_window = win
|
|
win.withdraw()
|
|
root.after(100, _poll)
|
|
return win
|
|
|
|
def show() -> None:
|
|
if _window:
|
|
_window.deiconify()
|
|
_window.lift()
|
|
|
|
def _clear_log() -> None:
|
|
if _text:
|
|
_text.config(state="normal")
|
|
_text.delete("1.0", "end")
|
|
_text.config(state="disabled")
|
|
|
|
def _tag_for(msg: str) -> str:
|
|
low = msg.lower()
|
|
if any(x in low for x in ("recording", "aufnahme")):
|
|
return "red"
|
|
if any(x in low for x in ("transcrib", "loading", "laden")):
|
|
return "yellow"
|
|
if any(x in low for x in ("result:", "ready", "bereit")):
|
|
return "green"
|
|
return "grey"
|
|
|
|
def _poll() -> None:
|
|
if _log_q and _text:
|
|
try:
|
|
while True:
|
|
msg = _log_q.get_nowait()
|
|
_append(msg)
|
|
except queue.Empty:
|
|
pass
|
|
if app.overlay_tk:
|
|
app.overlay_tk.after(100, _poll)
|
|
|
|
def _append(msg: str) -> None:
|
|
_text.config(state="normal")
|
|
# Trim to MAX_LINES
|
|
lines = int(_text.index("end-1c").split(".")[0])
|
|
if lines >= _MAX_LINES:
|
|
_text.delete("1.0", "2.0")
|
|
_text.insert("end", msg + "\n", _tag_for(msg))
|
|
_text.see("end")
|
|
_text.config(state="disabled")
|