diff --git a/gpt4all-chat/CMakeLists.txt b/gpt4all-chat/CMakeLists.txt index 783c726c..75952319 100644 --- a/gpt4all-chat/CMakeLists.txt +++ b/gpt4all-chat/CMakeLists.txt @@ -77,6 +77,7 @@ qt_add_qml_module(chat QML_FILES main.qml qml/ChatDrawer.qml + qml/CollectionsDialog.qml qml/LocalDocs.qml qml/ModelDownloaderDialog.qml qml/NetworkDialog.qml @@ -96,6 +97,7 @@ qt_add_qml_module(chat icons/stop_generating.svg icons/regenerate.svg icons/copy.svg + icons/db.svg icons/settings.svg icons/edit.svg icons/trash.svg diff --git a/gpt4all-chat/chat.cpp b/gpt4all-chat/chat.cpp index 9c9e9e14..1f80fe8e 100644 --- a/gpt4all-chat/chat.cpp +++ b/gpt4all-chat/chat.cpp @@ -116,7 +116,7 @@ void Chat::prompt(const QString &prompt, const QString &prompt_template, int32_t m_queuedPrompt.n_batch = n_batch; m_queuedPrompt.repeat_penalty = repeat_penalty; m_queuedPrompt.repeat_penalty_tokens = repeat_penalty_tokens; - LocalDocs::globalInstance()->requestRetrieve(QList("localdocs"), prompt); + LocalDocs::globalInstance()->requestRetrieve(m_collections, prompt); } void Chat::handleLocalDocsRetrieved() @@ -162,9 +162,9 @@ QString Chat::responseState() const { switch (m_responseState) { case ResponseStopped: return QStringLiteral("response stopped"); - case LocalDocsRetrieval: return QStringLiteral("retrieving localdocs"); - case LocalDocsProcessing: return QStringLiteral("processing localdocs"); - case PromptProcessing: return QStringLiteral("processing prompt"); + case LocalDocsRetrieval: return QStringLiteral("retrieving ") + m_collections.join(", "); + case LocalDocsProcessing: return QStringLiteral("processing ") + m_collections.join(", "); + case PromptProcessing: return QStringLiteral("processing"); case ResponseGeneration: return QStringLiteral("generating response"); }; Q_UNREACHABLE(); @@ -397,3 +397,31 @@ QList Chat::modelList() const return list; } + +QList Chat::collectionList() const +{ + return m_collections; +} + +bool Chat::hasCollection(const QString &collection) const +{ + return m_collections.contains(collection); +} + +void Chat::addCollection(const QString &collection) +{ + if (hasCollection(collection)) + return; + + m_collections.append(collection); + emit collectionListChanged(); +} + +void Chat::removeCollection(const QString &collection) +{ + if (!hasCollection(collection)) + return; + + m_collections.removeAll(collection); + emit collectionListChanged(); +} diff --git a/gpt4all-chat/chat.h b/gpt4all-chat/chat.h index 0f67ecba..da8ae7b4 100644 --- a/gpt4all-chat/chat.h +++ b/gpt4all-chat/chat.h @@ -23,6 +23,7 @@ class Chat : public QObject Q_PROPERTY(QList modelList READ modelList NOTIFY modelListChanged) Q_PROPERTY(bool isServer READ isServer NOTIFY isServerChanged) Q_PROPERTY(QString responseState READ responseState NOTIFY responseStateChanged) + Q_PROPERTY(QList collectionList READ collectionList NOTIFY collectionListChanged) QML_ELEMENT QML_UNCREATABLE("Only creatable from c++!") @@ -78,6 +79,12 @@ public: QList modelList() const; bool isServer() const { return m_isServer; } + QList collectionList() const; + + Q_INVOKABLE bool hasCollection(const QString &collection) const; + Q_INVOKABLE void addCollection(const QString &collection); + Q_INVOKABLE void removeCollection(const QString &collection); + public Q_SLOTS: void serverNewPromptResponsePair(const QString &prompt); @@ -104,6 +111,7 @@ Q_SIGNALS: void modelListChanged(); void modelLoadingError(const QString &error); void isServerChanged(); + void collectionListChanged(); private Q_SLOTS: void handleLocalDocsRetrieved(); @@ -132,6 +140,7 @@ private: QString m_name; QString m_userName; QString m_savedModelName; + QList m_collections; ChatModel *m_chatModel; bool m_responseInProgress; ResponseState m_responseState; diff --git a/gpt4all-chat/icons/db.svg b/gpt4all-chat/icons/db.svg new file mode 100644 index 00000000..4b0d1082 --- /dev/null +++ b/gpt4all-chat/icons/db.svg @@ -0,0 +1,5 @@ + + diff --git a/gpt4all-chat/main.qml b/gpt4all-chat/main.qml index dc94e7b6..305794ca 100644 --- a/gpt4all-chat/main.qml +++ b/gpt4all-chat/main.qml @@ -290,8 +290,13 @@ Window { } } + CollectionsDialog { + id: collectionsDialog + anchors.centerIn: parent + } + Button { - id: settingsButton + id: collectionsButton anchors.right: networkButton.left anchors.top: parent.top anchors.topMargin: 30 @@ -301,6 +306,45 @@ Window { z: 200 padding: 15 + background: Item { + anchors.fill: parent + Rectangle { + anchors.fill: parent + color: "transparent" + visible: currentChat.collectionList.length + border.color: theme.backgroundLightest + border.width: 1 + radius: 10 + } + Image { + anchors.centerIn: parent + mipmap: true + width: 25 + height: 25 + source: "qrc:/gpt4all/icons/db.svg" + } + } + + Accessible.role: Accessible.Button + Accessible.name: qsTr("Add collections of documents to the chat") + Accessible.description: qsTr("Provides a button to add collections of documents to the chat") + + onClicked: { + collectionsDialog.open() + } + } + + Button { + id: settingsButton + anchors.right: collectionsButton.left + anchors.top: parent.top + anchors.topMargin: 30 + anchors.rightMargin: 30 + width: 40 + height: 40 + z: 200 + padding: 15 + background: Item { anchors.fill: parent Image { diff --git a/gpt4all-chat/qml/CollectionsDialog.qml b/gpt4all-chat/qml/CollectionsDialog.qml new file mode 100644 index 00000000..346080ea --- /dev/null +++ b/gpt4all-chat/qml/CollectionsDialog.qml @@ -0,0 +1,86 @@ +import QtCore +import QtQuick +import QtQuick.Controls +import QtQuick.Controls.Basic +import QtQuick.Layouts +import QtQuick.Dialogs +import localdocs +import llm + +Dialog { + id: collectionsDialog + modal: true + opacity: 0.9 + padding: 20 + width: 480 + height: 640 + + property var currentChat: LLM.chatListModel.currentChat + + background: Rectangle { + anchors.fill: parent + color: theme.backgroundDarkest + border.width: 1 + border.color: theme.dialogBorder + radius: 10 + } + + Label { + id: listLabel + anchors.top: parent.top + anchors.left: parent.left + text: "Available Collections:" + color: theme.textColor + } + + ScrollView { + id: scrollView + anchors.top: listLabel.bottom + anchors.topMargin: 20 + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + clip: true + contentHeight: 300 + ScrollBar.vertical.policy: ScrollBar.AlwaysOn + + background: Rectangle { + color: theme.backgroundLighter + } + + ListView { + id: listView + model: LocalDocs.localDocsModel + boundsBehavior: Flickable.StopAtBounds + delegate: Rectangle { + id: item + width: listView.width + height: collectionId.height + 40 + color: index % 2 === 0 ? theme.backgroundLight : theme.backgroundLighter + MyCheckBox { + id: checkBox + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.margins: 20 + checked: currentChat.hasCollection(collection) + onClicked: { + if (checkBox.checked) { + currentChat.addCollection(collection) + } else { + currentChat.removeCollection(collection) + } + } + } + Text { + id: collectionId + anchors.verticalCenter: parent.verticalCenter + anchors.left: checkBox.right + anchors.margins: 20 + text: collection + elide: Text.ElideRight + color: theme.textColor + } + } + } + } +} diff --git a/gpt4all-chat/qml/LocalDocs.qml b/gpt4all-chat/qml/LocalDocs.qml index 5c50a7bc..30a91304 100644 --- a/gpt4all-chat/qml/LocalDocs.qml +++ b/gpt4all-chat/qml/LocalDocs.qml @@ -186,7 +186,7 @@ Item { id: chunkSizeTextField Layout.row: 0 Layout.column: 1 - ToolTip.text: qsTr("Number of characters per document snippet. NOTE: larger numbers increase likelihood of factual responses, but also result in slower generation.") + ToolTip.text: qsTr("Number of characters per document snippet.\nNOTE: larger numbers increase likelihood of factual responses, but also result in slower generation.") ToolTip.visible: hovered } @@ -201,7 +201,7 @@ Item { MyTextField { Layout.row: 1 Layout.column: 1 - ToolTip.text: qsTr("Best N matches of retrieved document snippets to add to the context for prompt. NOTE: larger numbers increase likelihood of factual responses, but also result in slower generation.") + ToolTip.text: qsTr("Best N matches of retrieved document snippets to add to the context for prompt.\nNOTE: larger numbers increase likelihood of factual responses, but also result in slower generation.") ToolTip.visible: hovered } diff --git a/gpt4all-chat/qml/SettingsDialog.qml b/gpt4all-chat/qml/SettingsDialog.qml index 6d0e8ada..f6d9f79b 100644 --- a/gpt4all-chat/qml/SettingsDialog.qml +++ b/gpt4all-chat/qml/SettingsDialog.qml @@ -225,8 +225,7 @@ Dialog { contentItem: IconLabel { color: theme.textColor font.bold: localDocsButton.checked - font.pixelSize: localDocsButton.checked ? theme.fontSizeLarger : theme.fontSizeLarge - text: qsTr("Local Docs Plugin") + text: qsTr("LocalDocs Plugin (BETA)") } background: Rectangle { color: localDocsButton.checked ? theme.backgroundDarkest : theme.backgroundLight