gpt4all/gpt4all-chat/qml/SettingsDialog.qml

869 lines
37 KiB
QML

import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Dialogs
import QtQuick.Layouts
import Qt.labs.folderlistmodel
import chatlistmodel
import download
import modellist
import network
import llm
import mysettings
Dialog {
id: settingsDialog
modal: true
opacity: 0.9
padding: 20
bottomPadding: 30
background: Rectangle {
anchors.fill: parent
color: theme.backgroundDarkest
border.width: 1
border.color: theme.dialogBorder
radius: 10
}
onOpened: {
Network.sendSettingsDialog();
}
property var currentChat: ChatListModel.currentChat
Theme {
id: theme
}
property real defaultTemperature: 0.7
property real defaultTopP: 0.1
property int defaultTopK: 40
property int defaultMaxLength: 4096
property int defaultPromptBatchSize: 128
property real defaultRepeatPenalty: 1.18
property int defaultRepeatPenaltyTokens: 64
property int defaultThreadCount: 0
property bool defaultSaveChats: false
property bool defaultSaveChatGPTChats: true
property bool defaultServerChat: false
property string defaultPromptTemplate: "### Human:
%1
### Assistant:\n"
property string defaultModelPath: ModelList.defaultLocalModelsPath()
property string defaultUserDefaultModel: "Application default"
property alias temperature: settings.temperature
property alias topP: settings.topP
property alias topK: settings.topK
property alias maxLength: settings.maxLength
property alias promptBatchSize: settings.promptBatchSize
property alias promptTemplate: settings.promptTemplate
property alias repeatPenalty: settings.repeatPenalty
property alias repeatPenaltyTokens: settings.repeatPenaltyTokens
property alias threadCount: settings.threadCount
property alias saveChats: settings.saveChats
property alias saveChatGPTChats: settings.saveChatGPTChats
property alias serverChat: settings.serverChat
property alias modelPath: settings.modelPath
property alias userDefaultModel: settings.userDefaultModel
Settings {
id: settings
property real temperature: settingsDialog.defaultTemperature
property real topP: settingsDialog.defaultTopP
property int topK: settingsDialog.defaultTopK
property int maxLength: settingsDialog.defaultMaxLength
property int promptBatchSize: settingsDialog.defaultPromptBatchSize
property int threadCount: settingsDialog.defaultThreadCount
property bool saveChats: settingsDialog.defaultSaveChats
property bool saveChatGPTChats: settingsDialog.defaultSaveChatGPTChats
property bool serverChat: settingsDialog.defaultServerChat
property real repeatPenalty: settingsDialog.defaultRepeatPenalty
property int repeatPenaltyTokens: settingsDialog.defaultRepeatPenaltyTokens
property string promptTemplate: settingsDialog.defaultPromptTemplate
property string modelPath: settingsDialog.defaultModelPath
property string userDefaultModel: settingsDialog.defaultUserDefaultModel
}
function restoreGenerationDefaults() {
settings.temperature = defaultTemperature
settings.topP = defaultTopP
settings.topK = defaultTopK
settings.maxLength = defaultMaxLength
settings.promptBatchSize = defaultPromptBatchSize
settings.promptTemplate = defaultPromptTemplate
settings.repeatPenalty = defaultRepeatPenalty
settings.repeatPenaltyTokens = defaultRepeatPenaltyTokens
settings.sync()
}
function restoreApplicationDefaults() {
settings.modelPath = settingsDialog.defaultModelPath
settings.threadCount = defaultThreadCount
settings.saveChats = defaultSaveChats
settings.saveChatGPTChats = defaultSaveChatGPTChats
settings.serverChat = defaultServerChat
settings.userDefaultModel = defaultUserDefaultModel
ModelList.localModelsPath = settings.modelPath
LLM.threadCount = settings.threadCount
LLM.serverEnabled = settings.serverChat
ChatListModel.shouldSaveChats = settings.saveChats
ChatListModel.shouldSaveChatGPTChats = settings.saveChatGPTChats
MySettings.forceMetal = false
settings.sync()
}
Component.onCompleted: {
LLM.threadCount = settings.threadCount
LLM.serverEnabled = settings.serverChat
ChatListModel.shouldSaveChats = settings.saveChats
ChatListModel.shouldSaveChatGPTChats = settings.saveChatGPTChats
ModelList.localModelsPath = settings.modelPath
}
Connections {
target: settingsDialog
function onClosed() {
settings.sync()
}
}
Item {
Accessible.role: Accessible.Dialog
Accessible.name: qsTr("Settings dialog")
Accessible.description: qsTr("Dialog containing various application settings")
}
TabBar {
id: settingsTabBar
width: parent.width / 1.25
z: 200
TabButton {
id: genSettingsButton
contentItem: IconLabel {
color: theme.textColor
font.bold: genSettingsButton.checked
text: qsTr("Generation")
}
background: Rectangle {
color: genSettingsButton.checked ? theme.backgroundDarkest : theme.backgroundLight
Rectangle {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: genSettingsButton.checked
color: theme.tabBorder
}
Rectangle {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
height: !genSettingsButton.checked
color: theme.tabBorder
}
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: genSettingsButton.checked
color: theme.tabBorder
}
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
width: genSettingsButton.checked
color: theme.tabBorder
}
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Generation settings")
Accessible.description: qsTr("Settings related to how the model generates text")
}
TabButton {
id: appSettingsButton
contentItem: IconLabel {
color: theme.textColor
font.bold: appSettingsButton.checked
text: qsTr("Application")
}
background: Rectangle {
color: appSettingsButton.checked ? theme.backgroundDarkest : theme.backgroundLight
Rectangle {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: appSettingsButton.checked
color: theme.tabBorder
}
Rectangle {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
height: !appSettingsButton.checked
color: theme.tabBorder
}
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: appSettingsButton.checked
color: theme.tabBorder
}
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
width: appSettingsButton.checked
color: theme.tabBorder
}
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Application settings")
Accessible.description: qsTr("Settings related to general behavior of the application")
}
TabButton {
id: localDocsButton
contentItem: IconLabel {
color: theme.textColor
font.bold: localDocsButton.checked
text: qsTr("LocalDocs Plugin (BETA)")
}
background: Rectangle {
color: localDocsButton.checked ? theme.backgroundDarkest : theme.backgroundLight
Rectangle {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: localDocsButton.checked
color: theme.tabBorder
}
Rectangle {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
height: !localDocsButton.checked
color: theme.tabBorder
}
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: localDocsButton.checked
color: theme.tabBorder
}
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
width: localDocsButton.checked
color: theme.tabBorder
}
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("LocalDocs settings")
Accessible.description: qsTr("Settings related to localdocs plugin")
}
}
StackLayout {
anchors.top: settingsTabBar.bottom
anchors.topMargin: -1
width: parent.width
height: availableHeight
currentIndex: settingsTabBar.currentIndex
Item {
id: generationSettingsTab
ScrollView {
background: Rectangle {
color: 'transparent'
border.color: theme.tabBorder
border.width: 1
radius: 2
}
padding: 10
width: parent.width
height: parent.height - 30
contentWidth: availableWidth - 20
contentHeight: generationSettingsTabInner.implicitHeight + 40
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
GridLayout {
id: generationSettingsTabInner
anchors.margins: 10
columns: 2
rowSpacing: 10
columnSpacing: 10
anchors.fill: parent
Label {
id: tempLabel
text: qsTr("Temperature:")
color: theme.textColor
Layout.row: 0
Layout.column: 0
}
MyTextField {
text: settings.temperature.toString()
color: theme.textColor
ToolTip.text: qsTr("Temperature increases the chances of choosing less likely tokens.\nNOTE: Higher temperature gives more creative but less predictable outputs.")
ToolTip.visible: hovered
Layout.row: 0
Layout.column: 1
validator: DoubleValidator {
locale: "C"
}
onEditingFinished: {
var val = parseFloat(text)
if (!isNaN(val)) {
settings.temperature = val
settings.sync()
focus = false
} else {
text = settings.temperature.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: tempLabel.text
Accessible.description: ToolTip.text
}
Label {
id: topPLabel
text: qsTr("Top P:")
color: theme.textColor
Layout.row: 1
Layout.column: 0
}
MyTextField {
text: settings.topP.toString()
color: theme.textColor
ToolTip.text: qsTr("Only the most likely tokens up to a total probability of top_p can be chosen.\nNOTE: Prevents choosing highly unlikely tokens, aka Nucleus Sampling")
ToolTip.visible: hovered
Layout.row: 1
Layout.column: 1
validator: DoubleValidator {
locale: "C"
}
onEditingFinished: {
var val = parseFloat(text)
if (!isNaN(val)) {
settings.topP = val
settings.sync()
focus = false
} else {
text = settings.topP.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: topPLabel.text
Accessible.description: ToolTip.text
}
Label {
id: topKLabel
text: qsTr("Top K:")
color: theme.textColor
Layout.row: 2
Layout.column: 0
}
MyTextField {
text: settings.topK.toString()
color: theme.textColor
ToolTip.text: qsTr("Only the top K most likely tokens will be chosen from")
ToolTip.visible: hovered
Layout.row: 2
Layout.column: 1
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
settings.topK = val
settings.sync()
focus = false
} else {
text = settings.topK.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: topKLabel.text
Accessible.description: ToolTip.text
}
Label {
id: maxLengthLabel
text: qsTr("Max Length:")
color: theme.textColor
Layout.row: 3
Layout.column: 0
}
MyTextField {
text: settings.maxLength.toString()
color: theme.textColor
ToolTip.text: qsTr("Maximum length of response in tokens")
ToolTip.visible: hovered
Layout.row: 3
Layout.column: 1
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
settings.maxLength = val
settings.sync()
focus = false
} else {
text = settings.maxLength.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: maxLengthLabel.text
Accessible.description: ToolTip.text
}
Label {
id: batchSizeLabel
text: qsTr("Prompt Batch Size:")
color: theme.textColor
Layout.row: 4
Layout.column: 0
}
MyTextField {
text: settings.promptBatchSize.toString()
color: theme.textColor
ToolTip.text: qsTr("Amount of prompt tokens to process at once.\nNOTE: Higher values can speed up reading prompts but will use more RAM")
ToolTip.visible: hovered
Layout.row: 4
Layout.column: 1
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
settings.promptBatchSize = val
settings.sync()
focus = false
} else {
text = settings.promptBatchSize.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: batchSizeLabel.text
Accessible.description: ToolTip.text
}
Label {
id: repeatPenaltyLabel
text: qsTr("Repeat Penalty:")
color: theme.textColor
Layout.row: 5
Layout.column: 0
}
MyTextField {
text: settings.repeatPenalty.toString()
color: theme.textColor
ToolTip.text: qsTr("Amount to penalize repetitiveness of the output")
ToolTip.visible: hovered
Layout.row: 5
Layout.column: 1
validator: DoubleValidator {
locale: "C"
}
onEditingFinished: {
var val = parseFloat(text)
if (!isNaN(val)) {
settings.repeatPenalty = val
settings.sync()
focus = false
} else {
text = settings.repeatPenalty.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: repeatPenaltyLabel.text
Accessible.description: ToolTip.text
}
Label {
id: repeatPenaltyTokensLabel
text: qsTr("Repeat Penalty Tokens:")
color: theme.textColor
Layout.row: 6
Layout.column: 0
}
MyTextField {
text: settings.repeatPenaltyTokens.toString()
color: theme.textColor
ToolTip.text: qsTr("How far back in output to apply repeat penalty")
ToolTip.visible: hovered
Layout.row: 6
Layout.column: 1
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
settings.repeatPenaltyTokens = val
settings.sync()
focus = false
} else {
text = settings.repeatPenaltyTokens.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: repeatPenaltyTokensLabel.text
Accessible.description: ToolTip.text
}
ColumnLayout {
Layout.row: 7
Layout.column: 0
Layout.topMargin: 10
Layout.alignment: Qt.AlignTop
spacing: 20
Label {
id: promptTemplateLabel
text: qsTr("Prompt Template:")
color: theme.textColor
}
Label {
id: promptTemplateLabelHelp
Layout.maximumWidth: promptTemplateLabel.width
visible: settings.promptTemplate.indexOf(
"%1") === -1
color: theme.textErrorColor
text: qsTr("Must contain the string \"%1\" to be replaced with the user's input.")
wrapMode: TextArea.Wrap
Accessible.role: Accessible.EditableText
Accessible.name: text
}
}
Rectangle {
Layout.row: 7
Layout.column: 1
Layout.fillWidth: true
height: 200
color: "transparent"
clip: true
ScrollView {
id: templateScrollView
anchors.fill: parent
TextArea {
text: settings.promptTemplate
color: theme.textColor
background: Rectangle {
implicitWidth: 150
color: theme.backgroundLighter
radius: 10
}
padding: 10
wrapMode: TextArea.Wrap
onTextChanged: {
if (settings.promptTemplate.indexOf("%1") === -1)
return;
settings.promptTemplate = text
settings.sync()
}
bottomPadding: 10
Accessible.role: Accessible.EditableText
Accessible.name: promptTemplateLabel.text
Accessible.description: promptTemplateLabelHelp.text
ToolTip.text: qsTr("The prompt template partially determines how models will respond to prompts.\nNOTE: A longer, detailed template can lead to higher quality answers, but can also slow down generation.")
ToolTip.visible: hovered
}
}
}
MyButton {
Layout.row: 8
Layout.column: 1
Layout.fillWidth: true
text: qsTr("Restore Defaults")
Accessible.description: qsTr("Restores the settings dialog to a default state")
onClicked: {
settingsDialog.restoreGenerationDefaults()
}
}
}
}
}
Item {
id: applicationSettingsTab
ScrollView {
background: Rectangle {
color: 'transparent'
border.color: theme.tabBorder
border.width: 1
radius: 2
}
padding: 10
width: parent.width
height: parent.height - 30
contentWidth: availableWidth - 20
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
GridLayout {
anchors.margins: 10
columns: 3
rowSpacing: 10
columnSpacing: 10
anchors.fill: parent
Label {
id: defaultModelLabel
text: qsTr("Default model:")
color: theme.textColor
Layout.row: 1
Layout.column: 0
}
MyComboBox {
id: comboBox
Layout.row: 1
Layout.column: 1
Layout.minimumWidth: 350
model: ModelList.userDefaultModelList
Accessible.role: Accessible.ComboBox
Accessible.name: qsTr("ComboBox for displaying/picking the default model")
Accessible.description: qsTr("Use this for picking the default model to use; the first item is the current default model")
function updateModel() {
settings.sync();
comboBox.currentIndex = comboBox.indexOfValue(settingsDialog.userDefaultModel);
}
Component.onCompleted: {
comboBox.updateModel()
}
Connections {
target: settings
function onUserDefaultModelChanged() {
comboBox.updateModel()
}
}
onActivated: {
settingsDialog.userDefaultModel = comboBox.currentText
settings.sync()
}
}
FolderDialog {
id: modelPathDialog
title: "Please choose a directory"
currentFolder: "file://" + ModelList.localModelsPath
onAccepted: {
modelPathDisplayField.text = selectedFolder
ModelList.localModelsPath = modelPathDisplayField.text
settings.modelPath = ModelList.localModelsPath
settings.sync()
}
}
Label {
id: modelPathLabel
text: qsTr("Download path:")
color: theme.textColor
Layout.row: 2
Layout.column: 0
}
MyDirectoryField {
id: modelPathDisplayField
text: ModelList.localModelsPath
implicitWidth: 300
Layout.row: 2
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) {
ModelList.localModelsPath = modelPathDisplayField.text
settings.modelPath = ModelList.localModelsPath
settings.sync()
} else {
text = ModelList.localModelsPath
}
}
}
MyButton {
Layout.row: 2
Layout.column: 2
text: qsTr("Browse")
Accessible.description: qsTr("Opens a folder picker dialog to choose where to save model files")
onClicked: modelPathDialog.open()
}
Label {
id: nThreadsLabel
text: qsTr("CPU Threads:")
color: theme.textColor
Layout.row: 3
Layout.column: 0
}
MyTextField {
text: settingsDialog.threadCount.toString()
color: theme.textColor
ToolTip.text: qsTr("Amount of processing threads to use, a setting of 0 will use the lesser of 4 or your number of CPU threads")
ToolTip.visible: hovered
Layout.row: 3
Layout.column: 1
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
settingsDialog.threadCount = val
LLM.threadCount = val
settings.sync()
focus = false
} else {
text = settingsDialog.threadCount.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: nThreadsLabel.text
Accessible.description: ToolTip.text
}
Label {
id: saveChatsLabel
text: qsTr("Save chats to disk:")
color: theme.textColor
Layout.row: 4
Layout.column: 0
}
MyCheckBox {
id: saveChatsBox
Layout.row: 4
Layout.column: 1
checked: settingsDialog.saveChats
onClicked: {
Network.sendSaveChatsToggled(saveChatsBox.checked);
settingsDialog.saveChats = saveChatsBox.checked
ChatListModel.shouldSaveChats = saveChatsBox.checked
settings.sync()
}
ToolTip.text: qsTr("WARNING: Saving chats to disk can be ~2GB per chat")
ToolTip.visible: hovered
}
Label {
id: saveChatGPTChatsLabel
text: qsTr("Save ChatGPT chats to disk:")
color: theme.textColor
Layout.row: 5
Layout.column: 0
}
MyCheckBox {
id: saveChatGPTChatsBox
Layout.row: 5
Layout.column: 1
checked: settingsDialog.saveChatGPTChats
onClicked: {
settingsDialog.saveChatGPTChats = saveChatGPTChatsBox.checked
ChatListModel.shouldSaveChatGPTChats = saveChatGPTChatsBox.checked
settings.sync()
}
}
Label {
id: serverChatLabel
text: qsTr("Enable API server:")
color: theme.textColor
Layout.row: 6
Layout.column: 0
}
MyCheckBox {
id: serverChatBox
Layout.row: 6
Layout.column: 1
checked: settings.serverChat
onClicked: {
settingsDialog.serverChat = serverChatBox.checked
LLM.serverEnabled = serverChatBox.checked
settings.sync()
}
ToolTip.text: qsTr("WARNING: This enables the gui to act as a local REST web server(OpenAI API compliant) for API requests and will increase your RAM usage as well")
ToolTip.visible: hovered
}
Rectangle {
Layout.row: 7
Layout.column: 0
Layout.columnSpan: 3
Layout.fillWidth: true
height: 1
color: theme.dialogBorder
}
Rectangle {
Layout.row: 9
Layout.column: 0
Layout.fillWidth: true
Layout.columnSpan: 3
height: 1
color: theme.dialogBorder
}
Label {
id: gpuOverrideLabel
text: qsTr("Force Metal (macOS+arm):")
color: theme.textColor
Layout.row: 8
Layout.column: 0
}
RowLayout {
Layout.row: 8
Layout.column: 1
Layout.columnSpan: 2
MyCheckBox {
id: gpuOverrideBox
checked: MySettings.forceMetal
onClicked: {
MySettings.forceMetal = !MySettings.forceMetal
}
}
Label {
id: warningLabel
Layout.maximumWidth: 730
Layout.alignment: Qt.AlignTop
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.")
}
}
MyButton {
Layout.row: 10
Layout.column: 1
Layout.columnSpan: 2
Layout.fillWidth: true
text: qsTr("Restore Defaults")
Accessible.description: qsTr("Restores the settings dialog to a default state")
onClicked: {
settingsDialog.restoreApplicationDefaults()
}
}
}
}
}
Item {
id: localDocsTab
ScrollView {
background: Rectangle {
color: 'transparent'
border.color: theme.tabBorder
border.width: 1
radius: 2
}
padding: 10
width: parent.width
height: parent.height - 30
contentWidth: availableWidth - 20
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
LocalDocs {
anchors.margins: 10
anchors.fill: parent
}
}
}
}
}