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" Rectangle { id: header anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top height: 100 color: "#202123" Item { anchors.centerIn: parent width: childrenRect.width height: childrenRect.height visible: LLM.isModelLoaded Label { id: modelNameField color: "#d1d5db" padding: 20 font.pixelSize: 24 text: "GPT4ALL Model: " + LLM.modelName background: Rectangle { color: "#202123" } horizontalAlignment: TextInput.AlignHCenter } } BusyIndicator { anchors.centerIn: parent visible: !LLM.isModelLoaded running: !LLM.isModelLoaded } } Dialog { id: settingsDialog modal: true anchors.centerIn: parent title: qsTr("Settings") height: 600 width: 600 property real defaultTemperature: 0.7 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" property string promptTemplate: "" property real temperature: 0.0 property real topP: 0.0 property int topK: 0 property int maxLength: 0 property int promptBatchSize: 0 function restoreDefaults() { temperature = defaultTemperature; topP = defaultTopP; topK = defaultTopK; maxLength = defaultMaxLength; promptBatchSize = defaultPromptBatchSize; promptTemplate = defaultPromptTemplate; } Component.onCompleted: { restoreDefaults(); } GridLayout { columns: 2 rowSpacing: 10 columnSpacing: 10 anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom Label { text: qsTr("Temperature:") Layout.row: 0 Layout.column: 0 } TextField { text: settingsDialog.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)) { settingsDialog.temperature = val focus = false } else { text = settingsDialog.temperature.toString() } } } Label { text: qsTr("Top P:") Layout.row: 1 Layout.column: 0 } TextField { text: settingsDialog.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)) { settingsDialog.topP = val focus = false } else { text = settingsDialog.topP.toString() } } } Label { text: qsTr("Top K:") Layout.row: 2 Layout.column: 0 } TextField { text: settingsDialog.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)) { settingsDialog.topK = val focus = false } else { text = settingsDialog.topK.toString() } } } Label { text: qsTr("Max Length:") Layout.row: 3 Layout.column: 0 } TextField { text: settingsDialog.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)) { settingsDialog.maxLength = val focus = false } else { text = settingsDialog.maxLength.toString() } } } Label { text: qsTr("Prompt Batch Size:") Layout.row: 4 Layout.column: 0 } TextField { text: settingsDialog.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)) { settingsDialog.promptBatchSize = val focus = false } else { text = settingsDialog.promptBatchSize.toString() } } } Label { text: qsTr("Prompt Template:") Layout.row: 5 Layout.column: 0 } Rectangle { Layout.row: 5 Layout.column: 1 Layout.fillWidth: true height: 200 color: "#222" border.width: 1 border.color: "#ccc" radius: 5 Label { visible: settingsDialog.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 } ScrollView { id: templateScrollView anchors.fill: parent TextArea { text: settingsDialog.promptTemplate wrapMode: TextArea.Wrap onTextChanged: { settingsDialog.promptTemplate = text } bottomPadding: 10 } } } Button { Layout.row: 6 Layout.column: 1 Layout.fillWidth: true padding: 15 contentItem: Text { text: qsTr("Restore Defaults") horizontalAlignment: Text.AlignHCenter color: "#d1d5db" } 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 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" } } 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" } 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 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 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" } background: Rectangle { anchors.fill: parent color: "#202123" border.width: 1 border.color: "white" radius: 10 } } 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 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" } 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" } 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" } Button { anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom padding: 15 contentItem: Text { text: qsTr("Check for updates...") horizontalAlignment: Text.AlignHCenter color: "#d1d5db" } background: Rectangle { opacity: .5 border.color: "#7d7d8e" border.width: 1 radius: 10 color: "#343541" } onClicked: { if (!LLM.checkForUpdates()) checkForUpdatesError.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: textInput.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 delegate: TextArea { text: currentResponse ? LLM.response : 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" } leftPadding: 100 BusyIndicator { anchors.left: parent.left anchors.leftMargin: 90 anchors.top: parent.top anchors.topMargin: 5 visible: currentResponse && LLM.response === "" && LLM.responseInProgress running: currentResponse && LLM.response === "" && LLM.responseInProgress } 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.resetResponse() 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, settingsDialog.promptTemplate, settingsDialog.maxLength, settingsDialog.topK, settingsDialog.topP, settingsDialog.temperature, settingsDialog.promptBatchSize) } } } } anchors.bottom: textInput.top anchors.horizontalCenter: textInput.horizontalCenter anchors.bottomMargin: 40 padding: 15 contentItem: Text { text: LLM.responseInProgress ? qsTr("Stop generating") : qsTr("Regenerate response") color: "#d1d5db" } background: Rectangle { opacity: .5 border.color: "#7d7d8e" border.width: 1 radius: 10 color: "#343541" } } TextField { id: textInput anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom anchors.margins: 30 color: "#dadadc" padding: 20 enabled: LLM.isModelLoaded font.pixelSize: 24 placeholderText: qsTr("Send a message...") placeholderTextColor: "#7d7d8e" background: Rectangle { color: "#40414f" radius: 10 } onAccepted: { 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, settingsDialog.promptTemplate, settingsDialog.maxLength, settingsDialog.topK, settingsDialog.topP, settingsDialog.temperature, settingsDialog.promptBatchSize) textInput.text = "" } Button { anchors.right: textInput.right anchors.verticalCenter: textInput.verticalCenter anchors.rightMargin: 15 width: 30 height: 30 background: Image { anchors.centerIn: parent source: "qrc:/gpt4all-chat/icons/send_message.svg" } onClicked: { textInput.accepted() } } } } }