Simplify daemon tray
This commit is contained in:
parent
4e8edc3e40
commit
3f15a0e686
1 changed files with 28 additions and 45 deletions
73
src/leld.py
73
src/leld.py
|
|
@ -31,6 +31,12 @@ class State:
|
||||||
OUTPUTTING = "outputting"
|
OUTPUTTING = "outputting"
|
||||||
|
|
||||||
|
|
||||||
|
ASSETS_DIR = Path(__file__).parent / "assets"
|
||||||
|
RECORD_TIMEOUT_SEC = 300
|
||||||
|
STT_LANGUAGE = "en"
|
||||||
|
TRAY_UPDATE_MS = 250
|
||||||
|
|
||||||
|
|
||||||
def _compute_type(device: str) -> str:
|
def _compute_type(device: str) -> str:
|
||||||
dev = (device or "cpu").lower()
|
dev = (device or "cpu").lower()
|
||||||
if dev == "cuda":
|
if dev == "cuda":
|
||||||
|
|
@ -51,7 +57,14 @@ class Daemon:
|
||||||
device=cfg.stt.get("device", "cpu"),
|
device=cfg.stt.get("device", "cpu"),
|
||||||
compute_type=_compute_type(cfg.stt.get("device", "cpu")),
|
compute_type=_compute_type(cfg.stt.get("device", "cpu")),
|
||||||
)
|
)
|
||||||
self.tray = _Tray(self.get_state, self._quit)
|
self.icon = Gtk.StatusIcon()
|
||||||
|
self.icon.set_visible(True)
|
||||||
|
self.icon.connect("popup-menu", self._on_tray_menu)
|
||||||
|
self.menu = Gtk.Menu()
|
||||||
|
quit_item = Gtk.MenuItem(label="Quit")
|
||||||
|
quit_item.connect("activate", lambda *_: self._quit())
|
||||||
|
self.menu.append(quit_item)
|
||||||
|
self.menu.show_all()
|
||||||
|
|
||||||
def set_state(self, state: str):
|
def set_state(self, state: str):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
|
|
@ -67,6 +80,9 @@ class Daemon:
|
||||||
def _quit(self):
|
def _quit(self):
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
|
||||||
|
def _on_tray_menu(self, _icon, _button, _time):
|
||||||
|
self.menu.popup(None, None, None, None, 0, _time)
|
||||||
|
|
||||||
def toggle(self):
|
def toggle(self):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if self.state == State.IDLE:
|
if self.state == State.IDLE:
|
||||||
|
|
@ -90,7 +106,7 @@ class Daemon:
|
||||||
logging.info("recording started (%s)", record.wav_path)
|
logging.info("recording started (%s)", record.wav_path)
|
||||||
if self.timer:
|
if self.timer:
|
||||||
self.timer.cancel()
|
self.timer.cancel()
|
||||||
self.timer = threading.Timer(300, self._timeout_stop)
|
self.timer = threading.Timer(RECORD_TIMEOUT_SEC, self._timeout_stop)
|
||||||
self.timer.daemon = True
|
self.timer.daemon = True
|
||||||
self.timer.start()
|
self.timer.start()
|
||||||
|
|
||||||
|
|
@ -184,11 +200,7 @@ class Daemon:
|
||||||
threading.Thread(target=self._stop_and_process, daemon=True).start()
|
threading.Thread(target=self._stop_and_process, daemon=True).start()
|
||||||
|
|
||||||
def _transcribe(self, wav_path: str) -> str:
|
def _transcribe(self, wav_path: str) -> str:
|
||||||
segments, _info = self.model.transcribe(
|
segments, _info = self.model.transcribe(wav_path, language=STT_LANGUAGE, vad_filter=True)
|
||||||
wav_path,
|
|
||||||
language=None,
|
|
||||||
vad_filter=True,
|
|
||||||
)
|
|
||||||
parts = []
|
parts = []
|
||||||
for seg in segments:
|
for seg in segments:
|
||||||
text = (seg.text or "").strip()
|
text = (seg.text or "").strip()
|
||||||
|
|
@ -196,35 +208,14 @@ class Daemon:
|
||||||
parts.append(text)
|
parts.append(text)
|
||||||
return " ".join(parts).strip()
|
return " ".join(parts).strip()
|
||||||
|
|
||||||
def run_tray(self):
|
|
||||||
self.tray.run()
|
|
||||||
|
|
||||||
|
|
||||||
class _Tray:
|
|
||||||
def __init__(self, state_getter, on_quit):
|
|
||||||
self.state_getter = state_getter
|
|
||||||
self.on_quit = on_quit
|
|
||||||
self.base = Path(__file__).parent / "assets"
|
|
||||||
self.icon = Gtk.StatusIcon()
|
|
||||||
self.icon.set_visible(True)
|
|
||||||
self.icon.connect("popup-menu", self._on_menu)
|
|
||||||
self.menu = Gtk.Menu()
|
|
||||||
quit_item = Gtk.MenuItem(label="Quit")
|
|
||||||
quit_item.connect("activate", lambda *_: self.on_quit())
|
|
||||||
self.menu.append(quit_item)
|
|
||||||
self.menu.show_all()
|
|
||||||
|
|
||||||
def _on_menu(self, _icon, _button, _time):
|
|
||||||
self.menu.popup(None, None, None, None, 0, _time)
|
|
||||||
|
|
||||||
def _icon_path(self, state: str) -> str:
|
def _icon_path(self, state: str) -> str:
|
||||||
if state == State.RECORDING:
|
if state == State.RECORDING:
|
||||||
return str(self.base / "recording.png")
|
return str(ASSETS_DIR / "recording.png")
|
||||||
if state == State.STT:
|
if state == State.STT:
|
||||||
return str(self.base / "transcribing.png")
|
return str(ASSETS_DIR / "transcribing.png")
|
||||||
if state == State.PROCESSING:
|
if state == State.PROCESSING:
|
||||||
return str(self.base / "processing.png")
|
return str(ASSETS_DIR / "processing.png")
|
||||||
return str(self.base / "idle.png")
|
return str(ASSETS_DIR / "idle.png")
|
||||||
|
|
||||||
def _title(self, state: str) -> str:
|
def _title(self, state: str) -> str:
|
||||||
if state == State.RECORDING:
|
if state == State.RECORDING:
|
||||||
|
|
@ -235,15 +226,15 @@ class _Tray:
|
||||||
return "AI Processing"
|
return "AI Processing"
|
||||||
return "Idle"
|
return "Idle"
|
||||||
|
|
||||||
def update(self):
|
def _update_tray(self):
|
||||||
state = self.state_getter()
|
state = self.get_state()
|
||||||
self.icon.set_from_file(self._icon_path(state))
|
self.icon.set_from_file(self._icon_path(state))
|
||||||
self.icon.set_tooltip_text(self._title(state))
|
self.icon.set_tooltip_text(self._title(state))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def run(self):
|
def run_tray(self):
|
||||||
self.update()
|
self._update_tray()
|
||||||
GLib.timeout_add(250, self.update)
|
GLib.timeout_add(TRAY_UPDATE_MS, self._update_tray)
|
||||||
Gtk.main()
|
Gtk.main()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -265,7 +256,6 @@ def _lock_single_instance():
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--config", default="", help="path to config.json")
|
parser.add_argument("--config", default="", help="path to config.json")
|
||||||
parser.add_argument("--no-tray", action="store_true", help="disable tray icon")
|
|
||||||
parser.add_argument("--dry-run", action="store_true", help="log hotkey only")
|
parser.add_argument("--dry-run", action="store_true", help="log hotkey only")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
@ -289,13 +279,6 @@ def main():
|
||||||
signal.signal(signal.SIGINT, handle_signal)
|
signal.signal(signal.SIGINT, handle_signal)
|
||||||
signal.signal(signal.SIGTERM, handle_signal)
|
signal.signal(signal.SIGTERM, handle_signal)
|
||||||
|
|
||||||
if args.no_tray:
|
|
||||||
listen(
|
|
||||||
cfg.daemon.get("hotkey", ""),
|
|
||||||
lambda: logging.info("hotkey pressed (dry-run)") if args.dry_run else daemon.toggle(),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
threading.Thread(
|
threading.Thread(
|
||||||
target=lambda: listen(
|
target=lambda: listen(
|
||||||
cfg.daemon.get("hotkey", ""),
|
cfg.daemon.get("hotkey", ""),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue