mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-09-07 11:30:05 +00:00
Modellist temp
This commit is contained in:
@@ -3,6 +3,7 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls.Basic
|
||||
import QtQuick.Layouts
|
||||
import chatlistmodel
|
||||
import llm
|
||||
import download
|
||||
import network
|
||||
@@ -48,8 +49,8 @@ Drawer {
|
||||
color: newChat.hovered ? theme.backgroundDark : theme.backgroundDarkest
|
||||
}
|
||||
onClicked: {
|
||||
LLM.chatListModel.addChat();
|
||||
Network.sendNewChat(LLM.chatListModel.count)
|
||||
ChatListModel.addChat();
|
||||
Network.sendNewChat(ChatListModel.count)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,15 +70,15 @@ Drawer {
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 10
|
||||
|
||||
model: LLM.chatListModel
|
||||
model: ChatListModel
|
||||
|
||||
delegate: Rectangle {
|
||||
id: chatRectangle
|
||||
width: conversationList.width
|
||||
height: chatName.height
|
||||
opacity: 0.9
|
||||
property bool isCurrent: LLM.chatListModel.currentChat === LLM.chatListModel.get(index)
|
||||
property bool isServer: LLM.chatListModel.get(index) && LLM.chatListModel.get(index).isServer
|
||||
property bool isCurrent: ChatListModel.currentChat === ChatListModel.get(index)
|
||||
property bool isServer: ChatListModel.get(index) && ChatListModel.get(index).isServer
|
||||
property bool trashQuestionDisplayed: false
|
||||
visible: !isServer || LLM.serverEnabled
|
||||
z: isCurrent ? 199 : 1
|
||||
@@ -119,7 +120,7 @@ Drawer {
|
||||
Network.sendRenameChat()
|
||||
}
|
||||
function changeName() {
|
||||
LLM.chatListModel.get(index).name = chatName.text
|
||||
ChatListModel.get(index).name = chatName.text
|
||||
chatName.focus = false
|
||||
chatName.readOnly = true
|
||||
chatName.selectByMouse = false
|
||||
@@ -128,7 +129,7 @@ Drawer {
|
||||
onTapped: {
|
||||
if (isCurrent)
|
||||
return;
|
||||
LLM.chatListModel.currentChat = LLM.chatListModel.get(index);
|
||||
ChatListModel.currentChat = ChatListModel.get(index);
|
||||
}
|
||||
}
|
||||
Accessible.role: Accessible.Button
|
||||
@@ -201,7 +202,7 @@ Drawer {
|
||||
color: "transparent"
|
||||
}
|
||||
onClicked: {
|
||||
LLM.chatListModel.removeChat(LLM.chatListModel.get(index))
|
||||
ChatListModel.removeChat(ChatListModel.get(index))
|
||||
Network.sendRemoveChat()
|
||||
}
|
||||
Accessible.role: Accessible.Button
|
||||
|
@@ -4,6 +4,7 @@ import QtQuick.Controls
|
||||
import QtQuick.Controls.Basic
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
import chatlistmodel
|
||||
import localdocs
|
||||
import llm
|
||||
|
||||
@@ -15,7 +16,7 @@ Dialog {
|
||||
width: 480
|
||||
height: 640
|
||||
|
||||
property var currentChat: LLM.chatListModel.currentChat
|
||||
property var currentChat: ChatListModel.currentChat
|
||||
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
|
@@ -4,15 +4,17 @@ import QtQuick.Controls
|
||||
import QtQuick.Controls.Basic
|
||||
import QtQuick.Dialogs
|
||||
import QtQuick.Layouts
|
||||
import chatlistmodel
|
||||
import download
|
||||
import llm
|
||||
import modellist
|
||||
import network
|
||||
|
||||
Dialog {
|
||||
id: modelDownloaderDialog
|
||||
modal: true
|
||||
opacity: 0.9
|
||||
closePolicy: LLM.chatListModel.currentChat.modelList.length === 0 ? Popup.NoAutoClose : (Popup.CloseOnEscape | Popup.CloseOnPressOutside)
|
||||
closePolicy: ModelList.installedModels.count === 0 ? Popup.NoAutoClose : (Popup.CloseOnEscape | Popup.CloseOnPressOutside)
|
||||
padding: 20
|
||||
bottomPadding: 30
|
||||
background: Rectangle {
|
||||
@@ -27,7 +29,7 @@ Dialog {
|
||||
Network.sendModelDownloaderDialog();
|
||||
}
|
||||
|
||||
property string defaultModelPath: Download.defaultLocalModelsPath()
|
||||
property string defaultModelPath: ModelList.defaultLocalModelsPath()
|
||||
property alias modelPath: settings.modelPath
|
||||
Settings {
|
||||
id: settings
|
||||
@@ -35,13 +37,19 @@ Dialog {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Download.downloadLocalModelsPath = settings.modelPath
|
||||
ModelList.localModelsPath = settings.modelPath
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
settings.sync()
|
||||
}
|
||||
|
||||
PopupDialog {
|
||||
id: downloadingErrorPopup
|
||||
anchors.centerIn: parent
|
||||
shouldTimeOut: false
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20
|
||||
@@ -56,7 +64,7 @@ Dialog {
|
||||
}
|
||||
|
||||
Label {
|
||||
visible: !Download.modelList.length
|
||||
visible: !ModelList.downloadableModels.count
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
@@ -73,323 +81,327 @@ Dialog {
|
||||
clip: true
|
||||
|
||||
ListView {
|
||||
id: modelList
|
||||
model: Download.modelList
|
||||
id: modelListView
|
||||
model: ModelList.downloadableModels
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
delegate: Item {
|
||||
delegate: Rectangle {
|
||||
id: delegateItem
|
||||
width: modelList.width
|
||||
height: modelName.height + modelName.padding
|
||||
+ description.height + description.padding
|
||||
objectName: "delegateItem"
|
||||
property bool downloading: false
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: index % 2 === 0 ? theme.backgroundLight : theme.backgroundLighter
|
||||
}
|
||||
width: modelListView.width
|
||||
height: childrenRect.height
|
||||
color: index % 2 === 0 ? theme.backgroundLight : theme.backgroundLighter
|
||||
|
||||
Text {
|
||||
id: modelName
|
||||
objectName: "modelName"
|
||||
property string filename: modelData.filename
|
||||
text: !modelData.isChatGPT ? (filename.startsWith("ggml-") ? filename.slice(5, filename.length - 4) : filename.slice(0, filename.length - 4)) : filename
|
||||
padding: 20
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
font.bold: modelData.isDefault || modelData.bestGPTJ || modelData.bestLlama || modelData.bestMPT
|
||||
color: theme.assistantColor
|
||||
Accessible.role: Accessible.Paragraph
|
||||
Accessible.name: qsTr("Model file")
|
||||
Accessible.description: qsTr("Model file to be downloaded")
|
||||
}
|
||||
GridLayout {
|
||||
columns: 2
|
||||
width: parent.width
|
||||
|
||||
Text {
|
||||
id: description
|
||||
text: " - " + modelData.description
|
||||
leftPadding: 20
|
||||
rightPadding: 20
|
||||
anchors.top: modelName.bottom
|
||||
anchors.left: modelName.left
|
||||
anchors.right: parent.right
|
||||
wrapMode: Text.WordWrap
|
||||
textFormat: Text.StyledText
|
||||
color: theme.textColor
|
||||
linkColor: theme.textColor
|
||||
Accessible.role: Accessible.Paragraph
|
||||
Accessible.name: qsTr("Description")
|
||||
Accessible.description: qsTr("The description of the file")
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
}
|
||||
|
||||
Text {
|
||||
id: isDefault
|
||||
text: qsTr("(default)")
|
||||
visible: modelData.isDefault
|
||||
anchors.top: modelName.top
|
||||
anchors.left: modelName.right
|
||||
padding: 20
|
||||
color: theme.textColor
|
||||
Accessible.role: Accessible.Paragraph
|
||||
Accessible.name: qsTr("Default file")
|
||||
Accessible.description: qsTr("Whether the file is the default model")
|
||||
}
|
||||
|
||||
Text {
|
||||
text: modelData.filesize
|
||||
anchors.top: modelName.top
|
||||
anchors.left: isDefault.visible ? isDefault.right : modelName.right
|
||||
padding: 20
|
||||
color: theme.textColor
|
||||
Accessible.role: Accessible.Paragraph
|
||||
Accessible.name: qsTr("File size")
|
||||
Accessible.description: qsTr("The size of the file")
|
||||
}
|
||||
|
||||
Label {
|
||||
id: speedLabel
|
||||
anchors.top: modelName.top
|
||||
anchors.right: itemProgressBar.left
|
||||
padding: 20
|
||||
objectName: "speedLabel"
|
||||
color: theme.textColor
|
||||
text: ""
|
||||
visible: downloading
|
||||
Accessible.role: Accessible.Paragraph
|
||||
Accessible.name: qsTr("Download speed")
|
||||
Accessible.description: qsTr("Download speed in bytes/kilobytes/megabytes per second")
|
||||
}
|
||||
|
||||
ProgressBar {
|
||||
id: itemProgressBar
|
||||
objectName: "itemProgressBar"
|
||||
anchors.top: modelName.top
|
||||
anchors.right: downloadButton.left
|
||||
anchors.topMargin: 20
|
||||
anchors.rightMargin: 20
|
||||
width: 100
|
||||
visible: downloading
|
||||
background: Rectangle {
|
||||
implicitWidth: 200
|
||||
implicitHeight: 30
|
||||
color: theme.backgroundDarkest
|
||||
radius: 3
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
implicitWidth: 200
|
||||
implicitHeight: 25
|
||||
|
||||
Rectangle {
|
||||
width: itemProgressBar.visualPosition * parent.width
|
||||
height: parent.height
|
||||
radius: 2
|
||||
color: theme.assistantColor
|
||||
}
|
||||
}
|
||||
Accessible.role: Accessible.ProgressBar
|
||||
Accessible.name: qsTr("Download progressBar")
|
||||
Accessible.description: qsTr("Shows the progress made in the download")
|
||||
}
|
||||
|
||||
Item {
|
||||
visible: modelData.calcHash
|
||||
anchors.top: modelName.top
|
||||
anchors.right: parent.right
|
||||
|
||||
Label {
|
||||
id: calcHashLabel
|
||||
anchors.right: busyCalcHash.left
|
||||
padding: 20
|
||||
objectName: "calcHashLabel"
|
||||
color: theme.textColor
|
||||
text: qsTr("Calculating MD5...")
|
||||
Text {
|
||||
textFormat: Text.StyledText
|
||||
text: "<h2>" + (name !== "" ? name : filename) + "</h2>"
|
||||
Layout.row: 0
|
||||
Layout.column: 0
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 20
|
||||
Layout.columnSpan: 2
|
||||
color: theme.assistantColor
|
||||
Accessible.role: Accessible.Paragraph
|
||||
Accessible.name: text
|
||||
Accessible.description: qsTr("Whether the file hash is being calculated")
|
||||
Accessible.name: qsTr("Model file")
|
||||
Accessible.description: qsTr("Model file to be downloaded")
|
||||
}
|
||||
|
||||
MyBusyIndicator {
|
||||
id: busyCalcHash
|
||||
anchors.right: parent.right
|
||||
padding: 20
|
||||
running: modelData.calcHash
|
||||
Accessible.role: Accessible.Animation
|
||||
Accessible.name: qsTr("Busy indicator")
|
||||
Accessible.description: qsTr("Displayed when the file hash is being calculated")
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
id: actionBox
|
||||
width: childrenRect.width + 20
|
||||
color: theme.backgroundDark
|
||||
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
|
||||
|
||||
Item {
|
||||
anchors.top: modelName.top
|
||||
anchors.topMargin: 15
|
||||
anchors.right: parent.right
|
||||
visible: modelData.installed
|
||||
|
||||
Label {
|
||||
id: installedLabel
|
||||
anchors.verticalCenter: removeButton.verticalCenter
|
||||
anchors.right: removeButton.left
|
||||
anchors.rightMargin: 15
|
||||
objectName: "installedLabel"
|
||||
color: theme.textColor
|
||||
text: qsTr("Already installed")
|
||||
Accessible.role: Accessible.Paragraph
|
||||
Accessible.name: text
|
||||
Accessible.description: qsTr("Whether the file is already installed on your system")
|
||||
}
|
||||
|
||||
MyButton {
|
||||
id: removeButton
|
||||
text: "Remove"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 20
|
||||
Accessible.description: qsTr("Remove button to remove model from filesystem")
|
||||
onClicked: {
|
||||
Download.removeModel(modelData.filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
visible: modelData.isChatGPT && !modelData.installed
|
||||
anchors.top: modelName.top
|
||||
anchors.topMargin: 15
|
||||
anchors.right: parent.right
|
||||
|
||||
TextField {
|
||||
id: openaiKey
|
||||
anchors.right: installButton.left
|
||||
anchors.rightMargin: 15
|
||||
color: theme.textColor
|
||||
background: Rectangle {
|
||||
color: theme.backgroundLighter
|
||||
radius: 10
|
||||
}
|
||||
placeholderText: qsTr("enter $OPENAI_API_KEY")
|
||||
placeholderTextColor: theme.backgroundLightest
|
||||
Accessible.role: Accessible.EditableText
|
||||
Accessible.name: placeholderText
|
||||
Accessible.description: qsTr("Whether the file hash is being calculated")
|
||||
}
|
||||
|
||||
Button {
|
||||
id: installButton
|
||||
contentItem: Text {
|
||||
color: openaiKey.text === "" ? theme.backgroundLightest : theme.textColor
|
||||
text: "Install"
|
||||
}
|
||||
enabled: openaiKey.text !== ""
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 20
|
||||
background: Rectangle {
|
||||
opacity: .5
|
||||
border.color: theme.backgroundLightest
|
||||
border.width: 1
|
||||
radius: 10
|
||||
color: theme.backgroundLight
|
||||
}
|
||||
onClicked: {
|
||||
Download.installModel(modelData.filename, openaiKey.text);
|
||||
}
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: qsTr("Install button")
|
||||
Accessible.description: qsTr("Install button to install chatgpt model")
|
||||
}
|
||||
}
|
||||
|
||||
MyButton {
|
||||
id: downloadButton
|
||||
text: downloading ? qsTr("Cancel") : qsTr("Download")
|
||||
anchors.top: modelName.top
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 15
|
||||
anchors.rightMargin: 20
|
||||
visible: !modelData.isChatGPT && !modelData.installed && !modelData.calcHash
|
||||
Accessible.description: qsTr("Cancel/Download button to stop/start the download")
|
||||
onClicked: {
|
||||
if (!downloading) {
|
||||
downloading = true;
|
||||
Download.downloadModel(modelData.filename);
|
||||
} else {
|
||||
downloading = false;
|
||||
Download.cancelDownload(modelData.filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Download.downloadProgress.connect(updateProgress);
|
||||
Download.downloadFinished.connect(resetProgress);
|
||||
}
|
||||
|
||||
property var lastUpdate: ({})
|
||||
|
||||
function updateProgress(bytesReceived, bytesTotal, modelName) {
|
||||
let currentTime = new Date().getTime();
|
||||
|
||||
for (let i = 0; i < modelList.contentItem.children.length; i++) {
|
||||
let delegateItem = modelList.contentItem.children[i];
|
||||
if (delegateItem.objectName === "delegateItem") {
|
||||
let modelNameText = delegateItem.children.find(child => child.objectName === "modelName").filename;
|
||||
if (modelNameText === modelName) {
|
||||
let progressBar = delegateItem.children.find(child => child.objectName === "itemProgressBar");
|
||||
progressBar.value = bytesReceived / bytesTotal;
|
||||
|
||||
let updated = false;
|
||||
|
||||
// Calculate the download speed
|
||||
if (lastUpdate[modelName] && lastUpdate[modelName].timestamp) {
|
||||
let timeDifference = currentTime - lastUpdate[modelName].timestamp;
|
||||
if (timeDifference >= 1500) {
|
||||
let bytesDifference = bytesReceived - lastUpdate[modelName].bytesReceived;
|
||||
let speed = (bytesDifference / timeDifference) * 1000; // bytes per second
|
||||
delegateItem.downloading = true
|
||||
|
||||
// Update the speed label
|
||||
let speedLabel = delegateItem.children.find(child => child.objectName === "speedLabel");
|
||||
if (speed < 1024) {
|
||||
speedLabel.text = speed.toFixed(2) + " B/s";
|
||||
} else if (speed < 1024 * 1024) {
|
||||
speedLabel.text = (speed / 1024).toFixed(2) + " KB/s";
|
||||
} else {
|
||||
speedLabel.text = (speed / (1024 * 1024)).toFixed(2) + " MB/s";
|
||||
}
|
||||
|
||||
updated = true;
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
MyButton {
|
||||
id: downloadButton
|
||||
text: isDownloading ? qsTr("Cancel") : isIncomplete ? qsTr("Resume") : qsTr("Download")
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 20
|
||||
Layout.minimumWidth: openaiKey.width
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||
visible: !isChatGPT && !installed && !calcHash && downloadError === ""
|
||||
Accessible.description: qsTr("Cancel/Resume/Download button to stop/restart/start the download")
|
||||
background: Rectangle {
|
||||
border.color: downloadButton.down ? theme.backgroundLightest : theme.buttonBorder
|
||||
border.width: 2
|
||||
radius: 10
|
||||
color: downloadButton.hovered ? theme.backgroundDark : theme.backgroundDarkest
|
||||
}
|
||||
onClicked: {
|
||||
if (!isDownloading) {
|
||||
Download.downloadModel(filename);
|
||||
} else {
|
||||
Download.cancelDownload(filename);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updated = true; // To get an initial entry in lastUpdate
|
||||
}
|
||||
|
||||
// Update the lastUpdate object for the current model
|
||||
if (updated) {
|
||||
lastUpdate[modelName] = {"timestamp": currentTime, "bytesReceived": bytesReceived};
|
||||
MyButton {
|
||||
id: removeButton
|
||||
text: qsTr("Remove")
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 20
|
||||
Layout.minimumWidth: openaiKey.width
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||
visible: installed || downloadError !== ""
|
||||
Accessible.description: qsTr("Remove button to remove model from filesystem")
|
||||
background: Rectangle {
|
||||
border.color: removeButton.down ? theme.backgroundLightest : theme.buttonBorder
|
||||
border.width: 2
|
||||
radius: 10
|
||||
color: removeButton.hovered ? theme.backgroundDark : theme.backgroundDarkest
|
||||
}
|
||||
onClicked: {
|
||||
Download.removeModel(filename);
|
||||
}
|
||||
}
|
||||
|
||||
MyButton {
|
||||
id: installButton
|
||||
visible: !installed && isChatGPT
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 20
|
||||
Layout.minimumWidth: openaiKey.width
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||
text: qsTr("Install")
|
||||
background: Rectangle {
|
||||
border.color: installButton.down ? theme.backgroundLightest : theme.buttonBorder
|
||||
border.width: 2
|
||||
radius: 10
|
||||
color: installButton.hovered ? theme.backgroundDark : theme.backgroundDarkest
|
||||
}
|
||||
onClicked: {
|
||||
if (openaiKey.text === "")
|
||||
openaiKey.showError();
|
||||
else
|
||||
Download.installModel(filename, openaiKey.text);
|
||||
}
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: qsTr("Install button")
|
||||
Accessible.description: qsTr("Install button to install chatgpt 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
|
||||
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("Download size: ") + filesize)
|
||||
+ "<br>"
|
||||
+ (qsTr("RAM required: ") + (ramrequired > 0 ? ramrequired + " GB" : qsTr("minimal")))
|
||||
+ "<br>"
|
||||
+ (qsTr("Parameters: ") + parameters)
|
||||
+ "<br>"
|
||||
+ (qsTr("Quantization: ") + quant)
|
||||
+ "<br>"
|
||||
+ (qsTr("Type: ") + type)
|
||||
+ "</strong></font>"
|
||||
color: theme.textColor
|
||||
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: openaiKey.width
|
||||
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
|
||||
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: openaiKey.width
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||
spacing: 20
|
||||
|
||||
ProgressBar {
|
||||
id: itemProgressBar
|
||||
Layout.fillWidth: true
|
||||
width: openaiKey.width
|
||||
value: bytesReceived / bytesTotal
|
||||
background: Rectangle {
|
||||
implicitHeight: 45
|
||||
color: theme.backgroundDarkest
|
||||
radius: 3
|
||||
}
|
||||
contentItem: Item {
|
||||
implicitHeight: 40
|
||||
|
||||
Rectangle {
|
||||
width: itemProgressBar.visualPosition * parent.width
|
||||
height: parent.height
|
||||
radius: 2
|
||||
color: theme.assistantColor
|
||||
}
|
||||
}
|
||||
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
|
||||
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: openaiKey.width
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||
|
||||
Label {
|
||||
id: calcHashLabel
|
||||
color: theme.textColor
|
||||
text: qsTr("Calculating MD5...")
|
||||
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: openaiKey
|
||||
visible: !installed && isChatGPT
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 20
|
||||
Layout.minimumWidth: 150
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||
color: theme.textColor
|
||||
background: Rectangle {
|
||||
color: theme.backgroundLighter
|
||||
radius: 10
|
||||
}
|
||||
function showError() {
|
||||
openaiKey.placeholderTextColor = theme.textErrorColor
|
||||
}
|
||||
onTextChanged: {
|
||||
openaiKey.placeholderTextColor = theme.backgroundLightest
|
||||
}
|
||||
placeholderText: qsTr("enter $OPENAI_API_KEY")
|
||||
placeholderTextColor: theme.backgroundLightest
|
||||
Accessible.role: Accessible.EditableText
|
||||
Accessible.name: placeholderText
|
||||
Accessible.description: qsTr("Whether the file hash is being calculated")
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: descriptionText
|
||||
text: description
|
||||
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("The description of the file")
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetProgress(modelName) {
|
||||
for (let i = 0; i < modelList.contentItem.children.length; i++) {
|
||||
let delegateItem = modelList.contentItem.children[i];
|
||||
if (delegateItem.objectName === "delegateItem") {
|
||||
let modelNameText = delegateItem.children.find(child => child.objectName === "modelName").filename;
|
||||
if (modelNameText === modelName) {
|
||||
let progressBar = delegateItem.children.find(child => child.objectName === "itemProgressBar");
|
||||
progressBar.value = 0;
|
||||
delegateItem.downloading = false;
|
||||
|
||||
// Remove speed label text
|
||||
let speedLabel = delegateItem.children.find(child => child.objectName === "speedLabel");
|
||||
speedLabel.text = "";
|
||||
|
||||
// Remove the lastUpdate object for the canceled model
|
||||
delete lastUpdate[modelName];
|
||||
break;
|
||||
footer: Component {
|
||||
Rectangle {
|
||||
width: modelListView.width
|
||||
height: expandButton.height + 80
|
||||
color: ModelList.downloadableModels.count % 2 === 0 ? theme.backgroundLight : theme.backgroundLighter
|
||||
MyButton {
|
||||
id: expandButton
|
||||
anchors.centerIn: parent
|
||||
padding: 40
|
||||
text: ModelList.downloadableModels.expanded ? qsTr("Show fewer models") : qsTr("Show more models")
|
||||
background: Rectangle {
|
||||
border.color: expandButton.down ? theme.backgroundLightest : theme.buttonBorder
|
||||
border.width: 2
|
||||
radius: 10
|
||||
color: expandButton.hovered ? theme.backgroundDark : theme.backgroundDarkest
|
||||
}
|
||||
onClicked: {
|
||||
ModelList.downloadableModels.expanded = !ModelList.downloadableModels.expanded;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -404,11 +416,11 @@ Dialog {
|
||||
FolderDialog {
|
||||
id: modelPathDialog
|
||||
title: "Please choose a directory"
|
||||
currentFolder: "file://" + Download.downloadLocalModelsPath
|
||||
currentFolder: "file://" + ModelList.localModelsPath
|
||||
onAccepted: {
|
||||
modelPathDisplayField.text = selectedFolder
|
||||
Download.downloadLocalModelsPath = modelPathDisplayField.text
|
||||
settings.modelPath = Download.downloadLocalModelsPath
|
||||
ModelList.localModelsPath = modelPathDisplayField.text
|
||||
settings.modelPath = ModelList.localModelsPath
|
||||
settings.sync()
|
||||
}
|
||||
}
|
||||
@@ -421,7 +433,7 @@ Dialog {
|
||||
}
|
||||
MyDirectoryField {
|
||||
id: modelPathDisplayField
|
||||
text: Download.downloadLocalModelsPath
|
||||
text: ModelList.localModelsPath
|
||||
Layout.fillWidth: true
|
||||
ToolTip.text: qsTr("Path where model files will be downloaded to")
|
||||
ToolTip.visible: hovered
|
||||
@@ -430,11 +442,11 @@ Dialog {
|
||||
Accessible.description: ToolTip.text
|
||||
onEditingFinished: {
|
||||
if (isValid) {
|
||||
Download.downloadLocalModelsPath = modelPathDisplayField.text
|
||||
settings.modelPath = Download.downloadLocalModelsPath
|
||||
ModelList.localModelsPath = modelPathDisplayField.text
|
||||
settings.modelPath = ModelList.localModelsPath
|
||||
settings.sync()
|
||||
} else {
|
||||
text = Download.downloadLocalModelsPath
|
||||
text = ModelList.localModelsPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -23,18 +23,21 @@ Dialog {
|
||||
anchors.centerIn: parent
|
||||
spacing: 20
|
||||
|
||||
Text {
|
||||
Label {
|
||||
id: textField
|
||||
width: Math.min(1024, implicitWidth)
|
||||
height: Math.min(600, implicitHeight)
|
||||
anchors.verticalCenter: shouldShowBusy ? busyIndicator.verticalCenter : parent.verticalCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
textFormat: Text.StyledText
|
||||
wrapMode: Text.WordWrap
|
||||
color: theme.textColor
|
||||
linkColor: theme.linkColor
|
||||
Accessible.role: Accessible.HelpBalloon
|
||||
Accessible.name: text
|
||||
Accessible.description: qsTr("Reveals a shortlived help balloon")
|
||||
onLinkActivated: { Qt.openUrlExternally("https://discord.gg/4M2QFmTt2k") }
|
||||
}
|
||||
|
||||
MyBusyIndicator {
|
||||
|
@@ -5,7 +5,9 @@ import QtQuick.Controls.Basic
|
||||
import QtQuick.Dialogs
|
||||
import QtQuick.Layouts
|
||||
import Qt.labs.folderlistmodel
|
||||
import chatlistmodel
|
||||
import download
|
||||
import modellist
|
||||
import network
|
||||
import llm
|
||||
|
||||
@@ -27,7 +29,7 @@ Dialog {
|
||||
Network.sendSettingsDialog();
|
||||
}
|
||||
|
||||
property var currentChat: LLM.chatListModel.currentChat
|
||||
property var currentChat: ChatListModel.currentChat
|
||||
|
||||
Theme {
|
||||
id: theme
|
||||
@@ -47,7 +49,7 @@ Dialog {
|
||||
property string defaultPromptTemplate: "### Human:
|
||||
%1
|
||||
### Assistant:\n"
|
||||
property string defaultModelPath: Download.defaultLocalModelsPath()
|
||||
property string defaultModelPath: ModelList.defaultLocalModelsPath()
|
||||
property string defaultUserDefaultModel: "Application default"
|
||||
|
||||
property alias temperature: settings.temperature
|
||||
@@ -102,20 +104,20 @@ Dialog {
|
||||
settings.saveChatGPTChats = defaultSaveChatGPTChats
|
||||
settings.serverChat = defaultServerChat
|
||||
settings.userDefaultModel = defaultUserDefaultModel
|
||||
Download.downloadLocalModelsPath = settings.modelPath
|
||||
ModelList.localModelsPath = settings.modelPath
|
||||
LLM.threadCount = settings.threadCount
|
||||
LLM.serverEnabled = settings.serverChat
|
||||
LLM.chatListModel.shouldSaveChats = settings.saveChats
|
||||
LLM.chatListModel.shouldSaveChatGPTChats = settings.saveChatGPTChats
|
||||
ChatListModel.shouldSaveChats = settings.saveChats
|
||||
chatListModel.shouldSaveChatGPTChats = settings.saveChatGPTChats
|
||||
settings.sync()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
LLM.threadCount = settings.threadCount
|
||||
LLM.serverEnabled = settings.serverChat
|
||||
LLM.chatListModel.shouldSaveChats = settings.saveChats
|
||||
LLM.chatListModel.shouldSaveChatGPTChats = settings.saveChatGPTChats
|
||||
Download.downloadLocalModelsPath = settings.modelPath
|
||||
ChatListModel.shouldSaveChats = settings.saveChats
|
||||
ChatListModel.shouldSaveChatGPTChats = settings.saveChatGPTChats
|
||||
ModelList.localModelsPath = settings.modelPath
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -515,13 +517,32 @@ Dialog {
|
||||
Accessible.description: ToolTip.text
|
||||
}
|
||||
|
||||
Label {
|
||||
id: promptTemplateLabel
|
||||
text: qsTr("Prompt Template:")
|
||||
color: theme.textColor
|
||||
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
|
||||
@@ -529,20 +550,6 @@ Dialog {
|
||||
height: 200
|
||||
color: "transparent"
|
||||
clip: true
|
||||
Label {
|
||||
id: promptTemplateLabelHelp
|
||||
visible: settings.promptTemplate.indexOf(
|
||||
"%1") === -1
|
||||
font.bold: true
|
||||
color: theme.textErrorColor
|
||||
text: qsTr("Prompt template must contain %1 to be replaced with the user's input.")
|
||||
anchors.fill: templateScrollView
|
||||
z: 200
|
||||
padding: 10
|
||||
wrapMode: TextArea.Wrap
|
||||
Accessible.role: Accessible.EditableText
|
||||
Accessible.name: text
|
||||
}
|
||||
ScrollView {
|
||||
id: templateScrollView
|
||||
anchors.fill: parent
|
||||
@@ -615,31 +622,21 @@ Dialog {
|
||||
Layout.row: 1
|
||||
Layout.column: 1
|
||||
Layout.minimumWidth: 350
|
||||
model: modelList
|
||||
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(newModelList) {
|
||||
var newArray = Array.from(newModelList);
|
||||
newArray.unshift('Application default');
|
||||
comboBox.model = newArray;
|
||||
function updateModel() {
|
||||
settings.sync();
|
||||
comboBox.currentIndex = comboBox.indexOfValue(settingsDialog.userDefaultModel);
|
||||
|
||||
}
|
||||
Component.onCompleted: {
|
||||
comboBox.updateModel(currentChat.modelList)
|
||||
comboBox.updateModel()
|
||||
}
|
||||
Connections {
|
||||
target: settings
|
||||
function onUserDefaultModelChanged() {
|
||||
comboBox.updateModel(currentChat.modelList)
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: currentChat
|
||||
function onModelListChanged() {
|
||||
comboBox.updateModel(currentChat.modelList)
|
||||
comboBox.updateModel()
|
||||
}
|
||||
}
|
||||
onActivated: {
|
||||
@@ -650,11 +647,11 @@ Dialog {
|
||||
FolderDialog {
|
||||
id: modelPathDialog
|
||||
title: "Please choose a directory"
|
||||
currentFolder: "file://" + Download.downloadLocalModelsPath
|
||||
currentFolder: "file://" + ModelList.localModelsPath
|
||||
onAccepted: {
|
||||
modelPathDisplayField.text = selectedFolder
|
||||
Download.downloadLocalModelsPath = modelPathDisplayField.text
|
||||
settings.modelPath = Download.downloadLocalModelsPath
|
||||
ModelList.localModelsPath = modelPathDisplayField.text
|
||||
settings.modelPath = ModelList.localModelsPath
|
||||
settings.sync()
|
||||
}
|
||||
}
|
||||
@@ -667,7 +664,7 @@ Dialog {
|
||||
}
|
||||
MyDirectoryField {
|
||||
id: modelPathDisplayField
|
||||
text: Download.downloadLocalModelsPath
|
||||
text: ModelList.localModelsPath
|
||||
implicitWidth: 300
|
||||
Layout.row: 2
|
||||
Layout.column: 1
|
||||
@@ -679,11 +676,11 @@ Dialog {
|
||||
Accessible.description: ToolTip.text
|
||||
onEditingFinished: {
|
||||
if (isValid) {
|
||||
Download.downloadLocalModelsPath = modelPathDisplayField.text
|
||||
settings.modelPath = Download.downloadLocalModelsPath
|
||||
ModelList.localModelsPath = modelPathDisplayField.text
|
||||
settings.modelPath = ModelList.localModelsPath
|
||||
settings.sync()
|
||||
} else {
|
||||
text = Download.downloadLocalModelsPath
|
||||
text = ModelList.localModelsPath
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -741,7 +738,7 @@ Dialog {
|
||||
onClicked: {
|
||||
Network.sendSaveChatsToggled(saveChatsBox.checked);
|
||||
settingsDialog.saveChats = saveChatsBox.checked
|
||||
LLM.chatListModel.shouldSaveChats = saveChatsBox.checked
|
||||
ChatListModel.shouldSaveChats = saveChatsBox.checked
|
||||
settings.sync()
|
||||
}
|
||||
ToolTip.text: qsTr("WARNING: Saving chats to disk can be ~2GB per chat")
|
||||
@@ -761,7 +758,7 @@ Dialog {
|
||||
checked: settingsDialog.saveChatGPTChats
|
||||
onClicked: {
|
||||
settingsDialog.saveChatGPTChats = saveChatGPTChatsBox.checked
|
||||
LLM.chatListModel.shouldSaveChatGPTChats = saveChatGPTChatsBox.checked
|
||||
ChatListModel.shouldSaveChatGPTChats = saveChatGPTChatsBox.checked
|
||||
settings.sync()
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user