mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-09-03 01:24:53 +00:00
chat: major UI redesign for v3.0.0 (#2396)
Signed-off-by: Adam Treat <treat.adam@gmail.com> Signed-off-by: Jared Van Bortel <jared@nomic.ai> Co-authored-by: Jared Van Bortel <jared@nomic.ai>
This commit is contained in:
@@ -10,14 +10,15 @@ import download
|
||||
import modellist
|
||||
import network
|
||||
import gpt4all
|
||||
import localdocs
|
||||
import mysettings
|
||||
|
||||
Window {
|
||||
id: window
|
||||
width: 1920
|
||||
height: 1080
|
||||
minimumWidth: 720
|
||||
minimumHeight: 480
|
||||
minimumWidth: 1280
|
||||
minimumHeight: 720
|
||||
visible: true
|
||||
title: qsTr("GPT4All v") + Qt.application.version
|
||||
|
||||
@@ -32,6 +33,128 @@ Window {
|
||||
id: theme
|
||||
}
|
||||
|
||||
Item {
|
||||
Accessible.role: Accessible.Window
|
||||
Accessible.name: title
|
||||
}
|
||||
|
||||
// Startup code
|
||||
Component.onCompleted: {
|
||||
startupDialogs();
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
Network.trackEvent("session_end")
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: firstStartDialog
|
||||
function onClosed() {
|
||||
startupDialogs();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Download
|
||||
function onHasNewerReleaseChanged() {
|
||||
startupDialogs();
|
||||
}
|
||||
}
|
||||
|
||||
property bool hasCheckedFirstStart: false
|
||||
property bool hasShownSettingsAccess: false
|
||||
|
||||
function startupDialogs() {
|
||||
if (!LLM.compatHardware()) {
|
||||
Network.trackEvent("noncompat_hardware")
|
||||
errorCompatHardware.open();
|
||||
return;
|
||||
}
|
||||
|
||||
// check if we have access to settings and if not show an error
|
||||
if (!hasShownSettingsAccess && !LLM.hasSettingsAccess()) {
|
||||
errorSettingsAccess.open();
|
||||
hasShownSettingsAccess = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// check for first time start of this version
|
||||
if (!hasCheckedFirstStart) {
|
||||
if (Download.isFirstStart(/*writeVersion*/ true)) {
|
||||
firstStartDialog.open();
|
||||
return;
|
||||
}
|
||||
|
||||
// send startup or opt-out now that the user has made their choice
|
||||
Network.sendStartup()
|
||||
// start localdocs
|
||||
LocalDocs.requestStart()
|
||||
|
||||
hasCheckedFirstStart = true
|
||||
}
|
||||
|
||||
// check for new version
|
||||
if (Download.hasNewerRelease && !firstStartDialog.opened) {
|
||||
newVersionDialog.open();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PopupDialog {
|
||||
id: errorCompatHardware
|
||||
anchors.centerIn: parent
|
||||
shouldTimeOut: false
|
||||
shouldShowBusy: false
|
||||
closePolicy: Popup.NoAutoClose
|
||||
modal: true
|
||||
text: qsTr("<h3>Encountered an error starting up:</h3><br>")
|
||||
+ qsTr("<i>\"Incompatible hardware detected.\"</i>")
|
||||
+ qsTr("<br><br>Unfortunately, your CPU does not meet the minimal requirements to run ")
|
||||
+ qsTr("this program. In particular, it does not support AVX intrinsics which this ")
|
||||
+ qsTr("program requires to successfully run a modern large language model. ")
|
||||
+ qsTr("The only solution at this time is to upgrade your hardware to a more modern CPU.")
|
||||
+ qsTr("<br><br>See here for more information: <a href=\"https://en.wikipedia.org/wiki/Advanced_Vector_Extensions\">")
|
||||
+ qsTr("https://en.wikipedia.org/wiki/Advanced_Vector_Extensions</a>")
|
||||
}
|
||||
|
||||
PopupDialog {
|
||||
id: errorSettingsAccess
|
||||
anchors.centerIn: parent
|
||||
shouldTimeOut: false
|
||||
shouldShowBusy: false
|
||||
modal: true
|
||||
text: qsTr("<h3>Encountered an error starting up:</h3><br>")
|
||||
+ qsTr("<i>\"Inability to access settings file.\"</i>")
|
||||
+ qsTr("<br><br>Unfortunately, something is preventing the program from accessing ")
|
||||
+ qsTr("the settings file. This could be caused by incorrect permissions in the local ")
|
||||
+ qsTr("app config directory where the settings file is located. ")
|
||||
+ qsTr("Check out our <a href=\"https://discord.gg/4M2QFmTt2k\">discord channel</a> for help.")
|
||||
}
|
||||
|
||||
StartupDialog {
|
||||
id: firstStartDialog
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
NewVersionDialog {
|
||||
id: newVersionDialog
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Network
|
||||
function onHealthCheckFailed(code) {
|
||||
healthCheckFailed.open();
|
||||
}
|
||||
}
|
||||
|
||||
PopupDialog {
|
||||
id: healthCheckFailed
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Connection to datalake failed.")
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
}
|
||||
|
||||
property bool hasSaved: false
|
||||
|
||||
PopupDialog {
|
||||
@@ -43,6 +166,18 @@ 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")
|
||||
}
|
||||
}
|
||||
|
||||
onClosing: function(close) {
|
||||
if (window.hasSaved)
|
||||
return;
|
||||
@@ -61,9 +196,440 @@ Window {
|
||||
}
|
||||
}
|
||||
|
||||
color: theme.black
|
||||
color: theme.viewBarBackground
|
||||
|
||||
ChatView {
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
id: viewBar
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
width: MySettings.fontSize === "Small" ? 86 : 100
|
||||
color: theme.viewBarBackground
|
||||
|
||||
ColumnLayout {
|
||||
id: viewsLayout
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 30
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
Layout.margins: 0
|
||||
spacing: 18
|
||||
|
||||
MyToolButton {
|
||||
id: homeButton
|
||||
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
|
||||
backgroundColorHovered: theme.iconBackgroundViewBarHovered
|
||||
Layout.preferredWidth: 48
|
||||
Layout.preferredHeight: 48
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
toggledWidth: 0
|
||||
toggled: homeView.isShown()
|
||||
toggledColor: theme.iconBackgroundViewBarToggled
|
||||
imageWidth: 34
|
||||
imageHeight: 34
|
||||
source: "qrc:/gpt4all/icons/home.svg"
|
||||
Accessible.name: qsTr("Home view")
|
||||
Accessible.description: qsTr("Home view of application")
|
||||
onClicked: {
|
||||
homeView.show()
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.topMargin: -20
|
||||
text: qsTr("Home")
|
||||
font.pixelSize: theme.fontSizeLargeCapped
|
||||
font.bold: true
|
||||
color: homeButton.hovered ? homeButton.backgroundColorHovered : homeButton.backgroundColor
|
||||
Layout.preferredWidth: 48
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
TapHandler {
|
||||
onTapped: function(eventPoint, button) {
|
||||
homeView.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MyToolButton {
|
||||
id: chatButton
|
||||
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
|
||||
backgroundColorHovered: theme.iconBackgroundViewBarHovered
|
||||
Layout.preferredWidth: 48
|
||||
Layout.preferredHeight: 48
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
toggledWidth: 0
|
||||
toggled: chatView.isShown()
|
||||
toggledColor: theme.iconBackgroundViewBarToggled
|
||||
imageWidth: 34
|
||||
imageHeight: 34
|
||||
source: "qrc:/gpt4all/icons/chat.svg"
|
||||
Accessible.name: qsTr("Chat view")
|
||||
Accessible.description: qsTr("Chat view to interact with models")
|
||||
onClicked: {
|
||||
chatView.show()
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.topMargin: -20
|
||||
text: qsTr("Chats")
|
||||
font.pixelSize: theme.fontSizeLargeCapped
|
||||
font.bold: true
|
||||
color: chatButton.hovered ? chatButton.backgroundColorHovered : chatButton.backgroundColor
|
||||
Layout.preferredWidth: 48
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
TapHandler {
|
||||
onTapped: function(eventPoint, button) {
|
||||
chatView.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MyToolButton {
|
||||
id: modelsButton
|
||||
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
|
||||
backgroundColorHovered: theme.iconBackgroundViewBarHovered
|
||||
Layout.preferredWidth: 48
|
||||
Layout.preferredHeight: 48
|
||||
toggledWidth: 0
|
||||
toggled: modelsView.isShown()
|
||||
toggledColor: theme.iconBackgroundViewBarToggled
|
||||
imageWidth: 34
|
||||
imageHeight: 34
|
||||
source: "qrc:/gpt4all/icons/models.svg"
|
||||
Accessible.name: qsTr("Models")
|
||||
Accessible.description: qsTr("Models view for installed models")
|
||||
onClicked: {
|
||||
modelsView.show()
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.topMargin: -20
|
||||
text: qsTr("Models")
|
||||
font.pixelSize: theme.fontSizeLargeCapped
|
||||
font.bold: true
|
||||
color: modelsButton.hovered ? modelsButton.backgroundColorHovered : modelsButton.backgroundColor
|
||||
Layout.preferredWidth: 48
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
TapHandler {
|
||||
onTapped: function(eventPoint, button) {
|
||||
modelsView.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MyToolButton {
|
||||
id: localdocsButton
|
||||
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
|
||||
backgroundColorHovered: theme.iconBackgroundViewBarHovered
|
||||
Layout.preferredWidth: 48
|
||||
Layout.preferredHeight: 48
|
||||
toggledWidth: 0
|
||||
toggledColor: theme.iconBackgroundViewBarToggled
|
||||
toggled: localDocsView.isShown()
|
||||
imageWidth: 34
|
||||
imageHeight: 34
|
||||
source: "qrc:/gpt4all/icons/db.svg"
|
||||
Accessible.name: qsTr("LocalDocs")
|
||||
Accessible.description: qsTr("LocalDocs view to configure and use local docs")
|
||||
onClicked: {
|
||||
localDocsView.show()
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.topMargin: -20
|
||||
text: qsTr("LocalDocs")
|
||||
font.pixelSize: theme.fontSizeLargeCapped
|
||||
font.bold: true
|
||||
color: localdocsButton.hovered ? localdocsButton.backgroundColorHovered : localdocsButton.backgroundColor
|
||||
Layout.preferredWidth: 48
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
TapHandler {
|
||||
onTapped: function(eventPoint, button) {
|
||||
localDocsView.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MyToolButton {
|
||||
id: settingsButton
|
||||
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
|
||||
backgroundColorHovered: theme.iconBackgroundViewBarHovered
|
||||
Layout.preferredWidth: 48
|
||||
Layout.preferredHeight: 48
|
||||
toggledWidth: 0
|
||||
toggledColor: theme.iconBackgroundViewBarToggled
|
||||
toggled: settingsView.isShown()
|
||||
imageWidth: 34
|
||||
imageHeight: 34
|
||||
source: "qrc:/gpt4all/icons/settings.svg"
|
||||
Accessible.name: qsTr("Settings")
|
||||
Accessible.description: qsTr("Settings view for application configuration")
|
||||
onClicked: {
|
||||
settingsView.show(0 /*pageToDisplay*/)
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.topMargin: -20
|
||||
text: qsTr("Settings")
|
||||
font.pixelSize: theme.fontSizeLargeCapped
|
||||
font.bold: true
|
||||
color: settingsButton.hovered ? settingsButton.backgroundColorHovered : settingsButton.backgroundColor
|
||||
Layout.preferredWidth: 48
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
TapHandler {
|
||||
onTapped: function(eventPoint, button) {
|
||||
settingsView.show(0 /*pageToDisplay*/)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: buttonsLayout
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 0
|
||||
anchors.bottomMargin: 25
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
Layout.margins: 0
|
||||
spacing: 22
|
||||
|
||||
Rectangle {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.preferredWidth: image.width
|
||||
Layout.preferredHeight: image.height
|
||||
color: "transparent"
|
||||
|
||||
Image {
|
||||
id: image
|
||||
anchors.centerIn: parent
|
||||
sourceSize: Qt.size(60, 40)
|
||||
fillMode: Image.PreserveAspectFit
|
||||
mipmap: true
|
||||
visible: false
|
||||
source: "qrc:/gpt4all/icons/nomic_logo.svg"
|
||||
}
|
||||
|
||||
ColorOverlay {
|
||||
anchors.fill: image
|
||||
source: image
|
||||
color: image.hovered ? theme.mutedDarkTextColorHovered : theme.mutedDarkTextColor
|
||||
TapHandler {
|
||||
onTapped: function(eventPoint, button) {
|
||||
Qt.openUrlExternally("https://nomic.ai")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: roundedFrame
|
||||
z: 299
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: viewBar.right
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 15
|
||||
anchors.bottomMargin: 15
|
||||
anchors.rightMargin: 15
|
||||
radius: 15
|
||||
border.width: 1
|
||||
border.color: theme.dividerColor
|
||||
color: "transparent"
|
||||
clip: true
|
||||
}
|
||||
|
||||
RectangularGlow {
|
||||
id: effect
|
||||
anchors.fill: roundedFrame
|
||||
glowRadius: 15
|
||||
spread: 0
|
||||
color: theme.dividerColor
|
||||
cornerRadius: 10
|
||||
opacity: 0.5
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
id: stackLayout
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: viewBar.right
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 15
|
||||
anchors.bottomMargin: 15
|
||||
anchors.rightMargin: 15
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Rectangle {
|
||||
width: roundedFrame.width
|
||||
height: roundedFrame.height
|
||||
radius: 15
|
||||
}
|
||||
}
|
||||
|
||||
HomeView {
|
||||
id: homeView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
shouldShowFirstStart: !hasCheckedFirstStart
|
||||
|
||||
function show() {
|
||||
stackLayout.currentIndex = 0;
|
||||
}
|
||||
|
||||
function isShown() {
|
||||
return stackLayout.currentIndex === 0
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: homeView
|
||||
function onChatViewRequested() {
|
||||
chatView.show();
|
||||
}
|
||||
function onLocalDocsViewRequested() {
|
||||
localDocsView.show();
|
||||
}
|
||||
function onAddModelViewRequested() {
|
||||
addModelView.show();
|
||||
}
|
||||
function onSettingsViewRequested(page) {
|
||||
settingsView.show(page);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChatView {
|
||||
id: chatView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
function show() {
|
||||
stackLayout.currentIndex = 1;
|
||||
}
|
||||
|
||||
function isShown() {
|
||||
return stackLayout.currentIndex === 1
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: chatView
|
||||
function onAddCollectionViewRequested() {
|
||||
addCollectionView.show();
|
||||
}
|
||||
function onAddModelViewRequested() {
|
||||
addModelView.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModelsView {
|
||||
id: modelsView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
function show() {
|
||||
stackLayout.currentIndex = 2;
|
||||
// FIXME This expanded code should be removed and we should be changing the names of
|
||||
// the classes here in ModelList for the proxy/filter models
|
||||
ModelList.downloadableModels.expanded = true
|
||||
}
|
||||
|
||||
function isShown() {
|
||||
return stackLayout.currentIndex === 2
|
||||
}
|
||||
|
||||
Item {
|
||||
Accessible.name: qsTr("Installed models")
|
||||
Accessible.description: qsTr("View of installed models")
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: modelsView
|
||||
function onAddModelViewRequested() {
|
||||
addModelView.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LocalDocsView {
|
||||
id: localDocsView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
function show() {
|
||||
stackLayout.currentIndex = 3;
|
||||
}
|
||||
|
||||
function isShown() {
|
||||
return stackLayout.currentIndex === 3
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: localDocsView
|
||||
function onAddCollectionViewRequested() {
|
||||
addCollectionView.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsView {
|
||||
id: settingsView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
function show(page) {
|
||||
settingsView.pageToDisplay = page;
|
||||
stackLayout.currentIndex = 4;
|
||||
}
|
||||
|
||||
function isShown() {
|
||||
return stackLayout.currentIndex === 4
|
||||
}
|
||||
}
|
||||
|
||||
AddCollectionView {
|
||||
id: addCollectionView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
function show() {
|
||||
stackLayout.currentIndex = 5;
|
||||
}
|
||||
function isShown() {
|
||||
return stackLayout.currentIndex === 5
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: addCollectionView
|
||||
function onLocalDocsViewRequested() {
|
||||
localDocsView.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddModelView {
|
||||
id: addModelView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
function show() {
|
||||
stackLayout.currentIndex = 6;
|
||||
}
|
||||
function isShown() {
|
||||
return stackLayout.currentIndex === 6
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: addModelView
|
||||
function onModelsViewRequested() {
|
||||
modelsView.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user