What dictation needs to work, as inspectable data.
Every failure we hit getting dictation running looked identical from the
outside — "nothing happens" — and each had a different cause: a missing
permission, a missing model, an agent that was not loaded. The checks are
therefore individually reportable: the setup wizard, the doctor command and
any future UI all read the same list, and each item says what is wrong AND
what to do about it.
Pure enough to test: each check returns a verdict, and only the probes it
calls touch the system.
Classes
Check
dataclass
Check(
name: str,
ok: bool,
detail: str,
fix: str = "",
blocking: bool = True,
)
One requirement, its state, and the single next action.
Functions:
check_permissions
check_permissions() -> List[Check]
The three TCC grants, reported separately.
Separately, because they fail separately and each has its own pane —
lumping them into one "permissions OK" line is what made the microphone
failure so hard to see.
Source code in src/diapason/desktop/setup_check.py
| def check_permissions() -> List[Check]:
"""The three TCC grants, reported separately.
Separately, because they fail separately and each has its own pane —
lumping them into one "permissions OK" line is what made the microphone
failure so hard to see.
"""
from diapason.desktop import permissions
probes: List[tuple[str, Callable[[], bool], str, str]] = [
(
"Input Monitoring",
permissions.input_monitoring_ok,
"hear the dictation key",
"System Settings › Privacy & Security › Input Monitoring",
),
(
"Microphone",
permissions.microphone_ok,
"record your voice",
"System Settings › Privacy & Security › Microphone",
),
(
"Accessibility",
permissions.accessibility_ok,
"paste into the app in front",
"System Settings › Privacy & Security › Accessibility",
),
]
out: List[Check] = []
for name, probe, purpose, pane in probes:
ok = probe()
out.append(
Check(
name=name,
ok=ok,
detail=f"needed to {purpose}",
fix="" if ok else f"Enable this app in {pane}, then restart it.",
)
)
return out
|
check_model
check_model(config=None) -> Check
Is a speech backend actually resolvable right now?
Source code in src/diapason/desktop/setup_check.py
| def check_model(config=None) -> Check:
"""Is a speech backend actually resolvable right now?"""
try:
from diapason.core.config import load_config
from diapason.speech._discovery import get_speech_backend
cfg = config or load_config()
backend = get_speech_backend(cfg)
model = str(getattr(cfg.speech, "model", "") or "?")
if backend is None:
return Check(
name="Speech model",
ok=False,
detail="no backend could be resolved",
fix=(
"Run `diapason model pull small`, or set [privacy] "
"local_only = false to allow a cloud backend."
),
)
return Check(
name="Speech model",
ok=True,
detail=f"{type(backend).__name__} ({model})",
)
except Exception as exc: # noqa: BLE001 - report, never crash setup
return Check(
name="Speech model",
ok=False,
detail=f"could not check: {exc}",
fix="Run `diapason doctor` for details.",
)
|
check_service
Is the background agent installed and loaded?
Source code in src/diapason/desktop/setup_check.py
| def check_service() -> Check:
"""Is the background agent installed and loaded?"""
try:
from diapason.desktop import launch_agent
loaded = launch_agent.is_loaded()
return Check(
name="Background service",
ok=loaded,
detail="running at login" if loaded else "not installed",
fix="" if loaded else "Run `diapason dictate-service install`.",
blocking=False, # dictation works in the foreground without it
)
except Exception as exc: # noqa: BLE001
return Check(
name="Background service",
ok=False,
detail=f"could not check: {exc}",
blocking=False,
)
|
check_hotkey
check_hotkey(config=None) -> Check
Is the configured hotkey one the tap can actually bind?
Source code in src/diapason/desktop/setup_check.py
| def check_hotkey(config=None) -> Check:
"""Is the configured hotkey one the tap can actually bind?"""
from diapason.desktop.keycodes import SUPPORTED_HOTKEYS, normalize_hotkey
try:
from diapason.core.config import load_config
cfg = config or load_config()
raw = str(getattr(cfg.dictation, "hotkey", "") or "control")
except Exception: # noqa: BLE001
raw = "control"
key = normalize_hotkey(raw)
coerced = key != raw.strip().lower()
return Check(
name="Hotkey",
ok=not coerced,
detail=f"hold {key.capitalize()}"
+ (f" (config says {raw!r}, which is not a bare modifier)" if coerced else ""),
fix=(
f"Run `diapason config set dictation.hotkey {key}` "
f"(one of: {', '.join(SUPPORTED_HOTKEYS)})."
if coerced
else ""
),
blocking=False, # it still works, it just says something misleading
)
|
run_all
run_all(config=None) -> List[Check]
Every check, in the order a first-time user should fix them.
Source code in src/diapason/desktop/setup_check.py
| def run_all(config=None) -> List[Check]:
"""Every check, in the order a first-time user should fix them."""
checks: List[Check] = []
checks.extend(check_permissions())
checks.append(check_model(config))
checks.append(check_hotkey(config))
checks.append(check_service())
return checks
|
is_ready
is_ready(checks: List[Check]) -> bool
Ready means: dictation would work right now if you held the key.
Source code in src/diapason/desktop/setup_check.py
| def is_ready(checks: List[Check]) -> bool:
"""Ready means: dictation would work right now if you held the key."""
return not blocking_failures(checks)
|