mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-10-22 00:19:41 +00:00
Add a new model download feature.
This commit is contained in:
219
qml/ModelDownloaderDialog.qml
Normal file
219
qml/ModelDownloaderDialog.qml
Normal file
@@ -0,0 +1,219 @@
|
||||
import QtQuick 6.5
|
||||
import QtQuick.Controls 6.5
|
||||
import QtQuick.Layouts 1.12
|
||||
import download
|
||||
import llm
|
||||
|
||||
Dialog {
|
||||
id: modelDownloaderDialog
|
||||
width: 900
|
||||
height: 400
|
||||
title: "Model Downloader"
|
||||
modal: true
|
||||
opacity: 0.9
|
||||
closePolicy: LLM.modelList.length === 0 ? Popup.NoAutoClose : (Popup.CloseOnEscape | Popup.CloseOnPressOutside)
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -20
|
||||
color: "#202123"
|
||||
border.width: 1
|
||||
border.color: "white"
|
||||
radius: 10
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (LLM.modelList.length === 0)
|
||||
open();
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20
|
||||
spacing: 10
|
||||
|
||||
Label {
|
||||
id: listLabel
|
||||
text: "Available Models:"
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.fillWidth: true
|
||||
color: "#d1d5db"
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: modelList
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
model: Download.modelList
|
||||
clip: true
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
width: modelList.width
|
||||
height: 50
|
||||
objectName: "delegateItem"
|
||||
property bool downloading: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: index % 2 === 0 ? "#2c2f33" : "#1e2125"
|
||||
}
|
||||
|
||||
Text {
|
||||
id: modelName
|
||||
objectName: "modelName"
|
||||
text: modelData.filename
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10
|
||||
font.pixelSize: 24
|
||||
color: "#d1d5db"
|
||||
Accessible.role: Accessible.Paragraph
|
||||
Accessible.name: qsTr("Model file")
|
||||
Accessible.description: qsTr("Model file to be downloaded")
|
||||
}
|
||||
|
||||
Text {
|
||||
text: qsTr("(default)")
|
||||
visible: modelData.isDefault
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: modelName.right
|
||||
anchors.leftMargin: 10
|
||||
font.pixelSize: 24
|
||||
color: "#d1d5db"
|
||||
Accessible.role: Accessible.Paragraph
|
||||
Accessible.name: qsTr("Default file")
|
||||
Accessible.description: qsTr("Whether the file is the default model")
|
||||
}
|
||||
|
||||
Label {
|
||||
id: speedLabel
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: itemProgressBar.left
|
||||
anchors.rightMargin: 10
|
||||
objectName: "speedLabel"
|
||||
color: "#d1d5db"
|
||||
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.verticalCenter: parent.verticalCenter
|
||||
anchors.right: downloadButton.left
|
||||
anchors.rightMargin: 10
|
||||
width: 100
|
||||
visible: downloading
|
||||
Accessible.role: Accessible.ProgressBar
|
||||
Accessible.name: qsTr("Download progressBar")
|
||||
Accessible.description: qsTr("Shows the progress made in the download")
|
||||
}
|
||||
|
||||
Label {
|
||||
id: installedLabel
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 15
|
||||
objectName: "installedLabel"
|
||||
color: "#d1d5db"
|
||||
text: qsTr("Already installed")
|
||||
visible: modelData.installed
|
||||
Accessible.role: Accessible.Paragraph
|
||||
Accessible.name: text
|
||||
Accessible.description: qsTr("Whether the file is already installed on your system")
|
||||
}
|
||||
|
||||
Button {
|
||||
id: downloadButton
|
||||
text: downloading ? "Cancel" : "Download"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 10
|
||||
visible: !modelData.installed
|
||||
onClicked: {
|
||||
if (!downloading) {
|
||||
downloading = true;
|
||||
Download.downloadModel(modelData.filename);
|
||||
} else {
|
||||
downloading = false;
|
||||
Download.cancelDownload(modelData.filename);
|
||||
}
|
||||
}
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: text
|
||||
Accessible.description: qsTr("Cancel/Download button to stop/start the download")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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").text;
|
||||
if (modelNameText === modelName) {
|
||||
let progressBar = delegateItem.children.find(child => child.objectName === "itemProgressBar");
|
||||
progressBar.value = bytesReceived / bytesTotal;
|
||||
|
||||
// Calculate the download speed
|
||||
if (lastUpdate[modelName] && lastUpdate[modelName].timestamp) {
|
||||
let timeDifference = currentTime - lastUpdate[modelName].timestamp;
|
||||
let bytesDifference = bytesReceived - lastUpdate[modelName].bytesReceived;
|
||||
let speed = (bytesDifference / timeDifference) * 1000; // bytes per second
|
||||
|
||||
// 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";
|
||||
}
|
||||
}
|
||||
|
||||
// Update the lastUpdate object for the current model
|
||||
lastUpdate[modelName] = {"timestamp": currentTime, "bytesReceived": bytesReceived};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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").text;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user