Moving everything to subdir for monorepo merge.

This commit is contained in:
Adam Treat
2023-05-10 10:12:25 -04:00
parent bd0250a6f0
commit 6015154bef
73 changed files with 1 additions and 1 deletions

View File

@@ -0,0 +1,113 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import download
import network
import llm
Dialog {
id: abpoutDialog
anchors.centerIn: parent
modal: false
opacity: 0.9
padding: 20
width: 1024
height: column.height + 40
Theme {
id: theme
}
Column {
id: column
spacing: 20
Item {
width: childrenRect.width
height: childrenRect.height
Image {
id: img
anchors.top: parent.top
anchors.left: parent.left
width: 60
height: 60
source: "qrc:/gpt4all/icons/logo.svg"
}
Text {
anchors.left: img.right
anchors.leftMargin: 30
anchors.verticalCenter: img.verticalCenter
text: qsTr("About GPT4All")
color: theme.textColor
}
}
ScrollView {
clip: true
height: 200
width: 1024 - 40
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
TextArea {
id: welcome
wrapMode: Text.Wrap
width: 1024 - 40
padding: 20
textFormat: TextEdit.MarkdownText
text: qsTr("### Release notes\n")
+ Download.releaseInfo.notes
+ qsTr("### Contributors\n")
+ Download.releaseInfo.contributors
color: theme.textColor
focus: false
readOnly: true
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Release notes")
Accessible.description: qsTr("Release notes for this version")
background: Rectangle {
color: theme.backgroundLight
radius: 10
}
}
}
Label {
id: discordLink
width: parent.width
textFormat: Text.RichText
wrapMode: Text.WordWrap
text: qsTr("Check out our discord channel <a href=\"https://discord.gg/4M2QFmTt2k\">https://discord.gg/4M2QFmTt2k</a>")
onLinkActivated: { Qt.openUrlExternally("https://discord.gg/4M2QFmTt2k") }
color: theme.textColor
linkColor: theme.linkColor
Accessible.role: Accessible.Link
Accessible.name: qsTr("Discord link")
}
Label {
id: nomicProps
width: parent.width
textFormat: Text.RichText
wrapMode: Text.WordWrap
text: qsTr("Thank you to <a href=\"https://home.nomic.ai\">Nomic AI</a> and the community for contributing so much great data, code, ideas, and energy to the growing open source AI ecosystem!")
onLinkActivated: { Qt.openUrlExternally("https://home.nomic.ai") }
color: theme.textColor
linkColor: theme.linkColor
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Thank you blurb")
Accessible.description: qsTr("Contains embedded link to https://home.nomic.ai")
}
}
background: Rectangle {
anchors.fill: parent
color: theme.backgroundDarkest
border.width: 1
border.color: theme.dialogBorder
radius: 10
}
}

View File

@@ -0,0 +1,353 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import llm
import download
import network
Drawer {
id: chatDrawer
modal: false
opacity: 0.9
Theme {
id: theme
}
signal downloadClicked
signal aboutClicked
background: Rectangle {
height: parent.height
color: theme.backgroundDarkest
}
Item {
anchors.fill: parent
anchors.margins: 10
Accessible.role: Accessible.Pane
Accessible.name: qsTr("Drawer on the left of the application")
Accessible.description: qsTr("Drawer that is revealed by pressing the hamburger button")
Button {
id: newChat
anchors.left: parent.left
anchors.right: parent.right
padding: 15
font.pixelSize: theme.fontSizeLarger
background: Rectangle {
color: theme.backgroundDarkest
opacity: .5
border.color: theme.backgroundLightest
border.width: 1
radius: 10
}
contentItem: Text {
text: qsTr("New chat")
horizontalAlignment: Text.AlignHCenter
color: theme.textColor
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.description: qsTr("Use this to launch an external application that will check for updates to the installer")
}
onClicked: {
LLM.chatListModel.addChat();
Network.sendNewChat(LLM.chatListModel.count)
}
}
ScrollView {
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: -10
anchors.topMargin: 10
anchors.top: newChat.bottom
anchors.bottom: checkForUpdatesButton.top
anchors.bottomMargin: 10
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
ListView {
id: conversationList
anchors.fill: parent
anchors.rightMargin: 10
model: LLM.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 trashQuestionDisplayed: false
z: isCurrent ? 199 : 1
color: index % 2 === 0 ? theme.backgroundLight : theme.backgroundLighter
border.width: isCurrent
border.color: chatName.readOnly ? theme.assistantColor : theme.userColor
TextField {
id: chatName
anchors.left: parent.left
anchors.right: buttons.left
color: theme.textColor
padding: 15
focus: false
readOnly: true
wrapMode: Text.NoWrap
hoverEnabled: false // Disable hover events on the TextArea
selectByMouse: false // Disable text selection in the TextArea
font.pixelSize: theme.fontSizeLarger
text: readOnly ? metrics.elidedText : name
horizontalAlignment: TextInput.AlignLeft
opacity: trashQuestionDisplayed ? 0.5 : 1.0
TextMetrics {
id: metrics
font: chatName.font
text: name
elide: Text.ElideRight
elideWidth: chatName.width - 25
}
background: Rectangle {
color: "transparent"
}
onEditingFinished: {
// Work around a bug in qml where we're losing focus when the whole window
// goes out of focus even though this textfield should be marked as not
// having focus
if (chatName.readOnly)
return;
changeName();
Network.sendRenameChat()
}
function changeName() {
LLM.chatListModel.get(index).name = chatName.text
chatName.focus = false
chatName.readOnly = true
chatName.selectByMouse = false
}
TapHandler {
onTapped: {
if (isCurrent)
return;
LLM.chatListModel.currentChat = LLM.chatListModel.get(index);
}
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Select the current chat")
Accessible.description: qsTr("Provides a button to select the current chat or edit the chat when in edit mode")
}
Row {
id: buttons
anchors.verticalCenter: chatName.verticalCenter
anchors.right: chatRectangle.right
anchors.rightMargin: 10
spacing: 10
Button {
id: editButton
width: 30
height: 30
visible: isCurrent
opacity: trashQuestionDisplayed ? 0.5 : 1.0
background: Image {
width: 30
height: 30
source: "qrc:/gpt4all/icons/edit.svg"
}
onClicked: {
chatName.focus = true
chatName.readOnly = false
chatName.selectByMouse = true
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Edit the chat name")
Accessible.description: qsTr("Provides a button to edit the chat name")
}
Button {
id: c
width: 30
height: 30
visible: isCurrent
background: Image {
width: 30
height: 30
source: "qrc:/gpt4all/icons/trash.svg"
}
onClicked: {
trashQuestionDisplayed = true
timer.start()
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Delete of the chat")
Accessible.description: qsTr("Provides a button to delete the chat")
}
}
Rectangle {
id: trashSureQuestion
anchors.top: buttons.bottom
anchors.topMargin: 10
anchors.right: buttons.right
width: childrenRect.width
height: childrenRect.height
color: chatRectangle.color
visible: isCurrent && trashQuestionDisplayed
opacity: 1.0
radius: 10
z: 200
Row {
spacing: 10
Button {
id: checkMark
width: 30
height: 30
contentItem: Text {
color: theme.textErrorColor
text: "\u2713"
font.pixelSize: theme.fontSizeLarger
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
width: 30
height: 30
color: "transparent"
}
onClicked: {
LLM.chatListModel.removeChat(LLM.chatListModel.get(index))
Network.sendRemoveChat()
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Confirm delete of the chat")
Accessible.description: qsTr("Provides a button to confirm delete of the chat")
}
Button {
id: cancel
width: 30
height: 30
contentItem: Text {
color: theme.textColor
text: "\u2715"
font.pixelSize: theme.fontSizeLarger
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
width: 30
height: 30
color: "transparent"
}
onClicked: {
trashQuestionDisplayed = false
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Cancel the delete of the chat")
Accessible.description: qsTr("Provides a button to cancel delete of the chat")
}
}
}
Timer {
id: timer
interval: 3000; running: false; repeat: false
onTriggered: trashQuestionDisplayed = false
}
}
Accessible.role: Accessible.List
Accessible.name: qsTr("List of chats")
Accessible.description: qsTr("List of chats in the drawer dialog")
}
}
Button {
id: checkForUpdatesButton
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: downloadButton.top
anchors.bottomMargin: 10
padding: 15
contentItem: Text {
text: qsTr("Updates")
horizontalAlignment: Text.AlignHCenter
color: theme.textColor
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.description: qsTr("Use this to launch an external application that will check for updates to the installer")
}
background: Rectangle {
opacity: .5
border.color: theme.backgroundLightest
border.width: 1
radius: 10
color: theme.backgroundLight
}
onClicked: {
if (!LLM.checkForUpdates())
checkForUpdatesError.open()
}
}
Button {
id: downloadButton
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: aboutButton.top
anchors.bottomMargin: 10
padding: 15
contentItem: Text {
text: qsTr("Downloads")
horizontalAlignment: Text.AlignHCenter
color: theme.textColor
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.description: qsTr("Use this to launch a dialog to download new models")
}
background: Rectangle {
opacity: .5
border.color: theme.backgroundLightest
border.width: 1
radius: 10
color: theme.backgroundLight
}
onClicked: {
downloadClicked()
}
}
Button {
id: aboutButton
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
padding: 15
contentItem: Text {
text: qsTr("About")
horizontalAlignment: Text.AlignHCenter
color: theme.textColor
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.description: qsTr("Use this to launch a dialog to show the about page")
}
background: Rectangle {
opacity: .5
border.color: theme.backgroundLightest
border.width: 1
radius: 10
color: theme.backgroundLight
}
onClicked: {
aboutClicked()
}
}
}
}

View File

@@ -0,0 +1,383 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Dialogs
import QtQuick.Layouts
import download
import llm
import network
Dialog {
id: modelDownloaderDialog
modal: true
opacity: 0.9
closePolicy: LLM.chatListModel.currentChat.modelList.length === 0 ? Popup.NoAutoClose : (Popup.CloseOnEscape | Popup.CloseOnPressOutside)
background: Rectangle {
anchors.fill: parent
anchors.margins: -20
color: theme.backgroundDarkest
border.width: 1
border.color: theme.dialogBorder
radius: 10
}
onOpened: {
Network.sendModelDownloaderDialog();
}
property string defaultModelPath: Download.defaultLocalModelsPath()
property alias modelPath: settings.modelPath
Settings {
id: settings
property string modelPath: modelDownloaderDialog.defaultModelPath
}
Component.onCompleted: {
Download.downloadLocalModelsPath = settings.modelPath
}
Component.onDestruction: {
settings.sync()
}
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 30
Label {
id: listLabel
text: "Available Models:"
Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
color: theme.textColor
}
ScrollView {
id: scrollView
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
ListView {
id: modelList
model: Download.modelList
boundsBehavior: Flickable.StopAtBounds
delegate: Item {
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
}
Text {
id: modelName
objectName: "modelName"
property string filename: modelData.filename
text: filename.slice(5, filename.length - 4)
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")
}
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
color: theme.textColor
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Description")
Accessible.description: qsTr("The description of the file")
}
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...")
Accessible.role: Accessible.Paragraph
Accessible.name: text
Accessible.description: qsTr("Whether the file hash is being calculated")
}
BusyIndicator {
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")
}
}
Label {
id: installedLabel
anchors.top: modelName.top
anchors.right: parent.right
padding: 20
objectName: "installedLabel"
color: theme.textColor
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
contentItem: Text {
color: theme.textColor
text: downloading ? "Cancel" : "Download"
}
anchors.top: modelName.top
anchors.right: parent.right
anchors.topMargin: 15
anchors.rightMargin: 20
visible: !modelData.installed && !modelData.calcHash
onClicked: {
if (!downloading) {
downloading = true;
Download.downloadModel(modelData.filename);
} else {
downloading = false;
Download.cancelDownload(modelData.filename);
}
}
background: Rectangle {
opacity: .5
border.color: theme.backgroundLightest
border.width: 1
radius: 10
color: theme.backgroundLight
}
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").filename;
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
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";
}
}
// 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").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;
}
}
}
}
}
}
RowLayout {
Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
spacing: 20
FolderDialog {
id: modelPathDialog
title: "Please choose a directory"
currentFolder: Download.downloadLocalModelsPath
onAccepted: {
Download.downloadLocalModelsPath = selectedFolder
settings.modelPath = Download.downloadLocalModelsPath
settings.sync()
}
}
Label {
id: modelPathLabel
text: qsTr("Download path:")
color: theme.textColor
Layout.row: 1
Layout.column: 0
}
TextField {
id: modelPathDisplayLabel
text: Download.downloadLocalModelsPath
readOnly: true
color: theme.textColor
Layout.fillWidth: true
ToolTip.text: qsTr("Path where model files will be downloaded to")
ToolTip.visible: hovered
Accessible.role: Accessible.ToolTip
Accessible.name: modelPathDisplayLabel.text
Accessible.description: ToolTip.text
background: Rectangle {
color: theme.backgroundLighter
radius: 10
}
}
Button {
text: qsTr("Browse")
contentItem: Text {
text: qsTr("Browse")
horizontalAlignment: Text.AlignHCenter
color: theme.textColor
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.description: qsTr("Opens a folder picker dialog to choose where to save model files")
}
background: Rectangle {
opacity: .5
border.color: theme.backgroundLightest
border.width: 1
radius: 10
color: theme.backgroundLight
}
onClicked: modelPathDialog.open()
}
}
}
}

View File

@@ -0,0 +1,174 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import download
import network
import llm
Dialog {
id: networkDialog
anchors.centerIn: parent
modal: true
opacity: 0.9
padding: 20
Theme {
id: theme
}
Settings {
id: settings
category: "network"
property string attribution: ""
}
Component.onDestruction: {
settings.sync()
}
Column {
id: column
spacing: 20
Item {
width: childrenRect.width
height: childrenRect.height
Image {
id: img
anchors.top: parent.top
anchors.left: parent.left
width: 60
height: 60
source: "qrc:/gpt4all/icons/logo.svg"
}
Text {
anchors.left: img.right
anchors.leftMargin: 30
anchors.verticalCenter: img.verticalCenter
text: qsTr("Contribute data to the GPT4All Opensource Datalake.")
color: theme.textColor
}
}
ScrollView {
clip: true
height: 300
width: 1024 - 40
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
TextArea {
id: textOptIn
wrapMode: Text.Wrap
width: 1024 - 40
padding: 20
text: qsTr("By enabling this feature, you will be able to participate in the democratic process of training a large language model by contributing data for future model improvements.
When a GPT4All model responds to you and you have opted-in, your conversation will be sent to the GPT4All Open Source Datalake. Additionally, you can like/dislike its response. If you dislike a response, you can suggest an alternative response. This data will be collected and aggregated in the GPT4All Datalake.
NOTE: By turning on this feature, you will be sending your data to the GPT4All Open Source Datalake. You should have no expectation of chat privacy when this feature is enabled. You should; however, have an expectation of an optional attribution if you wish. Your chat data will be openly available for anyone to download and will be used by Nomic AI to improve future GPT4All models. Nomic AI will retain all attribution information attached to your data and you will be credited as a contributor to any GPT4All model release that uses your data!")
color: theme.textColor
focus: false
readOnly: true
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Terms for opt-in")
Accessible.description: qsTr("Describes what will happen when you opt-in")
background: Rectangle {
color: theme.backgroundLight
radius: 10
}
}
}
TextField {
id: attribution
color: theme.textColor
padding: 20
width: parent.width
text: settings.attribution
font.pixelSize: theme.fontSizeLarge
placeholderText: qsTr("Please provide a name for attribution (optional)")
placeholderTextColor: theme.backgroundLightest
background: Rectangle {
color: theme.backgroundLighter
radius: 10
}
Accessible.role: Accessible.EditableText
Accessible.name: qsTr("Attribution (optional)")
Accessible.description: qsTr("Textfield for providing attribution")
onEditingFinished: {
settings.attribution = attribution.text;
settings.sync();
}
}
}
background: Rectangle {
anchors.fill: parent
color: theme.backgroundDarkest
border.width: 1
border.color: theme.dialogBorder
radius: 10
}
footer: DialogButtonBox {
id: dialogBox
padding: 20
alignment: Qt.AlignRight
spacing: 10
Button {
contentItem: Text {
color: theme.textColor
text: qsTr("Enable")
}
background: Rectangle {
border.color: theme.backgroundLightest
border.width: 1
radius: 10
color: theme.backgroundLight
}
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.description: qsTr("Enable opt-in button")
padding: 15
DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
}
Button {
contentItem: Text {
color: theme.textColor
text: qsTr("Cancel")
}
background: Rectangle {
border.color: theme.backgroundLightest
border.width: 1
radius: 10
color: theme.backgroundLight
}
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.description: qsTr("Cancel opt-in button")
padding: 15
DialogButtonBox.buttonRole: DialogButtonBox.RejectRole
}
background: Rectangle {
color: "transparent"
}
}
onAccepted: {
if (Network.isActive)
return
Network.isActive = true;
Network.sendNetworkToggled(true);
}
onRejected: {
if (!Network.isActive)
return
Network.isActive = false;
Network.sendNetworkToggled(false);
}
}

View File

@@ -0,0 +1,76 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import download
import network
import llm
Dialog {
id: newVerionDialog
anchors.centerIn: parent
modal: true
opacity: 0.9
width: contentItem.width
height: contentItem.height
padding: 20
Theme {
id: theme
}
background: Rectangle {
anchors.fill: parent
color: theme.backgroundDarkest
border.width: 1
border.color: theme.dialogBorder
radius: 10
}
Item {
id: contentItem
width: childrenRect.width + 40
height: childrenRect.height + 40
Label {
id: label
anchors.top: parent.top
anchors.left: parent.left
topPadding: 20
bottomPadding: 20
text: qsTr("New version is available:")
color: theme.textColor
}
Button {
id: button
anchors.left: label.right
anchors.leftMargin: 10
anchors.verticalCenter: label.verticalCenter
padding: 20
contentItem: Text {
text: qsTr("Update")
horizontalAlignment: Text.AlignHCenter
color: theme.textColor
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.description: qsTr("Use this to launch an external application that will check for updates to the installer")
}
background: Rectangle {
opacity: .5
border.color: theme.backgroundLightest
border.width: 1
radius: 10
color: theme.backgroundLight
}
onClicked: {
if (!LLM.checkForUpdates())
checkForUpdatesError.open()
}
}
}
}

View File

@@ -0,0 +1,71 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
Dialog {
id: popupDialog
anchors.centerIn: parent
opacity: 0.9
padding: 20
property alias text: textField.text
property bool shouldTimeOut: true
property bool shouldShowBusy: false
modal: shouldShowBusy
closePolicy: shouldShowBusy ? Popup.NoAutoClose : (Popup.CloseOnEscape | Popup.CloseOnPressOutside)
Theme {
id: theme
}
Row {
anchors.centerIn: parent
width: childrenRect.width
height: childrenRect.height
spacing: 20
Text {
id: textField
anchors.verticalCenter: busyIndicator.verticalCenter
horizontalAlignment: Text.AlignJustify
color: theme.textColor
Accessible.role: Accessible.HelpBalloon
Accessible.name: text
Accessible.description: qsTr("Reveals a shortlived help balloon")
}
BusyIndicator {
id: busyIndicator
visible: shouldShowBusy
running: shouldShowBusy
Accessible.role: Accessible.Animation
Accessible.name: qsTr("Busy indicator")
Accessible.description: qsTr("Displayed when the popup is showing busy")
}
}
background: Rectangle {
anchors.fill: parent
color: theme.backgroundDarkest
border.width: 1
border.color: theme.dialogBorder
radius: 10
}
exit: Transition {
NumberAnimation { duration: 500; property: "opacity"; from: 1.0; to: 0.0 }
}
onOpened: {
if (shouldTimeOut)
timer.start()
}
Timer {
id: timer
interval: 500; running: false; repeat: false
onTriggered: popupDialog.close()
}
}

View File

@@ -0,0 +1,828 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Dialogs
import QtQuick.Layouts
import download
import network
import llm
Dialog {
id: settingsDialog
modal: true
opacity: 0.9
background: Rectangle {
anchors.fill: parent
anchors.margins: -20
color: theme.backgroundDarkest
border.width: 1
border.color: theme.dialogBorder
radius: 10
}
onOpened: {
Network.sendSettingsDialog();
}
property var currentChat: LLM.chatListModel.currentChat
Theme {
id: theme
}
property real defaultTemperature: 0.28
property real defaultTopP: 0.95
property int defaultTopK: 40
property int defaultMaxLength: 4096
property int defaultPromptBatchSize: 9
property real defaultRepeatPenalty: 1.10
property int defaultRepeatPenaltyTokens: 64
property int defaultThreadCount: 0
property bool defaultSaveChats: false
property string defaultPromptTemplate: "### Human:
%1
### Assistant:\n"
property string defaultModelPath: Download.defaultLocalModelsPath()
property string defaultUserDefaultModel: "Application default"
property alias temperature: settings.temperature
property alias topP: settings.topP
property alias topK: settings.topK
property alias maxLength: settings.maxLength
property alias promptBatchSize: settings.promptBatchSize
property alias promptTemplate: settings.promptTemplate
property alias repeatPenalty: settings.repeatPenalty
property alias repeatPenaltyTokens: settings.repeatPenaltyTokens
property alias threadCount: settings.threadCount
property alias saveChats: settings.saveChats
property alias modelPath: settings.modelPath
property alias userDefaultModel: settings.userDefaultModel
Settings {
id: settings
property real temperature: settingsDialog.defaultTemperature
property real topP: settingsDialog.defaultTopP
property int topK: settingsDialog.defaultTopK
property int maxLength: settingsDialog.defaultMaxLength
property int promptBatchSize: settingsDialog.defaultPromptBatchSize
property int threadCount: settingsDialog.defaultThreadCount
property bool saveChats: settingsDialog.defaultSaveChats
property real repeatPenalty: settingsDialog.defaultRepeatPenalty
property int repeatPenaltyTokens: settingsDialog.defaultRepeatPenaltyTokens
property string promptTemplate: settingsDialog.defaultPromptTemplate
property string modelPath: settingsDialog.defaultModelPath
property string userDefaultModel: settingsDialog.defaultUserDefaultModel
}
function restoreGenerationDefaults() {
settings.temperature = defaultTemperature
settings.topP = defaultTopP
settings.topK = defaultTopK
settings.maxLength = defaultMaxLength
settings.promptBatchSize = defaultPromptBatchSize
settings.promptTemplate = defaultPromptTemplate
settings.repeatPenalty = defaultRepeatPenalty
settings.repeatPenaltyTokens = defaultRepeatPenaltyTokens
settings.sync()
}
function restoreApplicationDefaults() {
settings.modelPath = settingsDialog.defaultModelPath
settings.threadCount = defaultThreadCount
settings.saveChats = defaultSaveChats
settings.userDefaultModel = defaultUserDefaultModel
Download.downloadLocalModelsPath = settings.modelPath
LLM.threadCount = settings.threadCount
LLM.chatListModel.shouldSaveChats = settings.saveChats
settings.sync()
}
Component.onCompleted: {
LLM.threadCount = settings.threadCount
LLM.chatListModel.shouldSaveChats = settings.saveChats
Download.downloadLocalModelsPath = settings.modelPath
}
Connections {
target: settingsDialog
function onClosed() {
settings.sync()
}
}
Item {
Accessible.role: Accessible.Dialog
Accessible.name: qsTr("Settings dialog")
Accessible.description: qsTr("Dialog containing various application settings")
}
TabBar {
id: settingsTabBar
width: parent.width / 1.5
TabButton {
id: genSettingsButton
contentItem: IconLabel {
color: theme.textColor
font.bold: genSettingsButton.checked
font.pixelSize: genSettingsButton.checked ? theme.fontSizeLarger : theme.fontSizeLarge
text: qsTr("Generation")
}
background: Rectangle {
color: genSettingsButton.checked ? theme.backgroundDarkest : theme.backgroundLight
border.color: theme.tabBorder
border.width: 1 ? genSettingsButton.checked : 0
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Generation settings")
Accessible.description: qsTr("Settings related to how the model generates text")
}
TabButton {
id: appSettingsButton
contentItem: IconLabel {
color: theme.textColor
font.bold: appSettingsButton.checked
font.pixelSize: appSettingsButton.checked ? theme.fontSizeLarger : theme.fontSizeLarge
text: qsTr("Application")
}
background: Rectangle {
color: appSettingsButton.checked ? theme.backgroundDarkest : theme.backgroundLight
border.color: theme.tabBorder
border.width: 1 ? appSettingsButton.checked : 0
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Application settings")
Accessible.description: qsTr("Settings related to general behavior of the application")
}
}
StackLayout {
anchors.top: settingsTabBar.bottom
width: parent.width
height: availableHeight
currentIndex: settingsTabBar.currentIndex
Item {
id: generationSettingsTab
ScrollView {
background: Rectangle {
color: 'transparent'
border.color: theme.tabBorder
border.width: 1
radius: 2
}
padding: 10
width: parent.width
height: parent.height - 30
contentWidth: availableWidth - 20
contentHeight: generationSettingsTabInner.implicitHeight + 40
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
GridLayout {
id: generationSettingsTabInner
anchors.margins: 10
columns: 2
rowSpacing: 10
columnSpacing: 10
anchors.fill: parent
Label {
id: tempLabel
text: qsTr("Temperature:")
color: theme.textColor
Layout.row: 0
Layout.column: 0
}
TextField {
text: settings.temperature.toString()
color: theme.textColor
background: Rectangle {
implicitWidth: 150
color: theme.backgroundLighter
radius: 10
}
padding: 10
ToolTip.text: qsTr("Temperature increases the chances of choosing less likely tokens - higher temperature gives more creative but less predictable outputs")
ToolTip.visible: hovered
Layout.row: 0
Layout.column: 1
validator: DoubleValidator {
locale: "C"
}
onEditingFinished: {
var val = parseFloat(text)
if (!isNaN(val)) {
settings.temperature = val
settings.sync()
focus = false
} else {
text = settings.temperature.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: tempLabel.text
Accessible.description: ToolTip.text
}
Label {
id: topPLabel
text: qsTr("Top P:")
color: theme.textColor
Layout.row: 1
Layout.column: 0
}
TextField {
text: settings.topP.toString()
color: theme.textColor
background: Rectangle {
implicitWidth: 150
color: theme.backgroundLighter
radius: 10
}
padding: 10
ToolTip.text: qsTr("Only the most likely tokens up to a total probability of top_p can be chosen, prevents choosing highly unlikely tokens, aka Nucleus Sampling")
ToolTip.visible: hovered
Layout.row: 1
Layout.column: 1
validator: DoubleValidator {
locale: "C"
}
onEditingFinished: {
var val = parseFloat(text)
if (!isNaN(val)) {
settings.topP = val
settings.sync()
focus = false
} else {
text = settings.topP.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: topPLabel.text
Accessible.description: ToolTip.text
}
Label {
id: topKLabel
text: qsTr("Top K:")
color: theme.textColor
Layout.row: 2
Layout.column: 0
}
TextField {
text: settings.topK.toString()
color: theme.textColor
background: Rectangle {
implicitWidth: 150
color: theme.backgroundLighter
radius: 10
}
padding: 10
ToolTip.text: qsTr("Only the top K most likely tokens will be chosen from")
ToolTip.visible: hovered
Layout.row: 2
Layout.column: 1
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
settings.topK = val
settings.sync()
focus = false
} else {
text = settings.topK.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: topKLabel.text
Accessible.description: ToolTip.text
}
Label {
id: maxLengthLabel
text: qsTr("Max Length:")
color: theme.textColor
Layout.row: 3
Layout.column: 0
}
TextField {
text: settings.maxLength.toString()
color: theme.textColor
background: Rectangle {
implicitWidth: 150
color: theme.backgroundLighter
radius: 10
}
padding: 10
ToolTip.text: qsTr("Maximum length of response in tokens")
ToolTip.visible: hovered
Layout.row: 3
Layout.column: 1
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
settings.maxLength = val
settings.sync()
focus = false
} else {
text = settings.maxLength.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: maxLengthLabel.text
Accessible.description: ToolTip.text
}
Label {
id: batchSizeLabel
text: qsTr("Prompt Batch Size:")
color: theme.textColor
Layout.row: 4
Layout.column: 0
}
TextField {
text: settings.promptBatchSize.toString()
color: theme.textColor
background: Rectangle {
implicitWidth: 150
color: theme.backgroundLighter
radius: 10
}
padding: 10
ToolTip.text: qsTr("Amount of prompt tokens to process at once, higher values can speed up reading prompts but will use more RAM")
ToolTip.visible: hovered
Layout.row: 4
Layout.column: 1
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
settings.promptBatchSize = val
settings.sync()
focus = false
} else {
text = settings.promptBatchSize.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: batchSizeLabel.text
Accessible.description: ToolTip.text
}
Label {
id: repeatPenaltyLabel
text: qsTr("Repeat Penalty:")
color: theme.textColor
Layout.row: 5
Layout.column: 0
}
TextField {
text: settings.repeatPenalty.toString()
color: theme.textColor
background: Rectangle {
implicitWidth: 150
color: theme.backgroundLighter
radius: 10
}
padding: 10
ToolTip.text: qsTr("Amount to penalize repetitiveness of the output")
ToolTip.visible: hovered
Layout.row: 5
Layout.column: 1
validator: DoubleValidator {
locale: "C"
}
onEditingFinished: {
var val = parseFloat(text)
if (!isNaN(val)) {
settings.repeatPenalty = val
settings.sync()
focus = false
} else {
text = settings.repeatPenalty.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: repeatPenaltyLabel.text
Accessible.description: ToolTip.text
}
Label {
id: repeatPenaltyTokensLabel
text: qsTr("Repeat Penalty Tokens:")
color: theme.textColor
Layout.row: 6
Layout.column: 0
}
TextField {
text: settings.repeatPenaltyTokens.toString()
color: theme.textColor
background: Rectangle {
implicitWidth: 150
color: theme.backgroundLighter
radius: 10
}
padding: 10
ToolTip.text: qsTr("How far back in output to apply repeat penalty")
ToolTip.visible: hovered
Layout.row: 6
Layout.column: 1
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
settings.repeatPenaltyTokens = val
settings.sync()
focus = false
} else {
text = settings.repeatPenaltyTokens.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: repeatPenaltyTokensLabel.text
Accessible.description: ToolTip.text
}
Label {
id: promptTemplateLabel
text: qsTr("Prompt Template:")
color: theme.textColor
Layout.row: 7
Layout.column: 0
}
Rectangle {
Layout.row: 7
Layout.column: 1
Layout.fillWidth: true
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
TextArea {
text: settings.promptTemplate
color: theme.textColor
background: Rectangle {
implicitWidth: 150
color: theme.backgroundLighter
radius: 10
}
padding: 10
wrapMode: TextArea.Wrap
onTextChanged: {
settings.promptTemplate = text
settings.sync()
}
bottomPadding: 10
Accessible.role: Accessible.EditableText
Accessible.name: promptTemplateLabel.text
Accessible.description: promptTemplateLabelHelp.text
}
}
}
Button {
Layout.row: 8
Layout.column: 1
Layout.fillWidth: true
padding: 10
contentItem: Text {
text: qsTr("Restore Defaults")
horizontalAlignment: Text.AlignHCenter
color: theme.textColor
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.description: qsTr("Restores the settings dialog to a default state")
}
background: Rectangle {
opacity: .5
border.color: theme.backgroundLightest
border.width: 1
radius: 10
color: theme.backgroundLight
}
onClicked: {
settingsDialog.restoreGenerationDefaults()
}
}
}
}
}
Item {
id: applicationSettingsTab
ScrollView {
background: Rectangle {
color: 'transparent'
border.color: theme.tabBorder
border.width: 1
radius: 2
}
padding: 10
width: parent.width
height: parent.height - 30
contentWidth: availableWidth - 20
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
GridLayout {
anchors.margins: 10
columns: 3
rowSpacing: 10
columnSpacing: 10
anchors.fill: parent
Label {
id: defaultModelLabel
text: qsTr("Default model:")
color: theme.textColor
Layout.row: 1
Layout.column: 0
}
ComboBox {
id: comboBox
Layout.row: 1
Layout.column: 1
Layout.minimumWidth: 350
font.pixelSize: theme.fontSizeLarge
spacing: 0
padding: 10
model: modelList
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;
settings.sync();
comboBox.currentIndex = comboBox.indexOfValue(settingsDialog.userDefaultModel);
}
Component.onCompleted: {
comboBox.updateModel(currentChat.modelList)
}
Connections {
target: settings
function onUserDefaultModelChanged() {
comboBox.updateModel(currentChat.modelList)
}
}
Connections {
target: currentChat
function onModelListChanged() {
comboBox.updateModel(currentChat.modelList)
}
}
contentItem: Text {
anchors.horizontalCenter: parent.horizontalCenter
leftPadding: 10
rightPadding: 10
text: comboBox.displayText
font: comboBox.font
color: theme.textColor
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
}
delegate: ItemDelegate {
width: comboBox.width
contentItem: Text {
text: modelData
color: theme.textColor
font: comboBox.font
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
color: highlighted ? theme.backgroundLight : theme.backgroundDark
}
highlighted: comboBox.highlightedIndex === index
}
popup: Popup {
y: comboBox.height - 1
width: comboBox.width
implicitHeight: contentItem.implicitHeight
padding: 0
contentItem: ListView {
clip: true
implicitHeight: contentHeight
model: comboBox.popup.visible ? comboBox.delegateModel : null
currentIndex: comboBox.highlightedIndex
ScrollIndicator.vertical: ScrollIndicator { }
}
background: Rectangle {
color: theme.backgroundDark
}
}
background: Rectangle {
color: theme.backgroundDark
border.width: 1
border.color: theme.backgroundLightest
radius: 10
}
onActivated: {
settingsDialog.userDefaultModel = comboBox.currentText
settings.sync()
}
}
FolderDialog {
id: modelPathDialog
title: "Please choose a directory"
currentFolder: Download.downloadLocalModelsPath
onAccepted: {
Download.downloadLocalModelsPath = selectedFolder
settings.modelPath = Download.downloadLocalModelsPath
settings.sync()
}
}
Label {
id: modelPathLabel
text: qsTr("Download path:")
color: theme.textColor
Layout.row: 2
Layout.column: 0
}
TextField {
id: modelPathDisplayLabel
text: Download.downloadLocalModelsPath
readOnly: true
color: theme.textColor
implicitWidth: 300
padding: 10
Layout.row: 2
Layout.column: 1
Layout.fillWidth: true
ToolTip.text: qsTr("Path where model files will be downloaded to")
ToolTip.visible: hovered
Accessible.role: Accessible.ToolTip
Accessible.name: modelPathDisplayLabel.text
Accessible.description: ToolTip.text
background: Rectangle {
color: theme.backgroundLighter
radius: 10
}
}
Button {
Layout.row: 2
Layout.column: 2
text: qsTr("Browse")
contentItem: Text {
text: qsTr("Browse")
horizontalAlignment: Text.AlignHCenter
color: theme.textColor
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.description: qsTr("Opens a folder picker dialog to choose where to save model files")
}
background: Rectangle {
opacity: .5
border.color: theme.backgroundLightest
border.width: 1
radius: 10
color: theme.backgroundLight
}
onClicked: modelPathDialog.open()
}
Label {
id: nThreadsLabel
text: qsTr("CPU Threads:")
color: theme.textColor
Layout.row: 3
Layout.column: 0
}
TextField {
text: settingsDialog.threadCount.toString()
color: theme.textColor
background: Rectangle {
implicitWidth: 150
color: theme.backgroundLighter
radius: 10
}
padding: 10
ToolTip.text: qsTr("Amount of processing threads to use, a setting of 0 will use the lesser of 4 or your number of CPU threads")
ToolTip.visible: hovered
Layout.row: 3
Layout.column: 1
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt(text)
if (!isNaN(val)) {
settingsDialog.threadCount = val
LLM.threadCount = val
settings.sync()
focus = false
} else {
text = settingsDialog.threadCount.toString()
}
}
Accessible.role: Accessible.EditableText
Accessible.name: nThreadsLabel.text
Accessible.description: ToolTip.text
}
Label {
id: saveChatsLabel
text: qsTr("Save chats to disk:")
color: theme.textColor
Layout.row: 4
Layout.column: 0
}
CheckBox {
id: saveChatsBox
Layout.row: 4
Layout.column: 1
checked: settingsDialog.saveChats
onClicked: {
Network.sendSaveChatsToggled(saveChatsBox.checked);
settingsDialog.saveChats = saveChatsBox.checked
LLM.chatListModel.shouldSaveChats = saveChatsBox.checked
settings.sync()
}
ToolTip.text: qsTr("WARNING: Saving chats to disk can be ~2GB per chat")
ToolTip.visible: hovered
background: Rectangle {
color: "transparent"
}
indicator: Rectangle {
implicitWidth: 26
implicitHeight: 26
x: saveChatsBox.leftPadding
y: parent.height / 2 - height / 2
border.color: theme.dialogBorder
color: "transparent"
Rectangle {
width: 14
height: 14
x: 6
y: 6
color: theme.textColor
visible: saveChatsBox.checked
}
}
contentItem: Text {
text: saveChatsBox.text
font: saveChatsBox.font
opacity: enabled ? 1.0 : 0.3
color: theme.textColor
verticalAlignment: Text.AlignVCenter
leftPadding: saveChatsBox.indicator.width + saveChatsBox.spacing
}
}
Button {
Layout.row: 5
Layout.column: 1
Layout.fillWidth: true
padding: 10
contentItem: Text {
text: qsTr("Restore Defaults")
horizontalAlignment: Text.AlignHCenter
color: theme.textColor
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.description: qsTr("Restores the settings dialog to a default state")
}
background: Rectangle {
opacity: .5
border.color: theme.backgroundLightest
border.width: 1
radius: 10
color: theme.backgroundLight
}
onClicked: {
settingsDialog.restoreApplicationDefaults()
}
}
}
}
}
}
}

View File

@@ -0,0 +1,357 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import download
import network
import llm
Dialog {
id: startupDialog
anchors.centerIn: parent
modal: true
opacity: 0.9
padding: 20
width: 1024
height: column.height + 40
closePolicy: !optInStatisticsRadio.choiceMade || !optInNetworkRadio.choiceMade ? Popup.NoAutoClose : (Popup.CloseOnEscape | Popup.CloseOnPressOutside)
Theme {
id: theme
}
Column {
id: column
spacing: 20
Item {
width: childrenRect.width
height: childrenRect.height
Image {
id: img
anchors.top: parent.top
anchors.left: parent.left
width: 60
height: 60
source: "qrc:/gpt4all/icons/logo.svg"
}
Text {
anchors.left: img.right
anchors.leftMargin: 30
anchors.verticalCenter: img.verticalCenter
text: qsTr("Welcome!")
color: theme.textColor
}
}
ScrollView {
clip: true
height: 200
width: 1024 - 40
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
TextArea {
id: welcome
wrapMode: Text.Wrap
width: 1024 - 40
padding: 20
textFormat: TextEdit.MarkdownText
text: qsTr("### Release notes\n")
+ Download.releaseInfo.notes
+ qsTr("### Contributors\n")
+ Download.releaseInfo.contributors
color: theme.textColor
focus: false
readOnly: true
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Release notes")
Accessible.description: qsTr("Release notes for this version")
background: Rectangle {
color: theme.backgroundLight
radius: 10
}
}
}
ScrollView {
clip: true
height: 150
width: 1024 - 40
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
TextArea {
id: optInTerms
wrapMode: Text.Wrap
width: 1024 - 40
padding: 20
textFormat: TextEdit.MarkdownText
text: qsTr(
"### Opt-ins for anonymous usage analytics and datalake
By enabling these features, you will be able to participate in the democratic process of training a
large language model by contributing data for future model improvements.
When a GPT4All model responds to you and you have opted-in, your conversation will be sent to the GPT4All
Open Source Datalake. Additionally, you can like/dislike its response. If you dislike a response, you
can suggest an alternative response. This data will be collected and aggregated in the GPT4All Datalake.
NOTE: By turning on this feature, you will be sending your data to the GPT4All Open Source Datalake.
You should have no expectation of chat privacy when this feature is enabled. You should; however, have
an expectation of an optional attribution if you wish. Your chat data will be openly available for anyone
to download and will be used by Nomic AI to improve future GPT4All models. Nomic AI will retain all
attribution information attached to your data and you will be credited as a contributor to any GPT4All
model release that uses your data!")
color: theme.textColor
focus: false
readOnly: true
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Terms for opt-in")
Accessible.description: qsTr("Describes what will happen when you opt-in")
background: Rectangle {
color: theme.backgroundLight
radius: 10
}
}
}
GridLayout {
columns: 2
rowSpacing: 10
columnSpacing: 10
anchors.right: parent.right
Label {
id: optInStatistics
text: "Opt-in to anonymous usage analytics used to improve GPT4All"
Layout.row: 0
Layout.column: 0
color: theme.textColor
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Opt-in for anonymous usage statistics")
Accessible.description: qsTr("Label for opt-in")
}
ButtonGroup {
buttons: optInStatisticsRadio.children
onClicked: {
Network.usageStatsActive = optInStatisticsRadio.checked
if (optInNetworkRadio.choiceMade && optInStatisticsRadio.choiceMade)
startupDialog.close();
}
}
RowLayout {
id: optInStatisticsRadio
Layout.alignment: Qt.AlignVCenter
Layout.row: 0
Layout.column: 1
property bool defaultChecked: Network.usageStatsActive
property alias checked: optInStatisticsRadioYes.checked
property bool choiceMade: optInStatisticsRadioYes.checked || optInStatisticsRadioNo.checked
RadioButton {
id: optInStatisticsRadioYes
checked: optInStatisticsRadio.defaultChecked
text: qsTr("Yes")
Accessible.role: Accessible.RadioButton
Accessible.name: qsTr("Opt-in for anonymous usage statistics")
Accessible.description: qsTr("Radio button to allow opt-in for anonymous usage statistics")
background: Rectangle {
color: "transparent"
}
indicator: Rectangle {
implicitWidth: 26
implicitHeight: 26
x: optInStatisticsRadioYes.leftPadding
y: parent.height / 2 - height / 2
radius: 13
border.color: theme.dialogBorder
color: "transparent"
Rectangle {
width: 14
height: 14
x: 6
y: 6
radius: 7
color: theme.textColor
visible: optInStatisticsRadioYes.checked
}
}
contentItem: Text {
text: optInStatisticsRadioYes.text
font: optInStatisticsRadioYes.font
opacity: enabled ? 1.0 : 0.3
color: theme.textColor
verticalAlignment: Text.AlignVCenter
leftPadding: optInStatisticsRadioYes.indicator.width + optInStatisticsRadioYes.spacing
}
}
RadioButton {
id: optInStatisticsRadioNo
text: qsTr("No")
Accessible.role: Accessible.RadioButton
Accessible.name: qsTr("Opt-out for anonymous usage statistics")
Accessible.description: qsTr("Radio button to allow opt-out for anonymous usage statistics")
background: Rectangle {
color: "transparent"
}
indicator: Rectangle {
implicitWidth: 26
implicitHeight: 26
x: optInStatisticsRadioNo.leftPadding
y: parent.height / 2 - height / 2
radius: 13
border.color: theme.dialogBorder
color: "transparent"
Rectangle {
width: 14
height: 14
x: 6
y: 6
radius: 7
color: theme.textColor
visible: optInStatisticsRadioNo.checked
}
}
contentItem: Text {
text: optInStatisticsRadioNo.text
font: optInStatisticsRadioNo.font
opacity: enabled ? 1.0 : 0.3
color: theme.textColor
verticalAlignment: Text.AlignVCenter
leftPadding: optInStatisticsRadioNo.indicator.width + optInStatisticsRadioNo.spacing
}
}
}
Label {
id: optInNetwork
text: "Opt-in to anonymous sharing of chats to the GPT4All Datalake"
Layout.row: 1
Layout.column: 0
color: theme.textColor
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Opt-in for network")
Accessible.description: qsTr("Checkbox to allow opt-in for network")
}
ButtonGroup {
buttons: optInNetworkRadio.children
onClicked: {
Network.isActive = optInNetworkRadio.checked
if (optInNetworkRadio.choiceMade && optInStatisticsRadio.choiceMade)
startupDialog.close();
}
}
RowLayout {
id: optInNetworkRadio
Layout.alignment: Qt.AlignVCenter
Layout.row: 1
Layout.column: 1
property bool defaultChecked: Network.isActive
property alias checked: optInNetworkRadioYes.checked
property bool choiceMade: optInNetworkRadioYes.checked || optInNetworkRadioNo.checked
RadioButton {
id: optInNetworkRadioYes
checked: optInNetworkRadio.defaultChecked
text: qsTr("Yes")
Accessible.role: Accessible.RadioButton
Accessible.name: qsTr("Opt-in for network")
Accessible.description: qsTr("Radio button to allow opt-in anonymous sharing of chats to the GPT4All Datalake")
background: Rectangle {
color: "transparent"
}
indicator: Rectangle {
implicitWidth: 26
implicitHeight: 26
x: optInNetworkRadioYes.leftPadding
y: parent.height / 2 - height / 2
radius: 13
border.color: theme.dialogBorder
color: "transparent"
Rectangle {
width: 14
height: 14
x: 6
y: 6
radius: 7
color: theme.textColor
visible: optInNetworkRadioYes.checked
}
}
contentItem: Text {
text: optInNetworkRadioYes.text
font: optInNetworkRadioYes.font
opacity: enabled ? 1.0 : 0.3
color: theme.textColor
verticalAlignment: Text.AlignVCenter
leftPadding: optInNetworkRadioYes.indicator.width + optInNetworkRadioYes.spacing
}
}
RadioButton {
id: optInNetworkRadioNo
text: qsTr("No")
Accessible.role: Accessible.RadioButton
Accessible.name: qsTr("Opt-out for network")
Accessible.description: qsTr("Radio button to allow opt-out anonymous sharing of chats to the GPT4All Datalake")
background: Rectangle {
color: "transparent"
}
indicator: Rectangle {
implicitWidth: 26
implicitHeight: 26
x: optInNetworkRadioNo.leftPadding
y: parent.height / 2 - height / 2
radius: 13
border.color: theme.dialogBorder
color: "transparent"
Rectangle {
width: 14
height: 14
x: 6
y: 6
radius: 7
color: theme.textColor
visible: optInNetworkRadioNo.checked
}
}
contentItem: Text {
text: optInNetworkRadioNo.text
font: optInNetworkRadioNo.font
opacity: enabled ? 1.0 : 0.3
color: theme.textColor
verticalAlignment: Text.AlignVCenter
leftPadding: optInNetworkRadioNo.indicator.width + optInNetworkRadioNo.spacing
}
}
}
}
}
background: Rectangle {
anchors.fill: parent
color: theme.backgroundDarkest
border.width: 1
border.color: theme.dialogBorder
radius: 10
}
}

View File

@@ -0,0 +1,20 @@
import QtCore
import QtQuick
import QtQuick.Controls.Basic
QtObject {
property color textColor: "#d1d5db"
property color textErrorColor: "red"
property color backgroundDarkest: "#202123"
property color backgroundDark: "#242528"
property color backgroundLight: "#343541"
property color backgroundLighter: "#444654"
property color backgroundLightest: "#7d7d8e"
property color dialogBorder: "#d1d5db"
property color userColor: "#ec86bf"
property color assistantColor: "#10a37f"
property color linkColor: "white"
property color tabBorder: "#aaa"
property real fontSizeLarge: Qt.application.font.pixelSize
property real fontSizeLarger: Qt.application.font.pixelSize + 2
}

View File

@@ -0,0 +1,112 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import download
import network
import llm
Dialog {
id: thumbsDownDialog
modal: true
opacity: 0.9
padding: 20
Theme {
id: theme
}
property alias response: thumbsDownNewResponse.text
Column {
anchors.fill: parent
spacing: 20
Item {
width: childrenRect.width
height: childrenRect.height
Image {
id: img
anchors.top: parent.top
anchors.left: parent.left
width: 60
height: 60
source: "qrc:/gpt4all/icons/thumbs_down.svg"
}
Text {
anchors.left: img.right
anchors.leftMargin: 30
anchors.verticalCenter: img.verticalCenter
text: qsTr("Please edit the text below to provide a better response. (optional)")
color: theme.textColor
}
}
ScrollView {
clip: true
height: 300
width: parent.width
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
TextArea {
id: thumbsDownNewResponse
color: theme.textColor
padding: 20
wrapMode: Text.Wrap
font.pixelSize: theme.fontSizeLarge
placeholderText: qsTr("Please provide a better response...")
placeholderTextColor: theme.backgroundLightest
background: Rectangle {
color: theme.backgroundLighter
radius: 10
}
}
}
}
background: Rectangle {
anchors.fill: parent
color: theme.backgroundDarkest
border.width: 1
border.color: theme.dialogBorder
radius: 10
}
footer: DialogButtonBox {
padding: 20
alignment: Qt.AlignRight
spacing: 10
Button {
contentItem: Text {
color: theme.textColor
text: qsTr("Submit")
}
background: Rectangle {
border.color: theme.backgroundLightest
border.width: 1
radius: 10
color: theme.backgroundLight
}
padding: 15
DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
}
Button {
contentItem: Text {
color: theme.textColor
text: qsTr("Cancel")
}
background: Rectangle {
border.color: theme.backgroundLightest
border.width: 1
radius: 10
color: theme.backgroundLight
}
padding: 15
DialogButtonBox.buttonRole: DialogButtonBox.RejectRole
}
background: Rectangle {
color: "transparent"
}
}
}