upd typer permissions, and relative path

This commit is contained in:
Christian Kauer 2026-03-25 09:04:53 +01:00
parent 6172cc0601
commit 79f5bfabe5
5 changed files with 77 additions and 21 deletions

View File

@ -71,7 +71,28 @@
"Bash(.venv-linux/bin/pyinstaller whisper-dictation.spec --clean)",
"Bash(.venv-linux/bin/pyinstaller whisper-dictation.spec --clean -y)",
"Bash(pactl --version)",
"Bash(pactl list:*)"
"Bash(pactl list:*)",
"Bash(grep -r \"input\\\\|permission\\\\|portal\\\\|access\" /mnt/ventoy/projects/chrka/whisper-dictation/whisper_app/*.py)",
"Read(//home/chk/.config/**)",
"Bash(ls ~/.config/xdg-desktop-portal*)",
"Read(//home/chk/.local/share/flatpak/**)",
"Read(//home/chk/.local/share/**)",
"Bash(find ~/.config -name *permission* -o -name *remote* -o -name *fakeinput* -o -name *access*control*)",
"Bash(qdbus org.freedesktop.impl.portal.desktop.kde /org/freedesktop/impl/portal/desktop/kde)",
"Bash(find ~/.local/share -name *permission*)",
"Bash(kwriteconfig6 --help)",
"Bash(plasma-browser-integration-host --version)",
"Read(//usr/share/xdg-desktop-portal/portals/**)",
"Bash(grep -E \"\\(Makefile|setup|build|spec|\\\\.sh$|\\\\.py$\\)\")",
"Bash(systemctl --user status ydotool)",
"Bash(ydotool key:*)",
"Bash(echo \"exit: $?\")",
"Bash(wl-copy)",
"Bash(wl-paste --no-newline)",
"Bash(ydotool type:*)",
"Bash(wl-copy -- \"XDOTOOL_TEST\")",
"Bash(xdotool key:*)",
"Bash(find /mnt/ventoy/projects/chrka/whisper-dictation/shared_data/ -name *.bin -o -name *.pt -o -name model*)"
]
}
}

View File

@ -2,6 +2,6 @@
"hotkey": "ctrl+shift+space",
"language": "de",
"sample_rate": 16000,
"vocab_path": "/run/media/chk/Ventoy/projects/chrka/whisper-dictation/shared_data/vocabulary.json",
"model_dir": "/run/media/chk/Ventoy/projects/chrka/whisper-dictation/shared_data/"
"vocab_path": "shared_data/vocabulary.json",
"model_dir": "shared_data/"
}

View File

@ -52,14 +52,19 @@ config: dict = {}
vocab: dict = {"words": [], "replacements": []}
def _resolve_path(value: str, fallback_name: str = "") -> str:
"""Resolve a config path: absolute stays absolute, relative is joined with DATA_DIR."""
if value:
return value if os.path.isabs(value) else os.path.join(DATA_DIR, value)
if fallback_name:
return os.path.join(DATA_DIR, fallback_name)
return ""
def _resolve_vocab_file() -> None:
"""Set VOCAB_FILE from config['vocab_path'], falling back to DATA_DIR."""
global VOCAB_FILE
vp = config.get("vocab_path", "")
if vp:
VOCAB_FILE = vp if os.path.isabs(vp) else os.path.join(DATA_DIR, vp)
else:
VOCAB_FILE = os.path.join(DATA_DIR, "vocabulary.json")
VOCAB_FILE = _resolve_path(config.get("vocab_path", ""), "vocabulary.json")
def load_config() -> None:

View File

@ -7,17 +7,20 @@ from whisper_app import app, config, grammar, media_duck, typer
def load_model() -> None:
app.log(f"Loading {config.config['model']} on {config.config['device']}...")
model_dir = config.config.get("model_dir") or None
app.model = WhisperModel(
config.config["model"],
device=config.config["device"],
compute_type=config.config["compute_type"],
download_root=model_dir,
)
app.log("Model ready.")
if config.config.get("grammar_check"):
grammar.init(config.config.get("language") or "de", log=app.log)
try:
app.log(f"Loading {config.config['model']} on {config.config['device']}...")
model_dir = config._resolve_path(config.config.get("model_dir", "")) or None
app.model = WhisperModel(
config.config["model"],
device=config.config["device"],
compute_type=config.config["compute_type"],
download_root=model_dir,
)
app.log("Model ready.")
if config.config.get("grammar_check"):
grammar.init(config.config.get("language") or "de", log=app.log)
except Exception as e:
app.log(f"Model load FAILED: {e}")
def stop_and_transcribe() -> None:

View File

@ -3,7 +3,7 @@ import shutil
import subprocess
import time
from whisper_app import config
from whisper_app import app, config
def _pynput_type(text):
@ -36,6 +36,31 @@ def _wl_copy_bytes(data):
pass
def _paste_via_ydotool():
"""Simulate Ctrl+V using ydotool (kernel-level, works on all compositors)."""
subprocess.run(["ydotool", "key", "29:1", "47:1", "47:0", "29:0"], check=False)
def _paste_via_wtype():
"""Simulate Ctrl+V using wtype (native Wayland, wlroots only)."""
subprocess.run(["wtype", "-M", "ctrl", "-P", "v", "-p", "v", "-m", "ctrl"],
check=False)
def _paste_via_xdotool():
"""Simulate Ctrl+V using xdotool (XWayland fallback)."""
subprocess.run(["xdotool", "key", "ctrl+v"], check=False)
def _pick_paste_cmd():
"""Select best available paste tool for the current Wayland session."""
if shutil.which("ydotool"):
return _paste_via_ydotool
if shutil.which("wtype"):
return _paste_via_wtype
return _paste_via_xdotool
def type_text(text):
"""Type text into the active window, cross-platform."""
if os.name == "nt":
@ -47,7 +72,9 @@ def type_text(text):
old_clipboard = _wl_paste()
subprocess.run(["wl-copy", "--", text], check=False)
time.sleep(0.05)
subprocess.run(["xdotool", "key", "ctrl+v"], check=False)
paste_fn = _pick_paste_cmd()
app.log(f"typer: using {paste_fn.__name__}, session={session}")
paste_fn()
time.sleep(delay)
if old_clipboard is not None:
_wl_copy_bytes(old_clipboard)