2026-02-21 18:35:20 -06:00

124 lines
4.3 KiB
Python

import asyncio
from nicegui import ui, app
from journal.core.config import (
SPEECH_RECOGNITION_ENGINE,
WHISPER_MODEL_SIZE,
SERVER_CONTROL_FILE,
)
from typing import cast
def settings_dialog():
"""Creates a dialog for application settings."""
async def request_server_action(action: str) -> None:
try:
SERVER_CONTROL_FILE.parent.mkdir(parents=True, exist_ok=True)
SERVER_CONTROL_FILE.write_text(action, encoding="utf-8")
except Exception as error:
ui.notify(f"Failed to queue server action: {error}", type="negative")
return
if action == "restart":
ui.notify("Server restart requested...", type="warning")
else:
ui.notify("Server shutdown requested...", type="warning")
# Give the notification a moment to flush before shutdown.
await asyncio.sleep(0.2)
app.shutdown()
async def restart_server() -> None:
await request_server_action("restart")
async def shutdown_server() -> None:
await request_server_action("shutdown")
with ui.dialog() as dialog, ui.card().classes("w-80"):
_ = ui.label("Settings").classes("text-xl font-bold")
_ = ui.label("Speech to Text").classes("text-lg font-medium mt-4")
if "speech_engine" in app.storage.user:
initial_engine_value = cast(str, app.storage.user["speech_engine"])
else:
initial_engine_value = SPEECH_RECOGNITION_ENGINE
_ = (
ui.select(
["whisper", "google", "sphinx"],
label="Recognition Engine",
value=initial_engine_value,
on_change=lambda e: ui.notify(
f"Engine set to {cast(str, e.value)}. Takes effect on next recording."
),
)
.bind_value(app.storage.user, "speech_engine")
.classes("w-full")
)
_ = ui.markdown(
"`whisper` is local & private (recommended).\n`google` is online.\n`sphinx` is offline & fast."
).classes("text-xs text-gray-500")
# Add whisper model select
_ = ui.separator().classes("my-2")
_ = ui.label("Whisper Model Size").classes("font-medium")
if "whisper_model" in app.storage.user:
initial_whisper_model = cast(str, app.storage.user["whisper_model"])
else:
initial_whisper_model = WHISPER_MODEL_SIZE
_ = (
ui.select(
["tiny", "base", "small", "medium", "large"],
label="Accuracy vs. Speed",
value=initial_whisper_model,
on_change=lambda e: ui.notify(
f"Whisper model set to {cast(str, e.value)}. Takes effect on next recording."
),
)
.bind_value(app.storage.user, "whisper_model")
.classes("w-full")
)
_ = ui.markdown(
"`base` is a good balance. Larger models are more accurate but slower."
).classes("text-xs text-gray-500")
_ = ui.separator().classes("my-2")
_ = ui.label("Server Controls").classes("font-medium")
if cast(bool, app.storage.user.get("authenticated", False)):
_ = ui.markdown(
"Use these when running via `run_desktop.py`.\n"
"`Restart` reconnects quickly, `Shutdown` stops the server wrapper."
).classes("text-xs text-gray-500")
with ui.row().classes("w-full gap-2 mt-1"):
_ = (
ui.button(
"Restart Server",
on_click=restart_server,
)
.props("color=warning")
.classes("flex-1")
)
_ = (
ui.button(
"Shutdown Server",
on_click=shutdown_server,
)
.props("color=negative")
.classes("flex-1")
)
else:
_ = ui.label("Log in to enable restart/shutdown controls.").classes(
"text-xs text-gray-500"
)
_ = (
ui.button("Close", on_click=dialog.close)
.props("flat")
.classes("mt-4 self-end")
)
return dialog