mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-09-03 01:24:53 +00:00
Complete revamp of model loading to allow for more discreet control by
the user of the models loading behavior. Signed-off-by: Adam Treat <treat.adam@gmail.com>
This commit is contained in:
@@ -126,6 +126,10 @@ Window {
|
||||
}
|
||||
}
|
||||
|
||||
function currentModelName() {
|
||||
return ModelList.modelInfo(currentChat.modelInfo.id).name;
|
||||
}
|
||||
|
||||
PopupDialog {
|
||||
id: errorCompatHardware
|
||||
anchors.centerIn: parent
|
||||
@@ -282,6 +286,18 @@ Window {
|
||||
}
|
||||
}
|
||||
|
||||
SwitchModelDialog {
|
||||
id: switchModelDialog
|
||||
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("Switch model dialog")
|
||||
Accessible.description: qsTr("Warn the user if they switch models, then context will be erased")
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: header
|
||||
anchors.left: parent.left
|
||||
@@ -292,7 +308,9 @@ Window {
|
||||
Item {
|
||||
anchors.centerIn: parent
|
||||
height: childrenRect.height
|
||||
visible: currentChat.isModelLoaded || currentChat.modelLoadingError !== "" || currentChat.isServer
|
||||
visible: true
|
||||
|| currentChat.modelLoadingError !== ""
|
||||
|| currentChat.isServer
|
||||
|
||||
Label {
|
||||
id: modelLabel
|
||||
@@ -306,102 +324,168 @@ Window {
|
||||
horizontalAlignment: TextInput.AlignRight
|
||||
}
|
||||
|
||||
MyComboBox {
|
||||
id: comboBox
|
||||
implicitWidth: 375
|
||||
width: window.width >= 750 ? implicitWidth : implicitWidth - ((750 - window.width))
|
||||
RowLayout {
|
||||
id: comboLayout
|
||||
anchors.top: modelLabel.top
|
||||
anchors.bottom: modelLabel.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.horizontalCenterOffset: window.width >= 950 ? 0 : Math.max(-((950 - window.width) / 2), -99.5)
|
||||
enabled: !currentChat.isServer
|
||||
model: ModelList.installedModels
|
||||
valueRole: "id"
|
||||
textRole: "name"
|
||||
property string currentModelName: ""
|
||||
function updateCurrentModelName() {
|
||||
var info = ModelList.modelInfo(currentChat.modelInfo.id);
|
||||
comboBox.currentModelName = info.name;
|
||||
}
|
||||
Connections {
|
||||
target: currentChat
|
||||
function onModelInfoChanged() {
|
||||
comboBox.updateCurrentModelName();
|
||||
spacing: 20
|
||||
|
||||
MyComboBox {
|
||||
id: comboBox
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
implicitWidth: 575
|
||||
width: window.width >= 750 ? implicitWidth : implicitWidth - ((750 - window.width))
|
||||
enabled: !currentChat.isServer
|
||||
model: ModelList.installedModels
|
||||
valueRole: "id"
|
||||
textRole: "name"
|
||||
property bool isCurrentlyLoading: false
|
||||
property real modelLoadingPercentage: 0.0
|
||||
property bool trySwitchContextInProgress: false
|
||||
|
||||
function changeModel(index) {
|
||||
comboBox.modelLoadingPercentage = 0.0;
|
||||
comboBox.isCurrentlyLoading = true;
|
||||
currentChat.stopGenerating()
|
||||
currentChat.reset();
|
||||
currentChat.modelInfo = ModelList.modelInfo(comboBox.valueAt(index))
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: window
|
||||
function onCurrentChatChanged() {
|
||||
comboBox.updateCurrentModelName();
|
||||
|
||||
Connections {
|
||||
target: currentChat
|
||||
function onModelLoadingPercentageChanged() {
|
||||
comboBox.modelLoadingPercentage = currentChat.modelLoadingPercentage;
|
||||
comboBox.isCurrentlyLoading = currentChat.modelLoadingPercentage !== 0.0
|
||||
&& currentChat.modelLoadingPercentage !== 1.0;
|
||||
}
|
||||
function onTrySwitchContextOfLoadedModelAttempted() {
|
||||
comboBox.trySwitchContextInProgress = true;
|
||||
}
|
||||
function onTrySwitchContextOfLoadedModelCompleted() {
|
||||
comboBox.trySwitchContextInProgress = false;
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: switchModelDialog
|
||||
function onAccepted() {
|
||||
comboBox.changeModel(switchModelDialog.index)
|
||||
}
|
||||
}
|
||||
|
||||
background: ProgressBar {
|
||||
id: modelProgress
|
||||
value: comboBox.modelLoadingPercentage
|
||||
background: Rectangle {
|
||||
color: theme.mainComboBackground
|
||||
radius: 10
|
||||
}
|
||||
contentItem: Item {
|
||||
Rectangle {
|
||||
visible: comboBox.isCurrentlyLoading
|
||||
anchors.bottom: parent.bottom
|
||||
width: modelProgress.visualPosition * parent.width
|
||||
height: 10
|
||||
radius: 2
|
||||
color: theme.progressForeground
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
background: Rectangle {
|
||||
color: theme.mainComboBackground
|
||||
radius: 10
|
||||
}
|
||||
contentItem: Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
leftPadding: 10
|
||||
rightPadding: 20
|
||||
text: currentChat.modelLoadingError !== ""
|
||||
? qsTr("Model loading error...")
|
||||
: comboBox.currentModelName
|
||||
font.pixelSize: theme.fontSizeLarger
|
||||
color: theme.white
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
delegate: ItemDelegate {
|
||||
width: comboBox.width
|
||||
contentItem: Text {
|
||||
text: name
|
||||
color: theme.textColor
|
||||
font: comboBox.font
|
||||
elide: Text.ElideRight
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
leftPadding: 10
|
||||
rightPadding: 20
|
||||
text: {
|
||||
if (currentChat.modelLoadingError !== "")
|
||||
return qsTr("Model loading error...")
|
||||
if (comboBox.trySwitchContextInProgress)
|
||||
return qsTr("Switching context...")
|
||||
if (currentModelName() === "")
|
||||
return qsTr("Choose a model...")
|
||||
if (currentChat.modelLoadingPercentage === 0.0)
|
||||
return qsTr("Reload \u00B7 ") + currentModelName()
|
||||
if (comboBox.isCurrentlyLoading)
|
||||
return qsTr("Loading \u00B7 ") + currentModelName()
|
||||
return currentModelName()
|
||||
}
|
||||
font.pixelSize: theme.fontSizeLarger
|
||||
color: theme.white
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
background: Rectangle {
|
||||
color: (index % 2 === 0 ? theme.darkContrast : theme.lightContrast)
|
||||
border.width: highlighted
|
||||
border.color: theme.accentColor
|
||||
delegate: ItemDelegate {
|
||||
id: comboItemDelegate
|
||||
width: comboBox.width
|
||||
contentItem: Text {
|
||||
text: name
|
||||
color: theme.textColor
|
||||
font: comboBox.font
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
background: Rectangle {
|
||||
color: (index % 2 === 0 ? theme.darkContrast : theme.lightContrast)
|
||||
border.width: highlighted
|
||||
border.color: theme.accentColor
|
||||
}
|
||||
highlighted: comboBox.highlightedIndex === index
|
||||
}
|
||||
Accessible.role: Accessible.ComboBox
|
||||
Accessible.name: currentModelName()
|
||||
Accessible.description: qsTr("The top item is the current model")
|
||||
onActivated: function (index) {
|
||||
var newInfo = ModelList.modelInfo(comboBox.valueAt(index));
|
||||
if (currentModelName() !== ""
|
||||
&& newInfo !== currentChat.modelInfo
|
||||
&& chatModel.count !== 0) {
|
||||
switchModelDialog.index = index;
|
||||
switchModelDialog.open();
|
||||
} else {
|
||||
comboBox.changeModel(index);
|
||||
}
|
||||
}
|
||||
highlighted: comboBox.highlightedIndex === index
|
||||
}
|
||||
Accessible.role: Accessible.ComboBox
|
||||
Accessible.name: comboBox.currentModelName
|
||||
Accessible.description: qsTr("The top item is the current model")
|
||||
onActivated: function (index) {
|
||||
currentChat.stopGenerating()
|
||||
currentChat.reset();
|
||||
currentChat.modelInfo = ModelList.modelInfo(comboBox.valueAt(index))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.centerIn: parent
|
||||
visible: ModelList.installedModels.count
|
||||
&& !currentChat.isModelLoaded
|
||||
&& currentChat.modelLoadingError === ""
|
||||
&& !currentChat.isServer
|
||||
width: childrenRect.width
|
||||
height: childrenRect.height
|
||||
Row {
|
||||
spacing: 5
|
||||
MyBusyIndicator {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
running: parent.visible
|
||||
Accessible.role: Accessible.Animation
|
||||
Accessible.name: qsTr("Busy indicator")
|
||||
Accessible.description: qsTr("loading model...")
|
||||
}
|
||||
MyMiniButton {
|
||||
id: ejectButton
|
||||
visible: currentChat.isModelLoaded
|
||||
z: 500
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 50
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
source: "qrc:/gpt4all/icons/eject.svg"
|
||||
backgroundColor: theme.gray300
|
||||
backgroundColorHovered: theme.iconBackgroundLight
|
||||
onClicked: {
|
||||
currentChat.forceUnloadModel();
|
||||
}
|
||||
ToolTip.text: qsTr("Eject the currently loaded model")
|
||||
ToolTip.visible: hovered
|
||||
}
|
||||
|
||||
Label {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Loading model...")
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
color: theme.oppositeTextColor
|
||||
MyMiniButton {
|
||||
id: reloadButton
|
||||
visible: currentChat.modelLoadingError === ""
|
||||
&& !comboBox.trySwitchContextInProgress
|
||||
&& (currentChat.isModelLoaded || currentModelName() !== "")
|
||||
z: 500
|
||||
anchors.right: ejectButton.visible ? ejectButton.left : parent.right
|
||||
anchors.rightMargin: ejectButton.visible ? 10 : 50
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
source: "qrc:/gpt4all/icons/regenerate.svg"
|
||||
backgroundColor: theme.gray300
|
||||
backgroundColorHovered: theme.iconBackgroundLight
|
||||
onClicked: {
|
||||
if (currentChat.isModelLoaded)
|
||||
currentChat.forceReloadModel();
|
||||
else
|
||||
currentChat.reloadModel();
|
||||
}
|
||||
ToolTip.text: qsTr("Reload the currently loaded model")
|
||||
ToolTip.visible: hovered
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -790,9 +874,9 @@ Window {
|
||||
|
||||
Rectangle {
|
||||
id: homePage
|
||||
color: "transparent"//theme.green200
|
||||
color: "transparent"
|
||||
anchors.fill: parent
|
||||
visible: (ModelList.installedModels.count === 0 || chatModel.count === 0) && !currentChat.isServer
|
||||
visible: !currentChat.isModelLoaded && (ModelList.installedModels.count === 0 || currentModelName() === "") && !currentChat.isServer
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
@@ -1138,50 +1222,84 @@ Window {
|
||||
}
|
||||
}
|
||||
|
||||
MyButton {
|
||||
id: myButton
|
||||
visible: chatModel.count && !currentChat.isServer
|
||||
textColor: theme.textColor
|
||||
Image {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 15
|
||||
source: currentChat.responseInProgress ? "qrc:/gpt4all/icons/stop_generating.svg" : "qrc:/gpt4all/icons/regenerate.svg"
|
||||
}
|
||||
leftPadding: 50
|
||||
onClicked: {
|
||||
var index = Math.max(0, chatModel.count - 1);
|
||||
var listElement = chatModel.get(index);
|
||||
|
||||
if (currentChat.responseInProgress) {
|
||||
listElement.stopped = true
|
||||
currentChat.stopGenerating()
|
||||
} else {
|
||||
currentChat.regenerateResponse()
|
||||
if (chatModel.count) {
|
||||
if (listElement.name === qsTr("Response: ")) {
|
||||
chatModel.updateCurrentResponse(index, true);
|
||||
chatModel.updateStopped(index, false);
|
||||
chatModel.updateThumbsUpState(index, false);
|
||||
chatModel.updateThumbsDownState(index, false);
|
||||
chatModel.updateNewResponse(index, "");
|
||||
currentChat.prompt(listElement.prompt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
background: Rectangle {
|
||||
border.color: theme.conversationButtonBorder
|
||||
border.width: 2
|
||||
radius: 10
|
||||
color: myButton.hovered ? theme.conversationButtonBackgroundHovered : theme.conversationButtonBackground
|
||||
}
|
||||
RowLayout {
|
||||
anchors.bottom: textInputView.top
|
||||
anchors.horizontalCenter: textInputView.horizontalCenter
|
||||
anchors.bottomMargin: 20
|
||||
padding: 15
|
||||
text: currentChat.responseInProgress ? qsTr("Stop generating") : qsTr("Regenerate response")
|
||||
Accessible.description: qsTr("Controls generation of the response")
|
||||
spacing: 10
|
||||
MyButton {
|
||||
textColor: theme.textColor
|
||||
visible: chatModel.count && !currentChat.isServer && currentChat.isModelLoaded
|
||||
Image {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 15
|
||||
source: currentChat.responseInProgress ? "qrc:/gpt4all/icons/stop_generating.svg" : "qrc:/gpt4all/icons/regenerate.svg"
|
||||
}
|
||||
leftPadding: 50
|
||||
onClicked: {
|
||||
var index = Math.max(0, chatModel.count - 1);
|
||||
var listElement = chatModel.get(index);
|
||||
|
||||
if (currentChat.responseInProgress) {
|
||||
listElement.stopped = true
|
||||
currentChat.stopGenerating()
|
||||
} else {
|
||||
currentChat.regenerateResponse()
|
||||
if (chatModel.count) {
|
||||
if (listElement.name === qsTr("Response: ")) {
|
||||
chatModel.updateCurrentResponse(index, true);
|
||||
chatModel.updateStopped(index, false);
|
||||
chatModel.updateThumbsUpState(index, false);
|
||||
chatModel.updateThumbsDownState(index, false);
|
||||
chatModel.updateNewResponse(index, "");
|
||||
currentChat.prompt(listElement.prompt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
borderWidth: 1
|
||||
backgroundColor: theme.conversationButtonBackground
|
||||
backgroundColorHovered: theme.conversationButtonBackgroundHovered
|
||||
backgroundRadius: 5
|
||||
padding: 15
|
||||
topPadding: 4
|
||||
bottomPadding: 4
|
||||
text: currentChat.responseInProgress ? qsTr("Stop generating") : qsTr("Regenerate response")
|
||||
fontPixelSize: theme.fontSizeSmaller
|
||||
Accessible.description: qsTr("Controls generation of the response")
|
||||
}
|
||||
|
||||
MyButton {
|
||||
textColor: theme.textColor
|
||||
visible: chatModel.count
|
||||
&& !currentChat.isServer
|
||||
&& !currentChat.isModelLoaded
|
||||
&& currentChat.modelLoadingPercentage === 0.0
|
||||
&& currentChat.modelInfo.name !== ""
|
||||
Image {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 15
|
||||
source: "qrc:/gpt4all/icons/regenerate.svg"
|
||||
}
|
||||
leftPadding: 50
|
||||
onClicked: {
|
||||
currentChat.reloadModel();
|
||||
}
|
||||
|
||||
borderWidth: 1
|
||||
backgroundColor: theme.conversationButtonBackground
|
||||
backgroundColorHovered: theme.conversationButtonBackgroundHovered
|
||||
backgroundRadius: 5
|
||||
padding: 15
|
||||
topPadding: 4
|
||||
bottomPadding: 4
|
||||
text: qsTr("Reload \u00B7 ") + currentChat.modelInfo.name
|
||||
fontPixelSize: theme.fontSizeSmaller
|
||||
Accessible.description: qsTr("Reloads the model")
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
@@ -1224,7 +1342,7 @@ Window {
|
||||
rightPadding: 40
|
||||
enabled: currentChat.isModelLoaded && !currentChat.isServer
|
||||
font.pixelSize: theme.fontSizeLarger
|
||||
placeholderText: qsTr("Send a message...")
|
||||
placeholderText: currentChat.isModelLoaded ? qsTr("Send a message...") : qsTr("Load a model to continue...")
|
||||
Accessible.role: Accessible.EditableText
|
||||
Accessible.name: placeholderText
|
||||
Accessible.description: qsTr("Send messages/prompts to the model")
|
||||
|
Reference in New Issue
Block a user