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:
AT
2024-06-24 18:49:23 -04:00
committed by GitHub
parent 1272b694ae
commit 9273b49b62
111 changed files with 8540 additions and 7879 deletions

View File

@@ -1,101 +0,0 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import download
import network
import llm
MyDialog {
id: abpoutDialog
anchors.centerIn: parent
modal: false
padding: 20
width: 1024
height: column.height + 40
Theme {
id: theme
}
Column {
id: column
spacing: 20
Item {
width: childrenRect.width
height: childrenRect.height
Image {
id: img
anchors.top: parent.top
anchors.left: parent.left
width: 60
height: 60
source: "qrc:/gpt4all/icons/logo.svg"
}
Text {
anchors.left: img.right
anchors.leftMargin: 30
anchors.verticalCenter: img.verticalCenter
text: qsTr("About GPT4All")
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
font.bold: true
}
}
ScrollView {
clip: true
height: 200
width: 1024 - 40
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
MyTextArea {
id: welcome
width: 1024 - 40
textFormat: TextEdit.MarkdownText
text: qsTr("### Release notes\n")
+ Download.releaseInfo.notes
+ qsTr("### Contributors\n")
+ Download.releaseInfo.contributors
focus: false
readOnly: true
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Release notes")
Accessible.description: qsTr("Release notes for this version")
}
}
MySettingsLabel {
id: discordLink
width: parent.width
textFormat: Text.StyledText
wrapMode: Text.WordWrap
text: qsTr("Check out our discord channel <a href=\"https://discord.gg/4M2QFmTt2k\">https://discord.gg/4M2QFmTt2k</a>")
font.pixelSize: theme.fontSizeLarge
onLinkActivated: { Qt.openUrlExternally("https://discord.gg/4M2QFmTt2k") }
color: theme.textColor
linkColor: theme.linkColor
Accessible.role: Accessible.Link
Accessible.name: qsTr("Discord link")
}
MySettingsLabel {
id: nomicProps
width: parent.width
textFormat: Text.StyledText
wrapMode: Text.WordWrap
text: qsTr("Thank you to <a href=\"https://home.nomic.ai\">Nomic AI</a> and the community for contributing so much great data, code, ideas, and energy to the growing open source AI ecosystem!")
font.pixelSize: theme.fontSizeLarge
onLinkActivated: { Qt.openUrlExternally("https://home.nomic.ai") }
color: theme.textColor
linkColor: theme.linkColor
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Thank you blurb")
Accessible.description: qsTr("Contains embedded link to https://home.nomic.ai")
}
}
}

View File

@@ -0,0 +1,170 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import QtQuick.Dialogs
import Qt.labs.folderlistmodel
import Qt5Compat.GraphicalEffects
import llm
import chatlistmodel
import download
import modellist
import network
import gpt4all
import mysettings
import localdocs
Rectangle {
id: addCollectionView
Theme {
id: theme
}
color: theme.viewBackground
signal localDocsViewRequested()
ColumnLayout {
id: mainArea
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.margins: 30
spacing: 50
RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
spacing: 50
MyButton {
id: backButton
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
text: qsTr("\u2190 Existing Collections")
borderWidth: 0
backgroundColor: theme.lighterButtonBackground
backgroundColorHovered: theme.lighterButtonBackgroundHovered
backgroundRadius: 5
padding: 15
topPadding: 8
bottomPadding: 8
textColor: theme.lighterButtonForeground
fontPixelSize: theme.fontSizeLarge
fontPixelBold: true
onClicked: {
localDocsViewRequested()
}
}
}
ColumnLayout {
id: root
Layout.alignment: Qt.AlignTop | Qt.AlignCenter
spacing: 50
property alias collection: collection.text
property alias folder_path: folderEdit.text
FolderDialog {
id: folderDialog
title: qsTr("Please choose a directory")
}
function openFolderDialog(currentFolder, onAccepted) {
folderDialog.currentFolder = currentFolder;
folderDialog.accepted.connect(function() { onAccepted(folderDialog.currentFolder); });
folderDialog.open();
}
Text {
horizontalAlignment: Qt.AlignHCenter
text: qsTr("New Local Doc\nCollection")
font.pixelSize: theme.fontSizeBanner
color: theme.titleTextColor
}
MyTextField {
id: collection
Layout.alignment: Qt.AlignCenter
Layout.minimumWidth: 400
horizontalAlignment: Text.AlignJustify
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
placeholderText: qsTr("Collection name...")
placeholderTextColor: theme.mutedTextColor
ToolTip.text: qsTr("Name of the collection to add (Required)")
ToolTip.visible: hovered
Accessible.role: Accessible.EditableText
Accessible.name: collection.text
Accessible.description: ToolTip.text
function showError() {
collection.placeholderTextColor = theme.textErrorColor
}
onTextChanged: {
collection.placeholderTextColor = theme.mutedTextColor
}
}
RowLayout {
Layout.alignment: Qt.AlignCenter
Layout.minimumWidth: 400
Layout.maximumWidth: 400
spacing: 10
MyDirectoryField {
id: folderEdit
Layout.fillWidth: true
text: root.folder_path
placeholderText: qsTr("Folder path...")
font.pixelSize: theme.fontSizeLarge
placeholderTextColor: theme.mutedTextColor
ToolTip.text: qsTr("Folder path to documents (Required)")
ToolTip.visible: hovered
function showError() {
folderEdit.placeholderTextColor = theme.textErrorColor
}
onTextChanged: {
folderEdit.placeholderTextColor = theme.mutedTextColor
}
}
MySettingsButton {
id: browseButton
text: qsTr("Browse")
onClicked: {
root.openFolderDialog(StandardPaths.writableLocation(StandardPaths.HomeLocation), function(selectedFolder) {
root.folder_path = selectedFolder
})
}
}
}
MyButton {
Layout.alignment: Qt.AlignCenter
Layout.minimumWidth: 400
text: qsTr("Create Collection")
onClicked: {
var isError = false;
if (root.collection === "") {
isError = true;
collection.showError();
}
if (root.folder_path === "" || !folderEdit.isValid) {
isError = true;
folderEdit.showError();
}
if (isError)
return;
LocalDocs.addFolder(root.collection, root.folder_path)
root.collection = ""
root.folder_path = ""
collection.clear()
localDocsViewRequested()
}
}
}
}
}

View File

@@ -0,0 +1,726 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import QtQuick.Dialogs
import Qt.labs.folderlistmodel
import Qt5Compat.GraphicalEffects
import llm
import chatlistmodel
import download
import modellist
import network
import gpt4all
import mysettings
import localdocs
Rectangle {
id: addModelView
Theme {
id: theme
}
color: theme.viewBackground
signal modelsViewRequested()
PopupDialog {
id: downloadingErrorPopup
anchors.centerIn: parent
shouldTimeOut: false
}
ColumnLayout {
id: mainArea
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.margins: 30
spacing: 50
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
spacing: 50
MyButton {
id: backButton
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
text: qsTr("\u2190 Existing Models")
borderWidth: 0
backgroundColor: theme.lighterButtonBackground
backgroundColorHovered: theme.lighterButtonBackgroundHovered
backgroundRadius: 5
padding: 15
topPadding: 8
bottomPadding: 8
textColor: theme.lighterButtonForeground
fontPixelSize: theme.fontSizeLarge
fontPixelBold: true
onClicked: {
modelsViewRequested()
}
}
Text {
id: welcome
text: qsTr("Explore Models")
font.pixelSize: theme.fontSizeBanner
color: theme.titleTextColor
}
RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
Layout.margins: 0
spacing: 10
MyTextField {
id: discoverField
property string textBeingSearched: ""
readOnly: ModelList.discoverInProgress
Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
Layout.preferredHeight: 90
font.pixelSize: theme.fontSizeLarger
placeholderText: qsTr("Discover and download models by keyword search...")
Accessible.role: Accessible.EditableText
Accessible.name: placeholderText
Accessible.description: qsTr("Text field for discovering and filtering downloadable models")
Connections {
target: ModelList
function onDiscoverInProgressChanged() {
if (ModelList.discoverInProgress) {
discoverField.textBeingSearched = discoverField.text;
discoverField.text = qsTr("Searching \u00B7 ") + discoverField.textBeingSearched;
} else {
discoverField.text = discoverField.textBeingSearched;
discoverField.textBeingSearched = "";
}
}
}
background: ProgressBar {
id: discoverProgressBar
indeterminate: ModelList.discoverInProgress && ModelList.discoverProgress === 0.0
value: ModelList.discoverProgress
background: Rectangle {
color: theme.controlBackground
border.color: theme.controlBorder
radius: 10
}
contentItem: Item {
Rectangle {
visible: ModelList.discoverInProgress
anchors.bottom: parent.bottom
width: discoverProgressBar.visualPosition * parent.width
height: 10
radius: 2
color: theme.progressForeground
}
}
}
Keys.onReturnPressed: (event)=> {
if (event.modifiers & Qt.ControlModifier || event.modifiers & Qt.ShiftModifier)
event.accepted = false;
else {
editingFinished();
sendDiscovery()
}
}
function sendDiscovery() {
ModelList.downloadableModels.discoverAndFilter(discoverField.text);
}
RowLayout {
spacing: 0
anchors.right: discoverField.right
anchors.verticalCenter: discoverField.verticalCenter
anchors.rightMargin: 15
visible: !ModelList.discoverInProgress
MyMiniButton {
id: clearDiscoverButton
backgroundColor: theme.textColor
backgroundColorHovered: theme.iconBackgroundDark
visible: discoverField.text !== ""
contentItem: Text {
color: clearDiscoverButton.hovered ? theme.iconBackgroundDark : theme.textColor
text: "\u2715"
font.pixelSize: theme.fontSizeLarge
}
onClicked: {
discoverField.text = ""
discoverField.sendDiscovery() // should clear results
}
}
MyMiniButton {
backgroundColor: theme.textColor
backgroundColorHovered: theme.iconBackgroundDark
source: "qrc:/gpt4all/icons/settings.svg"
onClicked: {
discoveryTools.visible = !discoveryTools.visible
}
}
MyMiniButton {
id: sendButton
enabled: !ModelList.discoverInProgress
backgroundColor: theme.textColor
backgroundColorHovered: theme.iconBackgroundDark
source: "qrc:/gpt4all/icons/send_message.svg"
Accessible.name: qsTr("Initiate model discovery and filtering")
Accessible.description: qsTr("Triggers discovery and filtering of models")
onClicked: {
discoverField.sendDiscovery()
}
}
}
}
}
RowLayout {
id: discoveryTools
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
Layout.margins: 0
spacing: 20
visible: false
MyComboBox {
id: comboSort
model: [qsTr("Default"), qsTr("Likes"), qsTr("Downloads"), qsTr("Recent")]
currentIndex: ModelList.discoverSort
contentItem: Text {
anchors.horizontalCenter: parent.horizontalCenter
rightPadding: 30
color: theme.textColor
text: {
return qsTr("Sort by: ") + comboSort.displayText
}
font.pixelSize: theme.fontSizeLarger
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
}
onActivated: function (index) {
ModelList.discoverSort = index;
}
}
MyComboBox {
id: comboSortDirection
model: [qsTr("Asc"), qsTr("Desc")]
currentIndex: {
if (ModelList.discoverSortDirection === 1)
return 0
else
return 1;
}
contentItem: Text {
anchors.horizontalCenter: parent.horizontalCenter
rightPadding: 30
color: theme.textColor
text: {
return qsTr("Sort dir: ") + comboSortDirection.displayText
}
font.pixelSize: theme.fontSizeLarger
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
}
onActivated: function (index) {
if (index === 0)
ModelList.discoverSortDirection = 1;
else
ModelList.discoverSortDirection = -1;
}
}
MyComboBox {
id: comboLimit
model: ["5", "10", "20", "50", "100", qsTr("None")]
currentIndex: {
if (ModelList.discoverLimit === 5)
return 0;
else if (ModelList.discoverLimit === 10)
return 1;
else if (ModelList.discoverLimit === 20)
return 2;
else if (ModelList.discoverLimit === 50)
return 3;
else if (ModelList.discoverLimit === 100)
return 4;
else if (ModelList.discoverLimit === -1)
return 5;
}
contentItem: Text {
anchors.horizontalCenter: parent.horizontalCenter
rightPadding: 30
color: theme.textColor
text: {
return qsTr("Limit: ") + comboLimit.displayText
}
font.pixelSize: theme.fontSizeLarger
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
}
onActivated: function (index) {
switch (index) {
case 0:
ModelList.discoverLimit = 5; break;
case 1:
ModelList.discoverLimit = 10; break;
case 2:
ModelList.discoverLimit = 20; break;
case 3:
ModelList.discoverLimit = 50; break;
case 4:
ModelList.discoverLimit = 100; break;
case 5:
ModelList.discoverLimit = -1; break;
}
}
}
}
}
Label {
visible: !ModelList.downloadableModels.count && !ModelList.asyncModelRequestOngoing
Layout.fillWidth: true
Layout.fillHeight: true
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
text: qsTr("Network error: could not retrieve http://gpt4all.io/models/models3.json")
font.pixelSize: theme.fontSizeLarge
color: theme.mutedTextColor
}
MyBusyIndicator {
visible: !ModelList.downloadableModels.count && ModelList.asyncModelRequestOngoing
running: ModelList.asyncModelRequestOngoing
Accessible.role: Accessible.Animation
Layout.alignment: Qt.AlignCenter
Accessible.name: qsTr("Busy indicator")
Accessible.description: qsTr("Displayed when the models request is ongoing")
}
ScrollView {
id: scrollView
ScrollBar.vertical.policy: ScrollBar.AsNeeded
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
ListView {
id: modelListView
model: ModelList.downloadableModels
boundsBehavior: Flickable.StopAtBounds
spacing: 30
delegate: Rectangle {
id: delegateItem
width: modelListView.width
height: childrenRect.height + 60
color: theme.conversationBackground
radius: 10
border.width: 1
border.color: theme.controlBorder
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 30
Text {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
text: name
elide: Text.ElideRight
color: theme.titleTextColor
font.pixelSize: theme.fontSizeLargest
font.bold: true
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Model file")
Accessible.description: qsTr("Model file to be downloaded")
}
Rectangle {
Layout.fillWidth: true
height: 1
color: theme.dividerColor
}
RowLayout {
Layout.topMargin: 10
Layout.fillWidth: true
Text {
id: descriptionText
text: description
font.pixelSize: theme.fontSizeLarge
Layout.fillWidth: true
wrapMode: Text.WordWrap
textFormat: Text.StyledText
color: theme.textColor
linkColor: theme.textColor
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Description")
Accessible.description: qsTr("File description")
onLinkActivated: Qt.openUrlExternally(link)
}
// FIXME Need to overhaul design here which must take into account
// features not present in current figma including:
// * Ability to cancel a current download
// * Ability to resume a download
// * The presentation of an error if encountered
// * Whether to show already installed models
// * Install of remote models with API keys
// * The presentation of the progress bar
Rectangle {
id: actionBox
width: childrenRect.width + 20
color: "transparent"
border.width: 1
border.color: theme.dividerColor
radius: 10
Layout.rightMargin: 20
Layout.bottomMargin: 20
Layout.minimumHeight: childrenRect.height + 20
Layout.alignment: Qt.AlignRight | Qt.AlignTop
ColumnLayout {
spacing: 0
MySettingsButton {
id: downloadButton
text: isDownloading ? qsTr("Cancel") : isIncomplete ? qsTr("Resume") : qsTr("Download")
font.pixelSize: theme.fontSizeLarge
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.minimumWidth: 200
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
visible: !isOnline && !installed && !calcHash && downloadError === ""
Accessible.description: qsTr("Stop/restart/start the download")
onClicked: {
if (!isDownloading) {
Download.downloadModel(filename);
} else {
Download.cancelDownload(filename);
}
}
}
MySettingsDestructiveButton {
id: removeButton
text: qsTr("Remove")
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.minimumWidth: 200
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
visible: installed || downloadError !== ""
Accessible.description: qsTr("Remove model from filesystem")
onClicked: {
Download.removeModel(filename);
}
}
MySettingsButton {
id: installButton
visible: !installed && isOnline
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.minimumWidth: 200
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
text: qsTr("Install")
font.pixelSize: theme.fontSizeLarge
onClicked: {
if (apiKey.text === "")
apiKey.showError();
else
Download.installModel(filename, apiKey.text);
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Install")
Accessible.description: qsTr("Install online model")
}
ColumnLayout {
spacing: 0
Label {
Layout.topMargin: 20
Layout.leftMargin: 20
visible: downloadError !== ""
textFormat: Text.StyledText
text: "<strong><font size=\"1\">"
+ qsTr("<a href=\"#error\">Error</a>")
+ "</strong></font>"
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
linkColor: theme.textErrorColor
Accessible.role: Accessible.Paragraph
Accessible.name: text
Accessible.description: qsTr("Describes an error that occurred when downloading")
onLinkActivated: {
downloadingErrorPopup.text = downloadError;
downloadingErrorPopup.open();
}
}
Label {
visible: LLM.systemTotalRAMInGB() < ramrequired
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.maximumWidth: 300
textFormat: Text.StyledText
text: qsTr("<strong><font size=\"2\">WARNING: Not recommended for your hardware.")
+ qsTr(" Model requires more memory (") + ramrequired
+ qsTr(" GB) than your system has available (")
+ LLM.systemTotalRAMInGBString() + ").</strong></font>"
color: theme.textErrorColor
font.pixelSize: theme.fontSizeLarge
wrapMode: Text.WordWrap
Accessible.role: Accessible.Paragraph
Accessible.name: text
Accessible.description: qsTr("Error for incompatible hardware")
onLinkActivated: {
downloadingErrorPopup.text = downloadError;
downloadingErrorPopup.open();
}
}
}
ColumnLayout {
visible: isDownloading && !calcHash
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.minimumWidth: 200
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
spacing: 20
ProgressBar {
id: itemProgressBar
Layout.fillWidth: true
width: 200
value: bytesReceived / bytesTotal
background: Rectangle {
implicitHeight: 45
color: theme.progressBackground
radius: 3
}
contentItem: Item {
implicitHeight: 40
Rectangle {
width: itemProgressBar.visualPosition * parent.width
height: parent.height
radius: 2
color: theme.progressForeground
}
}
Accessible.role: Accessible.ProgressBar
Accessible.name: qsTr("Download progressBar")
Accessible.description: qsTr("Shows the progress made in the download")
}
Label {
id: speedLabel
color: theme.textColor
Layout.alignment: Qt.AlignRight
text: speed
font.pixelSize: theme.fontSizeLarge
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Download speed")
Accessible.description: qsTr("Download speed in bytes/kilobytes/megabytes per second")
}
}
RowLayout {
visible: calcHash
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.minimumWidth: 200
Layout.maximumWidth: 200
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
clip: true
Label {
id: calcHashLabel
color: theme.textColor
text: qsTr("Calculating...")
font.pixelSize: theme.fontSizeLarge
Accessible.role: Accessible.Paragraph
Accessible.name: text
Accessible.description: qsTr("Whether the file hash is being calculated")
}
MyBusyIndicator {
id: busyCalcHash
running: calcHash
Accessible.role: Accessible.Animation
Accessible.name: qsTr("Busy indicator")
Accessible.description: qsTr("Displayed when the file hash is being calculated")
}
}
MyTextField {
id: apiKey
visible: !installed && isOnline
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.minimumWidth: 200
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
wrapMode: Text.WrapAnywhere
function showError() {
apiKey.placeholderTextColor = theme.textErrorColor
}
onTextChanged: {
apiKey.placeholderTextColor = theme.mutedTextColor
}
placeholderText: qsTr("enter $API_KEY")
Accessible.role: Accessible.EditableText
Accessible.name: placeholderText
Accessible.description: qsTr("Whether the file hash is being calculated")
}
}
}
}
Item {
Layout.minimumWidth: childrenRect.width
Layout.minimumHeight: childrenRect.height
Layout.bottomMargin: 10
RowLayout {
id: paramRow
anchors.centerIn: parent
ColumnLayout {
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.leftMargin: 20
Layout.rightMargin: 20
Text {
text: qsTr("File size")
font.pixelSize: theme.fontSizeSmaller
color: theme.mutedDarkTextColor
}
Text {
text: filesize
color: theme.textColor
font.pixelSize: theme.fontSizeSmaller
font.bold: true
}
}
Rectangle {
width: 1
Layout.fillHeight: true
color: theme.dividerColor
}
ColumnLayout {
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.leftMargin: 20
Layout.rightMargin: 20
Text {
text: qsTr("RAM required")
font.pixelSize: theme.fontSizeSmaller
color: theme.mutedDarkTextColor
}
Text {
text: ramrequired + qsTr(" GB")
color: theme.textColor
font.pixelSize: theme.fontSizeSmaller
font.bold: true
}
}
Rectangle {
width: 1
Layout.fillHeight: true
color: theme.dividerColor
}
ColumnLayout {
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.leftMargin: 20
Layout.rightMargin: 20
Text {
text: qsTr("Parameters")
font.pixelSize: theme.fontSizeSmaller
color: theme.mutedDarkTextColor
}
Text {
text: parameters
color: theme.textColor
font.pixelSize: theme.fontSizeSmaller
font.bold: true
}
}
Rectangle {
width: 1
Layout.fillHeight: true
color: theme.dividerColor
}
ColumnLayout {
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.leftMargin: 20
Layout.rightMargin: 20
Text {
text: qsTr("Quant")
font.pixelSize: theme.fontSizeSmaller
color: theme.mutedDarkTextColor
}
Text {
text: quant
color: theme.textColor
font.pixelSize: theme.fontSizeSmaller
font.bold: true
}
}
Rectangle {
width: 1
Layout.fillHeight: true
color: theme.dividerColor
}
ColumnLayout {
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.leftMargin: 20
Layout.rightMargin: 20
Text {
text: qsTr("Type")
font.pixelSize: theme.fontSizeSmaller
color: theme.mutedDarkTextColor
}
Text {
text: type
color: theme.textColor
font.pixelSize: theme.fontSizeSmaller
font.bold: true
}
}
}
Rectangle {
color: "transparent"
anchors.fill: paramRow
border.color: theme.dividerColor
border.width: 1
radius: 10
}
}
Rectangle {
Layout.fillWidth: true
height: 1
color: theme.dividerColor
}
}
}
}
}
}
}

View File

@@ -7,31 +7,97 @@ import QtQuick.Dialogs
import modellist
import mysettings
import network
import llm
MySettingsTab {
onRestoreDefaultsClicked: {
MySettings.restoreApplicationDefaults();
}
title: qsTr("Application")
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")
}
}
Dialog {
id: checkForUpdatesError
anchors.centerIn: parent
modal: false
padding: 20
Text {
horizontalAlignment: Text.AlignJustify
text: qsTr("ERROR: Update system could not find the MaintenanceTool used<br>
to check for updates!<br><br>
Did you install this application using the online installer? If so,<br>
the MaintenanceTool executable should be located one directory<br>
above where this application resides on your filesystem.<br><br>
If you can't start it manually, then I'm afraid you'll have to<br>
reinstall.")
color: theme.textErrorColor
font.pixelSize: theme.fontSizeLarge
Accessible.role: Accessible.Dialog
Accessible.name: text
Accessible.description: qsTr("Error dialog")
}
background: Rectangle {
anchors.fill: parent
color: theme.containerBackground
border.width: 1
border.color: theme.dialogBorder
radius: 10
}
}
contentItem: GridLayout {
id: applicationSettingsTabInner
columns: 3
rowSpacing: 10
rowSpacing: 30
columnSpacing: 10
ColumnLayout {
Layout.row: 0
Layout.column: 0
Layout.columnSpan: 3
Layout.fillWidth: true
spacing: 10
Label {
color: theme.styledTextColor
font.pixelSize: theme.fontSizeLarge
font.bold: true
text: "General"
}
Rectangle {
Layout.fillWidth: true
height: 2
color: theme.settingsDivider
}
}
MySettingsLabel {
id: themeLabel
text: qsTr("Theme")
helpText: qsTr("Customize the colors of GPT4All")
Layout.row: 1
Layout.column: 0
}
MyComboBox {
id: themeBox
Layout.row: 1
Layout.column: 1
Layout.columnSpan: 1
Layout.column: 2
Layout.minimumWidth: 200
Layout.maximumWidth: 200
Layout.fillWidth: false
model: ["Dark", "Light", "LegacyDark"]
Layout.alignment: Qt.AlignRight
model: [qsTr("Dark"), qsTr("Light"), qsTr("LegacyDark")]
Accessible.role: Accessible.ComboBox
Accessible.name: qsTr("Color theme")
Accessible.description: qsTr("Color theme for the chat client to use")
@@ -54,16 +120,18 @@ MySettingsTab {
MySettingsLabel {
id: fontLabel
text: qsTr("Font Size")
helpText: qsTr("How big your font is displayed")
Layout.row: 2
Layout.column: 0
}
MyComboBox {
id: fontBox
Layout.row: 2
Layout.column: 1
Layout.columnSpan: 1
Layout.minimumWidth: 100
Layout.column: 2
Layout.minimumWidth: 200
Layout.maximumWidth: 200
Layout.fillWidth: false
Layout.alignment: Qt.AlignRight
model: ["Small", "Medium", "Large"]
Accessible.role: Accessible.ComboBox
Accessible.name: qsTr("Font size")
@@ -87,16 +155,18 @@ MySettingsTab {
MySettingsLabel {
id: deviceLabel
text: qsTr("Device")
helpText: qsTr("The hardware device used to load the model")
Layout.row: 3
Layout.column: 0
}
MyComboBox {
id: deviceBox
Layout.row: 3
Layout.column: 1
Layout.columnSpan: 1
Layout.minimumWidth: 350
Layout.column: 2
Layout.minimumWidth: 400
Layout.maximumWidth: 400
Layout.fillWidth: false
Layout.alignment: Qt.AlignRight
model: MySettings.deviceList
Accessible.role: Accessible.ComboBox
Accessible.name: qsTr("Device")
@@ -123,16 +193,17 @@ MySettingsTab {
MySettingsLabel {
id: defaultModelLabel
text: qsTr("Default model")
helpText: qsTr("The preferred default model")
Layout.row: 4
Layout.column: 0
}
MyComboBox {
id: comboBox
Layout.row: 4
Layout.column: 1
Layout.columnSpan: 2
Layout.minimumWidth: 350
Layout.fillWidth: true
Layout.column: 2
Layout.minimumWidth: 400
Layout.maximumWidth: 400
Layout.alignment: Qt.AlignRight
model: ModelList.userDefaultModelList
Accessible.role: Accessible.ComboBox
Accessible.name: qsTr("Default model")
@@ -156,45 +227,96 @@ MySettingsTab {
MySettingsLabel {
id: modelPathLabel
text: qsTr("Download path")
helpText: qsTr("The download folder for models")
Layout.row: 5
Layout.column: 0
}
MyDirectoryField {
id: modelPathDisplayField
text: MySettings.modelPath
font.pixelSize: theme.fontSizeLarge
implicitWidth: 300
RowLayout {
Layout.row: 5
Layout.column: 1
Layout.fillWidth: true
ToolTip.text: qsTr("Path where model files will be downloaded to")
ToolTip.visible: hovered
Accessible.role: Accessible.ToolTip
Accessible.name: modelPathDisplayField.text
Accessible.description: ToolTip.text
onEditingFinished: {
if (isValid) {
MySettings.modelPath = modelPathDisplayField.text
} else {
text = MySettings.modelPath
Layout.column: 2
Layout.alignment: Qt.AlignRight
Layout.minimumWidth: 400
Layout.maximumWidth: 400
spacing: 10
MyDirectoryField {
id: modelPathDisplayField
text: MySettings.modelPath
font.pixelSize: theme.fontSizeLarge
implicitWidth: 300
Layout.fillWidth: true
ToolTip.text: qsTr("Path where model files will be downloaded to")
ToolTip.visible: hovered
Accessible.role: Accessible.ToolTip
Accessible.name: modelPathDisplayField.text
Accessible.description: ToolTip.text
onEditingFinished: {
if (isValid) {
MySettings.modelPath = modelPathDisplayField.text
} else {
text = MySettings.modelPath
}
}
}
MySettingsButton {
text: qsTr("Browse")
Accessible.description: qsTr("Choose where to save model files")
onClicked: {
openFolderDialog("file://" + MySettings.modelPath, function(selectedFolder) {
MySettings.modelPath = selectedFolder
})
}
}
}
MySettingsButton {
Layout.row: 5
MySettingsLabel {
id: dataLakeLabel
text: qsTr("Opensource Datalake")
helpText: qsTr("Send your data to the GPT4All Open Source Datalake.")
Layout.row: 6
Layout.column: 0
}
MyCheckBox {
id: dataLakeBox
Layout.row: 6
Layout.column: 2
text: qsTr("Browse")
Accessible.description: qsTr("Choose where to save model files")
Layout.alignment: Qt.AlignRight
checked: MySettings.networkIsActive
onClicked: {
openFolderDialog("file://" + MySettings.modelPath, function(selectedFolder) {
MySettings.modelPath = selectedFolder
})
if (MySettings.networkIsActive) {
MySettings.networkIsActive = false
} else
networkDialog.open()
}
ToolTip.text: qsTr("Reveals a dialogue where you can opt-in for sharing data over network")
ToolTip.visible: hovered
}
ColumnLayout {
Layout.row: 7
Layout.column: 0
Layout.columnSpan: 3
Layout.fillWidth: true
spacing: 10
Label {
color: theme.styledTextColor
font.pixelSize: theme.fontSizeLarge
font.bold: true
text: "Advanced"
}
Rectangle {
Layout.fillWidth: true
height: 2
color: theme.settingsDivider
}
}
MySettingsLabel {
id: nThreadsLabel
text: qsTr("CPU Threads")
Layout.row: 6
helpText: qsTr("Number of CPU threads for inference and embedding")
Layout.row: 8
Layout.column: 0
}
MyTextField {
@@ -203,8 +325,11 @@ MySettingsTab {
font.pixelSize: theme.fontSizeLarge
ToolTip.text: qsTr("Amount of processing threads to use bounded by 1 and number of logical processors")
ToolTip.visible: hovered
Layout.row: 6
Layout.column: 1
Layout.alignment: Qt.AlignRight
Layout.row: 8
Layout.column: 2
Layout.minimumWidth: 200
Layout.maximumWidth: 200
validator: IntValidator {
bottom: 1
}
@@ -223,14 +348,16 @@ MySettingsTab {
}
MySettingsLabel {
id: saveChatsContextLabel
text: qsTr("Save chats context to disk")
Layout.row: 7
text: qsTr("Save chat context")
helpText: qsTr("Save chat context to disk")
Layout.row: 9
Layout.column: 0
}
MyCheckBox {
id: saveChatsContextBox
Layout.row: 7
Layout.column: 1
Layout.row: 9
Layout.column: 2
Layout.alignment: Qt.AlignRight
checked: MySettings.saveChatsContext
onClicked: {
MySettings.saveChatsContext = !MySettings.saveChatsContext
@@ -241,13 +368,15 @@ MySettingsTab {
MySettingsLabel {
id: serverChatLabel
text: qsTr("Enable API server")
Layout.row: 8
helpText: qsTr("A local http server running on local port")
Layout.row: 10
Layout.column: 0
}
MyCheckBox {
id: serverChatBox
Layout.row: 8
Layout.column: 1
Layout.row: 10
Layout.column: 2
Layout.alignment: Qt.AlignRight
checked: MySettings.serverChat
onClicked: {
MySettings.serverChat = !MySettings.serverChat
@@ -257,8 +386,9 @@ MySettingsTab {
}
MySettingsLabel {
id: serverPortLabel
text: qsTr("API Server Port (Requires restart):")
Layout.row: 9
text: qsTr("API Server Port:")
helpText: qsTr("A local port to run the server (Requires restart")
Layout.row: 11
Layout.column: 0
}
MyTextField {
@@ -268,8 +398,11 @@ MySettingsTab {
font.pixelSize: theme.fontSizeLarge
ToolTip.text: qsTr("Api server port. WARNING: You need to restart the application for it to take effect")
ToolTip.visible: hovered
Layout.row: 9
Layout.column: 1
Layout.row: 11
Layout.column: 2
Layout.minimumWidth: 200
Layout.maximumWidth: 200
Layout.alignment: Qt.AlignRight
validator: IntValidator {
bottom: 1
}
@@ -286,58 +419,53 @@ MySettingsTab {
Accessible.name: serverPortField.text
Accessible.description: ToolTip.text
}
Rectangle {
Layout.row: 10
Layout.column: 0
Layout.columnSpan: 3
Layout.fillWidth: true
height: 3
color: theme.accentColor
}
}
advancedSettings: GridLayout {
columns: 3
rowSpacing: 10
columnSpacing: 10
Rectangle {
Layout.row: 2
Layout.column: 0
Layout.fillWidth: true
Layout.columnSpan: 3
height: 3
color: theme.accentColor
}
MySettingsLabel {
id: gpuOverrideLabel
text: qsTr("Force Metal (macOS+arm)")
Layout.row: 1
Layout.row: 13
Layout.column: 0
}
RowLayout {
Layout.row: 1
Layout.column: 1
Layout.columnSpan: 2
MyCheckBox {
id: gpuOverrideBox
checked: MySettings.forceMetal
onClicked: {
MySettings.forceMetal = !MySettings.forceMetal
}
MyCheckBox {
id: gpuOverrideBox
Layout.row: 13
Layout.column: 2
Layout.alignment: Qt.AlignRight
checked: MySettings.forceMetal
onClicked: {
MySettings.forceMetal = !MySettings.forceMetal
}
ToolTip.text: qsTr("WARNING: On macOS with arm (M1+) this setting forces usage of the GPU. Can cause crashes if the model requires more RAM than the system supports. Because of crash possibility the setting will not persist across restarts of the application. This has no effect on non-macs or intel.")
ToolTip.visible: hovered
}
Item {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
Layout.minimumHeight: warningLabel.height
MySettingsLabel {
id: warningLabel
width: parent.width
color: theme.textErrorColor
wrapMode: Text.WordWrap
text: qsTr("WARNING: On macOS with arm (M1+) this setting forces usage of the GPU. Can cause crashes if the model requires more RAM than the system supports. Because of crash possibility the setting will not persist across restarts of the application. This has no effect on non-macs or intel.")
}
MySettingsLabel {
id: updatesLabel
text: qsTr("Check for updates")
helpText: qsTr("Click to see if an update to the application is available");
Layout.row: 14
Layout.column: 0
}
MySettingsButton {
Layout.row: 14
Layout.column: 2
Layout.alignment: Qt.AlignRight
text: qsTr("Updates");
onClicked: {
if (!LLM.checkForUpdates())
checkForUpdatesError.open()
}
}
Rectangle {
Layout.row: 15
Layout.column: 0
Layout.columnSpan: 3
Layout.fillWidth: true
height: 2
color: theme.settingsDivider
}
}
}

View File

@@ -16,23 +16,33 @@ Rectangle {
id: theme
}
signal downloadClicked
signal aboutClicked
color: theme.viewBackground
color: theme.containerBackground
Rectangle {
id: borderRight
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 2
color: theme.dividerColor
}
Item {
anchors.fill: parent
anchors.margins: 10
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: borderRight.left
Accessible.role: Accessible.Pane
Accessible.name: qsTr("Drawer")
Accessible.description: qsTr("Main navigation drawer")
MyButton {
MySettingsButton {
id: newChat
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 20
font.pixelSize: theme.fontSizeLarger
topPadding: 20
bottomPadding: 20
@@ -45,20 +55,31 @@ Rectangle {
}
}
Rectangle {
id: divider
anchors.top: newChat.bottom
anchors.margins: 20
anchors.topMargin: 15
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: theme.dividerColor
}
ScrollView {
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: -10
anchors.topMargin: 10
anchors.top: newChat.bottom
anchors.bottom: checkForUpdatesButton.top
anchors.bottomMargin: 10
anchors.topMargin: 15
anchors.top: divider.bottom
anchors.bottom: parent.bottom
anchors.bottomMargin: 15
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
clip: true
ListView {
id: conversationList
anchors.fill: parent
anchors.leftMargin: 10
anchors.rightMargin: 10
model: ChatListModel
@@ -71,6 +92,33 @@ Rectangle {
anchors.bottom: conversationList.bottom
}
Component {
id: sectionHeading
Rectangle {
width: ListView.view.width
height: childrenRect.height
color: "transparent"
property bool isServer: ChatListModel.get(parent.index) && ChatListModel.get(parent.index).isServer
visible: !isServer || MySettings.serverChat
required property string section
Text {
leftPadding: 10
rightPadding: 10
topPadding: 15
bottomPadding: 5
text: parent.section
color: theme.styledTextColor
font.pixelSize: theme.fontSizeLarge
}
}
}
section.property: "section"
section.criteria: ViewSection.FullString
section.delegate: sectionHeading
delegate: Rectangle {
id: chatRectangle
width: conversationList.width
@@ -80,21 +128,25 @@ Rectangle {
property bool trashQuestionDisplayed: false
visible: !isServer || MySettings.serverChat
z: isCurrent ? 199 : 1
color: index % 2 === 0 ? theme.darkContrast : theme.lightContrast
color: isCurrent ? theme.selectedBackground : "transparent"
border.width: isCurrent
border.color: chatName.readOnly ? theme.assistantColor : theme.userColor
border.color: theme.dividerColor
radius: 10
TextField {
id: chatName
anchors.left: parent.left
anchors.right: buttons.left
color: theme.textColor
padding: 15
color: theme.styledTextColor
topPadding: 15
bottomPadding: 15
focus: false
readOnly: true
wrapMode: Text.NoWrap
hoverEnabled: false // Disable hover events on the TextArea
selectByMouse: false // Disable text selection in the TextArea
font.pixelSize: theme.fontSizeLarge
font.bold: true
text: readOnly ? metrics.elidedText : name
horizontalAlignment: TextInput.AlignLeft
opacity: trashQuestionDisplayed ? 0.5 : 1.0
@@ -103,7 +155,7 @@ Rectangle {
font: chatName.font
text: name
elide: Text.ElideRight
elideWidth: chatName.width - 40
elideWidth: chatName.width - 15
}
background: Rectangle {
color: "transparent"
@@ -240,45 +292,5 @@ 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()
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,148 +0,0 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import QtQuick.Dialogs
import chatlistmodel
import localdocs
import llm
MyDialog {
id: collectionsDialog
modal: true
padding: 20
width: 480
height: 640
signal addRemoveClicked
property var currentChat: ChatListModel.currentChat
Label {
id: listLabel
anchors.top: parent.top
anchors.left: parent.left
text: qsTr("Local Documents")
color: theme.titleTextColor
font.pixelSize: theme.fontSizeLarge
font.bold: true
}
ScrollView {
id: scrollView
anchors.top: listLabel.bottom
anchors.topMargin: 20
anchors.bottom: collectionSettings.top
anchors.bottomMargin: 20
anchors.left: parent.left
anchors.right: parent.right
clip: true
contentHeight: 300
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
background: Rectangle {
color: theme.controlBackground
}
ListView {
id: listView
model: LocalDocs.localDocsModel
boundsBehavior: Flickable.StopAtBounds
ScrollBar.vertical: ScrollBar {
parent: listView.parent
anchors.top: listView.top
anchors.left: listView.right
anchors.bottom: listView.bottom
}
delegate: Rectangle {
id: item
width: listView.width
height: collectionId.height + 40
color: index % 2 === 0 ? theme.darkContrast : theme.lightContrast
MyCheckBox {
id: checkBox
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.margins: 20
checked: currentChat.hasCollection(collection)
onClicked: {
if (checkBox.checked) {
currentChat.addCollection(collection)
} else {
currentChat.removeCollection(collection)
}
}
ToolTip.text: qsTr("Warning: searching collections while indexing can return incomplete results")
ToolTip.visible: hovered && model.indexing
}
Text {
id: collectionId
anchors.verticalCenter: parent.verticalCenter
anchors.left: checkBox.right
anchors.margins: 20
anchors.leftMargin: 10
text: collection
font.pixelSize: theme.fontSizeLarge
elide: Text.ElideRight
color: theme.textColor
}
ProgressBar {
id: itemProgressBar
anchors.verticalCenter: parent.verticalCenter
anchors.left: collectionId.right
anchors.right: parent.right
anchors.margins: 20
anchors.leftMargin: 40
visible: model.indexing || model.currentEmbeddingsToIndex !== model.totalEmbeddingsToIndex || model.error !== ""
value: model.error !== "" ? 0 : model.indexing ?
(model.totalBytesToIndex - model.currentBytesToIndex) / model.totalBytesToIndex :
(model.currentEmbeddingsToIndex / model.totalEmbeddingsToIndex)
background: Rectangle {
implicitHeight: 45
color: model.error ? theme.textErrorColor : theme.progressBackground
radius: 3
}
contentItem: Item {
implicitHeight: 40
Rectangle {
width: itemProgressBar.visualPosition * parent.width
height: parent.height
radius: 2
color: theme.progressForeground
}
}
Accessible.role: Accessible.ProgressBar
Accessible.name: qsTr("Indexing progressBar")
Accessible.description: qsTr("Shows the progress made in the indexing")
ToolTip.text: model.error
ToolTip.visible: hovered && model.error !== ""
}
Label {
id: speedLabel
color: theme.progressText
visible: model.indexing || model.currentEmbeddingsToIndex !== model.totalEmbeddingsToIndex
anchors.verticalCenter: itemProgressBar.verticalCenter
anchors.left: itemProgressBar.left
anchors.right: itemProgressBar.right
horizontalAlignment: Text.AlignHCenter
text: model.error !== "" ? qsTr("error...") : (model.indexing ? qsTr("indexing...") : qsTr("embeddings..."))
elide: Text.ElideRight
font.pixelSize: theme.fontSizeLarge
}
}
}
}
MySettingsButton {
id: collectionSettings
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("Add & Remove")
font.pixelSize: theme.fontSizeLarger
onClicked: {
addRemoveClicked()
}
}
}

View File

@@ -0,0 +1,148 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import QtQuick.Dialogs
import chatlistmodel
import localdocs
import llm
Rectangle {
id: collectionsDrawer
color: "transparent"
signal addDocsClicked
property var currentChat: ChatListModel.currentChat
Rectangle {
id: borderLeft
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 2
color: theme.dividerColor
}
ScrollView {
id: scrollView
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: borderLeft.right
anchors.right: parent.right
anchors.margins: 15
clip: true
contentHeight: 300
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
ListView {
id: listView
model: LocalDocs.localDocsModel
boundsBehavior: Flickable.StopAtBounds
ScrollBar.vertical: ScrollBar {
parent: listView.parent
anchors.top: listView.top
anchors.left: listView.right
anchors.bottom: listView.bottom
}
spacing: 15
delegate: Rectangle {
width: listView.width
height: childrenRect.height + 15
color: checkBox.checked ? theme.collectionsButtonBackground : "transparent"
RowLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 7.5
MyCheckBox {
id: checkBox
Layout.alignment: Qt.AlignLeft
checked: currentChat.hasCollection(collection)
onClicked: {
if (checkBox.checked) {
currentChat.addCollection(collection)
} else {
currentChat.removeCollection(collection)
}
}
ToolTip.text: qsTr("Warning: searching collections while indexing can return incomplete results")
ToolTip.visible: hovered && model.indexing
}
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
Text {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
text: collection
font.pixelSize: theme.fontSizeLarger
elide: Text.ElideRight
color: theme.textColor
}
Text {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
text: "%1 %2".arg(qsTr("%n file(s)", "", model.totalDocs)).arg(qsTr("%n word(s)", "", model.totalWords))
elide: Text.ElideRight
color: theme.mutedTextColor
font.pixelSize: theme.fontSizeSmaller
}
RowLayout {
visible: model.updating
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
MyBusyIndicator {
color: theme.accentColor
size: 24
Layout.minimumWidth: 24
Layout.minimumHeight: 24
}
Text {
text: qsTr("Updating")
elide: Text.ElideRight
color: theme.accentColor
font.pixelSize: theme.fontSizeSmaller
font.bold: true
}
}
}
}
}
footer: ColumnLayout {
width: listView.width
spacing: 30
Rectangle {
visible: listView.count !== 0
Layout.topMargin: 30
Layout.fillWidth: true
height: 1
color: theme.dividerColor
}
MySettingsButton {
id: collectionSettings
enabled: LocalDocs.databaseValid
Layout.alignment: Qt.AlignCenter
text: qsTr("\uFF0B Add Docs")
font.pixelSize: theme.fontSizeLarger
onClicked: {
addDocsClicked()
}
}
Text {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
text: qsTr("Chat privately with local files using on-device Large Language Models (LLMs). Keeps data private and secure. Best results with Llama 3 Instruct.")
font.pixelSize: theme.fontSizeLarger
wrapMode: Text.WordWrap
elide: Text.ElideRight
color: theme.mutedTextColor
}
}
}
}
}

View File

@@ -0,0 +1,278 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import llm
import chatlistmodel
import download
import modellist
import network
import gpt4all
import mysettings
Rectangle {
id: homeView
Theme {
id: theme
}
color: theme.viewBackground
signal chatViewRequested()
signal localDocsViewRequested()
signal settingsViewRequested(int page)
signal addModelViewRequested()
property bool shouldShowFirstStart: false
ColumnLayout {
id: mainArea
anchors.fill: parent
anchors.margins: 30
spacing: 30
ColumnLayout {
Layout.fillWidth: true
Layout.maximumWidth: 1530
Layout.alignment: Qt.AlignCenter
spacing: 30
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: 5
Text {
id: welcome
Layout.alignment: Qt.AlignHCenter
text: qsTr("Welcome to GPT4All")
font.pixelSize: theme.fontSizeBanner
color: theme.titleTextColor
}
Text {
Layout.alignment: Qt.AlignHCenter
text: qsTr("the privacy-first LLM chat application")
font.pixelSize: theme.fontSizeLarge
color: theme.titleInfoTextColor
}
}
MyButton {
id: startChat
visible: shouldShowFirstStart
Layout.alignment: Qt.AlignHCenter
text: qsTr("Start chatting")
onClicked: {
chatViewRequested()
}
}
RowLayout {
spacing: 15
visible: !startChat.visible
Layout.alignment: Qt.AlignHCenter
MyWelcomeButton {
Layout.fillWidth: true
Layout.maximumWidth: 500
Layout.preferredHeight: 150
text: qsTr("Start Chatting")
description: qsTr("Chat with any LLM")
imageSource: "qrc:/gpt4all/icons/chat.svg"
onClicked: {
chatViewRequested()
}
}
MyWelcomeButton {
Layout.fillWidth: true
Layout.maximumWidth: 500
Layout.preferredHeight: 150
text: qsTr("LocalDocs")
description: qsTr("Chat with your local files")
imageSource: "qrc:/gpt4all/icons/db.svg"
onClicked: {
localDocsViewRequested()
}
}
MyWelcomeButton {
Layout.fillWidth: true
Layout.maximumWidth: 500
Layout.preferredHeight: 150
text: qsTr("Find Models")
description: qsTr("Explore and download models")
imageSource: "qrc:/gpt4all/icons/models.svg"
onClicked: {
addModelViewRequested()
}
}
}
Item {
visible: !startChat.visible && Download.latestNews !== ""
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: 120
Layout.maximumHeight: textAreaNews.height
Rectangle {
id: roundedFrameNews // latest news
anchors.fill: parent
z: 299
radius: 10
border.width: 1
border.color: theme.controlBorder
color: "transparent"
clip: true
}
Item {
anchors.fill: parent
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: roundedFrameNews.width
height: roundedFrameNews.height
radius: 10
}
}
RowLayout {
spacing: 0
anchors.fill: parent
Rectangle {
color: "transparent"
width: 82
height: 100
Image {
id: newsImg
anchors.centerIn: parent
sourceSize: Qt.size(40, 40)
mipmap: true
visible: false
source: "qrc:/gpt4all/icons/alt_logo.svg"
}
ColorOverlay {
anchors.fill: newsImg
source: newsImg
color: theme.styledTextColor
}
}
Item {
id: myItem
Layout.fillWidth: true
Layout.fillHeight: true
Rectangle {
anchors.fill: parent
color: theme.conversationBackground
}
ScrollView {
id: newsScroll
anchors.fill: parent
clip: true
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
Text {
id: textAreaNews
width: myItem.width
padding: 20
color: theme.styledTextColor
font.pixelSize: theme.fontSizeLarger
textFormat: TextEdit.MarkdownText
wrapMode: Text.WordWrap
text: Download.latestNews
focus: false
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Latest news")
Accessible.description: qsTr("Latest news from GPT4All")
}
}
}
}
}
}
}
Rectangle {
id: linkBar
Layout.alignment: Qt.AlignBottom
Layout.fillWidth: true
border.width: 1
border.color: theme.dividerColor
radius: 6
z: 200
height: 30
color: theme.conversationBackground
RowLayout {
anchors.fill: parent
spacing: 0
RowLayout {
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
spacing: 4
MyFancyLink {
text: qsTr("Release Notes")
imageSource: "qrc:/gpt4all/icons/notes.svg"
onClicked: { Qt.openUrlExternally("https://github.com/nomic-ai/gpt4all/releases") }
}
MyFancyLink {
text: qsTr("Discord")
imageSource: "qrc:/gpt4all/icons/discord.svg"
onClicked: { Qt.openUrlExternally("https://discord.gg/4M2QFmTt2k") }
}
MyFancyLink {
text: qsTr("X (Twitter)")
imageSource: "qrc:/gpt4all/icons/twitter.svg"
onClicked: { Qt.openUrlExternally("https://twitter.com/nomic_ai") }
}
MyFancyLink {
text: qsTr("Github")
imageSource: "qrc:/gpt4all/icons/github.svg"
onClicked: { Qt.openUrlExternally("https://github.com/nomic-ai/gpt4all") }
}
}
RowLayout {
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
spacing: 40
MyFancyLink {
text: qsTr("GPT4All.io")
imageSource: "qrc:/gpt4all/icons/globe.svg"
onClicked: { Qt.openUrlExternally("https://gpt4all.io") }
rightPadding: 15
}
}
}
}
}
Rectangle {
anchors.top: mainArea.top
anchors.right: mainArea.right
border.width: 1
border.color: theme.dividerColor
radius: 6
z: 200
height: 30
color: theme.conversationBackground
width: subscribeLink.width
RowLayout {
anchors.fill: parent
MyFancyLink {
id: subscribeLink
Layout.alignment: Qt.AlignCenter
text: qsTr("Subscribe to Newsletter")
imageSource: "qrc:/gpt4all/icons/email.svg"
onClicked: { Qt.openUrlExternally("https://forms.nomic.ai/gpt4all-release-notes-signup") }
}
}
}
}

View File

@@ -14,187 +14,155 @@ MySettingsTab {
MySettings.restoreLocalDocsDefaults();
}
property bool hasEmbeddingModel: ModelList.installedEmbeddingModels.count !== 0
showAdvancedSettingsButton: hasEmbeddingModel
showRestoreDefaultsButton: hasEmbeddingModel
showRestoreDefaultsButton: true
title: qsTr("LocalDocs")
contentItem: ColumnLayout {
id: root
spacing: 10
property alias collection: collection.text
property alias folder_path: folderEdit.text
MySettingsLabel {
id: downloadLabel
Layout.fillWidth: true
Layout.maximumWidth: parent.width
wrapMode: Text.Wrap
visible: !hasEmbeddingModel
Layout.alignment: Qt.AlignLeft
text: qsTr("This feature requires the download of a text embedding model in order to index documents for later search. Please download the <b>SBert</a> text embedding model from the download dialog to proceed.")
Label {
color: theme.styledTextColor
font.pixelSize: theme.fontSizeLarge
font.bold: true
text: "Indexing"
}
MySettingsButton {
visible: !hasEmbeddingModel
Layout.topMargin: 20
Layout.alignment: Qt.AlignLeft
text: qsTr("Download")
font.pixelSize: theme.fontSizeLarger
onClicked: {
downloadClicked()
Rectangle {
Layout.bottomMargin: 15
Layout.fillWidth: true
height: 2
color: theme.settingsDivider
}
RowLayout {
MySettingsLabel {
id: extsLabel
text: qsTr("Allowed File Extensions")
helpText: qsTr("Comma-separated list. LocalDocs will only attempt to process files with these extensions.")
}
MyTextField {
id: extsField
text: MySettings.localDocsFileExtensions.join(',')
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
Layout.alignment: Qt.AlignRight
Layout.minimumWidth: 200
validator: RegularExpressionValidator {
regularExpression: /([^ ,\/"']+,?)*/
}
onEditingFinished: {
// split and remove empty elements
var exts = text.split(',').filter(e => e);
// normalize and deduplicate
exts = exts.map(e => e.toLowerCase());
exts = Array.from(new Set(exts));
/* Blacklist common unsupported file extensions. We only support plain text and PDFs, and although we
* reject binary data, we don't want to waste time trying to index files that we don't support. */
exts = exts.filter(e => ![
/* Microsoft documents */ "rtf", "docx", "ppt", "pptx", "xls", "xlsx",
/* OpenOffice */ "odt", "ods", "odp", "odg",
/* photos */ "jpg", "jpeg", "png", "gif", "bmp", "tif", "tiff", "webp",
/* audio */ "mp3", "wma", "m4a", "wav", "flac",
/* videos */ "mp4", "mov", "webm", "mkv", "avi", "flv", "wmv",
/* executables */ "exe", "com", "dll", "so", "dylib", "msi",
/* binary images */ "iso", "img", "dmg",
/* archives */ "zip", "jar", "apk", "rar", "7z", "tar", "gz", "xz", "bz2", "tar.gz",
"tgz", "tar.xz", "tar.bz2",
/* misc */ "bin",
].includes(e));
MySettings.localDocsFileExtensions = exts;
extsField.text = exts.join(',');
focus = false;
}
Accessible.role: Accessible.EditableText
Accessible.name: extsLabel.text
Accessible.description: extsLabel.helpText
}
}
Item {
visible: hasEmbeddingModel
Layout.fillWidth: true
height: row.height
RowLayout {
id: row
anchors.left: parent.left
anchors.right: parent.right
height: collection.height
spacing: 10
MyTextField {
id: collection
width: 225
horizontalAlignment: Text.AlignJustify
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
placeholderText: qsTr("Collection name...")
placeholderTextColor: theme.mutedTextColor
ToolTip.text: qsTr("Name of the collection to add (Required)")
ToolTip.visible: hovered
Accessible.role: Accessible.EditableText
Accessible.name: collection.text
Accessible.description: ToolTip.text
function showError() {
collection.placeholderTextColor = theme.textErrorColor
}
onTextChanged: {
collection.placeholderTextColor = theme.mutedTextColor
}
}
MyDirectoryField {
id: folderEdit
Layout.fillWidth: true
text: root.folder_path
placeholderText: qsTr("Folder path...")
font.pixelSize: theme.fontSizeLarge
placeholderTextColor: theme.mutedTextColor
ToolTip.text: qsTr("Folder path to documents (Required)")
ToolTip.visible: hovered
function showError() {
folderEdit.placeholderTextColor = theme.textErrorColor
}
onTextChanged: {
folderEdit.placeholderTextColor = theme.mutedTextColor
}
}
MySettingsButton {
id: browseButton
text: qsTr("Browse")
onClicked: {
openFolderDialog(StandardPaths.writableLocation(StandardPaths.HomeLocation), function(selectedFolder) {
root.folder_path = selectedFolder
})
}
}
MySettingsButton {
id: addButton
text: qsTr("Add")
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.description: qsTr("Add collection")
onClicked: {
var isError = false;
if (root.collection === "") {
isError = true;
collection.showError();
}
if (root.folder_path === "" || !folderEdit.isValid) {
isError = true;
folderEdit.showError();
}
if (isError)
return;
LocalDocs.addFolder(root.collection, root.folder_path)
root.collection = ""
root.folder_path = ""
collection.clear()
}
}
}
Label {
Layout.topMargin: 15
color: theme.grayRed900
font.pixelSize: theme.fontSizeLarge
font.bold: true
text: "Embedding"
}
ColumnLayout {
visible: hasEmbeddingModel
spacing: 0
Repeater {
model: LocalDocs.localDocsModel
delegate: Rectangle {
id: item
Layout.fillWidth: true
height: buttons.height + 20
color: index % 2 === 0 ? theme.darkContrast : theme.lightContrast
property bool removing: false
Rectangle {
Layout.bottomMargin: 15
Layout.fillWidth: true
height: 2
color: theme.grayRed500
}
Text {
id: collectionId
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.margins: 20
text: collection
elide: Text.ElideRight
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
width: 200
}
RowLayout {
MySettingsLabel {
text: qsTr("Use Nomic Embed API")
helpText: qsTr("Embed documents using the fast Nomic API instead of a private local model.")
}
Text {
id: folderId
anchors.left: collectionId.right
anchors.right: buttons.left
anchors.margins: 20
anchors.verticalCenter: parent.verticalCenter
text: folder_path
elide: Text.ElideRight
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
}
Item {
id: buttons
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: 20
width: removeButton.width
height:removeButton.height
MySettingsButton {
id: removeButton
anchors.centerIn: parent
text: qsTr("Remove")
visible: !item.removing
onClicked: {
item.removing = true
LocalDocs.removeFolder(collection, folder_path)
}
}
}
MyCheckBox {
id: useNomicAPIBox
Component.onCompleted: {
useNomicAPIBox.checked = MySettings.localDocsUseRemoteEmbed;
}
onClicked: {
MySettings.localDocsUseRemoteEmbed = useNomicAPIBox.checked && MySettings.localDocsNomicAPIKey !== "";
}
}
}
RowLayout {
visible: hasEmbeddingModel
MySettingsLabel {
id: apiKeyLabel
text: qsTr("Nomic API Key")
helpText: qsTr("API key to use for Nomic Embed. Get one at https://atlas.nomic.ai/")
}
MyTextField {
id: apiKeyField
text: MySettings.localDocsNomicAPIKey
color: apiKeyField.acceptableInput ? theme.textColor : theme.textErrorColor
font.pixelSize: theme.fontSizeLarge
Layout.alignment: Qt.AlignRight
Layout.minimumWidth: 200
enabled: useNomicAPIBox.checked
validator: RegularExpressionValidator {
// may be empty
regularExpression: /|nk-[a-zA-Z0-9_-]{43}/
}
onEditingFinished: {
MySettings.localDocsNomicAPIKey = apiKeyField.text;
MySettings.localDocsUseRemoteEmbed = useNomicAPIBox.checked && MySettings.localDocsNomicAPIKey !== "";
focus = false;
}
Accessible.role: Accessible.EditableText
Accessible.name: apiKeyLabel.text
Accessible.description: apiKeyLabel.helpText
}
}
Label {
Layout.topMargin: 15
color: theme.grayRed900
font.pixelSize: theme.fontSizeLarge
font.bold: true
text: "Display"
}
Rectangle {
Layout.bottomMargin: 15
Layout.fillWidth: true
height: 2
color: theme.grayRed500
}
RowLayout {
MySettingsLabel {
id: showReferencesLabel
text: qsTr("Show references")
text: qsTr("Show sources")
helpText: qsTr("Shows sources in GUI generated by localdocs")
}
MyCheckBox {
id: showReferencesBox
@@ -202,104 +170,92 @@ MySettingsTab {
onClicked: {
MySettings.localDocsShowReferences = !MySettings.localDocsShowReferences
}
ToolTip.text: qsTr("Shows any references in GUI generated by localdocs")
ToolTip.visible: hovered
}
}
Label {
Layout.topMargin: 15
color: theme.styledTextColor
font.pixelSize: theme.fontSizeLarge
font.bold: true
text: "Advanced"
}
Rectangle {
visible: hasEmbeddingModel
Layout.bottomMargin: 15
Layout.fillWidth: true
height: 3
color: theme.accentColor
}
}
advancedSettings: GridLayout {
id: gridLayout
columns: 3
rowSpacing: 10
columnSpacing: 10
visible: hasEmbeddingModel
Rectangle {
Layout.row: 3
Layout.column: 0
Layout.fillWidth: true
Layout.columnSpan: 3
height: 3
color: theme.accentColor
height: 2
color: theme.settingsDivider
}
MySettingsLabel {
id: chunkLabel
Layout.row: 1
Layout.column: 0
text: qsTr("Document snippet size (characters)")
}
MyTextField {
id: chunkSizeTextField
Layout.row: 1
Layout.column: 1
ToolTip.text: qsTr("Number of characters per document snippet.\nNOTE: larger numbers increase likelihood of factual responses, but also result in slower generation.")
ToolTip.visible: hovered
text: MySettings.localDocsChunkSize
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
MySettings.localDocsChunkSize = val
focus = false
} else {
text = MySettings.localDocsChunkSize
}
}
}
MySettingsLabel {
id: contextItemsPerPrompt
Layout.row: 2
Layout.column: 0
text: qsTr("Max document snippets per prompt")
}
MyTextField {
Layout.row: 2
Layout.column: 1
ToolTip.text: qsTr("Max best N matches of retrieved document snippets to add to the context for prompt.\nNOTE: larger numbers increase likelihood of factual responses, but also result in slower generation.")
ToolTip.visible: hovered
text: MySettings.localDocsRetrievalSize
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
MySettings.localDocsRetrievalSize = val
focus = false
} else {
text = MySettings.localDocsRetrievalSize
}
}
}
Item {
Layout.row: 1
Layout.column: 2
Layout.rowSpan: 2
id: warningLabel
Layout.bottomMargin: 15
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
Layout.minimumHeight: warningLabel.height
color: theme.textErrorColor
wrapMode: Text.WordWrap
text: qsTr("Warning: Advanced usage only.")
helpText: qsTr("Values too large may cause localdocs failure, extremely slow responses or failure to respond at all. Roughly speaking, the {N chars x N snippets} are added to the model's context window. More info <a href=\"https://docs.gpt4all.io/gpt4all_chat.html#localdocs-beta-plugin-chat-with-your-data\">here.</a>")
onLinkActivated: function(link) { Qt.openUrlExternally(link) }
}
RowLayout {
MySettingsLabel {
id: warningLabel
width: parent.width
color: theme.textErrorColor
wrapMode: Text.WordWrap
text: qsTr("Warning: Advanced usage only. Values too large may cause localdocs failure, extremely slow responses or failure to respond at all. Roughly speaking, the {N chars x N snippets} are added to the model's context window. More info <a href=\"https://docs.gpt4all.io/gpt4all_chat.html#localdocs-beta-plugin-chat-with-your-data\">here.</a>")
onLinkActivated: function(link) { Qt.openUrlExternally(link) }
id: chunkLabel
Layout.fillWidth: true
text: qsTr("Document snippet size (characters)")
helpText: qsTr("Number of characters per document snippet. Larger numbers increase likelihood of factual responses, but also result in slower generation.")
}
MyTextField {
id: chunkSizeTextField
text: MySettings.localDocsChunkSize
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
MySettings.localDocsChunkSize = val
focus = false
} else {
text = MySettings.localDocsChunkSize
}
}
}
}
}
RowLayout {
Layout.topMargin: 15
MySettingsLabel {
id: contextItemsPerPrompt
text: qsTr("Max document snippets per prompt")
helpText: qsTr("Max best N matches of retrieved document snippets to add to the context for prompt. Larger numbers increase likelihood of factual responses, but also result in slower generation.")
}
MyTextField {
text: MySettings.localDocsRetrievalSize
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
MySettings.localDocsRetrievalSize = val
focus = false
} else {
text = MySettings.localDocsRetrievalSize
}
}
}
}
Rectangle {
Layout.topMargin: 15
Layout.fillWidth: true
height: 2
color: theme.settingsDivider
}
}
}

View File

@@ -0,0 +1,457 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import llm
import chatlistmodel
import download
import modellist
import network
import gpt4all
import mysettings
import localdocs
Rectangle {
id: localDocsView
Theme {
id: theme
}
color: theme.viewBackground
signal chatViewRequested()
signal localDocsViewRequested()
signal settingsViewRequested(int page)
signal addCollectionViewRequested()
ColumnLayout {
id: mainArea
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.margins: 30
spacing: 50
RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
visible: LocalDocs.databaseValid && LocalDocs.localDocsModel.count !== 0
spacing: 50
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
Layout.minimumWidth: 200
spacing: 5
Text {
id: welcome
text: qsTr("LocalDocs")
font.pixelSize: theme.fontSizeBanner
color: theme.titleTextColor
}
Text {
text: qsTr("Chat with your local files")
font.pixelSize: theme.fontSizeLarge
color: theme.titleInfoTextColor
}
}
Rectangle {
Layout.fillWidth: true
height: 0
}
MyButton {
Layout.alignment: Qt.AlignTop | Qt.AlignRight
text: qsTr("\uFF0B Add Doc Collection")
onClicked: {
addCollectionViewRequested()
}
}
}
Rectangle {
id: warning
Layout.fillWidth: true
Layout.fillHeight: true
visible: !LocalDocs.databaseValid
Text {
anchors.centerIn: parent
horizontalAlignment: Qt.AlignHCenter
text: qsTr("ERROR: The LocalDocs database is not valid.")
color: theme.textErrorColor
font.bold: true
font.pixelSize: theme.fontSizeLargest
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
visible: LocalDocs.databaseValid && LocalDocs.localDocsModel.count === 0
ColumnLayout {
id: noInstalledLabel
anchors.centerIn: parent
spacing: 0
Text {
Layout.alignment: Qt.AlignCenter
text: qsTr("No Collections Installed")
color: theme.mutedLightTextColor
font.pixelSize: theme.fontSizeBannerSmall
}
Text {
Layout.topMargin: 15
horizontalAlignment: Qt.AlignHCenter
color: theme.mutedLighterTextColor
text: qsTr("Install a collection of local documents to get started using this feature")
font.pixelSize: theme.fontSizeLarge
}
}
MyButton {
anchors.top: noInstalledLabel.bottom
anchors.topMargin: 50
anchors.horizontalCenter: noInstalledLabel.horizontalCenter
rightPadding: 60
leftPadding: 60
text: qsTr("\uFF0B Add Doc Collection")
onClicked: {
addCollectionViewRequested()
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Shows the add model view")
}
}
ScrollView {
id: scrollView
ScrollBar.vertical.policy: ScrollBar.AsNeeded
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
visible: LocalDocs.databaseValid && LocalDocs.localDocsModel.count !== 0
ListView {
id: collectionListView
model: LocalDocs.localDocsModel
boundsBehavior: Flickable.StopAtBounds
spacing: 30
delegate: Rectangle {
width: collectionListView.width
height: childrenRect.height + 60
color: theme.conversationBackground
radius: 10
border.width: 1
border.color: theme.controlBorder
property bool removing: false
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 30
spacing: 10
RowLayout {
Layout.fillWidth: true
Text {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
text: collection
elide: Text.ElideRight
color: theme.titleTextColor
font.pixelSize: theme.fontSizeLargest
font.bold: true
}
Item {
Layout.alignment: Qt.AlignRight
Layout.preferredWidth: state.contentWidth + 50
Layout.preferredHeight: state.contentHeight + 10
ProgressBar {
id: itemProgressBar
anchors.fill: parent
value: {
if (model.error !== "")
return 0
if (model.indexing)
return (model.totalBytesToIndex - model.currentBytesToIndex) / model.totalBytesToIndex
if (model.currentEmbeddingsToIndex !== 0)
return (model.totalEmbeddingsToIndex - model.currentEmbeddingsToIndex) / model.totalEmbeddingsToIndex
return 0
}
background: Rectangle {
implicitHeight: 45
color: {
if (model.error !== "")
return "transparent"
if (model.indexing)
return theme.altProgressBackground
if (model.currentEmbeddingsToIndex !== 0)
return theme.altProgressBackground
if (model.forceIndexing)
return theme.red200
return theme.lightButtonBackground
}
radius: 6
}
contentItem: Item {
implicitHeight: 40
Rectangle {
width: itemProgressBar.visualPosition * parent.width
height: parent.height
radius: 2
color: theme.altProgressForeground
}
}
Accessible.role: Accessible.ProgressBar
Accessible.name: qsTr("Indexing progressBar")
Accessible.description: qsTr("Shows the progress made in the indexing")
ToolTip.text: model.error
ToolTip.visible: hovered && model.error !== ""
}
Label {
id: state
anchors.centerIn: itemProgressBar
horizontalAlignment: Text.AlignHCenter
color: {
if (model.error !== "")
return theme.textErrorColor
if (model.indexing)
return theme.altProgressText
if (model.currentEmbeddingsToIndex !== 0)
return theme.altProgressText
if (model.forceIndexing)
return theme.textErrorColor
return theme.lighterButtonForeground
}
text: {
if (model.error !== "")
return qsTr("ERROR")
// indicates extracting snippets from documents
if (model.indexing)
return qsTr("INDEXING")
// indicates generating the embeddings for any outstanding snippets
if (model.currentEmbeddingsToIndex !== 0)
return qsTr("EMBEDDING")
if (model.forceIndexing)
return qsTr("REQUIRES UPDATE")
if (model.installed)
return qsTr("READY")
return qsTr("INSTALLING")
}
elide: Text.ElideRight
font.bold: true
font.pixelSize: theme.fontSizeSmaller
}
}
}
RowLayout {
Layout.fillWidth: true
Text {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
text: folder_path
elide: Text.ElideRight
color: theme.titleTextColor2
font.pixelSize: theme.fontSizeSmall
}
Text {
Layout.alignment: Qt.AlignRight
text: {
if (model.error !== "")
return model.error
if (model.indexing)
return qsTr("Indexing in progress")
if (model.currentEmbeddingsToIndex !== 0)
return qsTr("Embedding in progress")
if (model.forceIndexing)
return qsTr("This collection requires an update after version change")
if (model.installed)
return qsTr("Automatically reindexes upon changes to the folder")
return qsTr("Installation in progress")
}
elide: Text.ElideRight
color: theme.mutedDarkTextColor
font.pixelSize: theme.fontSizeSmaller
}
Text {
visible: {
return model.indexing || model.currentEmbeddingsToIndex !== 0
}
Layout.alignment: Qt.AlignRight
text: {
var percentComplete = Math.round(itemProgressBar.value * 100);
var formattedPercent = percentComplete < 10 ? " " + percentComplete : percentComplete.toString();
return formattedPercent + qsTr("%")
}
elide: Text.ElideRight
color: theme.mutedDarkTextColor
font.family: "monospace"
font.pixelSize: theme.fontSizeSmaller
}
}
RowLayout {
spacing: 7
Text {
text: "%1 %2".arg(qsTr("%n file(s)", "", model.totalDocs)).arg(qsTr("%n word(s)", "", model.totalWords))
elide: Text.ElideRight
color: theme.styledTextColor2
font.pixelSize: theme.fontSizeSmaller
}
Text {
text: model.embeddingModel
elide: Text.ElideRight
color: theme.mutedDarkTextColor
font.bold: true
font.pixelSize: theme.fontSizeSmaller
}
Text {
visible: Qt.formatDateTime(model.lastUpdate) !== ""
text: Qt.formatDateTime(model.lastUpdate)
elide: Text.ElideRight
color: theme.mutedTextColor
font.pixelSize: theme.fontSizeSmaller
}
Text {
visible: model.currentEmbeddingsToIndex !== 0
text: (model.totalEmbeddingsToIndex - model.currentEmbeddingsToIndex) + " of "
+ model.totalEmbeddingsToIndex + " embeddings"
elide: Text.ElideRight
color: theme.mutedTextColor
font.pixelSize: theme.fontSizeSmaller
}
}
Rectangle {
Layout.fillWidth: true
height: 1
color: theme.dividerColor
}
RowLayout {
id: fileProcessingRow
Layout.topMargin: 15
Layout.bottomMargin: 15
visible: model.fileCurrentlyProcessing !== "" && (model.indexing || model.currentEmbeddingsToIndex !== 0)
MyBusyIndicator {
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: 12
Layout.preferredHeight: 12
running: true
size: 12
color: theme.textColor
}
Text {
id: filename
Layout.alignment: Qt.AlignCenter
text: model.fileCurrentlyProcessing
elide: Text.ElideRight
color: theme.textColor
font.bold: true
font.pixelSize: theme.fontSizeLarge
}
}
Rectangle {
visible: fileProcessingRow.visible
Layout.fillWidth: true
height: 1
color: theme.dividerColor
}
RowLayout {
Layout.fillWidth: true
spacing: 30
Layout.leftMargin: 15
Layout.topMargin: 15
Text {
text: qsTr("Remove")
elide: Text.ElideRight
color: theme.red500
font.bold: true
font.pixelSize: theme.fontSizeSmall
TapHandler {
onTapped: {
LocalDocs.removeFolder(collection, folder_path)
}
}
}
Text {
Layout.alignment: Qt.AlignRight
visible: !model.forceIndexing && !model.indexing && model.currentEmbeddingsToIndex === 0
text: qsTr("Rebuild")
elide: Text.ElideRight
color: theme.red500
font.bold: true
font.pixelSize: theme.fontSizeSmall
TapHandler {
onTapped: { LocalDocs.forceRebuildFolder(folder_path); }
}
HoverHandler { id: hoverHandler1 }
ToolTip.text: qsTr("Reindex this folder from scratch. This is slow and usually not needed.")
ToolTip.visible: hoverHandler1.hovered
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
}
Item {
Layout.fillWidth: true
}
Text {
Layout.alignment: Qt.AlignRight
visible: model.forceIndexing
text: qsTr("Update")
elide: Text.ElideRight
color: theme.red500
font.bold: true
font.pixelSize: theme.fontSizeSmall
TapHandler {
onTapped: { LocalDocs.forceIndexing(collection); }
}
HoverHandler { id: hoverHandler2 }
ToolTip.text: qsTr("Update the collection to the new version. This is a slow operation.")
ToolTip.visible: hoverHandler2.hovered
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
}
}
}
}
}
}
}
}

View File

@@ -1,643 +0,0 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Dialogs
import QtQuick.Layouts
import chatlistmodel
import download
import llm
import modellist
import network
import mysettings
MyDialog {
id: modelDownloaderDialog
modal: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
padding: 10
property bool showEmbeddingModels: false
onOpened: {
Network.trackEvent("download_dialog")
if (showEmbeddingModels) {
ModelList.downloadableModels.expanded = true
var targetModelIndex = ModelList.defaultEmbeddingModelIndex
modelListView.positionViewAtIndex(targetModelIndex, ListView.Beginning)
}
}
PopupDialog {
id: downloadingErrorPopup
anchors.centerIn: parent
shouldTimeOut: false
}
ColumnLayout {
anchors.fill: parent
anchors.margins: 10
spacing: 30
Label {
id: listLabel
text: qsTr("Discover and Download Models")
visible: true
Layout.fillWidth: true
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
color: theme.titleTextColor
font.pixelSize: theme.fontSizeLargest
font.bold: true
}
RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
Layout.margins: 0
spacing: 10
MyTextField {
id: discoverField
property string textBeingSearched: ""
readOnly: ModelList.discoverInProgress
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: 720
Layout.preferredHeight: 90
font.pixelSize: theme.fontSizeLarger
placeholderText: qsTr("Discover and download models by keyword search...")
Accessible.role: Accessible.EditableText
Accessible.name: placeholderText
Accessible.description: qsTr("Text field for discovering and filtering downloadable models")
Connections {
target: ModelList
function onDiscoverInProgressChanged() {
if (ModelList.discoverInProgress) {
discoverField.textBeingSearched = discoverField.text;
discoverField.text = qsTr("Searching \u00B7 ") + discoverField.textBeingSearched;
} else {
discoverField.text = discoverField.textBeingSearched;
discoverField.textBeingSearched = "";
}
}
}
background: ProgressBar {
id: discoverProgressBar
indeterminate: ModelList.discoverInProgress && ModelList.discoverProgress === 0.0
value: ModelList.discoverProgress
background: Rectangle {
color: theme.controlBackground
radius: 10
}
contentItem: Item {
Rectangle {
visible: ModelList.discoverInProgress
anchors.bottom: parent.bottom
width: discoverProgressBar.visualPosition * parent.width
height: 10
radius: 2
color: theme.progressForeground
}
}
}
Keys.onReturnPressed: (event)=> {
if (event.modifiers & Qt.ControlModifier || event.modifiers & Qt.ShiftModifier)
event.accepted = false;
else {
editingFinished();
sendDiscovery()
}
}
function sendDiscovery() {
ModelList.downloadableModels.discoverAndFilter(discoverField.text);
}
RowLayout {
spacing: 0
anchors.right: discoverField.right
anchors.verticalCenter: discoverField.verticalCenter
anchors.rightMargin: 15
visible: !ModelList.discoverInProgress
MyMiniButton {
id: clearDiscoverButton
backgroundColor: theme.textColor
backgroundColorHovered: theme.iconBackgroundDark
visible: discoverField.text !== ""
contentItem: Text {
color: clearDiscoverButton.hovered ? theme.iconBackgroundDark : theme.textColor
text: "\u2715"
font.pixelSize: theme.fontSizeLarge
}
onClicked: {
discoverField.text = ""
discoverField.sendDiscovery() // should clear results
}
}
MyMiniButton {
backgroundColor: theme.textColor
backgroundColorHovered: theme.iconBackgroundDark
source: "qrc:/gpt4all/icons/settings.svg"
onClicked: {
discoveryTools.visible = !discoveryTools.visible
}
}
MyMiniButton {
id: sendButton
enabled: !ModelList.discoverInProgress
backgroundColor: theme.textColor
backgroundColorHovered: theme.iconBackgroundDark
source: "qrc:/gpt4all/icons/send_message.svg"
Accessible.name: qsTr("Initiate model discovery and filtering")
Accessible.description: qsTr("Triggers discovery and filtering of models")
onClicked: {
discoverField.sendDiscovery()
}
}
}
}
}
RowLayout {
id: discoveryTools
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
Layout.margins: 0
spacing: 20
visible: false
MyComboBox {
id: comboSort
model: [qsTr("Default"), qsTr("Likes"), qsTr("Downloads"), qsTr("Recent")]
currentIndex: ModelList.discoverSort
contentItem: Text {
anchors.horizontalCenter: parent.horizontalCenter
rightPadding: 30
color: theme.textColor
text: {
return qsTr("Sort by: ") + comboSort.displayText
}
font.pixelSize: theme.fontSizeLarger
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
}
onActivated: function (index) {
ModelList.discoverSort = index;
}
}
MyComboBox {
id: comboSortDirection
model: [qsTr("Asc"), qsTr("Desc")]
currentIndex: {
if (ModelList.discoverSortDirection === 1)
return 0
else
return 1;
}
contentItem: Text {
anchors.horizontalCenter: parent.horizontalCenter
rightPadding: 30
color: theme.textColor
text: {
return qsTr("Sort dir: ") + comboSortDirection.displayText
}
font.pixelSize: theme.fontSizeLarger
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
}
onActivated: function (index) {
if (index === 0)
ModelList.discoverSortDirection = 1;
else
ModelList.discoverSortDirection = -1;
}
}
MyComboBox {
id: comboLimit
model: ["5", "10", "20", "50", "100", qsTr("None")]
currentIndex: {
if (ModelList.discoverLimit === 5)
return 0;
else if (ModelList.discoverLimit === 10)
return 1;
else if (ModelList.discoverLimit === 20)
return 2;
else if (ModelList.discoverLimit === 50)
return 3;
else if (ModelList.discoverLimit === 100)
return 4;
else if (ModelList.discoverLimit === -1)
return 5;
}
contentItem: Text {
anchors.horizontalCenter: parent.horizontalCenter
rightPadding: 30
color: theme.textColor
text: {
return qsTr("Limit: ") + comboLimit.displayText
}
font.pixelSize: theme.fontSizeLarger
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
}
onActivated: function (index) {
switch (index) {
case 0:
ModelList.discoverLimit = 5; break;
case 1:
ModelList.discoverLimit = 10; break;
case 2:
ModelList.discoverLimit = 20; break;
case 3:
ModelList.discoverLimit = 50; break;
case 4:
ModelList.discoverLimit = 100; break;
case 5:
ModelList.discoverLimit = -1; break;
}
}
}
}
Label {
visible: !ModelList.downloadableModels.count && !ModelList.asyncModelRequestOngoing
Layout.fillWidth: true
Layout.fillHeight: true
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
text: qsTr("Network error: could not retrieve http://gpt4all.io/models/models3.json")
font.pixelSize: theme.fontSizeLarge
color: theme.mutedTextColor
}
MyBusyIndicator {
visible: !ModelList.downloadableModels.count && ModelList.asyncModelRequestOngoing
running: ModelList.asyncModelRequestOngoing
Accessible.role: Accessible.Animation
Layout.alignment: Qt.AlignCenter
Accessible.name: qsTr("Busy indicator")
Accessible.description: qsTr("Displayed when the models request is ongoing")
}
ScrollView {
id: scrollView
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
ListView {
id: modelListView
model: ModelList.downloadableModels
boundsBehavior: Flickable.StopAtBounds
delegate: Rectangle {
id: delegateItem
width: modelListView.width
height: childrenRect.height
color: index % 2 === 0 ? theme.darkContrast : theme.lightContrast
GridLayout {
columns: 2
width: parent.width
Text {
textFormat: Text.StyledText
text: "<h2>" + name + "</h2>"
font.pixelSize: theme.fontSizeLarger
Layout.row: 0
Layout.column: 0
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.columnSpan: 2
color: theme.titleTextColor
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Model file")
Accessible.description: qsTr("Model file to be downloaded")
}
Rectangle {
id: actionBox
width: childrenRect.width + 20
color: theme.containerBackground
border.color: theme.accentColor
border.width: 1
radius: 10
Layout.row: 1
Layout.column: 1
Layout.rightMargin: 20
Layout.bottomMargin: 20
Layout.fillHeight: true
Layout.minimumHeight: childrenRect.height + 20
Layout.alignment: Qt.AlignRight | Qt.AlignTop
Layout.rowSpan: 2
ColumnLayout {
spacing: 0
MySettingsButton {
id: downloadButton
text: isDownloading ? qsTr("Cancel") : isIncomplete ? qsTr("Resume") : qsTr("Download")
font.pixelSize: theme.fontSizeLarge
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.minimumWidth: 200
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
visible: !isOnline && !installed && !calcHash && downloadError === ""
Accessible.description: qsTr("Stop/restart/start the download")
onClicked: {
if (!isDownloading) {
Download.downloadModel(filename);
} else {
Download.cancelDownload(filename);
}
}
}
MySettingsDestructiveButton {
id: removeButton
text: qsTr("Remove")
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.minimumWidth: 200
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
visible: installed || downloadError !== ""
Accessible.description: qsTr("Remove model from filesystem")
onClicked: {
Download.removeModel(filename);
}
}
MySettingsButton {
id: installButton
visible: !installed && isOnline
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.minimumWidth: 200
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
text: qsTr("Install")
font.pixelSize: theme.fontSizeLarge
onClicked: {
if (apiKey.text === "")
apiKey.showError();
else
Download.installModel(filename, apiKey.text);
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Install")
Accessible.description: qsTr("Install online model")
}
ColumnLayout {
spacing: 0
Label {
Layout.topMargin: 20
Layout.leftMargin: 20
textFormat: Text.StyledText
text: "<strong><font size=\"1\">"
+ (qsTr("Status: ")
+ (installed ? qsTr("Installed")
: (downloadError !== "" ? qsTr("<a href=\"#error\">Error</a>")
: (isDownloading ? qsTr("Downloading") : qsTr("Available")))))
+ "</strong></font>"
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
linkColor: theme.textErrorColor
Accessible.role: Accessible.Paragraph
Accessible.name: text
Accessible.description: qsTr("Whether the file is already installed on your system")
onLinkActivated: {
downloadingErrorPopup.text = downloadError;
downloadingErrorPopup.open();
}
}
Label {
Layout.leftMargin: 20
textFormat: Text.StyledText
text: "<strong><font size=\"1\">"
+ (qsTr("File size: ") + filesize)
+ (ramrequired < 0 ? "" : "<br>" + (qsTr("RAM required: ") + (ramrequired > 0 ? ramrequired + " GB" : qsTr("minimal"))))
+ (parameters === "" ? "" : "<br>" + qsTr("Parameters: ") + parameters)
+ (quant === "" ? "" : "<br>" + (qsTr("Quantization: ") + quant))
+ (type === "" ? "" : "<br>" + (qsTr("Type: ") + type))
+ "</strong></font>"
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
Accessible.role: Accessible.Paragraph
Accessible.name: text
Accessible.description: qsTr("Metadata about the model")
onLinkActivated: {
downloadingErrorPopup.text = downloadError;
downloadingErrorPopup.open();
}
}
Label {
visible: LLM.systemTotalRAMInGB() < ramrequired
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.maximumWidth: 300
textFormat: Text.StyledText
text: qsTr("<strong><font size=\"2\">WARNING: Not recommended for your hardware.")
+ qsTr(" Model requires more memory (") + ramrequired
+ qsTr(" GB) than your system has available (")
+ LLM.systemTotalRAMInGBString() + ").</strong></font>"
color: theme.textErrorColor
font.pixelSize: theme.fontSizeLarge
wrapMode: Text.WordWrap
Accessible.role: Accessible.Paragraph
Accessible.name: text
Accessible.description: qsTr("Error for incompatible hardware")
onLinkActivated: {
downloadingErrorPopup.text = downloadError;
downloadingErrorPopup.open();
}
}
}
ColumnLayout {
visible: isDownloading && !calcHash
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.minimumWidth: 200
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
spacing: 20
ProgressBar {
id: itemProgressBar
Layout.fillWidth: true
width: 200
value: bytesReceived / bytesTotal
background: Rectangle {
implicitHeight: 45
color: theme.progressBackground
radius: 3
}
contentItem: Item {
implicitHeight: 40
Rectangle {
width: itemProgressBar.visualPosition * parent.width
height: parent.height
radius: 2
color: theme.progressForeground
}
}
Accessible.role: Accessible.ProgressBar
Accessible.name: qsTr("Download progressBar")
Accessible.description: qsTr("Shows the progress made in the download")
}
Label {
id: speedLabel
color: theme.textColor
Layout.alignment: Qt.AlignRight
text: speed
font.pixelSize: theme.fontSizeLarge
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Download speed")
Accessible.description: qsTr("Download speed in bytes/kilobytes/megabytes per second")
}
}
RowLayout {
visible: calcHash
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.minimumWidth: 200
Layout.maximumWidth: 200
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
clip: true
Label {
id: calcHashLabel
color: theme.textColor
text: qsTr("Calculating...")
font.pixelSize: theme.fontSizeLarge
Accessible.role: Accessible.Paragraph
Accessible.name: text
Accessible.description: qsTr("Whether the file hash is being calculated")
}
MyBusyIndicator {
id: busyCalcHash
running: calcHash
Accessible.role: Accessible.Animation
Accessible.name: qsTr("Busy indicator")
Accessible.description: qsTr("Displayed when the file hash is being calculated")
}
}
MyTextField {
id: apiKey
visible: !installed && isOnline
Layout.topMargin: 20
Layout.leftMargin: 20
Layout.minimumWidth: 200
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
wrapMode: Text.WrapAnywhere
function showError() {
apiKey.placeholderTextColor = theme.textErrorColor
}
onTextChanged: {
apiKey.placeholderTextColor = theme.mutedTextColor
}
placeholderText: qsTr("enter $API_KEY")
Accessible.role: Accessible.EditableText
Accessible.name: placeholderText
Accessible.description: qsTr("Whether the file hash is being calculated")
}
}
}
Text {
id: descriptionText
text: description
font.pixelSize: theme.fontSizeLarge
Layout.row: 1
Layout.column: 0
Layout.leftMargin: 20
Layout.bottomMargin: 20
Layout.maximumWidth: modelListView.width - actionBox.width - 60
wrapMode: Text.WordWrap
textFormat: Text.StyledText
color: theme.textColor
linkColor: theme.textColor
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Description")
Accessible.description: qsTr("File description")
onLinkActivated: Qt.openUrlExternally(link)
}
}
}
footer: Component {
Rectangle {
width: modelListView.width
height: expandButton.height + 80
color: ModelList.downloadableModels.count % 2 === 0 ? theme.darkContrast : theme.lightContrast
MySettingsButton {
id: expandButton
anchors.centerIn: parent
padding: 40
text: ModelList.downloadableModels.expanded ? qsTr("Show fewer models") : qsTr("Show more models")
onClicked: {
ModelList.downloadableModels.expanded = !ModelList.downloadableModels.expanded;
}
}
}
}
}
}
RowLayout {
Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
spacing: 20
FolderDialog {
id: modelPathDialog
title: "Please choose a directory"
currentFolder: "file://" + MySettings.modelPath
onAccepted: {
MySettings.modelPath = selectedFolder
}
}
MySettingsLabel {
id: modelPathLabel
text: qsTr("Download path")
font.pixelSize: theme.fontSizeLarge
color: theme.textColor
Layout.row: 1
Layout.column: 0
}
MyDirectoryField {
id: modelPathDisplayField
text: MySettings.modelPath
font.pixelSize: theme.fontSizeLarge
Layout.fillWidth: true
ToolTip.text: qsTr("Path where model files will be downloaded to")
ToolTip.visible: hovered
Accessible.role: Accessible.ToolTip
Accessible.name: modelPathDisplayField.text
Accessible.description: ToolTip.text
onEditingFinished: {
if (isValid) {
MySettings.modelPath = modelPathDisplayField.text
} else {
text = MySettings.modelPath
}
}
}
MySettingsButton {
text: qsTr("Browse")
Accessible.description: qsTr("Choose where to save model files")
onClicked: modelPathDialog.open()
}
}
}
}

View File

@@ -17,21 +17,43 @@ MySettingsTab {
columns: 3
rowSpacing: 10
columnSpacing: 10
enabled: ModelList.installedModels.count !== 0
property var currentModelName: comboBox.currentText
property var currentModelId: comboBox.currentValue
property var currentModelInfo: ModelList.modelInfo(root.currentModelId)
MySettingsLabel {
id: label
ColumnLayout {
Layout.row: 0
Layout.column: 0
Layout.columnSpan: 3
Layout.fillWidth: true
spacing: 10
Label {
color: theme.styledTextColor
font.pixelSize: theme.fontSizeLarge
font.bold: true
text: "General"
}
Rectangle {
Layout.fillWidth: true
height: 2
color: theme.settingsDivider
}
}
MySettingsLabel {
id: label
Layout.row: 1
Layout.column: 0
text: qsTr("Model/Character")
helpText: qsTr("Select or clone a model and change its settings")
}
RowLayout {
Layout.fillWidth: true
Layout.row: 1
Layout.row: 2
Layout.column: 0
Layout.columnSpan: 2
height: label.height + 20
@@ -95,20 +117,14 @@ MySettingsTab {
}
RowLayout {
Layout.row: 2
Layout.row: 3
Layout.column: 0
Layout.topMargin: 15
spacing: 10
MySettingsLabel {
id: uniqueNameLabel
text: qsTr("Unique Name")
}
MySettingsLabel {
id: uniqueNameLabelHelp
visible: false
text: qsTr("Must contain a non-empty unique name that does not match any existing model/character.")
color: theme.textErrorColor
wrapMode: TextArea.Wrap
helpText: qsTr("Must contain a non-empty unique name")
}
}
@@ -117,7 +133,7 @@ MySettingsTab {
text: root.currentModelName
font.pixelSize: theme.fontSizeLarge
enabled: root.currentModelInfo.isClone || root.currentModelInfo.description === ""
Layout.row: 3
Layout.row: 4
Layout.column: 0
Layout.columnSpan: 2
Layout.fillWidth: true
@@ -137,14 +153,13 @@ MySettingsTab {
if (text !== "" && ModelList.isUniqueName(text)) {
MySettings.setModelName(root.currentModelInfo, text);
}
uniqueNameLabelHelp.visible = root.currentModelInfo.name !== "" &&
(text === "" || (text !== root.currentModelInfo.name && !ModelList.isUniqueName(text)));
}
}
MySettingsLabel {
text: qsTr("Model File")
Layout.row: 4
helpText: qsTr("The filename of the selected model")
Layout.row: 5
Layout.column: 0
Layout.topMargin: 15
}
@@ -153,7 +168,7 @@ MySettingsTab {
text: root.currentModelInfo.filename
font.pixelSize: theme.fontSizeLarge
enabled: false
Layout.row: 5
Layout.row: 6
Layout.column: 0
Layout.columnSpan: 2
Layout.fillWidth: true
@@ -162,7 +177,8 @@ MySettingsTab {
MySettingsLabel {
visible: !root.currentModelInfo.isOnline
text: qsTr("System Prompt")
Layout.row: 6
helpText: qsTr("Prefixed at the beginning of every conversation")
Layout.row: 7
Layout.column: 0
Layout.topMargin: 15
}
@@ -170,7 +186,7 @@ MySettingsTab {
Rectangle {
id: systemPrompt
visible: !root.currentModelInfo.isOnline
Layout.row: 7
Layout.row: 8
Layout.column: 0
Layout.columnSpan: 2
Layout.fillWidth: true
@@ -203,7 +219,7 @@ MySettingsTab {
}
RowLayout {
Layout.row: 8
Layout.row: 9
Layout.column: 0
Layout.columnSpan: 2
Layout.topMargin: 15
@@ -211,6 +227,7 @@ MySettingsTab {
MySettingsLabel {
id: promptTemplateLabel
text: qsTr("Prompt Template")
helpText: qsTr("The template that wraps every prompt")
}
MySettingsLabel {
id: promptTemplateLabelHelp
@@ -223,7 +240,7 @@ MySettingsTab {
Rectangle {
id: promptTemplate
Layout.row: 9
Layout.row: 10
Layout.column: 0
Layout.columnSpan: 2
Layout.fillWidth: true
@@ -297,34 +314,21 @@ MySettingsTab {
}
}
MySettingsLabel {
text: qsTr("Generation Settings")
Layout.row: 10
Layout.column: 0
Layout.columnSpan: 2
Layout.topMargin: 15
Layout.alignment: Qt.AlignHCenter
Layout.minimumWidth: promptTemplate.width
horizontalAlignment: Qt.AlignHCenter
font.pixelSize: theme.fontSizeLarge
font.bold: true
}
GridLayout {
Layout.row: 11
Layout.column: 0
Layout.columnSpan: 2
Layout.topMargin: 15
Layout.fillWidth: true
Layout.minimumWidth: promptTemplate.width
columns: 4
rowSpacing: 10
rowSpacing: 30
columnSpacing: 10
MySettingsLabel {
id: contextLengthLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("Context Length")
helpText: qsTr("Conversation context window")
Layout.row: 0
Layout.column: 0
}
@@ -374,6 +378,7 @@ MySettingsTab {
MySettingsLabel {
id: tempLabel
text: qsTr("Temperature")
helpText: qsTr("The temperature for model token generation")
Layout.row: 1
Layout.column: 2
}
@@ -418,6 +423,7 @@ MySettingsTab {
MySettingsLabel {
id: topPLabel
text: qsTr("Top P")
helpText: qsTr("Prevents choosing highly unlikely tokens")
Layout.row: 2
Layout.column: 0
}
@@ -461,6 +467,7 @@ MySettingsTab {
MySettingsLabel {
id: minPLabel
text: qsTr("Min P")
helpText: qsTr("Minimum relative probability")
Layout.row: 3
Layout.column: 0
}
@@ -506,6 +513,7 @@ MySettingsTab {
id: topKLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("Top K")
helpText: qsTr("Size of selection pool for tokens")
Layout.row: 2
Layout.column: 2
}
@@ -551,6 +559,7 @@ MySettingsTab {
id: maxLengthLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("Max Length")
helpText: qsTr("Maximum length of response in tokens")
Layout.row: 0
Layout.column: 2
}
@@ -597,6 +606,7 @@ MySettingsTab {
id: batchSizeLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("Prompt Batch Size")
helpText: qsTr("Amount of prompt tokens to process at once")
Layout.row: 1
Layout.column: 0
}
@@ -642,6 +652,7 @@ MySettingsTab {
id: repeatPenaltyLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("Repeat Penalty")
helpText: qsTr("Penalize repetitiveness")
Layout.row: 4
Layout.column: 2
}
@@ -687,6 +698,7 @@ MySettingsTab {
id: repeatPenaltyTokensLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("Repeat Penalty Tokens")
helpText: qsTr("Length to apply penalty")
Layout.row: 3
Layout.column: 2
}
@@ -733,6 +745,7 @@ MySettingsTab {
id: gpuLayersLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("GPU Layers")
helpText: qsTr("How many GPU layers to load into VRAM")
Layout.row: 4
Layout.column: 0
}
@@ -790,9 +803,8 @@ MySettingsTab {
Layout.columnSpan: 2
Layout.topMargin: 15
Layout.fillWidth: true
Layout.minimumWidth: promptTemplate.width
height: 3
color: theme.accentColor
height: 2
color: theme.settingsDivider
}
}
}

View File

@@ -0,0 +1,321 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Dialogs
import QtQuick.Layouts
import chatlistmodel
import download
import llm
import modellist
import network
import mysettings
Rectangle {
id: modelsView
color: theme.viewBackground
signal addModelViewRequested()
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 30
Item {
Layout.fillWidth: true
Layout.fillHeight: true
visible: ModelList.installedModels.count === 0
ColumnLayout {
id: noInstalledLabel
anchors.centerIn: parent
spacing: 0
Text {
Layout.alignment: Qt.AlignCenter
text: qsTr("No Models Installed")
color: theme.mutedLightTextColor
font.pixelSize: theme.fontSizeBannerSmall
}
Text {
Layout.topMargin: 15
horizontalAlignment: Qt.AlignHCenter
color: theme.mutedLighterTextColor
text: qsTr("Install a model to get started using GPT4All")
font.pixelSize: theme.fontSizeLarge
}
}
MyButton {
anchors.top: noInstalledLabel.bottom
anchors.topMargin: 50
anchors.horizontalCenter: noInstalledLabel.horizontalCenter
rightPadding: 60
leftPadding: 60
text: qsTr("\uFF0B Add Model")
onClicked: {
addModelViewRequested()
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Shows the add model view")
}
}
RowLayout {
visible: ModelList.installedModels.count !== 0
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
spacing: 50
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
Layout.minimumWidth: 200
spacing: 5
Text {
id: welcome
text: qsTr("Installed Models")
font.pixelSize: theme.fontSizeBanner
color: theme.titleTextColor
}
Text {
text: qsTr("Locally installed large language models")
font.pixelSize: theme.fontSizeLarge
color: theme.titleInfoTextColor
}
}
Rectangle {
Layout.fillWidth: true
height: 0
}
MyButton {
Layout.alignment: Qt.AlignTop | Qt.AlignRight
text: qsTr("\uFF0B Add Model")
onClicked: {
addModelViewRequested()
}
}
}
ScrollView {
id: scrollView
visible: ModelList.installedModels.count !== 0
ScrollBar.vertical.policy: ScrollBar.AsNeeded
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
ListView {
id: modelListView
model: ModelList.installedModels
boundsBehavior: Flickable.StopAtBounds
spacing: 30
delegate: Rectangle {
id: delegateItem
width: modelListView.width
height: childrenRect.height + 60
color: theme.conversationBackground
radius: 10
border.width: 1
border.color: theme.controlBorder
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 30
Text {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
text: name
elide: Text.ElideRight
color: theme.titleTextColor
font.pixelSize: theme.fontSizeLargest
font.bold: true
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Model file")
Accessible.description: qsTr("Model file to be downloaded")
}
Rectangle {
Layout.fillWidth: true
height: 1
color: theme.dividerColor
}
Text {
id: descriptionText
text: description
font.pixelSize: theme.fontSizeLarge
Layout.row: 1
Layout.topMargin: 10
wrapMode: Text.WordWrap
textFormat: Text.StyledText
color: theme.textColor
linkColor: theme.textColor
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Description")
Accessible.description: qsTr("File description")
onLinkActivated: Qt.openUrlExternally(link)
}
Item {
Layout.minimumWidth: childrenRect.width
Layout.minimumHeight: childrenRect.height
Layout.bottomMargin: 10
RowLayout {
id: paramRow
anchors.centerIn: parent
ColumnLayout {
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.leftMargin: 20
Layout.rightMargin: 20
Text {
text: qsTr("File size")
font.pixelSize: theme.fontSizeSmaller
color: theme.mutedDarkTextColor
}
Text {
text: filesize
color: theme.textColor
font.pixelSize: theme.fontSizeSmaller
font.bold: true
}
}
Rectangle {
width: 1
Layout.fillHeight: true
color: theme.dividerColor
}
ColumnLayout {
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.leftMargin: 20
Layout.rightMargin: 20
Text {
text: qsTr("RAM required")
font.pixelSize: theme.fontSizeSmaller
color: theme.mutedDarkTextColor
}
Text {
text: ramrequired + qsTr(" GB")
color: theme.textColor
font.pixelSize: theme.fontSizeSmaller
font.bold: true
}
}
Rectangle {
width: 1
Layout.fillHeight: true
color: theme.dividerColor
}
ColumnLayout {
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.leftMargin: 20
Layout.rightMargin: 20
Text {
text: qsTr("Parameters")
font.pixelSize: theme.fontSizeSmaller
color: theme.mutedDarkTextColor
}
Text {
text: parameters
color: theme.textColor
font.pixelSize: theme.fontSizeSmaller
font.bold: true
}
}
Rectangle {
width: 1
Layout.fillHeight: true
color: theme.dividerColor
}
ColumnLayout {
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.leftMargin: 20
Layout.rightMargin: 20
Text {
text: qsTr("Quant")
font.pixelSize: theme.fontSizeSmaller
color: theme.mutedDarkTextColor
}
Text {
text: quant
color: theme.textColor
font.pixelSize: theme.fontSizeSmaller
font.bold: true
}
}
Rectangle {
width: 1
Layout.fillHeight: true
color: theme.dividerColor
}
ColumnLayout {
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.leftMargin: 20
Layout.rightMargin: 20
Text {
text: qsTr("Type")
font.pixelSize: theme.fontSizeSmaller
color: theme.mutedDarkTextColor
}
Text {
text: type
color: theme.textColor
font.pixelSize: theme.fontSizeSmaller
font.bold: true
}
}
}
Rectangle {
color: "transparent"
anchors.fill: paramRow
border.color: theme.dividerColor
border.width: 1
radius: 10
}
}
Rectangle {
Layout.fillWidth: true
height: 1
color: theme.dividerColor
}
RowLayout {
Layout.fillWidth: true
spacing: 30
Layout.leftMargin: 15
Layout.topMargin: 15
Text {
text: qsTr("Remove")
elide: Text.ElideRight
color: theme.red500
font.bold: true
font.pixelSize: theme.fontSizeSmall
TapHandler {
onTapped: {
Download.removeModel(filename);
}
}
}
}
}
}
}
}
}
}

View File

@@ -5,16 +5,19 @@ import QtQuick.Controls.Basic
BusyIndicator {
id: control
property real size: 48
property color color: theme.accentColor
contentItem: Item {
implicitWidth: 48
implicitHeight: 48
implicitWidth: control.size
implicitHeight: control.size
Item {
id: item
x: parent.width / 2 - width / 2
y: parent.height / 2 - height / 2
width: 48
height: 48
width: control.size
height: control.size
opacity: control.running ? 1 : 0
Behavior on opacity {
@@ -40,21 +43,21 @@ BusyIndicator {
id: delegate
x: item.width / 2 - width / 2
y: item.height / 2 - height / 2
implicitWidth: 10
implicitHeight: 10
radius: 5
color: theme.accentColor
implicitWidth: control.size * .2
implicitHeight: control.size * .2
radius: control.size * .1
color: control.color
required property int index
transform: [
Translate {
y: -Math.min(item.width, item.height) * 0.5 + 5
y: -Math.min(item.width, item.height) * 0.5 + delegate.radius
},
Rotation {
angle: delegate.index / repeater.count * 360
origin.x: 5
origin.y: 5
origin.x: delegate.radius
origin.y: delegate.radius
}
]
}

View File

@@ -17,11 +17,16 @@ Button {
property real borderWidth: MySettings.chatTheme === "LegacyDark" ? 1 : 0
property color borderColor: theme.buttonBorder
property real fontPixelSize: theme.fontSizeLarge
property bool fontPixelBold: false
property alias textAlignment: textContent.horizontalAlignment
contentItem: Text {
id: textContent
text: myButton.text
horizontalAlignment: Text.AlignHCenter
horizontalAlignment: myButton.textAlignment
color: myButton.enabled ? textColor : mutedTextColor
font.pixelSize: fontPixelSize
font.bold: fontPixelBold
Accessible.role: Accessible.Button
Accessible.name: text
}
@@ -29,7 +34,7 @@ Button {
radius: myButton.backgroundRadius
border.width: myButton.borderWidth
border.color: myButton.borderColor
color: myButton.hovered ? backgroundColorHovered : backgroundColor
color: !myButton.enabled ? theme.mutedTextColor : myButton.hovered ? backgroundColorHovered : backgroundColor
}
Accessible.role: Accessible.Button
Accessible.name: text

View File

@@ -73,7 +73,7 @@ ComboBox {
context.moveTo(0, height / 2 + 2);
context.lineTo(width / 2, height);
context.lineTo(width, height / 2 + 2);
context.strokeStyle = comboBox.pressed ? theme.gray400 : theme.gray300;
context.strokeStyle = comboBox.pressed ? theme.mutedLightTextColor : theme.mutedLighterTextColor;
context.stroke();
}

View File

@@ -12,6 +12,8 @@ TextField {
background: Rectangle {
implicitWidth: 150
color: theme.controlBackground
border.width: 1
border.color: theme.controlBorder
radius: 10
}
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval

View File

@@ -0,0 +1,44 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import Qt5Compat.GraphicalEffects
import mysettings
MyButton {
id: fancyLink
property alias imageSource: myimage.source
Image {
id: myimage
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 12
sourceSize: Qt.size(15, 15)
mipmap: true
visible: false
}
ColorOverlay {
anchors.fill: myimage
source: myimage
color: fancyLink.hovered ? theme.fancyLinkTextHovered : theme.fancyLinkText
}
borderWidth: 0
backgroundColor: "transparent"
backgroundColorHovered: "transparent"
fontPixelBold: true
leftPadding: 35
rightPadding: 8
topPadding: 1
bottomPadding: 1
textColor: fancyLink.hovered ? theme.fancyLinkTextHovered : theme.fancyLinkText
fontPixelSize: theme.fontSizeSmall
background: Rectangle {
color: "transparent"
}
Accessible.name: qsTr("Fancy link")
Accessible.description: qsTr("A stylized link")
}

View File

@@ -31,9 +31,10 @@ Button {
Image {
id: image
anchors.centerIn: parent
visible: false
mipmap: true
width: 20
height: 20
sourceSize.width: 20
sourceSize.height: 20
}
ColorOverlay {
anchors.fill: image

View File

@@ -9,10 +9,10 @@ Button {
padding: 10
rightPadding: 18
leftPadding: 18
property color textColor: MySettings.chatTheme === "Dark" ? theme.green800 : theme.green600
property color mutedTextColor: textColor
property color backgroundColor: MySettings.chatTheme === "Dark" ? theme.green400 : theme.green200
property color backgroundColorHovered: theme.green300
property color textColor: theme.lightButtonText
property color mutedTextColor: theme.lightButtonMutedText
property color backgroundColor: theme.lightButtonBackground
property color backgroundColorHovered: enabled ? theme.lightButtonBackgroundHovered : backgroundColor
property real borderWidth: 0
property color borderColor: "transparent"
property real fontPixelSize: theme.fontSizeLarge

View File

@@ -10,13 +10,13 @@ Button {
rightPadding: 18
leftPadding: 18
font.pixelSize: theme.fontSizeLarge
property color textColor: MySettings.chatTheme === "Dark" ? theme.red800 : theme.red600
property color mutedTextColor: MySettings.chatTheme === "Dark" ? theme.red400 : theme.red300
property color backgroundColor: enabled ? (MySettings.chatTheme === "Dark" ? theme.red400 : theme.red200) :
(MySettings.chatTheme === "Dark" ? theme.red200 : theme.red100)
property color backgroundColorHovered: enabled ? (MySettings.chatTheme === "Dark" ? theme.red500 : theme.red300) : backgroundColor
property color textColor: theme.darkButtonText
property color mutedTextColor: theme.darkButtonMutedText
property color backgroundColor: theme.darkButtonBackground
property color backgroundColorHovered: enabled ? theme.darkButtonBackgroundHovered : backgroundColor
property real borderWidth: 0
property color borderColor: "transparent"
contentItem: Text {
text: myButton.text
horizontalAlignment: Text.AlignHCenter

View File

@@ -2,9 +2,40 @@ import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
Label {
color: theme.settingsTitleTextColor
font.pixelSize: theme.fontSizeSmall
font.bold: true
ColumnLayout {
id: root
property alias text: mainTextLabel.text
property alias helpText: helpTextLabel.text
property alias textFormat: mainTextLabel.textFormat
property alias wrapMode: mainTextLabel.wrapMode
property alias font: mainTextLabel.font
property alias horizontalAlignment: mainTextLabel.horizontalAlignment
signal linkActivated(link : url);
property alias color: mainTextLabel.color
property alias linkColor: mainTextLabel.linkColor
Label {
id: mainTextLabel
color: theme.settingsTitleTextColor
font.pixelSize: theme.fontSizeSmall
font.bold: true
onLinkActivated: function(link) {
root.linkActivated(link);
}
}
Label {
id: helpTextLabel
Layout.fillWidth: true
wrapMode: Text.Wrap
color: theme.settingsTitleTextColor
text: mainTextLabel.text
font.pixelSize: theme.fontSizeSmaller
font.bold: false
onLinkActivated: function(link) {
root.linkActivated(link);
}
}
}

View File

@@ -14,44 +14,12 @@ Item {
id: theme
}
property alias title: titleLabelText.text
property ListModel tabTitlesModel: ListModel { }
property list<Component> tabs: [ ]
Rectangle {
id: titleLabel
anchors.top: parent.top
anchors.leftMargin: 20
anchors.rightMargin: 15
anchors.left: parent.left
anchors.right: parent.right
height: titleLabelText.height
color: "transparent"
Label {
id: titleLabelText
anchors.left: parent.left
color: theme.titleTextColor
topPadding: 10
bottomPadding: 10
font.pixelSize: theme.fontSizeLargest
font.bold: true
}
}
Rectangle {
anchors.top: titleLabel.bottom
anchors.leftMargin: 20
anchors.rightMargin: 15
anchors.left: parent.left
anchors.right: parent.right
height: 3
color: theme.accentColor
}
TabBar {
id: settingsTabBar
anchors.top: titleLabel.bottom
anchors.topMargin: 15
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width / 1.75
z: 200
@@ -89,8 +57,8 @@ Item {
anchors.rightMargin: 15
anchors.left: parent.left
anchors.right: parent.right
height: 3
color: theme.accentColor
height: 2
color: theme.settingsDivider
}
FolderDialog {
@@ -106,7 +74,8 @@ Item {
StackLayout {
id: stackLayout
anchors.top: tabTitlesModel.count > 1 ? dividerTabBar.bottom : titleLabel.bottom
anchors.top: tabTitlesModel.count > 1 ? dividerTabBar.bottom : parent.top
anchors.topMargin: 5
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom

View File

@@ -8,12 +8,9 @@ Item {
id: root
property string title: ""
property Item contentItem: null
property Item advancedSettings: null
property bool showAdvancedSettingsButton: true
property bool showRestoreDefaultsButton: true
property var openFolderDialog
signal restoreDefaultsClicked
signal downloadClicked
onContentItemChanged: function() {
if (contentItem) {
@@ -23,14 +20,6 @@ Item {
}
}
onAdvancedSettingsChanged: function() {
if (advancedSettings) {
advancedSettings.parent = advancedInner;
advancedSettings.anchors.left = advancedInner.left;
advancedSettings.anchors.right = advancedInner.right;
}
}
ScrollView {
id: scrollView
width: parent.width
@@ -61,14 +50,9 @@ Item {
Layout.fillWidth: true
}
Column {
id: advancedInner
visible: false
Layout.fillWidth: true
}
Item {
Layout.fillWidth: true
Layout.topMargin: 20
height: restoreDefaultsButton.height
MySettingsButton {
id: restoreDefaultsButton
@@ -84,20 +68,6 @@ Item {
root.restoreDefaultsClicked();
}
}
MySettingsButton {
id: advancedSettingsButton
anchors.right: parent.right
visible: root.advancedSettings && showAdvancedSettingsButton
width: implicitWidth
text: !advancedInner.visible ? qsTr("Advanced Settings") : qsTr("Hide Advanced Settings")
font.pixelSize: theme.fontSizeLarge
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.description: qsTr("Shows/hides the advanced settings")
onClicked: {
advancedInner.visible = !advancedInner.visible;
}
}
}
}
}

View File

@@ -8,7 +8,7 @@ Label {
padding: 3
rightPadding: 9
leftPadding: 9
font.pixelSize: theme.fontSizeFixedSmall
font.pixelSize: theme.fontSizeSmall
background: Rectangle {
radius: 6
border.width: 1

View File

@@ -9,9 +9,13 @@ 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
property alias imageWidth: image.sourceSize.width
property alias imageHeight: image.sourceSize.height
contentItem: Text {
text: myButton.text
horizontalAlignment: Text.AlignHCenter
@@ -25,18 +29,20 @@ Button {
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "transparent"
color: myButton.toggledColor
visible: myButton.toggled
border.color: theme.accentColor
border.width: 1
border.color: myButton.toggledColor
border.width: myButton.toggledWidth
radius: 10
}
Image {
id: image
anchors.centerIn: parent
visible: false
fillMode: Image.PreserveAspectFit
mipmap: true
width: 30
height: 30
sourceSize.width: 32
sourceSize.height: 32
}
ColorOverlay {
anchors.fill: image

View File

@@ -0,0 +1,77 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import Qt5Compat.GraphicalEffects
import QtQuick.Layouts
import mysettings
Button {
id: myButton
property alias imageSource: myimage.source
property alias description: description.text
contentItem: Item {
id: item
anchors.centerIn: parent
RowLayout {
anchors.fill: parent
Rectangle {
id: rec
color: "transparent"
Layout.preferredWidth: item.width * 1/5.5
Layout.preferredHeight: item.width * 1/5.5
Layout.alignment: Qt.AlignCenter
Image {
id: myimage
anchors.centerIn: parent
sourceSize.width: rec.width
sourceSize.height: rec.height
mipmap: true
visible: false
}
ColorOverlay {
anchors.fill: myimage
source: myimage
color: theme.welcomeButtonBorder
}
}
ColumnLayout {
Layout.preferredWidth: childrenRect.width
Text {
text: myButton.text
horizontalAlignment: Text.AlignHCenter
color: myButton.hovered ? theme.welcomeButtonTextHovered : theme.welcomeButtonText
font.pixelSize: theme.fontSizeBannerSmall
font.bold: true
Accessible.role: Accessible.Button
Accessible.name: text
}
Text {
id: description
horizontalAlignment: Text.AlignHCenter
color: myButton.hovered ? theme.welcomeButtonTextHovered : theme.welcomeButtonText
font.pixelSize: theme.fontSizeSmall
font.bold: false
Accessible.role: Accessible.Button
Accessible.name: text
}
}
}
}
background: Rectangle {
radius: 10
border.width: 1
border.color: myButton.hovered ? theme.welcomeButtonBorderHovered : theme.welcomeButtonBorder
color: theme.welcomeButtonBackground
}
Accessible.role: Accessible.Button
Accessible.name: text
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
}

View File

@@ -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
MyDialog {
id: settingsDialog
modal: true
padding: 20
onOpened: {
Network.trackEvent("settings_dialog")
}
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);
}
}
}
]
}
}
}

View File

@@ -0,0 +1,158 @@
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.viewBackground
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("Application")
}
ListElement {
title: qsTr("Model")
}
ListElement {
title: qsTr("LocalDocs")
}
}
ColumnLayout {
id: mainArea
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.margins: 30
spacing: 50
RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
spacing: 50
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
Layout.minimumWidth: 200
spacing: 5
Text {
id: welcome
text: qsTr("Settings")
font.pixelSize: theme.fontSizeBanner
color: theme.titleTextColor
}
}
Rectangle {
Layout.fillWidth: true
height: 0
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Rectangle {
id: stackList
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 220
color: theme.viewBackground
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.selectedBackground : theme.viewBackground
backgroundColorHovered: backgroundColor
borderColor: "transparent"
borderWidth: 0
textColor: theme.titleTextColor
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 10
font.bold: index === listView.currentIndex
text: title
textAlignment: Qt.AlignLeft
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 {
tabs: [
Component { ApplicationSettings { } }
]
}
MySettingsStack {
tabs: [
Component { ModelSettings { } }
]
}
MySettingsStack {
tabs: [
Component { LocalDocsSettings { } }
]
}
}
}
}
}

View File

@@ -3,6 +3,7 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import download
import network
import llm
@@ -31,13 +32,20 @@ MyDialog {
id: img
anchors.top: parent.top
anchors.left: parent.left
width: 60
height: 60
source: "qrc:/gpt4all/icons/logo.svg"
sourceSize.width: 60
sourceSize.height: 60
mipmap: true
visible: false
source: "qrc:/gpt4all/icons/globe.svg"
}
ColorOverlay {
anchors.fill: img
source: img
color: theme.titleTextColor
}
Text {
anchors.left: img.right
anchors.leftMargin: 30
anchors.leftMargin: 10
anchors.verticalCenter: img.verticalCenter
text: qsTr("Welcome!")
color: theme.textColor

View File

@@ -4,7 +4,6 @@ import QtQuick.Controls.Basic
import mysettings
QtObject {
// black and white
property color black: Qt.hsla(231/360, 0.15, 0.19)
property color white: Qt.hsla(0, 0, 1)
@@ -26,6 +25,18 @@ QtObject {
property color gray900: Qt.hsla(25/360, 0.05, 0.31)
property color gray950: Qt.hsla(25/360, 0.05, 0.15)
property color grayRed0: Qt.hsla(0/360, 0.108, 0.89)
property color grayRed50: Qt.hsla(0/360, 0.108, 0.85)
property color grayRed100: Qt.hsla(0/360, 0.108, 0.80)
property color grayRed200: Qt.hsla(0/360, 0.108, 0.76)
property color grayRed300: Qt.hsla(0/360, 0.108, 0.72)
property color grayRed400: Qt.hsla(0/360, 0.108, 0.68)
property color grayRed500: Qt.hsla(0/360, 0.108, 0.60)
property color grayRed600: Qt.hsla(0/360, 0.108, 0.56)
property color grayRed700: Qt.hsla(0/360, 0.108, 0.52)
property color grayRed800: Qt.hsla(0/360, 0.108, 0.48)
property color grayRed900: Qt.hsla(0/360, 0.108, 0.42)
// darkmode
property color darkgray0: Qt.hsla(25/360, 0.05, 0.23)
property color darkgray50: Qt.hsla(25/360, 0.05, 0.21)
@@ -54,6 +65,7 @@ QtObject {
property color green950: Qt.hsla(125/360, 0.22, 0.10)
// yellow
property color yellow25: Qt.hsla(47/360, 0.90, 0.98)
property color yellow50: Qt.hsla(47/360, 0.90, 0.96)
property color yellow100: Qt.hsla(46/360, 0.89, 0.89)
property color yellow200: Qt.hsla(45/360, 0.90, 0.77)
@@ -98,6 +110,7 @@ QtObject {
property color blue400: "#444654"
property color blue500: "#343541"
property color blue600: "#2c2d37"
property color blue700: "#26272f"
property color blue800: "#232628"
property color blue900: "#222527"
property color blue950: "#1c1f21"
@@ -152,7 +165,7 @@ QtObject {
case "LegacyDark":
return blue950;
case "Dark":
return darkgray100;
return darkgray300;
default:
return gray100;
}
@@ -169,12 +182,47 @@ QtObject {
}
}
property color conversationBackground: {
property color dividerColor: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue500;
return blue950;
case "Dark":
return darkgray200;
default:
return containerBackground;
return grayRed0;
}
}
property color conversationDivider: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue900;
case "Dark":
return darkgray100;
default:
return gray100;
}
}
property color settingsDivider: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return dividerColor
case "Dark":
return darkgray400;
default:
return grayRed500;
}
}
property color viewBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue600;
case "Dark":
return darkgray100;
default:
return gray50;
}
}
@@ -196,7 +244,18 @@ QtObject {
case "Dark":
return darkgray200;
default:
return gray200;
return gray100;
}
}
property color viewBarBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue950;
case "Dark":
return darkgray400;
default:
return gray100;
}
}
@@ -207,7 +266,7 @@ QtObject {
case "Dark":
return accentColor;
default:
return accentColor;
return green600;
}
}
@@ -218,18 +277,34 @@ QtObject {
case "Dark":
return green600;
default:
return green600;
return green100;
}
}
property color progressText: {
property color altProgressForeground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return "#ffffff";
case "Dark":
return "#000000";
return progressForeground;
default:
return "#000000";
return "#fcf0c9";
}
}
property color altProgressBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return progressBackground;
default:
return "#fff9d2";
}
}
property color altProgressText: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return textColor;
default:
return "#d16f0e";
}
}
@@ -249,7 +324,7 @@ QtObject {
case "LegacyDark":
return accentColor;
case "Dark":
return green600;
return green300;
default:
return green600;
}
@@ -260,9 +335,9 @@ QtObject {
case "LegacyDark":
return blue950;
case "Dark":
return green700;
return darkgray300;
default:
return green700;
return green600;
}
}
@@ -271,18 +346,161 @@ QtObject {
case "LegacyDark":
return blue900;
case "Dark":
return green500;
return darkgray400;
default:
return green500;
}
}
property color lightButtonText: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return textColor;
case "Dark":
return textColor;
default:
return green600;
}
}
property color lightButtonMutedText: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return mutedTextColor;
case "Dark":
return mutedTextColor;
default:
return green300;
}
}
property color lightButtonBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return buttonBackground;
case "Dark":
return buttonBackground;
default:
return green100;
}
}
property color lightButtonBackgroundHovered: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return buttonBackgroundHovered;
case "Dark":
return buttonBackgroundHovered;
default:
return green200;
}
}
property color darkButtonText: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return textColor;
case "Dark":
return textColor;
default:
return red600;
}
}
property color darkButtonMutedText: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return mutedTextColor;
case "Dark":
return mutedTextColor;
default:
return red300;
}
}
property color darkButtonBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return buttonBackground;
case "Dark":
return buttonBackground;
default:
return red200;
}
}
property color darkButtonBackgroundHovered: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return buttonBackgroundHovered;
case "Dark":
return buttonBackgroundHovered;
default:
return red300;
}
}
property color lighterButtonForeground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return textColor;
case "Dark":
return textColor;
default:
return green600;
}
}
property color lighterButtonBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return buttonBackground;
case "Dark":
return buttonBackground;
default:
return green100;
}
}
property color lighterButtonBackgroundHovered: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return buttonBackgroundHovered;
case "Dark":
return buttonBackgroundHovered;
default:
return green50;
}
}
property color sourcesBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return lighterButtonBackground;
case "Dark":
return lighterButtonBackground;
default:
return gray100;
}
}
property color sourcesBackgroundHovered: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return lighterButtonBackgroundHovered;
case "Dark":
return lighterButtonBackgroundHovered;
default:
return gray200;
}
}
property color buttonBorder: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return accentColor;
case "Dark":
return yellow200;
return controlBorder;
default:
return yellow200;
}
@@ -310,6 +528,17 @@ QtObject {
}
}
property color selectedBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue700;
case "Dark":
return darkgray200;
default:
return gray0;
}
}
property color conversationButtonBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
@@ -320,6 +549,27 @@ QtObject {
return gray0;
}
}
property color conversationBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue500;
case "Dark":
return darkgray50;
default:
return white;
}
}
property color conversationProgress: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return purple400;
case "Dark":
return green400;
default:
return green400;
}
}
property color conversationButtonBackgroundHovered: {
switch (MySettings.chatTheme) {
@@ -343,6 +593,141 @@ QtObject {
}
}
property color conversationHeader: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return purple400;
case "Dark":
return green400;
default:
return green500;
}
}
property color collectionsButtonText: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return black;
case "Dark":
return black;
default:
return white;
}
}
property color collectionsButtonProgress: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return purple400;
case "Dark":
return darkgray400
default:
return green400;
}
}
property color collectionsButtonForeground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return purple400;
case "Dark":
return green300;
default:
return green600;
}
}
property color collectionsButtonBackground: {
switch (MySettings.chatTheme) {
default:
return lighterButtonBackground;
}
}
property color collectionsButtonBackgroundHovered: {
switch (MySettings.chatTheme) {
default:
return lighterButtonBackgroundHovered;
}
}
property color welcomeButtonBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return buttonBackground;
case "Dark":
return buttonBackground;
default:
return lighterButtonBackground;
}
}
property color welcomeButtonBorder: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return buttonBorder;
case "Dark":
return buttonBorder;
default:
return green300;
}
}
property color welcomeButtonBorderHovered: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return purple200;
case "Dark":
return darkgray100;
default:
return green400;
}
}
property color welcomeButtonText: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return textColor
case "Dark":
return textColor
default:
return green700;
}
}
property color welcomeButtonTextHovered: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return purple200
case "Dark":
return gray400
default:
return green800;
}
}
property color fancyLinkText: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return textColor
case "Dark":
return textColor
default:
return grayRed900;
}
}
property color fancyLinkTextHovered: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return mutedTextColor
case "Dark":
return mutedTextColor
default:
return textColor;
}
}
property color iconBackgroundDark: {
switch (MySettings.chatTheme) {
case "LegacyDark":
@@ -361,7 +746,7 @@ QtObject {
case "Dark":
return darkwhite;
default:
return white;
return gray500;
}
}
@@ -370,12 +755,45 @@ QtObject {
case "LegacyDark":
return blue0;
case "Dark":
return accentColor;
return gray400;
default:
return accentColor;
}
}
property color iconBackgroundViewBar: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return iconBackgroundLight;
case "Dark":
return iconBackgroundLight;
default:
return green500;
}
}
property color iconBackgroundViewBarToggled: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return iconBackgroundLight;
case "Dark":
return darkgray50;
default:
return green200;
}
}
property color iconBackgroundViewBarHovered: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return iconBackgroundHovered;
case "Dark":
return iconBackgroundHovered;
default:
return green600;
}
}
property color slugBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
@@ -398,6 +816,27 @@ QtObject {
}
}
// lighter contrast
property color mutedLighterTextColor: {
switch (MySettings.chatTheme) {
// case "LegacyDark":
// case "Dark":
default:
return gray300;
}
}
// light contrast
property color mutedLightTextColor: {
switch (MySettings.chatTheme) {
// case "LegacyDark":
// case "Dark":
default:
return gray400;
}
}
// normal contrast
property color mutedTextColor: {
switch (MySettings.chatTheme) {
case "LegacyDark":
@@ -405,7 +844,29 @@ QtObject {
case "Dark":
return gray400;
default:
return gray600;
return gray500;
}
}
// dark contrast
property color mutedDarkTextColor: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return mutedTextColor;
case "Dark":
return mutedTextColor;
default:
return grayRed500;
}
}
// dark contrast hovered
property color mutedDarkTextColorHovered: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue400;
default:
return grayRed900;
}
}
@@ -458,9 +919,9 @@ QtObject {
case "LegacyDark":
return blue100;
case "Dark":
return green400;
return green200;
default:
return green700;
return black;
}
}
@@ -469,12 +930,56 @@ QtObject {
case "LegacyDark":
return purple400;
case "Dark":
return green400;
return green300;
default:
return green700;
}
}
property color titleTextColor2: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return darkwhite;
case "Dark":
return green200;
default:
return green700;
}
}
property color titleInfoTextColor: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue200;
case "Dark":
return gray400;
default:
return gray600;
}
}
property color styledTextColor: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return purple100
case "Dark":
return yellow25
default:
return grayRed900;
}
}
property color styledTextColor2: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue0;
case "Dark":
return yellow50
default:
return green500;
}
}
property color dialogBorder: {
switch (MySettings.chatTheme) {
case "LegacyDark":
@@ -510,12 +1015,8 @@ QtObject {
property color mainComboBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue950;
case "Dark":
return green700;
default:
return green700;
return "transparent";
}
}
@@ -552,18 +1053,19 @@ QtObject {
}
}
property real fontSizeFixedSmall: 16
property real fontSize: Qt.application.font.pixelSize
property real fontSizeLargeCapped: MySettings.fontSize === "Small" ? 12 : 17
property real fontSizeSmaller: fontSizeLarge - 4
property real fontSizeSmall: fontSizeLarge - 2
property real fontSizeLarge: MySettings.fontSize === "Small" ?
fontSize : MySettings.fontSize === "Medium" ?
fontSize + 5 : fontSize + 10
property real fontSizeLarger: MySettings.fontSize === "Small" ?
fontSize + 2 : MySettings.fontSize === "Medium" ?
fontSize + 7 : fontSize + 12
property real fontSizeLargest: MySettings.fontSize === "Small" ?
fontSize + 7 : MySettings.fontSize === "Medium" ?
fontSize + 12 : fontSize + 14
property real fontSizeLarge: MySettings.fontSize === "Small" ? 12 :
MySettings.fontSize === "Medium" ? 17 :
22
property real fontSizeLargest: MySettings.fontSize === "Small" ? 19 :
MySettings.fontSize === "Medium" ? 24 :
26
property real fontSizeSmaller: fontSizeLarge - 4
property real fontSizeSmall: fontSizeLarge - 2
property real fontSizeLarger: fontSizeLarge + 2
property real fontSizeBannerSmall: fontSizeLargest + 10
property real fontSizeBanner: fontSizeLargest + 40
}