diff --git a/gpt4all-chat/CMakeLists.txt b/gpt4all-chat/CMakeLists.txt index 8328c01d..fea8567a 100644 --- a/gpt4all-chat/CMakeLists.txt +++ b/gpt4all-chat/CMakeLists.txt @@ -103,11 +103,11 @@ qt_add_qml_module(chat qml/ChatDrawer.qml qml/ChatView.qml qml/CollectionsDialog.qml - qml/ModelDownloaderView.qml + qml/ModelDownloaderDialog.qml qml/NetworkDialog.qml qml/NewVersionDialog.qml qml/ThumbsDownDialog.qml - qml/SettingsView.qml + qml/SettingsDialog.qml qml/StartupDialog.qml qml/PopupDialog.qml qml/AboutDialog.qml @@ -136,7 +136,6 @@ qt_add_qml_module(chat icons/send_message.svg icons/stop_generating.svg icons/regenerate.svg - icons/chat.svg icons/close.svg icons/copy.svg icons/db.svg @@ -145,10 +144,6 @@ qt_add_qml_module(chat icons/eject.svg icons/edit.svg icons/image.svg - icons/info.svg - icons/local-docs.svg - icons/models.svg - icons/search.svg icons/trash.svg icons/network.svg icons/thumbs_up.svg diff --git a/gpt4all-chat/icons/chat.svg b/gpt4all-chat/icons/chat.svg deleted file mode 100644 index c510c50e..00000000 --- a/gpt4all-chat/icons/chat.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/gpt4all-chat/icons/db.svg b/gpt4all-chat/icons/db.svg index fc0816f7..4b0d1082 100644 --- a/gpt4all-chat/icons/db.svg +++ b/gpt4all-chat/icons/db.svg @@ -1,3 +1,5 @@ - - - + + diff --git a/gpt4all-chat/icons/edit.svg b/gpt4all-chat/icons/edit.svg index 5a79a50e..9820173b 100644 --- a/gpt4all-chat/icons/edit.svg +++ b/gpt4all-chat/icons/edit.svg @@ -1,3 +1,5 @@ - - - + + diff --git a/gpt4all-chat/icons/info.svg b/gpt4all-chat/icons/info.svg deleted file mode 100644 index 2c207ecb..00000000 --- a/gpt4all-chat/icons/info.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/gpt4all-chat/icons/local-docs.svg b/gpt4all-chat/icons/local-docs.svg deleted file mode 100644 index 06031c34..00000000 --- a/gpt4all-chat/icons/local-docs.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/gpt4all-chat/icons/models.svg b/gpt4all-chat/icons/models.svg deleted file mode 100644 index 4e9b5306..00000000 --- a/gpt4all-chat/icons/models.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/gpt4all-chat/icons/search.svg b/gpt4all-chat/icons/search.svg deleted file mode 100644 index bae556fc..00000000 --- a/gpt4all-chat/icons/search.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - diff --git a/gpt4all-chat/icons/settings.svg b/gpt4all-chat/icons/settings.svg index 3d885b3f..7542ea62 100644 --- a/gpt4all-chat/icons/settings.svg +++ b/gpt4all-chat/icons/settings.svg @@ -1,3 +1,46 @@ - - + + + + + + + diff --git a/gpt4all-chat/icons/trash.svg b/gpt4all-chat/icons/trash.svg index fa800005..b7c1a141 100644 --- a/gpt4all-chat/icons/trash.svg +++ b/gpt4all-chat/icons/trash.svg @@ -1,3 +1,5 @@ - - - + + diff --git a/gpt4all-chat/main.qml b/gpt4all-chat/main.qml index 94cd6fdd..c9d0ad67 100644 --- a/gpt4all-chat/main.qml +++ b/gpt4all-chat/main.qml @@ -43,25 +43,6 @@ Window { font.pixelSize: theme.fontSizeLarge } - NetworkDialog { - id: networkDialog - anchors.centerIn: parent - width: Math.min(1024, window.width - (window.width * .2)) - height: Math.min(600, window.height - (window.height * .2)) - Item { - Accessible.role: Accessible.Dialog - Accessible.name: qsTr("Network dialog") - Accessible.description: qsTr("opt-in to share feedback/conversations") - } - } - - AboutDialog { - id: aboutDialog - anchors.centerIn: parent - width: Math.min(1024, window.width - (window.width * .2)) - height: Math.min(600, window.height - (window.height * .2)) - } - onClosing: function(close) { if (window.hasSaved) return; @@ -82,173 +63,7 @@ Window { color: theme.black - Rectangle { - id: viewBar - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: parent.left - width: 80 - color: theme.viewBarBackground - - ColumnLayout { - id: viewsLayout - anchors.top: parent.top - anchors.topMargin: 30 - anchors.horizontalCenter: parent.horizontalCenter - Layout.margins: 0 - spacing: 25 - - MyToolButton { - id: chatButton - backgroundColor: toggled ? theme.iconBackgroundViewBarToggled : theme.iconBackgroundViewBar - backgroundColorHovered: toggled ? backgroundColor : theme.iconBackgroundViewBarHovered - Layout.preferredWidth: 40 - Layout.preferredHeight: 40 - Layout.alignment: Qt.AlignCenter - toggledWidth: 0 - toggled: stackLayout.currentIndex === 0 - toggledColor: theme.iconBackgroundViewBarToggled - scale: 1.5 - source: "qrc:/gpt4all/icons/chat.svg" - Accessible.name: qsTr("Chat view") - Accessible.description: qsTr("Chat view to interact with models") - onClicked: { - stackLayout.currentIndex = 0 - } - } - - MyToolButton { - id: searchButton - backgroundColor: toggled ? theme.iconBackgroundViewBarToggled : theme.iconBackgroundViewBar - backgroundColorHovered: toggled ? backgroundColor : theme.iconBackgroundViewBarHovered - Layout.preferredWidth: 40 - Layout.preferredHeight: 40 - toggledWidth: 0 - toggled: stackLayout.currentIndex === 1 - toggledColor: theme.iconBackgroundViewBarToggled - scale: 1.5 - source: "qrc:/gpt4all/icons/models.svg" - Accessible.name: qsTr("Search") - Accessible.description: qsTr("Launch a dialog to download new models") - onClicked: { - stackLayout.currentIndex = 1 - } - } - - MyToolButton { - id: settingsButton - backgroundColor: toggled ? theme.iconBackgroundViewBarToggled : theme.iconBackgroundViewBar - backgroundColorHovered: toggled ? backgroundColor : theme.iconBackgroundViewBarHovered - Layout.preferredWidth: 40 - Layout.preferredHeight: 40 - toggledWidth: 0 - toggledColor: theme.iconBackgroundViewBarToggled - toggled: stackLayout.currentIndex === 2 - scale: 1.5 - source: "qrc:/gpt4all/icons/settings.svg" - Accessible.name: qsTr("Settings") - Accessible.description: qsTr("Reveals a dialogue with settings") - - onClicked: { - stackLayout.currentIndex = 2 - } - } - } - - ColumnLayout { - id: buttonsLayout - anchors.bottom: parent.bottom - anchors.margins: 0 - anchors.bottomMargin: 25 - anchors.horizontalCenter: parent.horizontalCenter - Layout.margins: 0 - spacing: 25 - - MyToolButton { - id: networkButton - backgroundColor: toggled ? theme.iconBackgroundViewBarToggled : theme.iconBackgroundViewBar - backgroundColorHovered: toggled ? backgroundColor : theme.iconBackgroundViewBarHovered - toggledColor: theme.iconBackgroundViewBar - Layout.preferredWidth: 40 - Layout.preferredHeight: 40 - scale: 1.2 - toggled: MySettings.networkIsActive - source: "qrc:/gpt4all/icons/network.svg" - Accessible.name: qsTr("Network") - Accessible.description: qsTr("Reveals a dialogue where you can opt-in for sharing data over network") - - onClicked: { - if (MySettings.networkIsActive) { - MySettings.networkIsActive = false - Network.sendNetworkToggled(false); - } else - networkDialog.open() - } - } - - MyToolButton { - id: infoButton - backgroundColor: theme.iconBackgroundViewBar - backgroundColorHovered: theme.iconBackgroundViewBarHovered - Layout.preferredWidth: 40 - Layout.preferredHeight: 40 - scale: 1.2 - source: "qrc:/gpt4all/icons/info.svg" - Accessible.name: qsTr("About") - Accessible.description: qsTr("Reveals an about dialog") - onClicked: { - aboutDialog.open() - } - } - } - } - - StackLayout { - id: stackLayout - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: viewBar.right - anchors.right: parent.right - - ChatView { - id: chatView - Layout.fillWidth: true - Layout.fillHeight: true - - Connections { - target: chatView - function onDownloadViewRequested(showEmbeddingModels) { - console.log("onDownloadViewRequested") - stackLayout.currentIndex = 1; - if (showEmbeddingModels) - downloadView.showEmbeddingModels(); - } - function onSettingsViewRequested(page) { - settingsDialog.pageToDisplay = page; - stackLayout.currentIndex = 2; - } - } - } - - ModelDownloaderView { - id: downloadView - Layout.fillWidth: true - Layout.fillHeight: true - Item { - Accessible.role: Accessible.Dialog - Accessible.name: qsTr("Download new models") - Accessible.description: qsTr("View for downloading new models") - } - } - - SettingsView { - id: settingsDialog - Layout.fillWidth: true - Layout.fillHeight: true - onDownloadClicked: { - stackLayout.currentIndex = 1 - downloadView.showEmbeddingModels() - } - } + ChatView { + anchors.fill: parent } } diff --git a/gpt4all-chat/qml/AboutDialog.qml b/gpt4all-chat/qml/AboutDialog.qml index 8ce5ae7a..ca63f9e6 100644 --- a/gpt4all-chat/qml/AboutDialog.qml +++ b/gpt4all-chat/qml/AboutDialog.qml @@ -98,17 +98,4 @@ MyDialog { Accessible.description: qsTr("Contains embedded link to https://home.nomic.ai") } } - - MyButton { - id: checkForUpdatesButton - anchors.right: parent.right - anchors.bottom: parent.bottom - text: qsTr("Check for updates...") - font.pixelSize: theme.fontSizeLarge - Accessible.description: qsTr("Launch an external application that will check for updates to the installer") - onClicked: { - if (!LLM.checkForUpdates()) - checkForUpdatesError.open() - } - } } diff --git a/gpt4all-chat/qml/ChatDrawer.qml b/gpt4all-chat/qml/ChatDrawer.qml index dee8843a..2f243f36 100644 --- a/gpt4all-chat/qml/ChatDrawer.qml +++ b/gpt4all-chat/qml/ChatDrawer.qml @@ -16,22 +16,13 @@ Rectangle { id: theme } + signal downloadClicked + signal aboutClicked + color: theme.containerBackground - Rectangle { - id: borderRight - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: parent.right - width: 2 - color: theme.containerForeground - } - Item { - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: borderRight.left + anchors.fill: parent anchors.margins: 10 Accessible.role: Accessible.Pane @@ -59,7 +50,7 @@ Rectangle { anchors.rightMargin: -10 anchors.topMargin: 10 anchors.top: newChat.bottom - anchors.bottom: parent.bottom + anchors.bottom: checkForUpdatesButton.top anchors.bottomMargin: 10 ScrollBar.vertical.policy: ScrollBar.AlwaysOff clip: true @@ -245,5 +236,45 @@ Rectangle { Accessible.description: qsTr("List of chats in the drawer dialog") } } + + MyButton { + id: checkForUpdatesButton + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: downloadButton.top + anchors.bottomMargin: 10 + text: qsTr("Updates") + font.pixelSize: theme.fontSizeLarge + Accessible.description: qsTr("Launch an external application that will check for updates to the installer") + onClicked: { + if (!LLM.checkForUpdates()) + checkForUpdatesError.open() + } + } + + MyButton { + id: downloadButton + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: aboutButton.top + anchors.bottomMargin: 10 + text: qsTr("Downloads") + Accessible.description: qsTr("Launch a dialog to download new models") + onClicked: { + downloadClicked() + } + } + + MyButton { + id: aboutButton + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + text: qsTr("About") + Accessible.description: qsTr("Launch a dialog to show the about page") + onClicked: { + aboutClicked() + } + } } } diff --git a/gpt4all-chat/qml/ChatView.qml b/gpt4all-chat/qml/ChatView.qml index 26893ee6..830ca152 100644 --- a/gpt4all-chat/qml/ChatView.qml +++ b/gpt4all-chat/qml/ChatView.qml @@ -21,8 +21,6 @@ Rectangle { property var currentChat: ChatListModel.currentChat property var chatModel: currentChat.chatModel - signal settingsViewRequested(int page) - signal downloadViewRequested(bool showEmbeddingModels) color: theme.black @@ -38,6 +36,13 @@ Rectangle { } } + Connections { + target: downloadNewModels + function onClosed() { + startupDialogs(); + } + } + Connections { target: Download function onHasNewerReleaseChanged() { @@ -85,15 +90,15 @@ Rectangle { return; } - // check for any current models and if not, open download view once + // check for any current models and if not, open download dialog once if (!hasShownModelDownload && ModelList.installedModels.count === 0 && !firstStartDialog.opened) { - downloadViewRequested(); + downloadNewModels.open(); hasShownModelDownload = true; return; } // check for new version - if (Download.hasNewerRelease && !firstStartDialog.opened) { + if (Download.hasNewerRelease && !firstStartDialog.opened && !downloadNewModels.opened) { newVersionDialog.open(); return; } @@ -148,6 +153,13 @@ Rectangle { anchors.centerIn: parent } + AboutDialog { + id: aboutDialog + anchors.centerIn: parent + width: Math.min(1024, window.width - (window.width * .2)) + height: Math.min(600, window.height - (window.height * .2)) + } + Item { Accessible.role: Accessible.Window Accessible.name: title @@ -282,265 +294,265 @@ Rectangle { anchors.top: parent.top height: 100 color: theme.mainHeader + Item { + anchors.centerIn: parent + height: childrenRect.height + visible: true - RowLayout { - id: comboLayout - height: 80 - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: 20 - - Rectangle { - Layout.alignment: Qt.AlignLeft - Layout.leftMargin: 30 - Layout.fillWidth: true - Layout.preferredWidth: 100 - Layout.topMargin: 20 - color: "transparent" - Layout.preferredHeight: childrenRect.height - MyToolButton { - id: drawerButton - anchors.left: parent.left - backgroundColor: theme.iconBackgroundLight - width: 40 - height: 40 - scale: 1.5 - padding: 15 - source: conversation.state === "expanded" ? "qrc:/gpt4all/icons/left_panel_open.svg" : "qrc:/gpt4all/icons/left_panel_closed.svg" - Accessible.role: Accessible.ButtonMenu - Accessible.name: qsTr("Chat panel") - Accessible.description: qsTr("Chat panel with options") - onClicked: { - conversation.toggleLeftPanel() - } + Label { + id: modelLabel + color: theme.textColor + padding: 20 + font.pixelSize: theme.fontSizeLarger + text: "" + background: Rectangle { + color: theme.mainHeader } + horizontalAlignment: TextInput.AlignRight } - MyComboBox { - id: comboBox - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.fillWidth: true - Layout.preferredWidth: 100 - Layout.maximumWidth: 675 - enabled: !currentChat.isServer - && !window.trySwitchContextInProgress - && !window.isCurrentlyLoading - model: ModelList.installedModels - valueRole: "id" - textRole: "name" + RowLayout { + id: comboLayout + anchors.top: modelLabel.top + anchors.bottom: modelLabel.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.horizontalCenterOffset: window.width >= 950 ? 0 : Math.max(-((950 - window.width) / 2), -99.5) + spacing: 20 - function changeModel(index) { - window.modelLoadingPercentage = 0.0; - window.isCurrentlyLoading = true; - currentChat.stopGenerating() - currentChat.reset(); - currentChat.modelInfo = ModelList.modelInfo(comboBox.valueAt(index)) - } - - Connections { - target: currentChat - function onModelLoadingPercentageChanged() { - window.modelLoadingPercentage = currentChat.modelLoadingPercentage; - window.isCurrentlyLoading = currentChat.modelLoadingPercentage !== 0.0 - && currentChat.modelLoadingPercentage !== 1.0; - } - function onTrySwitchContextOfLoadedModelAttempted() { - window.trySwitchContextInProgress = true; - } - function onTrySwitchContextOfLoadedModelCompleted() { - window.trySwitchContextInProgress = false; - } - } - Connections { - target: switchModelDialog - function onAccepted() { - comboBox.changeModel(switchModelDialog.index) - } - } - - background: ProgressBar { - id: modelProgress - value: window.modelLoadingPercentage - background: Rectangle { - color: theme.mainComboBackground - radius: 10 - } - contentItem: Item { - Rectangle { - visible: window.isCurrentlyLoading - anchors.bottom: parent.bottom - width: modelProgress.visualPosition * parent.width - height: 10 - radius: 2 - color: theme.progressForeground - } - } - } - contentItem: Text { - anchors.horizontalCenter: parent.horizontalCenter - leftPadding: 10 - rightPadding: { - if (ejectButton.visible && reloadButton) - return 105; - if (reloadButton.visible) - return 65 - return 25 - } - text: { - if (currentChat.modelLoadingError !== "") - return qsTr("Model loading error...") - if (window.trySwitchContextInProgress) - return qsTr("Switching context...") - if (currentModelName() === "") - return qsTr("Choose a model...") - if (currentChat.modelLoadingPercentage === 0.0) - return qsTr("Reload \u00B7 ") + currentModelName() - if (window.isCurrentlyLoading) - return qsTr("Loading \u00B7 ") + currentModelName() - return currentModelName() - } - font.pixelSize: theme.fontSizeLarger - color: theme.white - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - elide: Text.ElideRight - } - delegate: ItemDelegate { - id: comboItemDelegate - width: comboBox.width - contentItem: Text { - text: name - color: theme.textColor - font: comboBox.font - elide: Text.ElideRight - verticalAlignment: Text.AlignVCenter - } - background: Rectangle { - color: (index % 2 === 0 ? theme.darkContrast : theme.lightContrast) - border.width: highlighted - border.color: theme.accentColor - } - highlighted: comboBox.highlightedIndex === index - } - Accessible.role: Accessible.ComboBox - Accessible.name: currentModelName() - Accessible.description: qsTr("The top item is the current model") - onActivated: function (index) { - var newInfo = ModelList.modelInfo(comboBox.valueAt(index)); - if (newInfo === currentChat.modelInfo) { - currentChat.reloadModel(); - } else if (currentModelName() !== "" && chatModel.count !== 0) { - switchModelDialog.index = index; - switchModelDialog.open(); - } else { - comboBox.changeModel(index); - } - } - - MyMiniButton { - id: ejectButton - visible: currentChat.isModelLoaded && !window.isCurrentlyLoading - z: 500 - anchors.right: parent.right - anchors.rightMargin: 50 - anchors.verticalCenter: parent.verticalCenter - source: "qrc:/gpt4all/icons/eject.svg" - backgroundColor: theme.gray300 - backgroundColorHovered: theme.iconBackgroundLight - onClicked: { - currentChat.forceUnloadModel(); - } - ToolTip.text: qsTr("Eject the currently loaded model") - ToolTip.visible: hovered - } - - MyMiniButton { - id: reloadButton - visible: currentChat.modelLoadingError === "" + MyComboBox { + id: comboBox + Layout.fillWidth: true + Layout.fillHeight: true + implicitWidth: 575 + width: window.width >= 750 ? implicitWidth : implicitWidth - (750 - window.width) + enabled: !currentChat.isServer && !window.trySwitchContextInProgress && !window.isCurrentlyLoading - && (currentChat.isModelLoaded || currentModelName() !== "") - z: 500 - anchors.right: ejectButton.visible ? ejectButton.left : parent.right - anchors.rightMargin: ejectButton.visible ? 10 : 50 - anchors.verticalCenter: parent.verticalCenter - source: "qrc:/gpt4all/icons/regenerate.svg" - backgroundColor: theme.gray300 - backgroundColorHovered: theme.iconBackgroundLight - onClicked: { - if (currentChat.isModelLoaded) - currentChat.forceReloadModel(); - else - currentChat.reloadModel(); + model: ModelList.installedModels + valueRole: "id" + textRole: "name" + + function changeModel(index) { + window.modelLoadingPercentage = 0.0; + window.isCurrentlyLoading = true; + currentChat.stopGenerating() + currentChat.reset(); + currentChat.modelInfo = ModelList.modelInfo(comboBox.valueAt(index)) } - ToolTip.text: qsTr("Reload the currently loaded model") - ToolTip.visible: hovered - } - } - Rectangle { - color: "transparent" - Layout.alignment: Qt.AlignRight - Layout.rightMargin: 30 - Layout.fillWidth: true - Layout.preferredWidth: 100 - Layout.preferredHeight: childrenRect.height - Layout.topMargin: 20 - - RowLayout { - spacing: 20 - anchors.right: parent.right - MyButton { - id: collectionsButton - Image { - id: collectionsImage - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: 15 - width: 24 - height: 24 - mipmap: true - source: "qrc:/gpt4all/icons/db.svg" + Connections { + target: currentChat + function onModelLoadingPercentageChanged() { + window.modelLoadingPercentage = currentChat.modelLoadingPercentage; + window.isCurrentlyLoading = currentChat.modelLoadingPercentage !== 0.0 + && currentChat.modelLoadingPercentage !== 1.0; } - - ColorOverlay { - anchors.fill: collectionsImage - source: collectionsImage - color: collectionsButton.hovered || collectionsImage.toggled ? theme.iconBackgroundHovered : theme.iconBackgroundLight + function onTrySwitchContextOfLoadedModelAttempted() { + window.trySwitchContextInProgress = true; } + function onTrySwitchContextOfLoadedModelCompleted() { + window.trySwitchContextInProgress = false; + } + } + Connections { + target: switchModelDialog + function onAccepted() { + comboBox.changeModel(switchModelDialog.index) + } + } - leftPadding: 50 - borderWidth: 0 - backgroundColor: theme.mainComboBackground - backgroundColorHovered: theme.conversationButtonBackgroundHovered - backgroundRadius: 5 - padding: 15 - topPadding: 8 - bottomPadding: 8 - textColor: hovered || toggled ? theme.iconBackgroundHovered : theme.iconBackgroundLight - text: qsTr("LocalDocs") - fontPixelSize: theme.fontSizeSmall - - property bool toggled: currentChat.collectionList.length + background: ProgressBar { + id: modelProgress + value: window.modelLoadingPercentage background: Rectangle { - radius: collectionsButton.backgroundRadius - color: collectionsButton.toggled ? collectionsButton.backgroundColorHovered : collectionsButton.backgroundColor + color: theme.mainComboBackground + radius: 10 } + contentItem: Item { + Rectangle { + visible: window.isCurrentlyLoading + anchors.bottom: parent.bottom + width: modelProgress.visualPosition * parent.width + height: 10 + radius: 2 + color: theme.progressForeground + } + } + } + contentItem: Text { + anchors.horizontalCenter: parent.horizontalCenter + leftPadding: 10 + rightPadding: { + if (ejectButton.visible && reloadButton) + return 105; + if (reloadButton.visible) + return 65 + return 25 + } + text: { + if (currentChat.modelLoadingError !== "") + return qsTr("Model loading error...") + if (window.trySwitchContextInProgress) + return qsTr("Switching context...") + if (currentModelName() === "") + return qsTr("Choose a model...") + if (currentChat.modelLoadingPercentage === 0.0) + return qsTr("Reload \u00B7 ") + currentModelName() + if (window.isCurrentlyLoading) + return qsTr("Loading \u00B7 ") + currentModelName() + return currentModelName() + } + font.pixelSize: theme.fontSizeLarger + color: theme.white + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + } + delegate: ItemDelegate { + id: comboItemDelegate + width: comboBox.width + contentItem: Text { + text: name + color: theme.textColor + font: comboBox.font + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + background: Rectangle { + color: (index % 2 === 0 ? theme.darkContrast : theme.lightContrast) + border.width: highlighted + border.color: theme.accentColor + } + highlighted: comboBox.highlightedIndex === index + } + Accessible.role: Accessible.ComboBox + Accessible.name: currentModelName() + Accessible.description: qsTr("The top item is the current model") + onActivated: function (index) { + var newInfo = ModelList.modelInfo(comboBox.valueAt(index)); + if (newInfo === currentChat.modelInfo) { + currentChat.reloadModel(); + } else if (currentModelName() !== "" && chatModel.count !== 0) { + switchModelDialog.index = index; + switchModelDialog.open(); + } else { + comboBox.changeModel(index); + } + } - Accessible.name: qsTr("Add documents") - Accessible.description: qsTr("add collections of documents to the chat") - + MyMiniButton { + id: ejectButton + visible: currentChat.isModelLoaded && !window.isCurrentlyLoading + z: 500 + anchors.right: parent.right + anchors.rightMargin: 50 + anchors.verticalCenter: parent.verticalCenter + source: "qrc:/gpt4all/icons/eject.svg" + backgroundColor: theme.gray300 + backgroundColorHovered: theme.iconBackgroundLight onClicked: { - collectionsDialog.open() + currentChat.forceUnloadModel(); } + ToolTip.text: qsTr("Eject the currently loaded model") + ToolTip.visible: hovered + } + + MyMiniButton { + id: reloadButton + visible: currentChat.modelLoadingError === "" + && !window.trySwitchContextInProgress + && !window.isCurrentlyLoading + && (currentChat.isModelLoaded || currentModelName() !== "") + z: 500 + anchors.right: ejectButton.visible ? ejectButton.left : parent.right + anchors.rightMargin: ejectButton.visible ? 10 : 50 + anchors.verticalCenter: parent.verticalCenter + source: "qrc:/gpt4all/icons/regenerate.svg" + backgroundColor: theme.gray300 + backgroundColorHovered: theme.iconBackgroundLight + onClicked: { + if (currentChat.isModelLoaded) + currentChat.forceReloadModel(); + else + currentChat.reloadModel(); + } + ToolTip.text: qsTr("Reload the currently loaded model") + ToolTip.visible: hovered } } } } } + SettingsDialog { + id: settingsDialog + anchors.centerIn: parent + width: Math.min(1920, window.width - (window.width * .1)) + height: window.height - (window.height * .1) + onDownloadClicked: { + downloadNewModels.showEmbeddingModels = true + downloadNewModels.open() + } + } + + MyToolButton { + id: drawerButton + backgroundColor: theme.iconBackgroundLight + anchors.left: parent.left + anchors.top: parent.top + anchors.topMargin: 42.5 + anchors.leftMargin: 30 + width: 40 + height: 40 + scale: 1.5 + z: 200 + padding: 15 + source: conversation.state === "expanded" ? "qrc:/gpt4all/icons/left_panel_open.svg" : "qrc:/gpt4all/icons/left_panel_closed.svg" + Accessible.role: Accessible.ButtonMenu + Accessible.name: qsTr("Chat panel") + Accessible.description: qsTr("Chat panel with options") + onClicked: { + conversation.toggleLeftPanel() + } + } + + NetworkDialog { + id: networkDialog + anchors.centerIn: parent + width: Math.min(1024, window.width - (window.width * .2)) + height: Math.min(600, window.height - (window.height * .2)) + Item { + Accessible.role: Accessible.Dialog + Accessible.name: qsTr("Network dialog") + Accessible.description: qsTr("opt-in to share feedback/conversations") + } + } + + MyToolButton { + id: networkButton + backgroundColor: theme.iconBackgroundLight + anchors.right: parent.right + anchors.top: parent.top + anchors.topMargin: 42.5 + anchors.rightMargin: 30 + width: 40 + height: 40 + z: 200 + padding: 15 + toggled: MySettings.networkIsActive + source: "qrc:/gpt4all/icons/network.svg" + Accessible.name: qsTr("Network") + Accessible.description: qsTr("Reveals a dialogue where you can opt-in for sharing data over network") + + onClicked: { + if (MySettings.networkIsActive) { + MySettings.networkIsActive = false + Network.sendNetworkToggled(false); + } else + networkDialog.open() + } + } + Connections { target: Network function onHealthCheckFailed(code) { @@ -552,7 +564,49 @@ Rectangle { id: collectionsDialog anchors.centerIn: parent onAddRemoveClicked: { - settingsViewRequested(2 /*page 2*/) + settingsDialog.pageToDisplay = 2; + settingsDialog.open(); + } + } + + MyToolButton { + id: collectionsButton + backgroundColor: theme.iconBackgroundLight + anchors.right: networkButton.left + anchors.top: parent.top + anchors.topMargin: 42.5 + anchors.rightMargin: 10 + width: 40 + height: 42.5 + z: 200 + padding: 15 + toggled: currentChat.collectionList.length + source: "qrc:/gpt4all/icons/db.svg" + Accessible.name: qsTr("Add documents") + Accessible.description: qsTr("add collections of documents to the chat") + + onClicked: { + collectionsDialog.open() + } + } + + MyToolButton { + id: settingsButton + backgroundColor: theme.iconBackgroundLight + anchors.right: collectionsButton.left + anchors.top: parent.top + anchors.topMargin: 42.5 + anchors.rightMargin: 10 + width: 40 + height: 40 + z: 200 + padding: 15 + source: "qrc:/gpt4all/icons/settings.svg" + Accessible.name: qsTr("Settings") + Accessible.description: qsTr("Reveals a dialogue with settings") + + onClicked: { + settingsDialog.open() } } @@ -596,6 +650,35 @@ Rectangle { } } + MyToolButton { + id: copyButton + backgroundColor: theme.iconBackgroundLight + anchors.right: settingsButton.left + anchors.top: parent.top + anchors.topMargin: 42.5 + anchors.rightMargin: 10 + width: 40 + height: 40 + z: 200 + padding: 15 + source: "qrc:/gpt4all/icons/copy.svg" + Accessible.name: qsTr("Copy") + Accessible.description: qsTr("Copy the conversation to the clipboard") + + TextEdit{ + id: copyEdit + visible: false + } + + onClicked: { + var conversation = getConversation() + copyEdit.text = conversation + copyEdit.selectAll() + copyEdit.copy() + copyMessage.open() + } + } + function getConversation() { var conversation = ""; for (var i = 0; i < chatModel.count; i++) { @@ -633,6 +716,29 @@ Rectangle { return str + "]}" } + MyToolButton { + id: resetContextButton + backgroundColor: theme.iconBackgroundLight + anchors.right: copyButton.left + anchors.top: parent.top + anchors.topMargin: 42.5 + anchors.rightMargin: 10 + width: 40 + height: 40 + z: 200 + padding: 15 + source: "qrc:/gpt4all/icons/regenerate.svg" + + Accessible.name: text + Accessible.description: qsTr("Reset the context and erase current conversation") + + onClicked: { + Network.sendResetContext(chatModel.count) + currentChat.reset(); + currentChat.processSystemPrompt(); + } + } + Dialog { id: checkForUpdatesError anchors.centerIn: parent @@ -662,12 +768,31 @@ Rectangle { } } + ModelDownloaderDialog { + id: downloadNewModels + anchors.centerIn: parent + width: Math.min(1920, window.width - (window.width * .1)) + height: window.height - (window.height * .1) + Item { + Accessible.role: Accessible.Dialog + Accessible.name: qsTr("Download new models") + Accessible.description: qsTr("Dialog for downloading new models") + } + } + ChatDrawer { id: drawer anchors.left: parent.left anchors.top: accentRibbon.bottom anchors.bottom: parent.bottom - width: Math.max(180, Math.min(600, 0.2 * window.width)) + width: Math.min(600, 0.2 * window.width) + onDownloadClicked: { + downloadNewModels.showEmbeddingModels = false + downloadNewModels.open() + } + onAboutClicked: { + aboutDialog.open() + } } PopupDialog { @@ -847,7 +972,7 @@ Rectangle { padding: 18 leftPadding: 50 Image { - id: downloadImage + id: image anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: 15 @@ -857,13 +982,12 @@ Rectangle { source: "qrc:/gpt4all/icons/download.svg" } ColorOverlay { - anchors.fill: downloadImage - source: downloadImage + anchors.fill: image + source: image color: theme.accentColor } onClicked: { - console.log("download button") - downloadViewRequested(false /*showEmbeddingModels*/); + downloadNewModels.open(); } } } @@ -872,7 +996,10 @@ Rectangle { ListView { id: listView visible: ModelList.installedModels.count !== 0 && chatModel.count !== 0 - anchors.fill: parent + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + width: Math.min(1280, parent.width) model: chatModel ScrollBar.vertical: ScrollBar { @@ -886,8 +1013,7 @@ Rectangle { delegate: TextArea { id: myTextArea text: value + (MySettings.localDocsShowReferences ? references : "") - anchors.horizontalCenter: listView.contentItem.horizontalCenter - width: Math.min(1280, listView.contentItem.width) + width: listView.width color: { if (!currentChat.isServer) return theme.textColor diff --git a/gpt4all-chat/qml/ModelDownloaderView.qml b/gpt4all-chat/qml/ModelDownloaderDialog.qml similarity index 98% rename from gpt4all-chat/qml/ModelDownloaderView.qml rename to gpt4all-chat/qml/ModelDownloaderDialog.qml index bd8a640c..acbb6290 100644 --- a/gpt4all-chat/qml/ModelDownloaderView.qml +++ b/gpt4all-chat/qml/ModelDownloaderDialog.qml @@ -11,15 +11,21 @@ import modellist import network import mysettings -Rectangle { +MyDialog { id: modelDownloaderDialog - color: theme.containerBackground + modal: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + padding: 10 + property bool showEmbeddingModels: false - function showEmbeddingModels() { + onOpened: { Network.sendModelDownloaderDialog(); - ModelList.downloadableModels.expanded = true - var targetModelIndex = ModelList.defaultEmbeddingModelIndex - modelListView.positionViewAtIndex(targetModelIndex, ListView.Beginning) + + if (showEmbeddingModels) { + ModelList.downloadableModels.expanded = true + var targetModelIndex = ModelList.defaultEmbeddingModelIndex + modelListView.positionViewAtIndex(targetModelIndex, ListView.Beginning) + } } PopupDialog { @@ -30,7 +36,7 @@ Rectangle { ColumnLayout { anchors.fill: parent - anchors.margins: 20 + anchors.margins: 10 spacing: 30 Label { diff --git a/gpt4all-chat/qml/MyToolButton.qml b/gpt4all-chat/qml/MyToolButton.qml index ec7196f8..2e79e37b 100644 --- a/gpt4all-chat/qml/MyToolButton.qml +++ b/gpt4all-chat/qml/MyToolButton.qml @@ -9,8 +9,6 @@ Button { padding: 10 property color backgroundColor: theme.iconBackgroundDark property color backgroundColorHovered: theme.iconBackgroundHovered - property color toggledColor: theme.accentColor - property real toggledWidth: 1 property bool toggled: false property alias source: image.source property alias fillMode: image.fillMode @@ -27,12 +25,11 @@ Button { anchors.fill: parent Rectangle { anchors.fill: parent - color: myButton.toggledColor + color: "transparent" visible: myButton.toggled - border.color: myButton.toggledColor - border.width: myButton.toggledWidth - radius: 6 - opacity: .2 + border.color: theme.accentColor + border.width: 1 + radius: 10 } Image { id: image diff --git a/gpt4all-chat/qml/SettingsDialog.qml b/gpt4all-chat/qml/SettingsDialog.qml new file mode 100644 index 00000000..ec8cdb4a --- /dev/null +++ b/gpt4all-chat/qml/SettingsDialog.qml @@ -0,0 +1,132 @@ +import QtCore +import QtQuick +import QtQuick.Controls +import QtQuick.Controls.Basic +import QtQuick.Dialogs +import QtQuick.Layouts +import Qt.labs.folderlistmodel +import download +import modellist +import network +import llm +import mysettings + +MyDialog { + id: settingsDialog + modal: true + padding: 20 + onOpened: { + Network.sendSettingsDialog(); + } + + signal downloadClicked + property alias pageToDisplay: listView.currentIndex + + Item { + Accessible.role: Accessible.Dialog + Accessible.name: qsTr("Settings") + Accessible.description: qsTr("Contains various application settings") + } + + ListModel { + id: stacksModel + ListElement { + title: qsTr("Models") + } + ListElement { + title: qsTr("Application") + } + ListElement { + title: qsTr("LocalDocs") + } + } + + Rectangle { + id: stackList + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + width: 220 + color: theme.controlBackground + radius: 10 + + ScrollView { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 10 + ScrollBar.vertical.policy: ScrollBar.AsNeeded + clip: true + + ListView { + id: listView + anchors.fill: parent + model: stacksModel + + delegate: Rectangle { + id: item + width: listView.width + height: titleLabel.height + 10 + color: "transparent" + + MyButton { + id: titleLabel + backgroundColor: index === listView.currentIndex ? theme.buttonBackground : theme.controlBackground + backgroundColorHovered: index === listView.currentIndex ? backgroundColor : theme.containerBackground + borderColor: index === listView.currentIndex ? theme.accentColor : "transparent" + borderWidth: index === listView.currentIndex ? 1 : 0 + textColor: index === listView.currentIndex ? theme.oppositeTextColor : theme.titleTextColor + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 10 + font.bold: index === listView.currentIndex + text: title + font.pixelSize: theme.fontSizeLarge + onClicked: { + listView.currentIndex = index + } + } + } + } + } + } + + StackLayout { + id: stackLayout + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: stackList.right + anchors.right: parent.right + currentIndex: listView.currentIndex + + MySettingsStack { + title: qsTr("Model/Character Settings") + tabs: [ + Component { ModelSettings { } } + ] + } + + MySettingsStack { + title: qsTr("Application General Settings") + tabs: [ + Component { ApplicationSettings { } } + ] + } + + MySettingsStack { + title: qsTr("Local Document Collections") + tabs: [ + Component { + LocalDocsSettings { + id: localDocsSettings + Component.onCompleted: { + localDocsSettings.downloadClicked.connect(settingsDialog.downloadClicked); + } + } + } + ] + } + } +} diff --git a/gpt4all-chat/qml/SettingsView.qml b/gpt4all-chat/qml/SettingsView.qml deleted file mode 100644 index b1bbf341..00000000 --- a/gpt4all-chat/qml/SettingsView.qml +++ /dev/null @@ -1,132 +0,0 @@ -import QtCore -import QtQuick -import QtQuick.Controls -import QtQuick.Controls.Basic -import QtQuick.Dialogs -import QtQuick.Layouts -import Qt.labs.folderlistmodel -import download -import modellist -import network -import llm -import mysettings - -Rectangle { - id: settingsDialog - color: theme.containerBackground - - signal downloadClicked - property alias pageToDisplay: listView.currentIndex - - Item { - Accessible.role: Accessible.Dialog - Accessible.name: qsTr("Settings") - Accessible.description: qsTr("Contains various application settings") - } - - ListModel { - id: stacksModel - ListElement { - title: qsTr("Models") - } - ListElement { - title: qsTr("Application") - } - ListElement { - title: qsTr("LocalDocs") - } - } - - Item { - anchors.fill: parent - anchors.margins: 20 - Rectangle { - id: stackList - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: parent.left - width: 220 - color: theme.controlBackground - radius: 10 - - ScrollView { - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 10 - ScrollBar.vertical.policy: ScrollBar.AsNeeded - clip: true - - ListView { - id: listView - anchors.fill: parent - model: stacksModel - - delegate: Rectangle { - id: item - width: listView.width - height: titleLabel.height + 10 - color: "transparent" - - MyButton { - id: titleLabel - backgroundColor: index === listView.currentIndex ? theme.buttonBackground : theme.controlBackground - backgroundColorHovered: index === listView.currentIndex ? backgroundColor : theme.containerBackground - borderColor: index === listView.currentIndex ? theme.accentColor : "transparent" - borderWidth: index === listView.currentIndex ? 1 : 0 - textColor: index === listView.currentIndex ? theme.oppositeTextColor : theme.titleTextColor - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: 10 - font.bold: index === listView.currentIndex - text: title - font.pixelSize: theme.fontSizeLarge - onClicked: { - listView.currentIndex = index - } - } - } - } - } - } - - StackLayout { - id: stackLayout - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: stackList.right - anchors.right: parent.right - currentIndex: listView.currentIndex - - MySettingsStack { - title: qsTr("Model/Character Settings") - tabs: [ - Component { ModelSettings { } } - ] - } - - MySettingsStack { - title: qsTr("Application General Settings") - tabs: [ - Component { ApplicationSettings { } } - ] - } - - MySettingsStack { - title: qsTr("Local Document Collections") - tabs: [ - Component { - LocalDocsSettings { - id: localDocsSettings - Component.onCompleted: { - localDocsSettings.downloadClicked.connect(settingsDialog.downloadClicked); - } - } - } - ] - } - } - } -} diff --git a/gpt4all-chat/qml/Theme.qml b/gpt4all-chat/qml/Theme.qml index 6768dacb..2b8c9733 100644 --- a/gpt4all-chat/qml/Theme.qml +++ b/gpt4all-chat/qml/Theme.qml @@ -200,17 +200,6 @@ QtObject { } } - property color viewBarBackground: { - switch (MySettings.chatTheme) { - case "LegacyDark": - return blue950; - case "Dark": - return darkgray300; - default: - return gray300; - } - } - property color progressForeground: { switch (MySettings.chatTheme) { case "LegacyDark": @@ -387,39 +376,6 @@ QtObject { } } - property color iconBackgroundViewBar: { - switch (MySettings.chatTheme) { - case "LegacyDark": - return iconBackgroundLight; - case "Dark": - return iconBackgroundLight; - default: - return green600; - } - } - - property color iconBackgroundViewBarToggled: { - switch (MySettings.chatTheme) { - case "LegacyDark": - return iconBackgroundHovered; - case "Dark": - return green400; - default: - return green950; - } - } - - property color iconBackgroundViewBarHovered: { - switch (MySettings.chatTheme) { - case "LegacyDark": - return iconBackgroundHovered; - case "Dark": - return iconBackgroundHovered; - default: - return green950; - } - } - property color slugBackground: { switch (MySettings.chatTheme) { case "LegacyDark":