gpt4all/gpt4all-chat/qml/ModelSettings.qml
AT 66bc04aa8e
chat: generate follow-up questions after response (#2634)
* user can configure the prompt and when they appear
* also make the name generation prompt configurable

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>
2024-07-10 15:45:20 -04:00

816 lines
31 KiB
QML

import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import modellist
import mysettings
import chatlistmodel
MySettingsTab {
onRestoreDefaultsClicked: {
MySettings.restoreModelDefaults(root.currentModelInfo);
}
title: qsTr("Model")
contentItem: GridLayout {
id: root
columns: 3
rowSpacing: 10
columnSpacing: 10
enabled: ModelList.selectableModels.count !== 0
property var currentModelName: comboBox.currentText
property var currentModelId: comboBox.currentValue
property var currentModelInfo: ModelList.modelInfo(root.currentModelId)
Label {
Layout.row: 1
Layout.column: 0
Layout.bottomMargin: 10
color: theme.settingsTitleTextColor
font.pixelSize: theme.fontSizeBannerSmall
font.bold: true
text: qsTr("Model Settings")
}
RowLayout {
Layout.fillWidth: true
Layout.row: 2
Layout.column: 0
Layout.columnSpan: 2
spacing: 10
MyComboBox {
id: comboBox
Layout.fillWidth: true
model: ModelList.selectableModels
valueRole: "id"
textRole: "name"
currentIndex: {
var i = comboBox.indexOfValue(ChatListModel.currentChat.modelInfo.id);
if (i >= 0)
return i;
return 0;
}
contentItem: Text {
leftPadding: 10
rightPadding: 20
text: comboBox.currentText
font: comboBox.font
color: theme.textColor
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
delegate: ItemDelegate {
width: comboBox.width -20
contentItem: Text {
text: name
color: theme.textColor
font: comboBox.font
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
radius: 10
color: highlighted ? theme.menuHighlightColor : theme.menuBackgroundColor
}
highlighted: comboBox.highlightedIndex === index
}
}
MySettingsButton {
id: cloneButton
text: qsTr("Clone")
onClicked: {
var id = ModelList.clone(root.currentModelInfo);
comboBox.currentIndex = comboBox.indexOfValue(id);
}
}
MySettingsDestructiveButton {
id: removeButton
enabled: root.currentModelInfo.isClone
text: qsTr("Remove")
onClicked: {
ModelList.removeClone(root.currentModelInfo);
comboBox.currentIndex = 0;
}
}
}
RowLayout {
Layout.row: 3
Layout.column: 0
Layout.topMargin: 15
spacing: 10
MySettingsLabel {
text: qsTr("Name")
}
}
MyTextField {
id: uniqueNameField
text: root.currentModelName
font.pixelSize: theme.fontSizeLarge
enabled: root.currentModelInfo.isClone || root.currentModelInfo.description === ""
Layout.row: 4
Layout.column: 0
Layout.columnSpan: 2
Layout.fillWidth: true
Connections {
target: MySettings
function onNameChanged() {
uniqueNameField.text = root.currentModelInfo.name;
}
}
Connections {
target: root
function onCurrentModelInfoChanged() {
uniqueNameField.text = root.currentModelInfo.name;
}
}
onTextChanged: {
if (text !== "" && ModelList.isUniqueName(text)) {
MySettings.setModelName(root.currentModelInfo, text);
}
}
}
MySettingsLabel {
text: qsTr("Model File")
Layout.row: 5
Layout.column: 0
Layout.topMargin: 15
}
MyTextField {
text: root.currentModelInfo.filename
font.pixelSize: theme.fontSizeLarge
enabled: false
Layout.row: 6
Layout.column: 0
Layout.columnSpan: 2
Layout.fillWidth: true
}
MySettingsLabel {
visible: !root.currentModelInfo.isOnline
text: qsTr("System Prompt")
helpText: qsTr("Prefixed at the beginning of every conversation. Must contain the appropriate framing tokens.")
Layout.row: 7
Layout.column: 0
Layout.topMargin: 15
}
Rectangle {
id: systemPrompt
visible: !root.currentModelInfo.isOnline
Layout.row: 8
Layout.column: 0
Layout.columnSpan: 2
Layout.fillWidth: true
color: "transparent"
Layout.minimumHeight: Math.max(100, systemPromptArea.contentHeight + 20)
MyTextArea {
id: systemPromptArea
anchors.fill: parent
text: root.currentModelInfo.systemPrompt
Connections {
target: MySettings
function onSystemPromptChanged() {
systemPromptArea.text = root.currentModelInfo.systemPrompt;
}
}
Connections {
target: root
function onCurrentModelInfoChanged() {
systemPromptArea.text = root.currentModelInfo.systemPrompt;
}
}
onTextChanged: {
MySettings.setModelSystemPrompt(root.currentModelInfo, text)
}
Accessible.role: Accessible.EditableText
}
}
RowLayout {
Layout.row: 9
Layout.column: 0
Layout.columnSpan: 2
Layout.topMargin: 15
spacing: 10
MySettingsLabel {
id: promptTemplateLabel
text: qsTr("Prompt Template")
helpText: qsTr("The template that wraps every prompt.")
}
MySettingsLabel {
id: promptTemplateLabelHelp
text: qsTr("Must contain the string \"%1\" to be replaced with the user's input.")
color: theme.textErrorColor
visible: templateTextArea.text.indexOf("%1") === -1
wrapMode: TextArea.Wrap
}
}
Rectangle {
id: promptTemplate
Layout.row: 10
Layout.column: 0
Layout.columnSpan: 2
Layout.fillWidth: true
Layout.minimumHeight: Math.max(100, templateTextArea.contentHeight + 20)
color: "transparent"
clip: true
MyTextArea {
id: templateTextArea
anchors.fill: parent
text: root.currentModelInfo.promptTemplate
Connections {
target: MySettings
function onPromptTemplateChanged() {
templateTextArea.text = root.currentModelInfo.promptTemplate;
}
}
Connections {
target: root
function onCurrentModelInfoChanged() {
templateTextArea.text = root.currentModelInfo.promptTemplate;
}
}
onTextChanged: {
if (templateTextArea.text.indexOf("%1") !== -1) {
MySettings.setModelPromptTemplate(root.currentModelInfo, text)
}
}
Accessible.role: Accessible.EditableText
Accessible.name: promptTemplateLabel.text
Accessible.description: promptTemplateLabelHelp.text
}
}
MySettingsLabel {
id: chatNamePromptLabel
text: qsTr("Chat Name Prompt")
helpText: qsTr("Prompt used to automatically generate chat names.")
Layout.row: 11
Layout.column: 0
Layout.topMargin: 15
}
Rectangle {
id: chatNamePrompt
Layout.row: 12
Layout.column: 0
Layout.columnSpan: 2
Layout.fillWidth: true
Layout.minimumHeight: Math.max(100, chatNamePromptTextArea.contentHeight + 20)
color: "transparent"
clip: true
MyTextArea {
id: chatNamePromptTextArea
anchors.fill: parent
text: root.currentModelInfo.chatNamePrompt
Accessible.role: Accessible.EditableText
Accessible.name: chatNamePromptLabel.text
Accessible.description: chatNamePromptLabel.text
}
}
MySettingsLabel {
id: suggestedFollowUpPromptLabel
text: qsTr("Suggested FollowUp Prompt")
helpText: qsTr("Prompt used to generate suggested follow-up questions.")
Layout.row: 13
Layout.column: 0
Layout.topMargin: 15
}
Rectangle {
id: suggestedFollowUpPrompt
Layout.row: 14
Layout.column: 0
Layout.columnSpan: 2
Layout.fillWidth: true
Layout.minimumHeight: Math.max(100, suggestedFollowUpPromptTextArea.contentHeight + 20)
color: "transparent"
clip: true
MyTextArea {
id: suggestedFollowUpPromptTextArea
anchors.fill: parent
text: root.currentModelInfo.suggestedFollowUpPrompt
Accessible.role: Accessible.EditableText
Accessible.name: suggestedFollowUpPromptLabel.text
Accessible.description: suggestedFollowUpPromptLabel.text
}
}
GridLayout {
Layout.row: 15
Layout.column: 0
Layout.columnSpan: 2
Layout.topMargin: 15
Layout.fillWidth: true
columns: 4
rowSpacing: 30
columnSpacing: 10
MySettingsLabel {
id: contextLengthLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("Context Length")
helpText: qsTr("Number of input and output tokens the model sees.")
Layout.row: 0
Layout.column: 0
Layout.maximumWidth: 300 * theme.fontScale
}
Item {
Layout.row: 0
Layout.column: 1
Layout.fillWidth: true
Layout.maximumWidth: 200
Layout.margins: 0
height: contextLengthField.height
MyTextField {
id: contextLengthField
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
visible: !root.currentModelInfo.isOnline
text: root.currentModelInfo.contextLength
font.pixelSize: theme.fontSizeLarge
color: theme.textColor
ToolTip.text: qsTr("Maximum combined prompt/response tokens before information is lost.\nUsing more context than the model was trained on will yield poor results.\nNOTE: Does not take effect until you reload the model.")
ToolTip.visible: hovered
Connections {
target: MySettings
function onContextLengthChanged() {
contextLengthField.text = root.currentModelInfo.contextLength;
}
}
Connections {
target: root
function onCurrentModelInfoChanged() {
contextLengthField.text = root.currentModelInfo.contextLength;
}
}
onEditingFinished: {
var val = parseInt(text)
if (isNaN(val)) {
text = root.currentModelInfo.contextLength
} else {
if (val < 8) {
val = 8
contextLengthField.text = val
} else if (val > root.currentModelInfo.maxContextLength) {
val = root.currentModelInfo.maxContextLength
contextLengthField.text = val
}
MySettings.setModelContextLength(root.currentModelInfo, val)
focus = false
}
}
Accessible.role: Accessible.EditableText
Accessible.name: contextLengthLabel.text
Accessible.description: ToolTip.text
}
}
MySettingsLabel {
id: tempLabel
text: qsTr("Temperature")
helpText: qsTr("Randomness of model output. Higher -> more variation.")
Layout.row: 1
Layout.column: 2
Layout.maximumWidth: 300 * theme.fontScale
}
MyTextField {
id: temperatureField
text: root.currentModelInfo.temperature
font.pixelSize: theme.fontSizeLarge
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: 1
Layout.column: 3
validator: DoubleValidator {
locale: "C"
}
Connections {
target: MySettings
function onTemperatureChanged() {
temperatureField.text = root.currentModelInfo.temperature;
}
}
Connections {
target: root
function onCurrentModelInfoChanged() {
temperatureField.text = root.currentModelInfo.temperature;
}
}
onEditingFinished: {
var val = parseFloat(text)
if (!isNaN(val)) {
MySettings.setModelTemperature(root.currentModelInfo, val)
focus = false
} else {
text = root.currentModelInfo.temperature
}
}
Accessible.role: Accessible.EditableText
Accessible.name: tempLabel.text
Accessible.description: ToolTip.text
}
MySettingsLabel {
id: topPLabel
text: qsTr("Top-P")
helpText: qsTr("Nucleus Sampling factor. Lower -> more predicatable.")
Layout.row: 2
Layout.column: 0
Layout.maximumWidth: 300 * theme.fontScale
}
MyTextField {
id: topPField
text: root.currentModelInfo.topP
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
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.")
ToolTip.visible: hovered
Layout.row: 2
Layout.column: 1
validator: DoubleValidator {
locale: "C"
}
Connections {
target: MySettings
function onTopPChanged() {
topPField.text = root.currentModelInfo.topP;
}
}
Connections {
target: root
function onCurrentModelInfoChanged() {
topPField.text = root.currentModelInfo.topP;
}
}
onEditingFinished: {
var val = parseFloat(text)
if (!isNaN(val)) {
MySettings.setModelTopP(root.currentModelInfo, val)
focus = false
} else {
text = root.currentModelInfo.topP
}
}
Accessible.role: Accessible.EditableText
Accessible.name: topPLabel.text
Accessible.description: ToolTip.text
}
MySettingsLabel {
id: minPLabel
text: qsTr("Min-P")
helpText: qsTr("Minimum token probability. Higher -> more predictable.")
Layout.row: 3
Layout.column: 0
Layout.maximumWidth: 300 * theme.fontScale
}
MyTextField {
id: minPField
text: root.currentModelInfo.minP
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
ToolTip.text: qsTr("Sets the minimum relative probability for a token to be considered.")
ToolTip.visible: hovered
Layout.row: 3
Layout.column: 1
validator: DoubleValidator {
locale: "C"
}
Connections {
target: MySettings
function onMinPChanged() {
minPField.text = root.currentModelInfo.minP;
}
}
Connections {
target: root
function onCurrentModelInfoChanged() {
minPField.text = root.currentModelInfo.minP;
}
}
onEditingFinished: {
var val = parseFloat(text)
if (!isNaN(val)) {
MySettings.setModelMinP(root.currentModelInfo, val)
focus = false
} else {
text = root.currentModelInfo.minP
}
}
Accessible.role: Accessible.EditableText
Accessible.name: minPLabel.text
Accessible.description: ToolTip.text
}
MySettingsLabel {
id: topKLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("Top-K")
helpText: qsTr("Size of selection pool for tokens.")
Layout.row: 2
Layout.column: 2
Layout.maximumWidth: 300 * theme.fontScale
}
MyTextField {
id: topKField
visible: !root.currentModelInfo.isOnline
text: root.currentModelInfo.topK
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
ToolTip.text: qsTr("Only the top K most likely tokens will be chosen from.")
ToolTip.visible: hovered
Layout.row: 2
Layout.column: 3
validator: IntValidator {
bottom: 1
}
Connections {
target: MySettings
function onTopKChanged() {
topKField.text = root.currentModelInfo.topK;
}
}
Connections {
target: root
function onCurrentModelInfoChanged() {
topKField.text = root.currentModelInfo.topK;
}
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
MySettings.setModelTopK(root.currentModelInfo, val)
focus = false
} else {
text = root.currentModelInfo.topK
}
}
Accessible.role: Accessible.EditableText
Accessible.name: topKLabel.text
Accessible.description: ToolTip.text
}
MySettingsLabel {
id: maxLengthLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("Max Length")
helpText: qsTr("Maximum response length, in tokens.")
Layout.row: 0
Layout.column: 2
Layout.maximumWidth: 300 * theme.fontScale
}
MyTextField {
id: maxLengthField
visible: !root.currentModelInfo.isOnline
text: root.currentModelInfo.maxLength
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
Layout.row: 0
Layout.column: 3
validator: IntValidator {
bottom: 1
}
Connections {
target: MySettings
function onMaxLengthChanged() {
maxLengthField.text = root.currentModelInfo.maxLength;
}
}
Connections {
target: root
function onCurrentModelInfoChanged() {
maxLengthField.text = root.currentModelInfo.maxLength;
}
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
MySettings.setModelMaxLength(root.currentModelInfo, val)
focus = false
} else {
text = root.currentModelInfo.maxLength
}
}
Accessible.role: Accessible.EditableText
Accessible.name: maxLengthLabel.text
Accessible.description: ToolTip.text
}
MySettingsLabel {
id: batchSizeLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("Prompt Batch Size")
helpText: qsTr("The batch size used for prompt processing.")
Layout.row: 1
Layout.column: 0
Layout.maximumWidth: 300 * theme.fontScale
}
MyTextField {
id: batchSizeField
visible: !root.currentModelInfo.isOnline
text: root.currentModelInfo.promptBatchSize
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
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: 1
Layout.column: 1
validator: IntValidator {
bottom: 1
}
Connections {
target: MySettings
function onPromptBatchSizeChanged() {
batchSizeField.text = root.currentModelInfo.promptBatchSize;
}
}
Connections {
target: root
function onCurrentModelInfoChanged() {
batchSizeField.text = root.currentModelInfo.promptBatchSize;
}
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
MySettings.setModelPromptBatchSize(root.currentModelInfo, val)
focus = false
} else {
text = root.currentModelInfo.promptBatchSize
}
}
Accessible.role: Accessible.EditableText
Accessible.name: batchSizeLabel.text
Accessible.description: ToolTip.text
}
MySettingsLabel {
id: repeatPenaltyLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("Repeat Penalty")
helpText: qsTr("Repetition penalty factor. Set to 1 to disable.")
Layout.row: 4
Layout.column: 2
Layout.maximumWidth: 300 * theme.fontScale
}
MyTextField {
id: repeatPenaltyField
visible: !root.currentModelInfo.isOnline
text: root.currentModelInfo.repeatPenalty
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
Layout.row: 4
Layout.column: 3
validator: DoubleValidator {
locale: "C"
}
Connections {
target: MySettings
function onRepeatPenaltyChanged() {
repeatPenaltyField.text = root.currentModelInfo.repeatPenalty;
}
}
Connections {
target: root
function onCurrentModelInfoChanged() {
repeatPenaltyField.text = root.currentModelInfo.repeatPenalty;
}
}
onEditingFinished: {
var val = parseFloat(text)
if (!isNaN(val)) {
MySettings.setModelRepeatPenalty(root.currentModelInfo, val)
focus = false
} else {
text = root.currentModelInfo.repeatPenalty
}
}
Accessible.role: Accessible.EditableText
Accessible.name: repeatPenaltyLabel.text
Accessible.description: ToolTip.text
}
MySettingsLabel {
id: repeatPenaltyTokensLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("Repeat Penalty Tokens")
helpText: qsTr("Number of previous tokens used for penalty.")
Layout.row: 3
Layout.column: 2
Layout.maximumWidth: 300 * theme.fontScale
}
MyTextField {
id: repeatPenaltyTokenField
visible: !root.currentModelInfo.isOnline
text: root.currentModelInfo.repeatPenaltyTokens
color: theme.textColor
font.pixelSize: theme.fontSizeLarge
Layout.row: 3
Layout.column: 3
validator: IntValidator {
bottom: 1
}
Connections {
target: MySettings
function onRepeatPenaltyTokensChanged() {
repeatPenaltyTokenField.text = root.currentModelInfo.repeatPenaltyTokens;
}
}
Connections {
target: root
function onCurrentModelInfoChanged() {
repeatPenaltyTokenField.text = root.currentModelInfo.repeatPenaltyTokens;
}
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
MySettings.setModelRepeatPenaltyTokens(root.currentModelInfo, val)
focus = false
} else {
text = root.currentModelInfo.repeatPenaltyTokens
}
}
Accessible.role: Accessible.EditableText
Accessible.name: repeatPenaltyTokensLabel.text
Accessible.description: ToolTip.text
}
MySettingsLabel {
id: gpuLayersLabel
visible: !root.currentModelInfo.isOnline
text: qsTr("GPU Layers")
helpText: qsTr("Number of model layers to load into VRAM.")
Layout.row: 4
Layout.column: 0
Layout.maximumWidth: 300 * theme.fontScale
}
MyTextField {
id: gpuLayersField
visible: !root.currentModelInfo.isOnline
text: root.currentModelInfo.gpuLayers
font.pixelSize: theme.fontSizeLarge
color: theme.textColor
ToolTip.text: qsTr("How many model layers to load into VRAM. Decrease this if GPT4All runs out of VRAM while loading this model.\nLower values increase CPU load and RAM usage, and make inference slower.\nNOTE: Does not take effect until you reload the model.")
ToolTip.visible: hovered
Layout.row: 4
Layout.column: 1
Connections {
target: MySettings
function onGpuLayersChanged() {
gpuLayersField.text = root.currentModelInfo.gpuLayers
}
}
Connections {
target: root
function onCurrentModelInfoChanged() {
if (root.currentModelInfo.gpuLayers === 100) {
gpuLayersField.text = root.currentModelInfo.maxGpuLayers
} else {
gpuLayersField.text = root.currentModelInfo.gpuLayers
}
}
}
onEditingFinished: {
var val = parseInt(text)
if (isNaN(val)) {
gpuLayersField.text = root.currentModelInfo.gpuLayers
} else {
if (val < 1) {
val = 1
gpuLayersField.text = val
} else if (val > root.currentModelInfo.maxGpuLayers) {
val = root.currentModelInfo.maxGpuLayers
gpuLayersField.text = val
}
MySettings.setModelGpuLayers(root.currentModelInfo, val)
focus = false
}
}
Accessible.role: Accessible.EditableText
Accessible.name: gpuLayersLabel.text
Accessible.description: ToolTip.text
}
}
Rectangle {
Layout.row: 16
Layout.column: 0
Layout.columnSpan: 2
Layout.topMargin: 15
Layout.fillWidth: true
height: 1
color: theme.settingsDivider
}
}
}