mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2024-10-01 01:06:10 -04:00
a910d65755
Signed-off-by: Adam Treat <treat.adam@gmail.com>
603 lines
21 KiB
QML
603 lines
21 KiB
QML
import QtCore
|
|
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Controls.Basic
|
|
import QtQuick.Layouts
|
|
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: 30
|
|
columnSpacing: 10
|
|
|
|
Label {
|
|
Layout.row: 0
|
|
Layout.column: 0
|
|
Layout.bottomMargin: 10
|
|
color: theme.settingsTitleTextColor
|
|
font.pixelSize: theme.fontSizeBannerSmall
|
|
font.bold: true
|
|
text: qsTr("Application Settings")
|
|
}
|
|
|
|
ColumnLayout {
|
|
Layout.row: 1
|
|
Layout.column: 0
|
|
Layout.columnSpan: 3
|
|
Layout.fillWidth: true
|
|
spacing: 10
|
|
Label {
|
|
color: theme.styledTextColor
|
|
font.pixelSize: theme.fontSizeLarge
|
|
font.bold: true
|
|
text: qsTr("General")
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
height: 1
|
|
color: theme.settingsDivider
|
|
}
|
|
}
|
|
|
|
MySettingsLabel {
|
|
id: themeLabel
|
|
text: qsTr("Theme")
|
|
helpText: qsTr("The application color scheme.")
|
|
Layout.row: 2
|
|
Layout.column: 0
|
|
}
|
|
MyComboBox {
|
|
id: themeBox
|
|
Layout.row: 2
|
|
Layout.column: 2
|
|
Layout.minimumWidth: 200
|
|
Layout.maximumWidth: 200
|
|
Layout.fillWidth: false
|
|
Layout.alignment: Qt.AlignRight
|
|
// NOTE: indices match values of ChatTheme enum, keep them in sync
|
|
model: ListModel {
|
|
ListElement { name: qsTr("Light") }
|
|
ListElement { name: qsTr("Dark") }
|
|
ListElement { name: qsTr("LegacyDark") }
|
|
}
|
|
Accessible.name: themeLabel.text
|
|
Accessible.description: themeLabel.helpText
|
|
function updateModel() {
|
|
themeBox.currentIndex = MySettings.chatTheme;
|
|
}
|
|
Component.onCompleted: {
|
|
themeBox.updateModel()
|
|
}
|
|
Connections {
|
|
target: MySettings
|
|
function onChatThemeChanged() {
|
|
themeBox.updateModel()
|
|
}
|
|
}
|
|
onActivated: {
|
|
MySettings.chatTheme = themeBox.currentIndex
|
|
}
|
|
}
|
|
MySettingsLabel {
|
|
id: fontLabel
|
|
text: qsTr("Font Size")
|
|
helpText: qsTr("The size of text in the application.")
|
|
Layout.row: 3
|
|
Layout.column: 0
|
|
}
|
|
MyComboBox {
|
|
id: fontBox
|
|
Layout.row: 3
|
|
Layout.column: 2
|
|
Layout.minimumWidth: 200
|
|
Layout.maximumWidth: 200
|
|
Layout.fillWidth: false
|
|
Layout.alignment: Qt.AlignRight
|
|
// NOTE: indices match values of FontSize enum, keep them in sync
|
|
model: ListModel {
|
|
ListElement { name: qsTr("Small") }
|
|
ListElement { name: qsTr("Medium") }
|
|
ListElement { name: qsTr("Large") }
|
|
}
|
|
Accessible.name: fontLabel.text
|
|
Accessible.description: fontLabel.helpText
|
|
function updateModel() {
|
|
fontBox.currentIndex = MySettings.fontSize;
|
|
}
|
|
Component.onCompleted: {
|
|
fontBox.updateModel()
|
|
}
|
|
Connections {
|
|
target: MySettings
|
|
function onFontSizeChanged() {
|
|
fontBox.updateModel()
|
|
}
|
|
}
|
|
onActivated: {
|
|
MySettings.fontSize = fontBox.currentIndex
|
|
}
|
|
}
|
|
MySettingsLabel {
|
|
id: languageLabel
|
|
visible: MySettings.uiLanguages.length > 1
|
|
text: qsTr("Language and Locale")
|
|
helpText: qsTr("The language and locale you wish to use.")
|
|
Layout.row: 4
|
|
Layout.column: 0
|
|
}
|
|
MyComboBox {
|
|
id: languageBox
|
|
visible: MySettings.uiLanguages.length > 1
|
|
Layout.row: 4
|
|
Layout.column: 2
|
|
Layout.minimumWidth: 200
|
|
Layout.maximumWidth: 200
|
|
Layout.fillWidth: false
|
|
Layout.alignment: Qt.AlignRight
|
|
model: ListModel {
|
|
Component.onCompleted: {
|
|
for (var i = 0; i < MySettings.uiLanguages.length; ++i)
|
|
append({"text": MySettings.uiLanguages[i]});
|
|
languageBox.updateModel();
|
|
}
|
|
ListElement { text: qsTr("System Locale") }
|
|
}
|
|
|
|
Accessible.name: languageLabel.text
|
|
Accessible.description: languageLabel.helpText
|
|
function updateModel() {
|
|
// This usage of 'System Locale' should not be translated
|
|
// FIXME: Make this refer to a string literal variable accessed by both QML and C++
|
|
if (MySettings.languageAndLocale === "System Locale")
|
|
languageBox.currentIndex = 0
|
|
else
|
|
languageBox.currentIndex = languageBox.indexOfValue(MySettings.languageAndLocale);
|
|
}
|
|
Component.onCompleted: {
|
|
languageBox.updateModel()
|
|
}
|
|
onActivated: {
|
|
// This usage of 'System Locale' should not be translated
|
|
// FIXME: Make this refer to a string literal variable accessed by both QML and C++
|
|
if (languageBox.currentIndex === 0)
|
|
MySettings.languageAndLocale = "System Locale";
|
|
else
|
|
MySettings.languageAndLocale = languageBox.currentText;
|
|
}
|
|
}
|
|
MySettingsLabel {
|
|
id: deviceLabel
|
|
text: qsTr("Device")
|
|
helpText: qsTr('The compute device used for text generation.')
|
|
Layout.row: 5
|
|
Layout.column: 0
|
|
}
|
|
MyComboBox {
|
|
id: deviceBox
|
|
Layout.row: 5
|
|
Layout.column: 2
|
|
Layout.minimumWidth: 400
|
|
Layout.maximumWidth: 400
|
|
Layout.fillWidth: false
|
|
Layout.alignment: Qt.AlignRight
|
|
model: ListModel {
|
|
Component.onCompleted: {
|
|
for (var i = 0; i < MySettings.deviceList.length; ++i)
|
|
append({"text": MySettings.deviceList[i]});
|
|
deviceBox.updateModel();
|
|
}
|
|
ListElement { text: qsTr("Application default") }
|
|
}
|
|
|
|
Accessible.name: deviceLabel.text
|
|
Accessible.description: deviceLabel.helpText
|
|
function updateModel() {
|
|
// This usage of 'Auto' should not be translated
|
|
// FIXME: Make this refer to a string literal variable accessed by both QML and C++
|
|
if (MySettings.device === "Auto")
|
|
deviceBox.currentIndex = 0
|
|
else
|
|
deviceBox.currentIndex = deviceBox.indexOfValue(MySettings.device);
|
|
}
|
|
Component.onCompleted: {
|
|
deviceBox.updateModel();
|
|
}
|
|
Connections {
|
|
target: MySettings
|
|
function onDeviceChanged() {
|
|
deviceBox.updateModel();
|
|
}
|
|
}
|
|
onActivated: {
|
|
// This usage of 'Auto' should not be translated
|
|
// FIXME: Make this refer to a string literal variable accessed by both QML and C++
|
|
if (deviceBox.currentIndex === 0)
|
|
MySettings.device = "Auto";
|
|
else
|
|
MySettings.device = deviceBox.currentText;
|
|
}
|
|
}
|
|
MySettingsLabel {
|
|
id: defaultModelLabel
|
|
text: qsTr("Default Model")
|
|
helpText: qsTr("The preferred model for new chats. Also used as the local server fallback.")
|
|
Layout.row: 6
|
|
Layout.column: 0
|
|
}
|
|
MyComboBox {
|
|
id: defaultModelBox
|
|
Layout.row: 6
|
|
Layout.column: 2
|
|
Layout.minimumWidth: 400
|
|
Layout.maximumWidth: 400
|
|
Layout.alignment: Qt.AlignRight
|
|
model: ListModel {
|
|
id: defaultModelBoxModel
|
|
Component.onCompleted: {
|
|
defaultModelBox.rebuildModel()
|
|
}
|
|
}
|
|
Accessible.name: defaultModelLabel.text
|
|
Accessible.description: defaultModelLabel.helpText
|
|
function rebuildModel() {
|
|
defaultModelBoxModel.clear();
|
|
defaultModelBoxModel.append({"text": qsTr("Application default")});
|
|
for (var i = 0; i < ModelList.selectableModelList.length; ++i)
|
|
defaultModelBoxModel.append({"text": ModelList.selectableModelList[i].name});
|
|
defaultModelBox.updateModel();
|
|
}
|
|
function updateModel() {
|
|
// This usage of 'Application default' should not be translated
|
|
// FIXME: Make this refer to a string literal variable accessed by both QML and C++
|
|
if (MySettings.userDefaultModel === "Application default")
|
|
defaultModelBox.currentIndex = 0
|
|
else
|
|
defaultModelBox.currentIndex = defaultModelBox.indexOfValue(MySettings.userDefaultModel);
|
|
}
|
|
onActivated: {
|
|
// This usage of 'Application default' should not be translated
|
|
// FIXME: Make this refer to a string literal variable accessed by both QML and C++
|
|
if (defaultModelBox.currentIndex === 0)
|
|
MySettings.userDefaultModel = "Application default";
|
|
else
|
|
MySettings.userDefaultModel = defaultModelBox.currentText;
|
|
}
|
|
Connections {
|
|
target: MySettings
|
|
function onUserDefaultModelChanged() {
|
|
defaultModelBox.updateModel()
|
|
}
|
|
}
|
|
Connections {
|
|
target: MySettings
|
|
function onLanguageAndLocaleChanged() {
|
|
defaultModelBox.rebuildModel()
|
|
}
|
|
}
|
|
Connections {
|
|
target: ModelList
|
|
function onSelectableModelListChanged() {
|
|
defaultModelBox.rebuildModel()
|
|
}
|
|
}
|
|
}
|
|
MySettingsLabel {
|
|
id: suggestionModeLabel
|
|
text: qsTr("Suggestion Mode")
|
|
helpText: qsTr("Generate suggested follow-up questions at the end of responses.")
|
|
Layout.row: 7
|
|
Layout.column: 0
|
|
}
|
|
MyComboBox {
|
|
id: suggestionModeBox
|
|
Layout.row: 7
|
|
Layout.column: 2
|
|
Layout.minimumWidth: 400
|
|
Layout.maximumWidth: 400
|
|
Layout.alignment: Qt.AlignRight
|
|
// NOTE: indices match values of SuggestionMode enum, keep them in sync
|
|
model: ListModel {
|
|
ListElement { name: qsTr("When chatting with LocalDocs") }
|
|
ListElement { name: qsTr("Whenever possible") }
|
|
ListElement { name: qsTr("Never") }
|
|
}
|
|
Accessible.name: suggestionModeLabel.text
|
|
Accessible.description: suggestionModeLabel.helpText
|
|
onActivated: {
|
|
MySettings.suggestionMode = suggestionModeBox.currentIndex;
|
|
}
|
|
Component.onCompleted: {
|
|
suggestionModeBox.currentIndex = MySettings.suggestionMode;
|
|
}
|
|
}
|
|
MySettingsLabel {
|
|
id: modelPathLabel
|
|
text: qsTr("Download Path")
|
|
helpText: qsTr("Where to store local models and the LocalDocs database.")
|
|
Layout.row: 8
|
|
Layout.column: 0
|
|
}
|
|
|
|
RowLayout {
|
|
Layout.row: 8
|
|
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
|
|
Accessible.name: modelPathLabel.text
|
|
Accessible.description: modelPathLabel.helpText
|
|
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
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
MySettingsLabel {
|
|
id: dataLakeLabel
|
|
text: qsTr("Enable Datalake")
|
|
helpText: qsTr("Send chats and feedback to the GPT4All Open-Source Datalake.")
|
|
Layout.row: 9
|
|
Layout.column: 0
|
|
}
|
|
MyCheckBox {
|
|
id: dataLakeBox
|
|
Layout.row: 9
|
|
Layout.column: 2
|
|
Layout.alignment: Qt.AlignRight
|
|
Component.onCompleted: { dataLakeBox.checked = MySettings.networkIsActive; }
|
|
Connections {
|
|
target: MySettings
|
|
function onNetworkIsActiveChanged() { dataLakeBox.checked = MySettings.networkIsActive; }
|
|
}
|
|
onClicked: {
|
|
if (MySettings.networkIsActive)
|
|
MySettings.networkIsActive = false;
|
|
else
|
|
networkDialog.open();
|
|
dataLakeBox.checked = MySettings.networkIsActive;
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
Layout.row: 10
|
|
Layout.column: 0
|
|
Layout.columnSpan: 3
|
|
Layout.fillWidth: true
|
|
spacing: 10
|
|
Label {
|
|
color: theme.styledTextColor
|
|
font.pixelSize: theme.fontSizeLarge
|
|
font.bold: true
|
|
text: qsTr("Advanced")
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
height: 1
|
|
color: theme.settingsDivider
|
|
}
|
|
}
|
|
|
|
MySettingsLabel {
|
|
id: nThreadsLabel
|
|
text: qsTr("CPU Threads")
|
|
helpText: qsTr("The number of CPU threads used for inference and embedding.")
|
|
Layout.row: 11
|
|
Layout.column: 0
|
|
}
|
|
MyTextField {
|
|
text: MySettings.threadCount
|
|
color: theme.textColor
|
|
font.pixelSize: theme.fontSizeLarge
|
|
Layout.alignment: Qt.AlignRight
|
|
Layout.row: 11
|
|
Layout.column: 2
|
|
Layout.minimumWidth: 200
|
|
Layout.maximumWidth: 200
|
|
validator: IntValidator {
|
|
bottom: 1
|
|
}
|
|
onEditingFinished: {
|
|
var val = parseInt(text)
|
|
if (!isNaN(val)) {
|
|
MySettings.threadCount = val
|
|
focus = false
|
|
} else {
|
|
text = MySettings.threadCount
|
|
}
|
|
}
|
|
Accessible.role: Accessible.EditableText
|
|
Accessible.name: nThreadsLabel.text
|
|
Accessible.description: ToolTip.text
|
|
}
|
|
MySettingsLabel {
|
|
id: saveChatsContextLabel
|
|
text: qsTr("Save Chat Context")
|
|
helpText: qsTr("Save the chat model's state to disk for faster loading. WARNING: Uses ~2GB per chat.")
|
|
Layout.row: 12
|
|
Layout.column: 0
|
|
}
|
|
MyCheckBox {
|
|
id: saveChatsContextBox
|
|
Layout.row: 12
|
|
Layout.column: 2
|
|
Layout.alignment: Qt.AlignRight
|
|
checked: MySettings.saveChatsContext
|
|
onClicked: {
|
|
MySettings.saveChatsContext = !MySettings.saveChatsContext
|
|
}
|
|
}
|
|
MySettingsLabel {
|
|
id: serverChatLabel
|
|
text: qsTr("Enable Local Server")
|
|
helpText: qsTr("Expose an OpenAI-Compatible server to localhost. WARNING: Results in increased resource usage.")
|
|
Layout.row: 13
|
|
Layout.column: 0
|
|
}
|
|
MyCheckBox {
|
|
id: serverChatBox
|
|
Layout.row: 13
|
|
Layout.column: 2
|
|
Layout.alignment: Qt.AlignRight
|
|
checked: MySettings.serverChat
|
|
onClicked: {
|
|
MySettings.serverChat = !MySettings.serverChat
|
|
}
|
|
}
|
|
MySettingsLabel {
|
|
id: serverPortLabel
|
|
text: qsTr("API Server Port")
|
|
helpText: qsTr("The port to use for the local server. Requires restart.")
|
|
Layout.row: 14
|
|
Layout.column: 0
|
|
}
|
|
MyTextField {
|
|
id: serverPortField
|
|
text: MySettings.networkPort
|
|
color: theme.textColor
|
|
font.pixelSize: theme.fontSizeLarge
|
|
Layout.row: 14
|
|
Layout.column: 2
|
|
Layout.minimumWidth: 200
|
|
Layout.maximumWidth: 200
|
|
Layout.alignment: Qt.AlignRight
|
|
validator: IntValidator {
|
|
bottom: 1
|
|
}
|
|
onEditingFinished: {
|
|
var val = parseInt(text)
|
|
if (!isNaN(val)) {
|
|
MySettings.networkPort = val
|
|
focus = false
|
|
} else {
|
|
text = MySettings.networkPort
|
|
}
|
|
}
|
|
Accessible.role: Accessible.EditableText
|
|
Accessible.name: serverPortLabel.text
|
|
Accessible.description: serverPortLabel.helpText
|
|
}
|
|
|
|
/*MySettingsLabel {
|
|
id: gpuOverrideLabel
|
|
text: qsTr("Force Metal (macOS+arm)")
|
|
Layout.row: 13
|
|
Layout.column: 0
|
|
}
|
|
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
|
|
}*/
|
|
|
|
MySettingsLabel {
|
|
id: updatesLabel
|
|
text: qsTr("Check For Updates")
|
|
helpText: qsTr("Manually check for an update to GPT4All.");
|
|
Layout.row: 15
|
|
Layout.column: 0
|
|
}
|
|
|
|
MySettingsButton {
|
|
Layout.row: 15
|
|
Layout.column: 2
|
|
Layout.alignment: Qt.AlignRight
|
|
text: qsTr("Updates");
|
|
onClicked: {
|
|
if (!LLM.checkForUpdates())
|
|
checkForUpdatesError.open()
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.row: 16
|
|
Layout.column: 0
|
|
Layout.columnSpan: 3
|
|
Layout.fillWidth: true
|
|
height: 1
|
|
color: theme.settingsDivider
|
|
}
|
|
}
|
|
}
|
|
|