2023-06-28 23:46:03 -04:00
import QtCore
import QtQuick
import QtQuick . Controls
import QtQuick . Controls . Basic
import QtQuick . Layouts
import QtQuick . Dialogs
import localdocs
2023-10-24 12:13:32 -04:00
import modellist
2023-06-28 23:46:03 -04:00
import mysettings
2023-07-01 11:34:21 -04:00
import network
2023-06-28 23:46:03 -04:00
MySettingsTab {
2023-07-01 11:34:21 -04:00
onRestoreDefaultsClicked: {
MySettings . restoreLocalDocsDefaults ( ) ;
}
2024-06-24 18:49:23 -04:00
showRestoreDefaultsButton: true
2023-10-24 12:13:32 -04:00
title: qsTr ( "LocalDocs" )
2023-06-28 23:46:03 -04:00
contentItem: ColumnLayout {
id: root
2024-06-28 12:57:57 -04:00
spacing: 30
2023-06-28 23:46:03 -04:00
2024-06-24 18:49:23 -04:00
Label {
2024-06-28 12:57:57 -04:00
Layout.bottomMargin: 10
color: theme . settingsTitleTextColor
font.pixelSize: theme . fontSizeBannerSmall
2024-06-24 18:49:23 -04:00
font.bold: true
2024-06-28 12:57:57 -04:00
text: qsTr ( "LocalDocs Settings" )
2024-06-24 18:49:23 -04:00
}
2023-06-28 23:46:03 -04:00
2024-06-28 12:57:57 -04:00
ColumnLayout {
spacing: 10
Label {
color: theme . styledTextColor
font.pixelSize: theme . fontSizeLarge
font.bold: true
text: qsTr ( "Indexing" )
}
Rectangle {
Layout.fillWidth: true
height: 1
color: theme . settingsDivider
}
2023-10-24 12:13:32 -04:00
}
2024-06-24 18:49:23 -04:00
RowLayout {
MySettingsLabel {
id: extsLabel
text: qsTr ( "Allowed File Extensions" )
helpText: qsTr ( "Comma-separated list. LocalDocs will only attempt to process files with these extensions." )
}
MyTextField {
id: extsField
text: MySettings . localDocsFileExtensions . join ( ',' )
color: theme . textColor
font.pixelSize: theme . fontSizeLarge
Layout.alignment: Qt . AlignRight
Layout.minimumWidth: 200
validator: RegularExpressionValidator {
regularExpression: /([^ ,\/"']+,?)*/
}
onEditingFinished: {
// split and remove empty elements
var exts = text . split ( ',' ) . filter ( e = > e ) ;
// normalize and deduplicate
exts = exts . map ( e = > e . toLowerCase ( ) ) ;
exts = Array . from ( new Set ( exts ) ) ;
/ * B l a c k l i s t c o m m o n u n s u p p o r t e d f i l e e x t e n s i o n s . W e o n l y s u p p o r t p l a i n t e x t a n d P D F s , a n d a l t h o u g h w e
* reject binary data , we don 't want to waste time trying to index files that we don' t support . * /
exts = exts . filter ( e = > ! [
/* Microsoft documents */ "rtf" , "docx" , "ppt" , "pptx" , "xls" , "xlsx" ,
/* OpenOffice */ "odt" , "ods" , "odp" , "odg" ,
/* photos */ "jpg" , "jpeg" , "png" , "gif" , "bmp" , "tif" , "tiff" , "webp" ,
/* audio */ "mp3" , "wma" , "m4a" , "wav" , "flac" ,
/* videos */ "mp4" , "mov" , "webm" , "mkv" , "avi" , "flv" , "wmv" ,
/* executables */ "exe" , "com" , "dll" , "so" , "dylib" , "msi" ,
/* binary images */ "iso" , "img" , "dmg" ,
/* archives */ "zip" , "jar" , "apk" , "rar" , "7z" , "tar" , "gz" , "xz" , "bz2" , "tar.gz" ,
"tgz" , "tar.xz" , "tar.bz2" ,
/* misc */ "bin" ,
] . includes ( e ) ) ;
MySettings . localDocsFileExtensions = exts ;
extsField . text = exts . join ( ',' ) ;
focus = false ;
}
Accessible.role: Accessible . EditableText
Accessible.name: extsLabel . text
Accessible.description: extsLabel . helpText
2023-10-24 12:13:32 -04:00
}
}
2024-06-28 12:57:57 -04:00
ColumnLayout {
spacing: 10
Label {
color: theme . grayRed900
font.pixelSize: theme . fontSizeLarge
font.bold: true
text: qsTr ( "Embedding" )
}
2024-06-24 18:49:23 -04:00
2024-06-28 12:57:57 -04:00
Rectangle {
Layout.fillWidth: true
height: 1
color: theme . grayRed500
}
2024-06-24 18:49:23 -04:00
}
2023-06-28 23:46:03 -04:00
2024-06-24 18:49:23 -04:00
RowLayout {
MySettingsLabel {
text: qsTr ( "Use Nomic Embed API" )
2024-06-28 12:57:57 -04:00
helpText: qsTr ( "Embed documents using the fast Nomic API instead of a private local model. Requires restart." )
2024-06-24 18:49:23 -04:00
}
2023-06-28 23:46:03 -04:00
2024-06-24 18:49:23 -04:00
MyCheckBox {
id: useNomicAPIBox
Component.onCompleted: {
useNomicAPIBox . checked = MySettings . localDocsUseRemoteEmbed ;
2023-06-28 23:46:03 -04:00
}
2024-06-24 18:49:23 -04:00
onClicked: {
MySettings . localDocsUseRemoteEmbed = useNomicAPIBox . checked && MySettings . localDocsNomicAPIKey !== "" ;
2023-06-28 23:46:03 -04:00
}
}
}
2024-06-24 18:49:23 -04:00
RowLayout {
MySettingsLabel {
id: apiKeyLabel
text: qsTr ( "Nomic API Key" )
2024-06-28 12:57:57 -04:00
helpText: qsTr ( 'API key to use for Nomic Embed. Get one from the Atlas <a href="https://atlas.nomic.ai/cli-login">API keys page</a>. Requires restart.' )
2024-06-27 11:08:32 -04:00
onLinkActivated: function ( link ) { Qt . openUrlExternally ( link ) }
2024-06-24 18:49:23 -04:00
}
2023-06-28 23:46:03 -04:00
2024-06-24 18:49:23 -04:00
MyTextField {
id: apiKeyField
2024-06-27 11:08:32 -04:00
property bool isValid: validate ( )
onTextChanged: { isValid = validate ( ) ; }
function validate ( ) { return /^(nk-[a-zA-Z0-9_-]{43})?$/ . test ( apiKeyField . text ) ; }
placeholderText: "nk-" + "X" . repeat ( 43 )
2024-06-24 18:49:23 -04:00
text: MySettings . localDocsNomicAPIKey
2024-06-27 11:08:32 -04:00
color: apiKeyField . isValid ? theme.textColor : theme . textErrorColor
2024-06-24 18:49:23 -04:00
font.pixelSize: theme . fontSizeLarge
Layout.alignment: Qt . AlignRight
Layout.minimumWidth: 200
enabled: useNomicAPIBox . checked
onEditingFinished: {
2024-06-27 11:08:32 -04:00
if ( apiKeyField . isValid ) {
MySettings . localDocsNomicAPIKey = apiKeyField . text ;
MySettings . localDocsUseRemoteEmbed = useNomicAPIBox . checked && MySettings . localDocsNomicAPIKey !== "" ;
}
2024-06-24 18:49:23 -04:00
focus = false ;
2023-06-28 23:46:03 -04:00
}
2024-06-24 18:49:23 -04:00
Accessible.role: Accessible . EditableText
Accessible.name: apiKeyLabel . text
Accessible.description: apiKeyLabel . helpText
2023-06-28 23:46:03 -04:00
}
}
2024-06-28 17:11:12 -04:00
RowLayout {
MySettingsLabel {
id: deviceLabel
text: qsTr ( "Embeddings Device" )
helpText: qsTr ( 'The compute device used for embeddings. "Auto" uses the CPU. Requires restart.' )
}
MyComboBox {
id: deviceBox
enabled: ! useNomicAPIBox . checked
Layout.minimumWidth: 400
Layout.maximumWidth: 400
Layout.fillWidth: false
Layout.alignment: Qt . AlignRight
model: MySettings . embeddingsDeviceList
Accessible.name: deviceLabel . text
Accessible.description: deviceLabel . helpText
function updateModel ( ) {
deviceBox . currentIndex = deviceBox . indexOfValue ( MySettings . localDocsEmbedDevice ) ;
}
Component.onCompleted: {
deviceBox . updateModel ( ) ;
}
Connections {
target: MySettings
function onDeviceChanged ( ) {
deviceBox . updateModel ( ) ;
}
}
onActivated: {
MySettings . localDocsEmbedDevice = deviceBox . currentText ;
}
}
}
2023-06-28 23:46:03 -04:00
2024-06-28 12:57:57 -04:00
ColumnLayout {
spacing: 10
Label {
color: theme . grayRed900
font.pixelSize: theme . fontSizeLarge
font.bold: true
text: qsTr ( "Display" )
}
2024-06-24 18:49:23 -04:00
2024-06-28 12:57:57 -04:00
Rectangle {
Layout.fillWidth: true
height: 1
color: theme . grayRed500
}
2024-06-24 18:49:23 -04:00
}
2023-07-05 19:41:07 -04:00
RowLayout {
2024-01-22 14:41:47 -05:00
MySettingsLabel {
2023-07-05 19:41:07 -04:00
id: showReferencesLabel
2024-06-28 12:57:57 -04:00
text: qsTr ( "Show Sources" )
helpText: qsTr ( "Display the sources used for each response." )
2023-07-05 19:41:07 -04:00
}
MyCheckBox {
id: showReferencesBox
checked: MySettings . localDocsShowReferences
onClicked: {
MySettings . localDocsShowReferences = ! MySettings . localDocsShowReferences
}
}
}
2024-06-28 12:57:57 -04:00
ColumnLayout {
spacing: 10
Label {
color: theme . styledTextColor
font.pixelSize: theme . fontSizeLarge
font.bold: true
text: qsTr ( "Advanced" )
}
2023-06-28 23:46:03 -04:00
2024-06-28 12:57:57 -04:00
Rectangle {
Layout.fillWidth: true
height: 1
color: theme . settingsDivider
}
2023-07-01 11:34:21 -04:00
}
2023-06-28 23:46:03 -04:00
2024-01-22 14:41:47 -05:00
MySettingsLabel {
2024-06-24 18:49:23 -04:00
id: warningLabel
Layout.bottomMargin: 15
Layout.fillWidth: true
color: theme . textErrorColor
wrapMode: Text . WordWrap
text: qsTr ( "Warning: Advanced usage only." )
helpText: qsTr ( "Values too large may cause localdocs failure, extremely slow responses or failure to respond at all. Roughly speaking, the {N chars x N snippets} are added to the model's context window. More info <a href=\"https://docs.gpt4all.io/gpt4all_chat.html#localdocs-beta-plugin-chat-with-your-data\">here.</a>" )
onLinkActivated: function ( link ) { Qt . openUrlExternally ( link ) }
2023-07-01 11:34:21 -04:00
}
2023-06-28 23:46:03 -04:00
2024-06-24 18:49:23 -04:00
RowLayout {
MySettingsLabel {
id: chunkLabel
Layout.fillWidth: true
text: qsTr ( "Document snippet size (characters)" )
helpText: qsTr ( "Number of characters per document snippet. Larger numbers increase likelihood of factual responses, but also result in slower generation." )
2023-06-28 23:46:03 -04:00
}
2024-06-24 18:49:23 -04:00
MyTextField {
id: chunkSizeTextField
text: MySettings . localDocsChunkSize
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt ( text )
if ( ! isNaN ( val ) ) {
MySettings . localDocsChunkSize = val
focus = false
} else {
text = MySettings . localDocsChunkSize
}
2023-06-28 23:46:03 -04:00
}
}
2023-07-01 11:34:21 -04:00
}
2023-06-28 23:46:03 -04:00
2024-06-24 18:49:23 -04:00
RowLayout {
Layout.topMargin: 15
MySettingsLabel {
id: contextItemsPerPrompt
text: qsTr ( "Max document snippets per prompt" )
helpText: qsTr ( "Max best N matches of retrieved document snippets to add to the context for prompt. Larger numbers increase likelihood of factual responses, but also result in slower generation." )
2023-06-28 23:46:03 -04:00
2023-07-01 11:34:21 -04:00
}
2024-06-24 18:49:23 -04:00
MyTextField {
text: MySettings . localDocsRetrievalSize
validator: IntValidator {
bottom: 1
}
onEditingFinished: {
var val = parseInt ( text )
if ( ! isNaN ( val ) ) {
MySettings . localDocsRetrievalSize = val
focus = false
} else {
text = MySettings . localDocsRetrievalSize
}
2023-06-28 23:46:03 -04:00
}
}
2023-07-01 11:34:21 -04:00
}
2023-06-28 23:46:03 -04:00
2024-06-24 18:49:23 -04:00
Rectangle {
Layout.topMargin: 15
2023-07-01 11:34:21 -04:00
Layout.fillWidth: true
2024-06-27 07:16:11 -04:00
height: 1
2024-06-24 18:49:23 -04:00
color: theme . settingsDivider
2023-06-28 23:46:03 -04:00
}
2024-06-24 18:49:23 -04:00
}
2023-06-28 23:46:03 -04:00
}