mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-09-09 12:29:56 +00:00
chat: major UI redesign for v3.0.0 (#2396)
Signed-off-by: Adam Treat <treat.adam@gmail.com> Signed-off-by: Jared Van Bortel <jared@nomic.ai> Co-authored-by: Jared Van Bortel <jared@nomic.ai>
This commit is contained in:
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
170
gpt4all-chat/qml/AddCollectionView.qml
Normal file
170
gpt4all-chat/qml/AddCollectionView.qml
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
726
gpt4all-chat/qml/AddModelView.qml
Normal file
726
gpt4all-chat/qml/AddModelView.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
148
gpt4all-chat/qml/CollectionsDrawer.qml
Normal file
148
gpt4all-chat/qml/CollectionsDrawer.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
278
gpt4all-chat/qml/HomeView.qml
Normal file
278
gpt4all-chat/qml/HomeView.qml
Normal 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") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
457
gpt4all-chat/qml/LocalDocsView.qml
Normal file
457
gpt4all-chat/qml/LocalDocsView.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
321
gpt4all-chat/qml/ModelsView.qml
Normal file
321
gpt4all-chat/qml/ModelsView.qml
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
|
||||
}
|
||||
|
@@ -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
|
||||
|
44
gpt4all-chat/qml/MyFancyLink.qml
Normal file
44
gpt4all-chat/qml/MyFancyLink.qml
Normal 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")
|
||||
}
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
77
gpt4all-chat/qml/MyWelcomeButton.qml
Normal file
77
gpt4all-chat/qml/MyWelcomeButton.qml
Normal 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
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
158
gpt4all-chat/qml/SettingsView.qml
Normal file
158
gpt4all-chat/qml/SettingsView.qml
Normal 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 { } }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
@@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user