import QtCore import QtQuick import QtQuick.Controls import QtQuick.Controls.Basic import QtQuick.Layouts import llm Window { id: window width: 1280 height: 720 visible: true title: qsTr("GPT4All v") + Qt.application.version color: "#d1d5db" Item { Accessible.role: Accessible.Window Accessible.name: title } Rectangle { id: header anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top height: 100 color: "#202123" Item { anchors.centerIn: parent height: childrenRect.height visible: LLM.isModelLoaded Label { id: modelLabel color: "#d1d5db" padding: 20 font.pixelSize: 24 text: "" background: Rectangle { color: "#202123" } horizontalAlignment: TextInput.AlignRight } ComboBox { id: comboBox width: 400 anchors.top: modelLabel.top anchors.bottom: modelLabel.bottom anchors.horizontalCenter: parent.horizontalCenter font.pixelSize: 24 spacing: 0 model: LLM.modelList Accessible.role: Accessible.ComboBox Accessible.name: qsTr("ComboBox for displaying/picking the current model") Accessible.description: qsTr("Use this for picking the current model to use; the first item is the current model") contentItem: Text { anchors.horizontalCenter: parent.horizontalCenter leftPadding: 10 rightPadding: 10 text: comboBox.displayText font: comboBox.font color: "#d1d5db" verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter elide: Text.ElideRight } background: Rectangle { color: "#242528" } onActivated: { LLM.stopGenerating() LLM.modelName = comboBox.currentText chatModel.clear() } } } BusyIndicator { anchors.centerIn: parent visible: !LLM.isModelLoaded running: !LLM.isModelLoaded Accessible.role: Accessible.Animation Accessible.name: qsTr("Busy indicator") Accessible.description: qsTr("Displayed when the model is loading") } } Dialog { id: settingsDialog modal: true anchors.centerIn: parent title: qsTr("Settings") height: 600 width: 600 opacity: 0.9 background: Rectangle { anchors.fill: parent anchors.margins: -20 color: "#202123" border.width: 1 border.color: "white" radius: 10 } property real defaultTemperature: 0.28 property real defaultTopP: 0.95 property int defaultTopK: 40 property int defaultMaxLength: 4096 property int defaultPromptBatchSize: 9 property string defaultPromptTemplate: "The prompt below is a question to answer, a task to complete, or a conversation to respond to; decide which and write an appropriate response. ### Prompt: %1 ### Response:\n" Settings { id: settings property string promptTemplate: settingsDialog.defaultPromptTemplate property real temperature: settingsDialog.defaultTemperature property real topP: settingsDialog.defaultTopP property int topK: settingsDialog.defaultTopK property int maxLength: settingsDialog.defaultMaxLength property int promptBatchSize: settingsDialog.defaultPromptBatchSize } function restoreDefaults() { settings.temperature = defaultTemperature; settings.topP = defaultTopP; settings.topK = defaultTopK; settings.maxLength = defaultMaxLength; settings.promptBatchSize = defaultPromptBatchSize; settings.promptTemplate = defaultPromptTemplate; } Component.onDestruction: { settings.sync() } Item { Accessible.role: Accessible.Dialog Accessible.name: qsTr("Settings dialog") Accessible.description: qsTr("Dialog containing various settings for model text generation") } GridLayout { columns: 2 rowSpacing: 2 columnSpacing: 10 anchors.fill: parent Label { id: tempLabel text: qsTr("Temperature:") Layout.row: 0 Layout.column: 0 } TextField { text: settings.temperature.toString() ToolTip.text: qsTr("Temperature increases the chances of choosing less likely tokens - higher temperature gives more creative but less predictable outputs") ToolTip.visible: hovered Layout.row: 0 Layout.column: 1 validator: DoubleValidator { } onAccepted: { var val = parseFloat(text) if (!isNaN(val)) { settings.temperature = val settings.sync() focus = false } else { text = settings.temperature.toString() } } Accessible.role: Accessible.EditableText Accessible.name: tempLabel.text Accessible.description: ToolTip.text } Label { id: topPLabel text: qsTr("Top P:") Layout.row: 1 Layout.column: 0 } TextField { text: settings.topP.toString() ToolTip.text: qsTr("Only the most likely tokens up to a total probability of top_p can be chosen, prevents choosing highly unlikely tokens, aka Nucleus Sampling") ToolTip.visible: hovered Layout.row: 1 Layout.column: 1 validator: DoubleValidator {} onAccepted: { var val = parseFloat(text) if (!isNaN(val)) { settings.topP = val settings.sync() focus = false } else { text = settings.topP.toString() } } Accessible.role: Accessible.EditableText Accessible.name: topPLabel.text Accessible.description: ToolTip.text } Label { id: topKLabel text: qsTr("Top K:") Layout.row: 2 Layout.column: 0 } TextField { text: settings.topK.toString() ToolTip.text: qsTr("Only the top K most likely tokens will be chosen from") ToolTip.visible: hovered Layout.row: 2 Layout.column: 1 validator: IntValidator { bottom: 1 } onAccepted: { var val = parseInt(text) if (!isNaN(val)) { settings.topK = val settings.sync() focus = false } else { text = settings.topK.toString() } } Accessible.role: Accessible.EditableText Accessible.name: topKLabel.text Accessible.description: ToolTip.text } Label { id: maxLengthLabel text: qsTr("Max Length:") Layout.row: 3 Layout.column: 0 } TextField { text: settings.maxLength.toString() ToolTip.text: qsTr("Maximum length of response in tokens") ToolTip.visible: hovered Layout.row: 3 Layout.column: 1 validator: IntValidator { bottom: 1 } onAccepted: { var val = parseInt(text) if (!isNaN(val)) { settings.maxLength = val settings.sync() focus = false } else { text = settings.maxLength.toString() } } Accessible.role: Accessible.EditableText Accessible.name: maxLengthLabel.text Accessible.description: ToolTip.text } Label { id: batchSizeLabel text: qsTr("Prompt Batch Size:") Layout.row: 4 Layout.column: 0 } TextField { text: settings.promptBatchSize.toString() ToolTip.text: qsTr("Amount of prompt tokens to process at once, higher values can speed up reading prompts but will use more RAM") ToolTip.visible: hovered Layout.row: 4 Layout.column: 1 validator: IntValidator { bottom: 1 } onAccepted: { var val = parseInt(text) if (!isNaN(val)) { settings.promptBatchSize = val settings.sync() focus = false } else { text = settings.promptBatchSize.toString() } } Accessible.role: Accessible.EditableText Accessible.name: batchSizeLabel.text Accessible.description: ToolTip.text } Label { id: nThreadsLabel text: qsTr("CPU Threads") Layout.row: 5 Layout.column: 0 } TextField { text: LLM.threadCount.toString() ToolTip.text: qsTr("Amount of processing threads to use") ToolTip.visible: hovered Layout.row: 5 Layout.column: 1 validator: IntValidator { bottom: 1 } onAccepted: { var val = parseInt(text) if (!isNaN(val)) { LLM.threadCount = val focus = false } else { text = settingsDialog.nThreads.toString() } } Accessible.role: Accessible.EditableText Accessible.name: nThreadsLabel.text Accessible.description: ToolTip.text } Label { id: promptTemplateLabel text: qsTr("Prompt Template:") Layout.row: 6 Layout.column: 0 } Rectangle { Layout.row: 6 Layout.column: 1 Layout.fillWidth: true height: 200 color: "transparent" border.width: 1 border.color: "#ccc" radius: 5 Label { id: promptTemplateLabelHelp visible: settings.promptTemplate.indexOf("%1") === -1 font.bold: true color: "red" text: qsTr("Prompt template must contain %1 to be replaced with the user's input.") anchors.bottom: templateScrollView.top Accessible.role: Accessible.EditableText Accessible.name: text } ScrollView { id: templateScrollView anchors.fill: parent TextArea { text: settings.promptTemplate wrapMode: TextArea.Wrap onTextChanged: { settings.promptTemplate = text settings.sync() } bottomPadding: 10 Accessible.role: Accessible.EditableText Accessible.name: promptTemplateLabel.text Accessible.description: promptTemplateLabelHelp.text } } } Button { Layout.row: 7 Layout.column: 1 Layout.fillWidth: true padding: 15 contentItem: Text { text: qsTr("Restore Defaults") horizontalAlignment: Text.AlignHCenter color: "#d1d5db" Accessible.role: Accessible.Button Accessible.name: text Accessible.description: qsTr("Restores the settings dialog to a default state") } background: Rectangle { opacity: .5 border.color: "#7d7d8e" border.width: 1 radius: 10 color: "#343541" } onClicked: { settingsDialog.restoreDefaults() } } } } Button { id: drawerButton anchors.left: parent.left anchors.top: parent.top anchors.topMargin: 30 anchors.leftMargin: 30 width: 60 height: 40 z: 200 padding: 15 Accessible.role: Accessible.ButtonMenu Accessible.name: qsTr("Hamburger button") Accessible.description: qsTr("Hamburger button that reveals a drawer on the left of the application") background: Item { anchors.fill: parent Rectangle { id: bar1 color: "#7d7d8e" width: parent.width height: 8 radius: 2 antialiasing: true } Rectangle { id: bar2 anchors.centerIn: parent color: "#7d7d8e" width: parent.width height: 8 radius: 2 antialiasing: true } Rectangle { id: bar3 anchors.bottom: parent.bottom color: "#7d7d8e" width: parent.width height: 8 radius: 2 antialiasing: true } } onClicked: { drawer.visible = !drawer.visible } } Button { id: settingsButton anchors.right: parent.right anchors.top: parent.top anchors.topMargin: 30 anchors.rightMargin: 30 width: 60 height: 40 z: 200 padding: 15 background: Item { anchors.fill: parent Image { anchors.centerIn: parent width: 40 height: 40 source: "qrc:/gpt4all-chat/icons/settings.svg" } } Accessible.role: Accessible.Button Accessible.name: qsTr("Settings button") Accessible.description: qsTr("Reveals a dialogue where you can change various settings") onClicked: { settingsDialog.open() } } Dialog { id: copyMessage anchors.centerIn: parent modal: false opacity: 0.9 Text { horizontalAlignment: Text.AlignJustify text: qsTr("Conversation copied to clipboard.") color: "#d1d5db" Accessible.role: Accessible.HelpBalloon Accessible.name: text Accessible.description: qsTr("Reveals a shortlived help balloon") } background: Rectangle { anchors.fill: parent color: "#202123" border.width: 1 border.color: "white" radius: 10 } exit: Transition { NumberAnimation { duration: 500; property: "opacity"; from: 1.0; to: 0.0 } } } Button { id: copyButton anchors.right: settingsButton.left anchors.top: parent.top anchors.topMargin: 30 anchors.rightMargin: 30 width: 60 height: 40 z: 200 padding: 15 Accessible.role: Accessible.Button Accessible.name: qsTr("Copy button") Accessible.description: qsTr("Copy the conversation to the clipboard") background: Item { anchors.fill: parent Image { anchors.centerIn: parent width: 40 height: 40 source: "qrc:/gpt4all-chat/icons/copy.svg" } } TextEdit{ id: copyEdit visible: false } onClicked: { var conversation = ""; for (var i = 0; i < chatModel.count; i++) { var item = chatModel.get(i) var string = item.name; if (item.currentResponse) string += LLM.response else string += chatModel.get(i).value string += "\n" conversation += string } copyEdit.text = conversation copyEdit.selectAll() copyEdit.copy() copyMessage.open() timer.start() } Timer { id: timer interval: 500; running: false; repeat: false onTriggered: copyMessage.close() } } Button { id: resetContextButton anchors.right: copyButton.left anchors.top: parent.top anchors.topMargin: 30 anchors.rightMargin: 30 width: 60 height: 40 z: 200 padding: 15 Accessible.role: Accessible.Button Accessible.name: text Accessible.description: qsTr("Reset the context which erases current conversation") background: Item { anchors.fill: parent Image { anchors.centerIn: parent width: 40 height: 40 source: "qrc:/gpt4all-chat/icons/regenerate.svg" } } onClicked: { LLM.stopGenerating() LLM.resetContext() chatModel.clear() } } Dialog { id: checkForUpdatesError anchors.centerIn: parent modal: false opacity: 0.9 Text { horizontalAlignment: Text.AlignJustify text: qsTr("ERROR: Update system could not find the MaintenanceTool used
to check for updates!

Did you install this application using the online installer? If so,
the MaintenanceTool executable should be located one directory
above where this application resides on your filesystem.

If you can't start it manually, then I'm afraid you'll have to
reinstall.") color: "#d1d5db" Accessible.role: Accessible.Dialog Accessible.name: text Accessible.description: qsTr("Dialog indicating an error") } background: Rectangle { anchors.fill: parent anchors.margins: -20 color: "#202123" border.width: 1 border.color: "white" radius: 10 } } ModelDownloaderDialog { id: downloadNewModels anchors.centerIn: parent Item { Accessible.role: Accessible.Dialog Accessible.name: qsTr("Download new models dialog") Accessible.description: qsTr("Dialog for downloading new models") } } Drawer { id: drawer y: header.height width: 0.3 * window.width height: window.height - y modal: false opacity: 0.9 background: Rectangle { height: parent.height color: "#202123" } Item { anchors.fill: parent anchors.margins: 30 Accessible.role: Accessible.Pane Accessible.name: qsTr("Drawer on the left of the application") Accessible.description: qsTr("Drawer that is revealed by pressing the hamburger button") Label { id: conversationList anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top wrapMode: Text.WordWrap text: qsTr("Chat lists of specific conversations coming soon! Check back often for new features :)") color: "#d1d5db" Accessible.role: Accessible.Paragraph Accessible.name: qsTr("Coming soon") Accessible.description: text } Label { id: discordLink textFormat: Text.RichText anchors.left: parent.left anchors.right: parent.right anchors.top: conversationList.bottom anchors.topMargin: 20 wrapMode: Text.WordWrap text: qsTr("Check out our discord channel https://discord.gg/4M2QFmTt2k") onLinkActivated: { Qt.openUrlExternally("https://discord.gg/4M2QFmTt2k") } color: "#d1d5db" linkColor: "#1e8cda" Accessible.role: Accessible.Link Accessible.name: qsTr("Discord link") } Label { id: nomicProps textFormat: Text.RichText anchors.left: parent.left anchors.right: parent.right anchors.top: discordLink.bottom anchors.topMargin: 20 wrapMode: Text.WordWrap text: qsTr("Thanks to nomic.ai and the community for contributing so much great data and energy!") onLinkActivated: { Qt.openUrlExternally("https://home.nomic.ai") } color: "#d1d5db" linkColor: "#1e8cda" Accessible.role: Accessible.Paragraph Accessible.name: qsTr("Thank you blurb") Accessible.description: qsTr("Contains embedded link to https://home.nomic.ai") } Button { anchors.left: parent.left anchors.right: parent.right anchors.bottom: downloadButton.top anchors.bottomMargin: 20 padding: 15 contentItem: Text { text: qsTr("Check for updates...") horizontalAlignment: Text.AlignHCenter color: "#d1d5db" Accessible.role: Accessible.Button Accessible.name: text Accessible.description: qsTr("Use this to launch an external application that will check for updates to the installer") } background: Rectangle { opacity: .5 border.color: "#7d7d8e" border.width: 1 radius: 10 color: "#343541" } onClicked: { if (!LLM.checkForUpdates()) checkForUpdatesError.open() } } Button { id: downloadButton anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom padding: 15 contentItem: Text { text: qsTr("Download new models...") horizontalAlignment: Text.AlignHCenter color: "#d1d5db" Accessible.role: Accessible.Button Accessible.name: text Accessible.description: qsTr("Use this to launch a dialog to download new models") } background: Rectangle { opacity: .5 border.color: "#7d7d8e" border.width: 1 radius: 10 color: "#343541" } onClicked: { downloadNewModels.open() } } } } Rectangle { id: conversation color: "#343541" anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom anchors.top: header.bottom ScrollView { id: scrollView anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top anchors.bottom: textInputView.top anchors.bottomMargin: 30 ScrollBar.vertical.policy: ScrollBar.AlwaysOn ListModel { id: chatModel } Rectangle { anchors.fill: parent color: "#444654" ListView { id: listView anchors.fill: parent model: chatModel Accessible.role: Accessible.List Accessible.name: qsTr("List of prompt/response pairs") Accessible.description: qsTr("This is the list of prompt/response pairs comprising the actual conversation with the model") delegate: TextArea { text: currentResponse ? LLM.response : (value ? value : "") width: listView.width color: "#d1d5db" wrapMode: Text.WordWrap focus: false readOnly: true padding: 20 font.pixelSize: 24 cursorVisible: currentResponse ? (LLM.response !== "" ? LLM.responseInProgress : false) : false cursorPosition: text.length background: Rectangle { color: name === qsTr("Response: ") ? "#444654" : "#343541" } Accessible.role: Accessible.Paragraph Accessible.name: name Accessible.description: name === qsTr("Response: ") ? "The response by the model" : "The prompt by the user" leftPadding: 100 BusyIndicator { anchors.left: parent.left anchors.leftMargin: 90 anchors.top: parent.top anchors.topMargin: 5 visible: (currentResponse ? true : false) && LLM.response === "" && LLM.responseInProgress running: (currentResponse ? true : false) && LLM.response === "" && LLM.responseInProgress Accessible.role: Accessible.Animation Accessible.name: qsTr("Busy indicator") Accessible.description: qsTr("Displayed when the model is thinking") } Rectangle { anchors.left: parent.left anchors.top: parent.top anchors.leftMargin: 20 anchors.topMargin: 20 width: 30 height: 30 radius: 5 color: name === qsTr("Response: ") ? "#10a37f" : "#ec86bf" Text { anchors.centerIn: parent text: name === qsTr("Response: ") ? "R" : "P" color: "white" } } } property bool shouldAutoScroll: true property bool isAutoScrolling: false Connections { target: LLM function onResponseChanged() { if (listView.shouldAutoScroll) { listView.isAutoScrolling = true listView.positionViewAtEnd() listView.isAutoScrolling = false } } } onContentYChanged: { if (!isAutoScrolling) shouldAutoScroll = atYEnd } Component.onCompleted: { shouldAutoScroll = true positionViewAtEnd() } footer: Item { id: bottomPadding width: parent.width height: 60 } } } } Button { Image { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: 15 source: LLM.responseInProgress ? "qrc:/gpt4all-chat/icons/stop_generating.svg" : "qrc:/gpt4all-chat/icons/regenerate.svg" } leftPadding: 50 onClicked: { if (LLM.responseInProgress) LLM.stopGenerating() else { LLM.regenerateResponse() if (chatModel.count) { var listElement = chatModel.get(chatModel.count - 1) if (listElement.name === qsTr("Response: ")) { listElement.currentResponse = true listElement.value = LLM.response LLM.prompt(listElement.prompt, settings.promptTemplate, settings.maxLength, settings.topK, settings.topP, settings.temperature, settings.promptBatchSize) } } } } anchors.bottom: textInputView.top anchors.horizontalCenter: textInputView.horizontalCenter anchors.bottomMargin: 40 padding: 15 contentItem: Text { text: LLM.responseInProgress ? qsTr("Stop generating") : qsTr("Regenerate response") color: "#d1d5db" Accessible.role: Accessible.Button Accessible.name: text Accessible.description: qsTr("Controls generation of the response") } background: Rectangle { opacity: .5 border.color: "#7d7d8e" border.width: 1 radius: 10 color: "#343541" } } ScrollView { id: textInputView anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom anchors.margins: 30 height: Math.min(contentHeight, 200) TextArea { id: textInput color: "#dadadc" padding: 20 enabled: LLM.isModelLoaded font.pixelSize: 24 placeholderText: qsTr("Send a message...") placeholderTextColor: "#7d7d8e" background: Rectangle { color: "#40414f" radius: 10 } Accessible.role: Accessible.EditableText Accessible.name: placeholderText Accessible.description: qsTr("Textfield for sending messages/prompts to the model") Keys.onReturnPressed: (event)=> { if (event.modifiers & Qt.ControlModifier || event.modifiers & Qt.ShiftModifier) event.accepted = false; else editingFinished(); } onEditingFinished: { if (textInput.text === "") return LLM.stopGenerating() if (chatModel.count) { var listElement = chatModel.get(chatModel.count - 1) listElement.currentResponse = false listElement.value = LLM.response } var prompt = textInput.text + "\n" chatModel.append({"name": qsTr("Prompt: "), "currentResponse": false, "value": textInput.text}) chatModel.append({"name": qsTr("Response: "), "currentResponse": true, "value": "", "prompt": prompt}) LLM.resetResponse() LLM.prompt(prompt, settings.promptTemplate, settings.maxLength, settings.topK, settings.topP, settings.temperature, settings.promptBatchSize) textInput.text = "" } } } Button { anchors.right: textInputView.right anchors.verticalCenter: textInputView.verticalCenter anchors.rightMargin: 15 width: 30 height: 30 background: Image { anchors.centerIn: parent source: "qrc:/gpt4all-chat/icons/send_message.svg" } Accessible.role: Accessible.Button Accessible.name: qsTr("Send the message button") Accessible.description: qsTr("Sends the message/prompt contained in textfield to the model") onClicked: { textInput.accepted() } } } }