mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2024-10-01 01:06:10 -04:00
f9cd2e321c
Signed-off-by: Shiranui <supersonic@livemail.tw> Signed-off-by: Jared Van Bortel <jared@nomic.ai> Co-authored-by: Jared Van Bortel <jared@nomic.ai>
597 lines
30 KiB
QML
597 lines
30 KiB
QML
import QtCore
|
|
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Controls.Basic
|
|
import QtQuick.Dialogs
|
|
import QtQuick.Layouts
|
|
import chatlistmodel
|
|
import download
|
|
import llm
|
|
import modellist
|
|
import network
|
|
import mysettings
|
|
|
|
Rectangle {
|
|
id: modelsView
|
|
color: theme.viewBackground
|
|
|
|
signal addModelViewRequested()
|
|
|
|
ToastManager {
|
|
id: messageToast
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
anchors.margins: 20
|
|
spacing: 30
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
visible: ModelList.installedModels.count === 0
|
|
ColumnLayout {
|
|
id: noInstalledLabel
|
|
anchors.centerIn: parent
|
|
spacing: 0
|
|
|
|
Text {
|
|
Layout.alignment: Qt.AlignCenter
|
|
text: qsTr("No Models Installed")
|
|
color: theme.mutedLightTextColor
|
|
font.pixelSize: theme.fontSizeBannerSmall
|
|
}
|
|
|
|
Text {
|
|
Layout.topMargin: 15
|
|
horizontalAlignment: Qt.AlignHCenter
|
|
color: theme.mutedLighterTextColor
|
|
text: qsTr("Install a model to get started using GPT4All")
|
|
font.pixelSize: theme.fontSizeLarge
|
|
}
|
|
}
|
|
|
|
MyButton {
|
|
anchors.top: noInstalledLabel.bottom
|
|
anchors.topMargin: 50
|
|
anchors.horizontalCenter: noInstalledLabel.horizontalCenter
|
|
rightPadding: 60
|
|
leftPadding: 60
|
|
text: qsTr("\uFF0B Add Model")
|
|
onClicked: {
|
|
addModelViewRequested()
|
|
}
|
|
Accessible.role: Accessible.Button
|
|
Accessible.name: qsTr("Shows the add model view")
|
|
}
|
|
}
|
|
|
|
RowLayout {
|
|
visible: ModelList.installedModels.count !== 0
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignTop
|
|
spacing: 50
|
|
|
|
ColumnLayout {
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignLeft
|
|
Layout.minimumWidth: 200
|
|
spacing: 5
|
|
|
|
Text {
|
|
id: welcome
|
|
text: qsTr("Installed Models")
|
|
font.pixelSize: theme.fontSizeBanner
|
|
color: theme.titleTextColor
|
|
}
|
|
|
|
Text {
|
|
text: qsTr("Locally installed chat models")
|
|
font.pixelSize: theme.fontSizeLarge
|
|
color: theme.titleInfoTextColor
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
height: 0
|
|
}
|
|
|
|
MyButton {
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
|
text: qsTr("\uFF0B Add Model")
|
|
onClicked: {
|
|
addModelViewRequested()
|
|
}
|
|
}
|
|
}
|
|
|
|
ScrollView {
|
|
id: scrollView
|
|
visible: ModelList.installedModels.count !== 0
|
|
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
clip: true
|
|
|
|
ListView {
|
|
id: modelListView
|
|
model: ModelList.installedModels
|
|
boundsBehavior: Flickable.StopAtBounds
|
|
spacing: 30
|
|
|
|
delegate: Rectangle {
|
|
id: delegateItem
|
|
width: modelListView.width
|
|
height: childrenRect.height + 60
|
|
color: theme.conversationBackground
|
|
radius: 10
|
|
border.width: 1
|
|
border.color: theme.controlBorder
|
|
|
|
ColumnLayout {
|
|
anchors.top: parent.top
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.margins: 30
|
|
|
|
Text {
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignLeft
|
|
text: name
|
|
elide: Text.ElideRight
|
|
color: theme.titleTextColor
|
|
font.pixelSize: theme.fontSizeLargest
|
|
font.bold: true
|
|
Accessible.role: Accessible.Paragraph
|
|
Accessible.name: qsTr("Model file")
|
|
Accessible.description: qsTr("Model file to be downloaded")
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
height: 1
|
|
color: theme.dividerColor
|
|
}
|
|
|
|
RowLayout {
|
|
Layout.topMargin: 10
|
|
Layout.fillWidth: true
|
|
Text {
|
|
id: descriptionText
|
|
text: description
|
|
font.pixelSize: theme.fontSizeLarge
|
|
Layout.fillWidth: true
|
|
wrapMode: Text.WordWrap
|
|
textFormat: Text.StyledText
|
|
color: theme.textColor
|
|
linkColor: theme.textColor
|
|
Accessible.role: Accessible.Paragraph
|
|
Accessible.name: qsTr("Description")
|
|
Accessible.description: qsTr("File description")
|
|
onLinkActivated: function(link) { Qt.openUrlExternally(link); }
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
acceptedButtons: Qt.NoButton // pass clicks to parent
|
|
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: actionBox
|
|
width: childrenRect.width + 20
|
|
color: "transparent"
|
|
border.width: 1
|
|
border.color: theme.dividerColor
|
|
radius: 10
|
|
Layout.rightMargin: 20
|
|
Layout.bottomMargin: 20
|
|
Layout.minimumHeight: childrenRect.height + 20
|
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
|
|
|
ColumnLayout {
|
|
spacing: 0
|
|
MySettingsButton {
|
|
id: downloadButton
|
|
text: isDownloading ? qsTr("Cancel") : qsTr("Resume")
|
|
font.pixelSize: theme.fontSizeLarge
|
|
Layout.topMargin: 20
|
|
Layout.leftMargin: 20
|
|
Layout.minimumWidth: 200
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
visible: (isDownloading || isIncomplete) && downloadError === "" && !isOnline && !calcHash
|
|
Accessible.description: qsTr("Stop/restart/start the download")
|
|
onClicked: {
|
|
if (!isDownloading) {
|
|
Download.downloadModel(filename);
|
|
} else {
|
|
Download.cancelDownload(filename);
|
|
}
|
|
}
|
|
}
|
|
|
|
MySettingsDestructiveButton {
|
|
id: removeButton
|
|
text: qsTr("Remove")
|
|
Layout.topMargin: 20
|
|
Layout.leftMargin: 20
|
|
Layout.minimumWidth: 200
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
visible: !isDownloading && (installed || isIncomplete)
|
|
Accessible.description: qsTr("Remove model from filesystem")
|
|
onClicked: {
|
|
Download.removeModel(filename);
|
|
}
|
|
}
|
|
|
|
MySettingsButton {
|
|
id: installButton
|
|
visible: !installed && isOnline
|
|
Layout.topMargin: 20
|
|
Layout.leftMargin: 20
|
|
Layout.minimumWidth: 200
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
text: qsTr("Install")
|
|
font.pixelSize: theme.fontSizeLarge
|
|
onClicked: {
|
|
var apiKeyText = apiKey.text.trim(),
|
|
baseUrlText = baseUrl.text.trim(),
|
|
modelNameText = modelName.text.trim();
|
|
|
|
var apiKeyOk = apiKeyText !== "",
|
|
baseUrlOk = !isCompatibleApi || baseUrlText !== "",
|
|
modelNameOk = !isCompatibleApi || modelNameText !== "";
|
|
|
|
if (!apiKeyOk)
|
|
apiKey.showError();
|
|
if (!baseUrlOk)
|
|
baseUrl.showError();
|
|
if (!modelNameOk)
|
|
modelName.showError();
|
|
|
|
if (!apiKeyOk || !baseUrlOk || !modelNameOk)
|
|
return;
|
|
|
|
if (!isCompatibleApi)
|
|
Download.installModel(
|
|
filename,
|
|
apiKeyText,
|
|
);
|
|
else
|
|
Download.installCompatibleModel(
|
|
modelNameText,
|
|
apiKeyText,
|
|
baseUrlText,
|
|
);
|
|
}
|
|
Accessible.role: Accessible.Button
|
|
Accessible.name: qsTr("Install")
|
|
Accessible.description: qsTr("Install online model")
|
|
}
|
|
|
|
ColumnLayout {
|
|
spacing: 0
|
|
Label {
|
|
Layout.topMargin: 20
|
|
Layout.leftMargin: 20
|
|
visible: downloadError !== ""
|
|
textFormat: Text.StyledText
|
|
text: qsTr("<strong><font size=\"1\"><a href=\"#error\">Error</a></strong></font>")
|
|
color: theme.textColor
|
|
font.pixelSize: theme.fontSizeLarge
|
|
linkColor: theme.textErrorColor
|
|
Accessible.role: Accessible.Paragraph
|
|
Accessible.name: text
|
|
Accessible.description: qsTr("Describes an error that occurred when downloading")
|
|
onLinkActivated: {
|
|
downloadingErrorPopup.text = downloadError;
|
|
downloadingErrorPopup.open();
|
|
}
|
|
}
|
|
|
|
Label {
|
|
visible: LLM.systemTotalRAMInGB() < ramrequired
|
|
Layout.topMargin: 20
|
|
Layout.leftMargin: 20
|
|
Layout.maximumWidth: 300
|
|
textFormat: Text.StyledText
|
|
text: qsTr("<strong><font size=\"2\">WARNING: Not recommended for your hardware. Model requires more memory (%1 GB) than your system has available (%2).</strong></font>").arg(ramrequired).arg(LLM.systemTotalRAMInGBString())
|
|
color: theme.textErrorColor
|
|
font.pixelSize: theme.fontSizeLarge
|
|
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: 200
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
spacing: 20
|
|
|
|
ProgressBar {
|
|
id: itemProgressBar
|
|
Layout.fillWidth: true
|
|
width: 200
|
|
value: bytesReceived / bytesTotal
|
|
background: Rectangle {
|
|
implicitHeight: 45
|
|
color: theme.progressBackground
|
|
radius: 3
|
|
}
|
|
contentItem: Item {
|
|
implicitHeight: 40
|
|
|
|
Rectangle {
|
|
width: itemProgressBar.visualPosition * parent.width
|
|
height: parent.height
|
|
radius: 2
|
|
color: theme.progressForeground
|
|
}
|
|
}
|
|
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
|
|
font.pixelSize: theme.fontSizeLarge
|
|
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: 200
|
|
Layout.maximumWidth: 200
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
clip: true
|
|
|
|
Label {
|
|
id: calcHashLabel
|
|
color: theme.textColor
|
|
text: qsTr("Calculating...")
|
|
font.pixelSize: theme.fontSizeLarge
|
|
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: apiKey
|
|
visible: !installed && isOnline
|
|
Layout.topMargin: 20
|
|
Layout.leftMargin: 20
|
|
Layout.minimumWidth: 200
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
wrapMode: Text.WrapAnywhere
|
|
function showError() {
|
|
messageToast.show(qsTr("ERROR: $API_KEY is empty."));
|
|
apiKey.placeholderTextColor = theme.textErrorColor;
|
|
}
|
|
onTextChanged: {
|
|
apiKey.placeholderTextColor = theme.mutedTextColor;
|
|
}
|
|
placeholderText: qsTr("enter $API_KEY")
|
|
Accessible.role: Accessible.EditableText
|
|
Accessible.name: placeholderText
|
|
Accessible.description: qsTr("Whether the file hash is being calculated")
|
|
}
|
|
|
|
MyTextField {
|
|
id: baseUrl
|
|
visible: !installed && isOnline && isCompatibleApi
|
|
Layout.topMargin: 20
|
|
Layout.leftMargin: 20
|
|
Layout.minimumWidth: 200
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
wrapMode: Text.WrapAnywhere
|
|
function showError() {
|
|
messageToast.show(qsTr("ERROR: $BASE_URL is empty."));
|
|
baseUrl.placeholderTextColor = theme.textErrorColor;
|
|
}
|
|
onTextChanged: {
|
|
baseUrl.placeholderTextColor = theme.mutedTextColor;
|
|
}
|
|
placeholderText: qsTr("enter $BASE_URL")
|
|
Accessible.role: Accessible.EditableText
|
|
Accessible.name: placeholderText
|
|
Accessible.description: qsTr("Whether the file hash is being calculated")
|
|
}
|
|
|
|
MyTextField {
|
|
id: modelName
|
|
visible: !installed && isOnline && isCompatibleApi
|
|
Layout.topMargin: 20
|
|
Layout.leftMargin: 20
|
|
Layout.minimumWidth: 200
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
wrapMode: Text.WrapAnywhere
|
|
function showError() {
|
|
messageToast.show(qsTr("ERROR: $MODEL_NAME is empty."))
|
|
modelName.placeholderTextColor = theme.textErrorColor;
|
|
}
|
|
onTextChanged: {
|
|
modelName.placeholderTextColor = theme.mutedTextColor;
|
|
}
|
|
placeholderText: qsTr("enter $MODEL_NAME")
|
|
Accessible.role: Accessible.EditableText
|
|
Accessible.name: placeholderText
|
|
Accessible.description: qsTr("Whether the file hash is being calculated")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
Layout.minimumWidth: childrenRect.width
|
|
Layout.minimumHeight: childrenRect.height
|
|
Layout.bottomMargin: 10
|
|
RowLayout {
|
|
id: paramRow
|
|
anchors.centerIn: parent
|
|
ColumnLayout {
|
|
Layout.topMargin: 10
|
|
Layout.bottomMargin: 10
|
|
Layout.leftMargin: 20
|
|
Layout.rightMargin: 20
|
|
Text {
|
|
text: qsTr("File size")
|
|
font.pixelSize: theme.fontSizeSmall
|
|
color: theme.mutedDarkTextColor
|
|
}
|
|
Text {
|
|
text: filesize
|
|
color: theme.textColor
|
|
font.pixelSize: theme.fontSizeSmall
|
|
font.bold: true
|
|
}
|
|
}
|
|
Rectangle {
|
|
width: 1
|
|
Layout.fillHeight: true
|
|
color: theme.dividerColor
|
|
}
|
|
ColumnLayout {
|
|
Layout.topMargin: 10
|
|
Layout.bottomMargin: 10
|
|
Layout.leftMargin: 20
|
|
Layout.rightMargin: 20
|
|
Text {
|
|
text: qsTr("RAM required")
|
|
font.pixelSize: theme.fontSizeSmall
|
|
color: theme.mutedDarkTextColor
|
|
}
|
|
Text {
|
|
text: ramrequired >= 0 ? qsTr("%1 GB").arg(ramrequired) : qsTr("?")
|
|
color: theme.textColor
|
|
font.pixelSize: theme.fontSizeSmall
|
|
font.bold: true
|
|
}
|
|
}
|
|
Rectangle {
|
|
width: 1
|
|
Layout.fillHeight: true
|
|
color: theme.dividerColor
|
|
}
|
|
ColumnLayout {
|
|
Layout.topMargin: 10
|
|
Layout.bottomMargin: 10
|
|
Layout.leftMargin: 20
|
|
Layout.rightMargin: 20
|
|
Text {
|
|
text: qsTr("Parameters")
|
|
font.pixelSize: theme.fontSizeSmall
|
|
color: theme.mutedDarkTextColor
|
|
}
|
|
Text {
|
|
text: parameters !== "" ? parameters : "?"
|
|
color: theme.textColor
|
|
font.pixelSize: theme.fontSizeSmall
|
|
font.bold: true
|
|
}
|
|
}
|
|
Rectangle {
|
|
width: 1
|
|
Layout.fillHeight: true
|
|
color: theme.dividerColor
|
|
}
|
|
ColumnLayout {
|
|
Layout.topMargin: 10
|
|
Layout.bottomMargin: 10
|
|
Layout.leftMargin: 20
|
|
Layout.rightMargin: 20
|
|
Text {
|
|
text: qsTr("Quant")
|
|
font.pixelSize: theme.fontSizeSmall
|
|
color: theme.mutedDarkTextColor
|
|
}
|
|
Text {
|
|
text: quant
|
|
color: theme.textColor
|
|
font.pixelSize: theme.fontSizeSmall
|
|
font.bold: true
|
|
}
|
|
}
|
|
Rectangle {
|
|
width: 1
|
|
Layout.fillHeight: true
|
|
color: theme.dividerColor
|
|
}
|
|
ColumnLayout {
|
|
Layout.topMargin: 10
|
|
Layout.bottomMargin: 10
|
|
Layout.leftMargin: 20
|
|
Layout.rightMargin: 20
|
|
Text {
|
|
text: qsTr("Type")
|
|
font.pixelSize: theme.fontSizeSmall
|
|
color: theme.mutedDarkTextColor
|
|
}
|
|
Text {
|
|
text: type
|
|
color: theme.textColor
|
|
font.pixelSize: theme.fontSizeSmall
|
|
font.bold: true
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
anchors.fill: paramRow
|
|
border.color: theme.dividerColor
|
|
border.width: 1
|
|
radius: 10
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
height: 1
|
|
color: theme.dividerColor
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: Download
|
|
function onToastMessage(message) {
|
|
messageToast.show(message);
|
|
}
|
|
}
|
|
}
|