import QtQuick import qs.config import qs.services // Dictation is an input method, so it lives under Input beside the keyboard — // but it listens through whichever device the Sound page selects, so the // microphone card below hands off there rather than duplicating the picker. SettingsPage { title: "Dictation" lede: Dictation.ready ? "Hold Super+D, speak, and release. The words are typed where the cursor is." : "Speech to text, on the GPU, once the one-time setup below has run." SettingsCard { title: "Dictation" subtitle: Dictation.ready ? "Hold Super+D, speak, and release. The words are typed where the cursor is." : "The one-time setup fetches a speech server and a ~490 MB model — neither ships with Panama, because both are large and want the network." // Status of the two pieces, read from the machine rather than guessed. TextRow { label: "Speech server" detail: Dictation.serverReady ? "Running" : (Dictation.imageBuilt ? "Ready — starts on the first dictation" : "Not set up yet") value: Dictation.imageBuilt ? "Ready" : "Missing" } TextRow { label: "Speech model" detail: Dictation.modelInstalled ? "Kept across rebuilds of the server" : "About 490 MB, downloaded once" value: Dictation.modelInstalled ? Math.round(Dictation.modelBytes / 1048576) + " MB" : "Missing" } // ONE action that actually works: panama-dictate setup pulls the // server image and downloads the model together. This card used to // offer a Download button wired to a command the helper does not have, // and told you to build a "panama app whisper-vulkan" that does not // exist -- so nothing here did anything. It does now. ActionRow { visible: !Dictation.ready || Dictation.downloading label: "Set up dictation" detail: { if (!Dictation.downloading) return "Fetches the speech server and the model. Runs once, keeps both."; if (Dictation.phase === "pulling") return "Fetching the speech server…"; if (Dictation.downloadTotalBytes > 0) return "Downloading model — " + Math.round(Dictation.downloadFraction * 100) + "% of " + Math.round(Dictation.downloadTotalBytes / 1048576) + " MB"; return "Setting up…"; } action: Dictation.downloading ? "Working…" : "Set up" enabled: !Dictation.downloading onTriggered: Dictation.setup() divider: !Dictation.typingAvailable || Dictation.lastError !== "" } TextRow { visible: !Dictation.typingAvailable label: "Typing" detail: "wtype is missing, so dictated text would go to the clipboard instead of being typed." value: "Missing" divider: Dictation.lastError !== "" } TextRow { visible: Dictation.lastError !== "" label: "Problem" detail: Dictation.lastError value: "" divider: false } } SettingsCard { title: "Microphone" subtitle: AudioDevices.current(false)?.description ?? "No input device" ActionRow { label: "Input device" detail: "Dictation listens through the input device selected in Sound" divider: false action: "Open Sound" onTriggered: ShellState.openSettings("sound") } } }