import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Effects Window { id: root width: 850 * (ui ? ui.uiScale : 1.0) height: 620 * (ui ? ui.uiScale : 1.0) visible: false flags: Qt.FramelessWindowHint | Qt.Window color: "transparent" title: "WhisperVoice Settings" Accessible.name: "WhisperVoice Settings" // Explicit sizing for Python to read // Prevent destruction on close onClosing: (close) => { close.accepted = false root.visible = false } // Load Font FontLoader { id: jetBrainsMono source: "fonts/ttf/JetBrainsMono-Bold.ttf" } readonly property string mainFont: jetBrainsMono.name property bool isLoaded: false Component.onCompleted: { isLoaded = true } // --- REUSABLE COMPONENTS --- component StatBox: Rectangle { property string label: "" property string value: "" property string unit: "" property color accent: SettingsStyle.accent Layout.fillWidth: true Layout.preferredHeight: 80 color: "#16161a" radius: 12 border.color: SettingsStyle.borderSubtle border.width: 1 Column { anchors.centerIn: parent spacing: 4 Text { text: label; color: SettingsStyle.textSecondary; font.pixelSize: 11; font.bold: true; anchors.horizontalCenter: parent.horizontalCenter } Row { anchors.horizontalCenter: parent.horizontalCenter spacing: 2 Text { text: value; color: accent; font.pixelSize: 22; font.bold: true; font.family: "JetBrains Mono" } Text { text: unit; color: SettingsStyle.textSecondary; font.pixelSize: 12; anchors.baseline: parent.bottom; anchors.baselineOffset: -4 } } } } // Main Container Rectangle { id: mainContainer anchors.fill: parent radius: 16 color: SettingsStyle.background border.color: SettingsStyle.borderSubtle border.width: 1 opacity: 0 transform: Translate { id: entryTranslate y: 20 } Component.onCompleted: { entryAnim.start() } ParallelAnimation { id: entryAnim NumberAnimation { target: mainContainer; property: "opacity"; to: 1; duration: 400; easing.type: Easing.OutCubic } NumberAnimation { target: entryTranslate; property: "y"; to: 0; duration: 500; easing.type: Easing.OutBack; easing.overshoot: 0.8 } } // --- TITLE BAR --- Item { id: titleBar height: 60 anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right MouseArea { anchors.fill: parent onPressed: root.startSystemMove() } RowLayout { anchors.fill: parent anchors.leftMargin: 24 anchors.rightMargin: 24 Image { source: "microphone.svg" sourceSize.width: 18 sourceSize.height: 18 Layout.alignment: Qt.AlignVCenter opacity: 0.7 // Colorize the icon layer.enabled: true layer.effect: MultiEffect { colorization: 1.0 colorizationColor: SettingsStyle.accent } } Text { text: "SETTINGS" color: SettingsStyle.textSecondary font.family: mainFont font.pixelSize: 13 font.letterSpacing: 2 font.bold: true Layout.alignment: Qt.AlignVCenter } Item { Layout.fillWidth: true } // Improved Close Button Rectangle { width: 32; height: 32 activeFocusOnTab: true Accessible.name: "Close settings" Accessible.role: Accessible.Button Keys.onReturnPressed: root.close() Keys.onSpacePressed: root.close() radius: 8 color: closeMa.containsMouse ? "#20FF8A8A" : "transparent" border.color: closeMa.containsMouse ? "#40FF8A8A" : "transparent" border.width: 1 Text { anchors.centerIn: parent text: "×" color: closeMa.containsMouse ? "#FF8A8A" : SettingsStyle.textSecondary font.family: mainFont font.pixelSize: 20 font.bold: true } MouseArea { id: closeMa anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: root.close() } Behavior on color { ColorAnimation { duration: 150 } } Behavior on border.color { ColorAnimation { duration: 150 } } // Focus ring Rectangle { anchors.fill: parent radius: 8 color: "transparent" border.width: SettingsStyle.focusRingWidth border.color: SettingsStyle.accent visible: parent.activeFocus } } } Rectangle { anchors.bottom: parent.bottom width: parent.width height: 1 color: SettingsStyle.borderSubtle } } // --- CONTENT AREA --- RowLayout { anchors.top: titleBar.bottom anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right spacing: 0 // --- SIDEBAR --- Rectangle { Layout.fillHeight: true Layout.preferredWidth: 220 Layout.minimumWidth: 220 Layout.maximumWidth: 220 color: Qt.rgba(1, 1, 1, 0.02) // Very subtle separation ColumnLayout { anchors.fill: parent anchors.margins: 16 spacing: 8 ListModel { id: navModel ListElement { name: "General"; icon: "settings.svg" } ListElement { name: "Audio"; icon: "microphone.svg" } ListElement { name: "Visuals"; icon: "visibility.svg" } ListElement { name: "AI Engine"; icon: "smart_toy.svg" } ListElement { name: "Debug"; icon: "terminal.svg" } } Repeater { model: navModel delegate: Rectangle { id: navBtnRoot Layout.fillWidth: true height: 38 color: stack.currentIndex === index ? SettingsStyle.surfaceHover : (ma.containsMouse ? Qt.rgba(1,1,1,0.03) : "transparent") radius: 6 activeFocusOnTab: true Accessible.name: name Accessible.role: Accessible.Tab Keys.onReturnPressed: stack.currentIndex = index Keys.onSpacePressed: stack.currentIndex = index Keys.onDownPressed: { if (index < navModel.count - 1) { var nextItem = navBtnRoot.parent.children[index + 2] if (nextItem && nextItem.forceActiveFocus) nextItem.forceActiveFocus() } } Keys.onUpPressed: { if (index > 0) { var prevItem = navBtnRoot.parent.children[index] if (prevItem && prevItem.forceActiveFocus) prevItem.forceActiveFocus() } } Behavior on color { ColorAnimation { duration: 150 } } // Left active stripe Rectangle { width: 3 height: 20 anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter radius: 2 color: SettingsStyle.accent visible: stack.currentIndex === index } RowLayout { anchors.fill: parent anchors.leftMargin: 12 spacing: 12 Image { source: icon sourceSize.width: 16 sourceSize.height: 16 fillMode: Image.PreserveAspectFit Layout.alignment: Qt.AlignVCenter opacity: stack.currentIndex === index ? 1.0 : 0.5 layer.enabled: true layer.effect: MultiEffect { colorization: 1.0 colorizationColor: stack.currentIndex === index ? SettingsStyle.accent : SettingsStyle.textSecondary } } Text { text: name color: stack.currentIndex === index ? SettingsStyle.textPrimary : SettingsStyle.textSecondary font.family: mainFont font.pixelSize: 13 font.weight: stack.currentIndex === index ? Font.Bold : Font.Normal } } MouseArea { id: ma anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: stack.currentIndex = index } // Focus ring Rectangle { anchors.fill: parent radius: 6 color: "transparent" border.width: SettingsStyle.focusRingWidth border.color: SettingsStyle.accent visible: parent.activeFocus } } } Item { Layout.fillHeight: true } } // Vertical Divider Rectangle { anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom width: 1 color: SettingsStyle.borderSubtle } } // --- MAIN CONTENT STACK --- Rectangle { Layout.fillWidth: true Layout.fillHeight: true color: "transparent" clip: true StackLayout { id: stack anchors.fill: parent currentIndex: 0 // --- TAB: GENERAL --- ScrollView { Accessible.role: Accessible.PageTab ScrollBar.vertical.policy: ScrollBar.AsNeeded contentWidth: availableWidth ColumnLayout { width: parent.width spacing: 24 anchors.margins: 32 // Header ColumnLayout { spacing: 4 Layout.topMargin: 32 Layout.leftMargin: 32 Layout.rightMargin: 32 Text { text: "General"; color: SettingsStyle.textPrimary; font.family: mainFont; font.pixelSize: 24; font.bold: true } Text { text: "System behavior and shortcuts"; color: SettingsStyle.textSecondary; font.family: mainFont; font.pixelSize: 14 } } ModernSettingsSection { title: "Application" Layout.margins: 32 Layout.topMargin: 0 content: ColumnLayout { width: parent.width spacing: 0 ModernSettingsItem { label: "Global Hotkey (Transcribe)" description: "Standard: Raw transcription" control: ModernKeySequenceRecorder { implicitWidth: 240 currentSequence: ui.getSetting("hotkey") onSequenceChanged: (seq) => ui.setSetting("hotkey", seq) } } ModernSettingsItem { label: "Global Hotkey (Correct)" description: "Enhanced: Transcribe + AI Correction" control: ModernKeySequenceRecorder { implicitWidth: 240 currentSequence: ui.getSetting("hotkey_correct") onSequenceChanged: (seq) => ui.setSetting("hotkey_correct", seq) } } ModernSettingsItem { label: "Global Hotkey (Translate)" description: "Press to record a new shortcut (e.g. F10)" control: ModernKeySequenceRecorder { implicitWidth: 240 currentSequence: ui.getSetting("hotkey_translate") onSequenceChanged: (seq) => ui.setSetting("hotkey_translate", seq) } } ModernSettingsItem { label: "Run on Startup" description: "Automatically launch when you log in" control: ModernSwitch { checked: ui.getSetting("run_on_startup") onToggled: ui.setSetting("run_on_startup", checked) } } ModernSettingsItem { label: "Input Method" description: "How text is sent to the active window" control: ModernComboBox { width: 160 model: ["Clipboard Paste", "Simulate Typing"] currentIndex: model.indexOf(ui.getSetting("input_method")) onActivated: ui.setSetting("input_method", currentText) } } ModernSettingsItem { label: "Typing Speed" description: "Chars/min" showSeparator: false control: ModernSlider { Layout.preferredWidth: 200 from: 10; to: 20000 stepSize: 100 snapMode: Slider.SnapAlways value: ui.getSetting("typing_speed") onMoved: ui.setSetting("typing_speed", value) } } } } } } // --- TAB: AUDIO --- ScrollView { Accessible.role: Accessible.PageTab ScrollBar.vertical.policy: ScrollBar.AsNeeded contentWidth: availableWidth ColumnLayout { width: parent.width spacing: 24 anchors.margins: 32 ColumnLayout { spacing: 4 Layout.topMargin: 32 Layout.leftMargin: 32 Layout.rightMargin: 32 Text { text: "Audio"; color: SettingsStyle.textPrimary; font.family: mainFont; font.pixelSize: 24; font.bold: true } Text { text: "Input devices and signal processing"; color: SettingsStyle.textSecondary; font.family: mainFont; font.pixelSize: 14 } } ModernSettingsSection { title: "Devices" Layout.margins: 32 Layout.topMargin: 0 content: ColumnLayout { width: parent.width spacing: 0 ModernSettingsItem { label: "Microphone" description: "Select your primary input device" control: ModernComboBox { Layout.preferredWidth: 280 textRole: "name" valueRole: "id" model: ui.getAudioDevices() onActivated: ui.setSetting("input_device", model[currentIndex].id) // Explicitly use model index } } ModernSettingsItem { label: "Save Recordings" description: "Save .wav files to ./recordings folder" showSeparator: false control: ModernSwitch { checked: ui.getSetting("save_recordings") onToggled: ui.setSetting("save_recordings", checked) } } } } ModernSettingsSection { title: "Signal Processing" Layout.margins: 32 Layout.topMargin: 0 content: ColumnLayout { width: parent.width spacing: 0 ModernSettingsItem { label: "VAD Threshold" description: "Silence detection sensitivity (" + (ui.getSetting("silence_threshold") * 100).toFixed(0) + "%)" control: ModernSlider { Layout.preferredWidth: 200 from: 1; to: 100 value: ui.getSetting("silence_threshold") * 100 onMoved: ui.setSetting("silence_threshold", Number((value / 100.0).toFixed(2))) } } ModernSettingsItem { label: "Silence Timeout" description: "Stop recording after " + (ui.getSetting("silence_duration")).toFixed(1) + "s of silence" showSeparator: false control: ModernSlider { Layout.preferredWidth: 200 from: 0.5; to: 5.0 value: ui.getSetting("silence_duration") onMoved: ui.setSetting("silence_duration", Number(value.toFixed(1))) } } } } } } // --- TAB: VISUALS --- ScrollView { Accessible.role: Accessible.PageTab ScrollBar.vertical.policy: ScrollBar.AsNeeded contentWidth: availableWidth ColumnLayout { width: parent.width spacing: 24 anchors.margins: 32 ColumnLayout { spacing: 4 Layout.topMargin: 32 Layout.leftMargin: 32 Layout.rightMargin: 32 Text { text: "Visuals"; color: SettingsStyle.textPrimary; font.family: mainFont; font.pixelSize: 24; font.bold: true } Text { text: "Customize the overlay appearance"; color: SettingsStyle.textSecondary; font.family: mainFont; font.pixelSize: 14 } } ModernSettingsSection { title: "Overlay" Layout.margins: 32 Layout.topMargin: 0 content: ColumnLayout { width: parent.width spacing: 0 ModernSettingsItem { label: "UI Scale" description: "Global interface scaling factor (" + ui.getSetting("ui_scale").toFixed(2) + "x)" control: ModernSlider { Layout.preferredWidth: 200 from: 0.75; to: 1.5 value: ui.getSetting("ui_scale") onMoved: ui.setSetting("ui_scale", Number(value.toFixed(2))) } } ModernSettingsItem { label: "Always on Top" description: "Keep the overlay visible above other windows" control: ModernSwitch { checked: ui.getSetting("always_on_top") onToggled: ui.setSetting("always_on_top", checked) } } ModernSettingsItem { label: "Window Opacity" description: "Transparency level" showSeparator: true control: ModernSlider { Layout.preferredWidth: 200 from: 0.1; to: 1.0 value: ui.getSetting("opacity") onMoved: ui.setSetting("opacity", Number(value.toFixed(2))) } } ModernSettingsItem { label: "Reduce Motion" description: "Disable animations for accessibility" showSeparator: false control: ModernSwitch { checked: ui.getSetting("reduce_motion") onToggled: ui.setSetting("reduce_motion", checked) } } } } ModernSettingsSection { title: "Window Position" Layout.margins: 32 Layout.topMargin: 0 content: ColumnLayout { width: parent.width spacing: 0 ModernSettingsItem { label: "Anchor Position" description: "Where the overlay snaps to on screen" control: ModernComboBox { width: 160 model: ["Bottom Center", "Top Center", "Bottom Right", "Top Right", "Bottom Left", "Top Left"] currentIndex: model.indexOf(ui.getSetting("overlay_position")) onActivated: ui.setSetting("overlay_position", currentText) } } ModernSettingsItem { label: "Horizontal Offset" description: "Fine-tune X position (" + ui.getSetting("overlay_offset_x") + "px)" control: ModernSlider { Layout.preferredWidth: 200 from: -500; to: 500 value: ui.getSetting("overlay_offset_x") onMoved: ui.setSetting("overlay_offset_x", value) } } ModernSettingsItem { label: "Vertical Offset" description: "Fine-tune Y position (" + ui.getSetting("overlay_offset_y") + "px)" showSeparator: false control: ModernSlider { Layout.preferredWidth: 200 from: -500; to: 500 value: ui.getSetting("overlay_offset_y") onMoved: ui.setSetting("overlay_offset_y", value) } } } } } } // --- TAB: AI ENGINE --- ScrollView { Accessible.role: Accessible.PageTab ScrollBar.vertical.policy: ScrollBar.AsNeeded contentWidth: availableWidth ColumnLayout { width: parent.width spacing: 24 anchors.margins: 32 ColumnLayout { spacing: 4 Layout.topMargin: 32 Layout.leftMargin: 32 Layout.rightMargin: 32 Text { text: "AI Engine"; color: SettingsStyle.textPrimary; font.family: mainFont; font.pixelSize: 24; font.bold: true } Text { text: "Model configuration and performance"; color: SettingsStyle.textSecondary; font.family: mainFont; font.pixelSize: 14 } } ModernSettingsSection { title: "Style & Prompting" Layout.margins: 32 Layout.topMargin: 0 content: ColumnLayout { width: parent.width spacing: 0 ModernSettingsItem { label: "Punctuation Style" description: "Hint for how to format text" control: ModernComboBox { id: styleCombo width: 180 model: ["Standard (Proper)", "Casual (Lowercase)", "Custom"] // Logic to determine initial index based on config string Component.onCompleted: { let current = ui.getSetting("initial_prompt") if (current === "Mm-hmm. Okay, let's go. I speak in full sentences.") currentIndex = 0 else if (current === "um, okay... i guess so.") currentIndex = 1 else currentIndex = 2 } onActivated: { if (index === 0) ui.setSetting("initial_prompt", "Mm-hmm. Okay, let's go. I speak in full sentences.") else if (index === 1) ui.setSetting("initial_prompt", "um, okay... i guess so.") // Custom: Don't change string immediately, let user type } } } ModernSettingsItem { label: "Custom Prompt" description: "Advanced: Define your own style hint" visible: styleCombo.currentIndex === 2 control: ModernTextField { Layout.preferredWidth: 280 placeholderText: "e.g. 'Hello, World.'" text: ui.getSetting("initial_prompt") || "" onEditingFinished: ui.setSetting("initial_prompt", text === "" ? null : text) } } } } ModernSettingsSection { title: "Model Config" Layout.margins: 32 Layout.topMargin: 0 content: ColumnLayout { width: parent.width spacing: 0 ListModel { id: modelDetailsModel ListElement { name: "tiny"; info: "39M params • <1GB VRAM • 32x speed. Fastest, best for weak hardware." } ListElement { name: "base"; info: "74M params • ~1GB VRAM • 16x speed. Efficient for simple commands." } ListElement { name: "small"; info: "244M params • ~2GB VRAM • 6x speed. Recommended for most users." } ListElement { name: "medium"; info: "769M params • ~5GB VRAM • Accurate, high fidelity. Mid-range GPU req." } ListElement { name: "large-v3"; info: "1.5B params • ~10GB VRAM • Pro quality. Requires high-end hardware." } ListElement { name: "turbo"; info: "800M params • ~6GB VRAM • Large-v3 quality with 8x speed boost." } } ModernSettingsItem { label: "Model Size" description: "Larger models are smarter but slower" control: ModernComboBox { id: modelSizeCombo width: 140 model: ["tiny", "base", "small", "medium", "large-v3", "turbo"] currentIndex: model.indexOf(ui.getSetting("model_size")) onActivated: ui.setSetting("model_size", currentText) } } // Model Info Card Rectangle { id: modelInfoCard Layout.fillWidth: true Layout.margins: 12 Layout.topMargin: 0 Layout.bottomMargin: 16 height: 54 color: "#0a0a0f" radius: 6 border.color: SettingsStyle.borderSubtle border.width: 1 // Improved reactive check property bool isDownloaded: false Timer { id: checkTimer interval: 1000 running: true repeat: true onTriggered: parent.checkStatus() } function checkStatus() { if (modelSizeCombo && modelSizeCombo.currentText) { isDownloaded = ui.isModelDownloaded(modelSizeCombo.currentText) } } // Refresh when notified by Python Connections { target: ui function onModelStatesChanged() { checkStatus() } } Component.onCompleted: checkStatus() // Also check when selection changes Connections { target: modelSizeCombo function onActivated() { modelInfoCard.checkStatus() } } RowLayout { anchors.fill: parent anchors.leftMargin: 12 anchors.rightMargin: 12 spacing: 12 Image { source: "smart_toy.svg" sourceSize: Qt.size(16, 16) layer.enabled: true layer.effect: MultiEffect { colorization: 1.0 colorizationColor: modelInfoCard.isDownloaded ? SettingsStyle.accent : "#808080" } } ColumnLayout { Layout.fillWidth: true spacing: 2 Text { text: { if (ui.isDownloading) return "Downloading AI Core..." for (var i = 0; i < modelDetailsModel.count; i++) { if (modelDetailsModel.get(i).name === modelSizeCombo.currentText) { return modelDetailsModel.get(i).info } } return "Select a model." } color: "#ffffff" font.family: "JetBrains Mono" font.pixelSize: 11 opacity: 1.0 elide: Text.ElideRight Layout.fillWidth: true } Rectangle { id: downloaderBar visible: ui.isDownloading Layout.fillWidth: true height: 2 color: "#20ffffff" Rectangle { width: downloaderBar.width * 0.5 height: downloaderBar.height color: SettingsStyle.accent SequentialAnimation on x { loops: Animation.Infinite NumberAnimation { from: -width; to: downloaderBar.width; duration: 1500 } } } } } Button { id: downloadBtn text: "Download" visible: !modelInfoCard.isDownloaded && !ui.isDownloading Layout.preferredHeight: 24 Layout.preferredWidth: 80 contentItem: Text { text: "DOWNLOAD" font.pixelSize: 10; font.bold: true; color: "#000000"; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter } background: Rectangle { color: downloadBtn.hovered ? "#ffffff" : SettingsStyle.accent; radius: 4 } onClicked: ui.downloadModel(modelSizeCombo.currentText) } // Status tag Rectangle { id: statusTag visible: modelInfoCard.isDownloaded && !ui.isDownloading height: 18; width: 64; radius: 4; color: "#1000f2ff" border.color: "#3000f2ff"; border.width: 1 Text { anchors.centerIn: statusTag; text: "INSTALLED"; font.pixelSize: 9 font.bold: true; color: SettingsStyle.accent; opacity: 0.9 } } } } ModernSettingsItem { label: "Language" description: "Spoken language to transcribe" control: ModernComboBox { Layout.preferredWidth: 200 model: ui.get_supported_languages() currentIndex: model.indexOf(ui.get_current_language_name()) onActivated: (index) => ui.set_language_by_name(currentText) } } // Task selector removed as per user request (Hotkeys handle this now) ModernSettingsItem { label: "Compute Device" description: "Hardware acceleration (CUDA requires NVidia GPU)" control: ModernComboBox { width: 140 model: ["auto", "cuda", "cpu"] currentIndex: model.indexOf(ui.getSetting("compute_device")) onActivated: ui.setSetting("compute_device", currentText) } } ModernSettingsItem { label: "Precision" description: "Quantization type (int8 is faster, float16 is accurate)" showSeparator: false control: ModernComboBox { width: 140 model: ["int8", "float16", "float32"] currentIndex: model.indexOf(ui.getSetting("compute_type")) onActivated: ui.setSetting("compute_type", currentText) } } ModernSettingsItem { label: "Low VRAM Mode" description: "Unload models immediately after use (Saves VRAM, Adds Delay)" showSeparator: false control: ModernSwitch { checked: ui.getSetting("unload_models_after_use") onToggled: ui.setSetting("unload_models_after_use", checked) } } } } ModernSettingsSection { title: "Correction & Rewriting" Layout.margins: 32 Layout.topMargin: 0 content: ColumnLayout { width: parent.width spacing: 0 ModernSettingsItem { label: "Enable Correction" description: "Post-process text with Llama 3.2 1B (Adds latency)" control: ModernSwitch { checked: ui.getSetting("llm_enabled") onToggled: ui.setSetting("llm_enabled", checked) } } ModernSettingsItem { label: "Correction Mode" description: "Grammar Fix vs. Complete Rewrite" visible: ui.getSetting("llm_enabled") control: ModernComboBox { width: 140 model: ["Grammar", "Standard", "Rewrite"] currentIndex: model.indexOf(ui.getSetting("llm_mode")) onActivated: ui.setSetting("llm_mode", currentText) } } // LLM Model Status Card Rectangle { Layout.fillWidth: true Layout.margins: 12 Layout.topMargin: 0 Layout.bottomMargin: 16 height: 54 color: "#0a0a0f" visible: ui.getSetting("llm_enabled") radius: 6 border.color: SettingsStyle.borderSubtle border.width: 1 property bool isDownloaded: false property bool isDownloading: ui.isDownloading && ui.statusText.indexOf("LLM") !== -1 Timer { interval: 2000 running: visible repeat: true onTriggered: parent.checkStatus() } function checkStatus() { isDownloaded = ui.isLLMModelDownloaded() } Component.onCompleted: checkStatus() Connections { target: ui function onModelStatesChanged() { parent.checkStatus() } function onIsDownloadingChanged() { parent.checkStatus() } } RowLayout { anchors.fill: parent anchors.leftMargin: 12 anchors.rightMargin: 12 spacing: 12 Image { source: "smart_toy.svg" sourceSize: Qt.size(16, 16) layer.enabled: true layer.effect: MultiEffect { colorization: 1.0 colorizationColor: parent.parent.isDownloaded ? SettingsStyle.accent : "#808080" } } ColumnLayout { Layout.fillWidth: true spacing: 2 Text { text: "Llama 3.2 1B (Instruct)" color: "#ffffff" font.family: "JetBrains Mono"; font.bold: true font.pixelSize: 11 } Text { text: parent.parent.isDownloaded ? "Ready." : "Model missing (~1.2GB)" color: SettingsStyle.textSecondary font.family: "JetBrains Mono"; font.pixelSize: 10 } } Button { id: dlBtn text: "Download" visible: !parent.parent.isDownloaded && !parent.parent.isDownloading Layout.preferredHeight: 24 Layout.preferredWidth: 80 contentItem: Text { text: "DOWNLOAD" font.pixelSize: 10; font.bold: true; color: "#000000"; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter } background: Rectangle { color: dlBtn.hovered ? "#ffffff" : SettingsStyle.accent; radius: 4 } onClicked: ui.downloadLLM() } // Progress Bar Rectangle { visible: parent.parent.isDownloading Layout.fillWidth: true height: 4 color: "#30ffffff" Rectangle { width: parent.width * (ui.downloadProgress / 100) height: parent.height color: SettingsStyle.accent } } } } } } ModernSettingsSection { title: "Advanced Decoding" Layout.margins: 32 Layout.topMargin: 0 content: ColumnLayout { width: parent.width spacing: 0 ModernSettingsItem { label: "Beam Size" description: "Search width (Higher = Better Accuracy, Slower)" control: ModernSlider { Layout.preferredWidth: 200 from: 1; to: 10 value: ui.getSetting("beam_size") onMoved: ui.setSetting("beam_size", value) } } ModernSettingsItem { label: "VAD Filter" description: "Skip silent audio segments (Speeds up processing)" control: ModernSwitch { checked: ui.getSetting("vad_filter") onToggled: ui.setSetting("vad_filter", checked) } } ModernSettingsItem { label: "Hallucination Check" description: "Prevent repetitive text loops (No Repeat N-Gram)" control: ModernSwitch { checked: ui.getSetting("no_repeat_ngram_size") > 0 onToggled: ui.setSetting("no_repeat_ngram_size", checked ? 3 : 0) } } ModernSettingsItem { label: "Context History" description: "Use previous text to improve coherence" showSeparator: false control: ModernSwitch { checked: ui.getSetting("condition_on_previous_text") onToggled: ui.setSetting("condition_on_previous_text", checked) } } } } } } // --- TAB: DEBUG --- ScrollView { Accessible.role: Accessible.PageTab ScrollBar.vertical.policy: ScrollBar.AsNeeded contentWidth: availableWidth ColumnLayout { width: parent.width spacing: 16 anchors.margins: 32 ColumnLayout { spacing: 4 Layout.topMargin: 32 Layout.leftMargin: 32 Layout.rightMargin: 32 Text { text: "System Diagnostics"; color: SettingsStyle.textPrimary; font.family: mainFont; font.pixelSize: 24; font.bold: true } Text { text: "Live performance and logs"; color: SettingsStyle.textSecondary; font.family: mainFont; font.pixelSize: 14 } } // --- PERFORMANCE STATS --- RowLayout { Layout.fillWidth: true Layout.leftMargin: 32 Layout.rightMargin: 32 spacing: 16 StatBox { label: "APP CPU"; value: ui.appCpu; unit: "%"; accent: "#00f2ff" } StatBox { label: "APP RAM"; value: ui.appRamMb; unit: "MB"; accent: "#CAA9FF" } StatBox { label: "GPU VRAM"; value: ui.appVramMb; unit: "MB"; accent: "#FF8FD0" } StatBox { label: "GPU LOAD"; value: ui.appVramPercent; unit: "%"; accent: "#FF8A8A" } } Rectangle { Layout.fillWidth: true Layout.preferredHeight: 300 Layout.margins: 32 Layout.topMargin: 0 color: "#0d0d10" radius: 8 border.color: SettingsStyle.borderSubtle border.width: 1 clip: true ScrollView { anchors.fill: parent anchors.margins: 12 ScrollBar.vertical.policy: ScrollBar.AlwaysOn TextArea { id: logArea text: ui.allLogs readOnly: true color: "#cccccc" font.family: "JetBrains Mono" font.pixelSize: 11 wrapMode: TextArea.Wrap background: null selectByMouse: true Connections { target: ui function onLogAppended(line) { logArea.append(line) } } } } } } } } } } } }