From 2c8d634b5bf8cc9a7e9307876da095879d6c0ffd Mon Sep 17 00:00:00 2001 From: Jared Van Bortel Date: Fri, 28 Jun 2024 12:57:57 -0400 Subject: [PATCH] UI and embedding device changes for GPT4All v3.0.0-rc3 (#2477) Signed-off-by: Jared Van Bortel --- gpt4all-chat/CMakeLists.txt | 35 +-- gpt4all-chat/chatllm.cpp | 373 ++++++++++++----------- gpt4all-chat/chatllm.h | 3 + gpt4all-chat/embllm.cpp | 112 +++++-- gpt4all-chat/main.qml | 64 ++-- gpt4all-chat/mysettings.cpp | 62 ++-- gpt4all-chat/mysettings.h | 14 +- gpt4all-chat/qml/AddModelView.qml | 20 +- gpt4all-chat/qml/ApplicationSettings.qml | 161 +++++----- gpt4all-chat/qml/ChatDrawer.qml | 2 +- gpt4all-chat/qml/ChatView.qml | 1 - gpt4all-chat/qml/CollectionsDrawer.qml | 4 +- gpt4all-chat/qml/HomeView.qml | 1 + gpt4all-chat/qml/LocalDocsSettings.qml | 145 ++++++--- gpt4all-chat/qml/LocalDocsView.qml | 64 ++-- gpt4all-chat/qml/ModelSettings.qml | 88 ++---- gpt4all-chat/qml/ModelsView.qml | 20 +- gpt4all-chat/qml/MySettingsLabel.qml | 7 +- gpt4all-chat/qml/MyTextButton.qml | 19 ++ gpt4all-chat/qml/MyToolButton.qml | 2 +- gpt4all-chat/qml/Theme.qml | 26 +- 21 files changed, 661 insertions(+), 562 deletions(-) create mode 100644 gpt4all-chat/qml/MyTextButton.qml diff --git a/gpt4all-chat/CMakeLists.txt b/gpt4all-chat/CMakeLists.txt index 2b978519..a3e01904 100644 --- a/gpt4all-chat/CMakeLists.txt +++ b/gpt4all-chat/CMakeLists.txt @@ -132,39 +132,40 @@ qt_add_qml_module(chat main.qml qml/AddCollectionView.qml qml/AddModelView.qml + qml/ApplicationSettings.qml qml/ChatDrawer.qml qml/ChatView.qml qml/CollectionsDrawer.qml qml/HomeView.qml + qml/LocalDocsSettings.qml + qml/LocalDocsView.qml + qml/ModelSettings.qml qml/ModelsView.qml qml/NetworkDialog.qml qml/NewVersionDialog.qml - qml/ThumbsDownDialog.qml + qml/PopupDialog.qml qml/SettingsView.qml qml/StartupDialog.qml - qml/PopupDialog.qml - qml/Theme.qml - qml/ModelSettings.qml - qml/ApplicationSettings.qml - qml/LocalDocsSettings.qml - qml/LocalDocsView.qml qml/SwitchModelDialog.qml - qml/MySettingsTab.qml - qml/MySettingsStack.qml - qml/MySettingsDestructiveButton.qml - qml/MySettingsButton.qml - qml/MySettingsLabel.qml - qml/MySlug.qml + qml/Theme.qml + qml/ThumbsDownDialog.qml + qml/MyBusyIndicator.qml qml/MyButton.qml + qml/MyCheckBox.qml qml/MyComboBox.qml qml/MyDialog.qml qml/MyDirectoryField.qml qml/MyFancyLink.qml - qml/MyTextArea.qml - qml/MyTextField.qml - qml/MyCheckBox.qml - qml/MyBusyIndicator.qml qml/MyMiniButton.qml + qml/MySettingsButton.qml + qml/MySettingsDestructiveButton.qml + qml/MySettingsLabel.qml + qml/MySettingsStack.qml + qml/MySettingsTab.qml + qml/MySlug.qml + qml/MyTextArea.qml + qml/MyTextButton.qml + qml/MyTextField.qml qml/MyToolButton.qml qml/MyWelcomeButton.qml RESOURCES diff --git a/gpt4all-chat/chatllm.cpp b/gpt4all-chat/chatllm.cpp index 96239fdb..dcfc2dd7 100644 --- a/gpt4all-chat/chatllm.cpp +++ b/gpt4all-chat/chatllm.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -340,181 +339,8 @@ bool ChatLLM::loadModel(const ModelInfo &modelInfo) model->setRequestURL(modelInfo.url()); model->setAPIKey(apiKey); m_llModelInfo.resetModel(this, model); - } else { - QElapsedTimer modelLoadTimer; - modelLoadTimer.start(); - - auto requestedDevice = MySettings::globalInstance()->device(); - auto n_ctx = MySettings::globalInstance()->modelContextLength(modelInfo); - m_ctx.n_ctx = n_ctx; - auto ngl = MySettings::globalInstance()->modelGpuLayers(modelInfo); - - std::string backend = "auto"; -#ifdef Q_OS_MAC - if (requestedDevice == "CPU") { - backend = "cpu"; - } else if (m_forceMetal) { -#ifdef __aarch64__ - backend = "metal"; -#endif - } -#else // !defined(Q_OS_MAC) - if (requestedDevice.startsWith("CUDA: ")) - backend = "cuda"; -#endif - - QString constructError; - m_llModelInfo.resetModel(this); - try { - auto *model = LLModel::Implementation::construct(filePath.toStdString(), backend, n_ctx); - m_llModelInfo.resetModel(this, model); - } catch (const LLModel::MissingImplementationError &e) { - modelLoadProps.insert("error", "missing_model_impl"); - constructError = e.what(); - } catch (const LLModel::UnsupportedModelError &e) { - modelLoadProps.insert("error", "unsupported_model_file"); - constructError = e.what(); - } catch (const LLModel::BadArchError &e) { - constructError = e.what(); - modelLoadProps.insert("error", "unsupported_model_arch"); - modelLoadProps.insert("model_arch", QString::fromStdString(e.arch())); - } - - if (m_llModelInfo.model) { - if (m_llModelInfo.model->isModelBlacklisted(filePath.toStdString())) { - static QSet warned; - auto fname = modelInfo.filename(); - if (!warned.contains(fname)) { - emit modelLoadingWarning( - u"%1 is known to be broken. Please get a replacement via the download dialog."_s.arg(fname) - ); - warned.insert(fname); // don't warn again until restart - } - } - - m_llModelInfo.model->setProgressCallback([this](float progress) -> bool { - progress = std::max(progress, std::numeric_limits::min()); // keep progress above zero - emit modelLoadingPercentageChanged(progress); - return m_shouldBeLoaded; - }); - - auto approxDeviceMemGB = [](const LLModel::GPUDevice *dev) { - float memGB = dev->heapSize / float(1024 * 1024 * 1024); - return std::floor(memGB * 10.f) / 10.f; // truncate to 1 decimal place - }; - - std::vector availableDevices; - const LLModel::GPUDevice *defaultDevice = nullptr; - { - const size_t requiredMemory = m_llModelInfo.model->requiredMem(filePath.toStdString(), n_ctx, ngl); - availableDevices = m_llModelInfo.model->availableGPUDevices(requiredMemory); - // Pick the best device - // NB: relies on the fact that Kompute devices are listed first - if (!availableDevices.empty() && availableDevices.front().type == 2 /*a discrete gpu*/) { - defaultDevice = &availableDevices.front(); - float memGB = defaultDevice->heapSize / float(1024 * 1024 * 1024); - memGB = std::floor(memGB * 10.f) / 10.f; // truncate to 1 decimal place - modelLoadProps.insert("default_device", QString::fromStdString(defaultDevice->name)); - modelLoadProps.insert("default_device_mem", approxDeviceMemGB(defaultDevice)); - modelLoadProps.insert("default_device_backend", QString::fromStdString(defaultDevice->backendName())); - } - } - - bool actualDeviceIsCPU = true; - -#if defined(Q_OS_MAC) && defined(__aarch64__) - if (m_llModelInfo.model->implementation().buildVariant() == "metal") - actualDeviceIsCPU = false; -#else - if (requestedDevice != "CPU") { - const auto *device = defaultDevice; - if (requestedDevice != "Auto") { - // Use the selected device - for (const LLModel::GPUDevice &d : availableDevices) { - if (QString::fromStdString(d.selectionName()) == requestedDevice) { - device = &d; - break; - } - } - } - - std::string unavail_reason; - if (!device) { - // GPU not available - } else if (!m_llModelInfo.model->initializeGPUDevice(device->index, &unavail_reason)) { - m_llModelInfo.fallbackReason = QString::fromStdString(unavail_reason); - } else { - actualDeviceIsCPU = false; - modelLoadProps.insert("requested_device_mem", approxDeviceMemGB(device)); - } - } -#endif - - // Report which device we're actually using - bool success = m_llModelInfo.model->loadModel(filePath.toStdString(), n_ctx, ngl); - - if (!m_shouldBeLoaded) { - m_llModelInfo.resetModel(this); - if (!m_isServer) - LLModelStore::globalInstance()->releaseModel(std::move(m_llModelInfo)); - resetModel(); - emit modelLoadingPercentageChanged(0.0f); - return false; - } - - if (actualDeviceIsCPU) { - // we asked llama.cpp to use the CPU - } else if (!success) { - // llama_init_from_file returned nullptr - m_llModelInfo.fallbackReason = "GPU loading failed (out of VRAM?)"; - modelLoadProps.insert("cpu_fallback_reason", "gpu_load_failed"); - success = m_llModelInfo.model->loadModel(filePath.toStdString(), n_ctx, 0); - - if (!m_shouldBeLoaded) { - m_llModelInfo.resetModel(this); - if (!m_isServer) - LLModelStore::globalInstance()->releaseModel(std::move(m_llModelInfo)); - resetModel(); - emit modelLoadingPercentageChanged(0.0f); - return false; - } - } else if (!m_llModelInfo.model->usingGPUDevice()) { - // ggml_vk_init was not called in llama.cpp - // We might have had to fallback to CPU after load if the model is not possible to accelerate - // for instance if the quantization method is not supported on Vulkan yet - m_llModelInfo.fallbackReason = "model or quant has no GPU support"; - modelLoadProps.insert("cpu_fallback_reason", "gpu_unsupported_model"); - } - - if (!success) { - m_llModelInfo.resetModel(this); - if (!m_isServer) - LLModelStore::globalInstance()->releaseModel(std::move(m_llModelInfo)); - resetModel(); - emit modelLoadingError(u"Could not load model due to invalid model file for %1"_s.arg(modelInfo.filename())); - modelLoadProps.insert("error", "loadmodel_failed"); - } else { - switch (m_llModelInfo.model->implementation().modelType()[0]) { - case 'L': m_llModelType = LLModelType::LLAMA_; break; - case 'G': m_llModelType = LLModelType::GPTJ_; break; - default: - { - m_llModelInfo.resetModel(this); - if (!m_isServer) - LLModelStore::globalInstance()->releaseModel(std::move(m_llModelInfo)); - resetModel(); - emit modelLoadingError(u"Could not determine model type for %1"_s.arg(modelInfo.filename())); - } - } - - modelLoadProps.insert("$duration", modelLoadTimer.elapsed() / 1000.); - } - } else { - if (!m_isServer) - LLModelStore::globalInstance()->releaseModel(std::move(m_llModelInfo)); - resetModel(); - emit modelLoadingError(u"Error loading %1: %2"_s.arg(modelInfo.filename(), constructError)); - } + } else if (!loadNewModel(modelInfo, modelLoadProps)) { + return false; // m_shouldBeLoaded became false } #if defined(DEBUG_MODEL_LOADING) qDebug() << "new model" << m_llmThread.objectName() << m_llModelInfo.model.get(); @@ -544,6 +370,201 @@ bool ChatLLM::loadModel(const ModelInfo &modelInfo) return bool(m_llModelInfo.model); } +/* Returns false if the model should no longer be loaded (!m_shouldBeLoaded). + * Otherwise returns true, even on error. */ +bool ChatLLM::loadNewModel(const ModelInfo &modelInfo, QVariantMap &modelLoadProps) +{ + QElapsedTimer modelLoadTimer; + modelLoadTimer.start(); + + QString requestedDevice = MySettings::globalInstance()->device(); + int n_ctx = MySettings::globalInstance()->modelContextLength(modelInfo); + m_ctx.n_ctx = n_ctx; + int ngl = MySettings::globalInstance()->modelGpuLayers(modelInfo); + + std::string backend = "auto"; +#ifdef Q_OS_MAC + if (requestedDevice == "CPU") { + backend = "cpu"; + } else if (m_forceMetal) { +#ifdef __aarch64__ + backend = "metal"; +#endif + } +#else // !defined(Q_OS_MAC) + if (requestedDevice.startsWith("CUDA: ")) + backend = "cuda"; +#endif + + QString filePath = modelInfo.dirpath + modelInfo.filename(); + + auto construct = [this, &filePath, &modelInfo, &modelLoadProps, n_ctx](std::string const &backend) { + QString constructError; + m_llModelInfo.resetModel(this); + try { + auto *model = LLModel::Implementation::construct(filePath.toStdString(), backend, n_ctx); + m_llModelInfo.resetModel(this, model); + } catch (const LLModel::MissingImplementationError &e) { + modelLoadProps.insert("error", "missing_model_impl"); + constructError = e.what(); + } catch (const LLModel::UnsupportedModelError &e) { + modelLoadProps.insert("error", "unsupported_model_file"); + constructError = e.what(); + } catch (const LLModel::BadArchError &e) { + constructError = e.what(); + modelLoadProps.insert("error", "unsupported_model_arch"); + modelLoadProps.insert("model_arch", QString::fromStdString(e.arch())); + } + + if (!m_llModelInfo.model) { + if (!m_isServer) + LLModelStore::globalInstance()->releaseModel(std::move(m_llModelInfo)); + resetModel(); + emit modelLoadingError(u"Error loading %1: %2"_s.arg(modelInfo.filename(), constructError)); + return false; + } + + m_llModelInfo.model->setProgressCallback([this](float progress) -> bool { + progress = std::max(progress, std::numeric_limits::min()); // keep progress above zero + emit modelLoadingPercentageChanged(progress); + return m_shouldBeLoaded; + }); + return true; + }; + + if (!construct(backend)) + return true; + + if (m_llModelInfo.model->isModelBlacklisted(filePath.toStdString())) { + static QSet warned; + auto fname = modelInfo.filename(); + if (!warned.contains(fname)) { + emit modelLoadingWarning( + u"%1 is known to be broken. Please get a replacement via the download dialog."_s.arg(fname) + ); + warned.insert(fname); // don't warn again until restart + } + } + + auto approxDeviceMemGB = [](const LLModel::GPUDevice *dev) { + float memGB = dev->heapSize / float(1024 * 1024 * 1024); + return std::floor(memGB * 10.f) / 10.f; // truncate to 1 decimal place + }; + + std::vector availableDevices; + const LLModel::GPUDevice *defaultDevice = nullptr; + { + const size_t requiredMemory = m_llModelInfo.model->requiredMem(filePath.toStdString(), n_ctx, ngl); + availableDevices = m_llModelInfo.model->availableGPUDevices(requiredMemory); + // Pick the best device + // NB: relies on the fact that Kompute devices are listed first + if (!availableDevices.empty() && availableDevices.front().type == 2 /*a discrete gpu*/) { + defaultDevice = &availableDevices.front(); + float memGB = defaultDevice->heapSize / float(1024 * 1024 * 1024); + memGB = std::floor(memGB * 10.f) / 10.f; // truncate to 1 decimal place + modelLoadProps.insert("default_device", QString::fromStdString(defaultDevice->name)); + modelLoadProps.insert("default_device_mem", approxDeviceMemGB(defaultDevice)); + modelLoadProps.insert("default_device_backend", QString::fromStdString(defaultDevice->backendName())); + } + } + + bool actualDeviceIsCPU = true; + +#if defined(Q_OS_MAC) && defined(__aarch64__) + if (m_llModelInfo.model->implementation().buildVariant() == "metal") + actualDeviceIsCPU = false; +#else + if (requestedDevice != "CPU") { + const auto *device = defaultDevice; + if (requestedDevice != "Auto") { + // Use the selected device + for (const LLModel::GPUDevice &d : availableDevices) { + if (QString::fromStdString(d.selectionName()) == requestedDevice) { + device = &d; + break; + } + } + } + + std::string unavail_reason; + if (!device) { + // GPU not available + } else if (!m_llModelInfo.model->initializeGPUDevice(device->index, &unavail_reason)) { + m_llModelInfo.fallbackReason = QString::fromStdString(unavail_reason); + } else { + actualDeviceIsCPU = false; + modelLoadProps.insert("requested_device_mem", approxDeviceMemGB(device)); + } + } +#endif + + bool success = m_llModelInfo.model->loadModel(filePath.toStdString(), n_ctx, ngl); + + if (!m_shouldBeLoaded) { + m_llModelInfo.resetModel(this); + if (!m_isServer) + LLModelStore::globalInstance()->releaseModel(std::move(m_llModelInfo)); + resetModel(); + emit modelLoadingPercentageChanged(0.0f); + return false; + } + + if (actualDeviceIsCPU) { + // we asked llama.cpp to use the CPU + } else if (!success) { + // llama_init_from_file returned nullptr + m_llModelInfo.fallbackReason = "GPU loading failed (out of VRAM?)"; + modelLoadProps.insert("cpu_fallback_reason", "gpu_load_failed"); + + // For CUDA, make sure we don't use the GPU at all - ngl=0 still offloads matmuls + if (backend == "cuda" && !construct("auto")) + return true; + + success = m_llModelInfo.model->loadModel(filePath.toStdString(), n_ctx, 0); + + if (!m_shouldBeLoaded) { + m_llModelInfo.resetModel(this); + if (!m_isServer) + LLModelStore::globalInstance()->releaseModel(std::move(m_llModelInfo)); + resetModel(); + emit modelLoadingPercentageChanged(0.0f); + return false; + } + } else if (!m_llModelInfo.model->usingGPUDevice()) { + // ggml_vk_init was not called in llama.cpp + // We might have had to fallback to CPU after load if the model is not possible to accelerate + // for instance if the quantization method is not supported on Vulkan yet + m_llModelInfo.fallbackReason = "model or quant has no GPU support"; + modelLoadProps.insert("cpu_fallback_reason", "gpu_unsupported_model"); + } + + if (!success) { + m_llModelInfo.resetModel(this); + if (!m_isServer) + LLModelStore::globalInstance()->releaseModel(std::move(m_llModelInfo)); + resetModel(); + emit modelLoadingError(u"Could not load model due to invalid model file for %1"_s.arg(modelInfo.filename())); + modelLoadProps.insert("error", "loadmodel_failed"); + return true; + } + + switch (m_llModelInfo.model->implementation().modelType()[0]) { + case 'L': m_llModelType = LLModelType::LLAMA_; break; + case 'G': m_llModelType = LLModelType::GPTJ_; break; + default: + { + m_llModelInfo.resetModel(this); + if (!m_isServer) + LLModelStore::globalInstance()->releaseModel(std::move(m_llModelInfo)); + resetModel(); + emit modelLoadingError(u"Could not determine model type for %1"_s.arg(modelInfo.filename())); + } + } + + modelLoadProps.insert("$duration", modelLoadTimer.elapsed() / 1000.); + return true; +}; + bool ChatLLM::isModelLoaded() const { return m_llModelInfo.model && m_llModelInfo.model->isModelLoaded(); diff --git a/gpt4all-chat/chatllm.h b/gpt4all-chat/chatllm.h index 001eae6f..01237f84 100644 --- a/gpt4all-chat/chatllm.h +++ b/gpt4all-chat/chatllm.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -214,6 +215,8 @@ protected: quint32 m_promptResponseTokens; private: + bool loadNewModel(const ModelInfo &modelInfo, QVariantMap &modelLoadProps); + std::string m_response; std::string m_nameResponse; LLModelInfo m_llModelInfo; diff --git a/gpt4all-chat/embllm.cpp b/gpt4all-chat/embllm.cpp index 0b49270e..615a6ce4 100644 --- a/gpt4all-chat/embllm.cpp +++ b/gpt4all-chat/embllm.cpp @@ -26,6 +26,7 @@ #include #include +#include using namespace Qt::Literals::StringLiterals; @@ -63,9 +64,13 @@ void EmbeddingLLMWorker::wait() bool EmbeddingLLMWorker::loadModel() { + constexpr int n_ctx = 2048; + m_nomicAPIKey.clear(); m_model = nullptr; + // TODO(jared): react to setting changes without restarting + if (MySettings::globalInstance()->localDocsUseRemoteEmbed()) { m_nomicAPIKey = MySettings::globalInstance()->localDocsNomicAPIKey(); return true; @@ -79,29 +84,86 @@ bool EmbeddingLLMWorker::loadModel() QString filePath = embPathFmt.arg(QCoreApplication::applicationDirPath(), LOCAL_EMBEDDING_MODEL); if (!QFileInfo::exists(filePath)) { - qWarning() << "WARNING: Local embedding model not found"; + qWarning() << "embllm WARNING: Local embedding model not found"; return false; } + QString requestedDevice = MySettings::globalInstance()->localDocsEmbedDevice(); + std::string backend = "auto"; +#ifdef Q_OS_MAC + if (requestedDevice == "Auto" || requestedDevice == "CPU") + backend = "cpu"; +#else + if (requestedDevice.startsWith("CUDA: ")) + backend = "cuda"; +#endif + try { - m_model = LLModel::Implementation::construct(filePath.toStdString()); + m_model = LLModel::Implementation::construct(filePath.toStdString(), backend, n_ctx); } catch (const std::exception &e) { - qWarning() << "WARNING: Could not load embedding model:" << e.what(); + qWarning() << "embllm WARNING: Could not load embedding model:" << e.what(); return false; } - // NOTE: explicitly loads model on CPU to avoid GPU OOM - // TODO(cebtenzzre): support GPU-accelerated embeddings - bool success = m_model->loadModel(filePath.toStdString(), 2048, 0); + bool actualDeviceIsCPU = true; + +#if defined(Q_OS_MAC) && defined(__aarch64__) + if (m_model->implementation().buildVariant() == "metal") + actualDeviceIsCPU = false; +#else + if (requestedDevice != "CPU") { + const LLModel::GPUDevice *device = nullptr; + std::vector availableDevices = m_model->availableGPUDevices(0); + if (requestedDevice != "Auto") { + // Use the selected device + for (const LLModel::GPUDevice &d : availableDevices) { + if (QString::fromStdString(d.selectionName()) == requestedDevice) { + device = &d; + break; + } + } + } + + std::string unavail_reason; + if (!device) { + // GPU not available + } else if (!m_model->initializeGPUDevice(device->index, &unavail_reason)) { + qWarning().noquote() << "embllm WARNING: Did not use GPU:" << QString::fromStdString(unavail_reason); + } else { + actualDeviceIsCPU = false; + } + } +#endif + + bool success = m_model->loadModel(filePath.toStdString(), n_ctx, 100); + + // CPU fallback + if (!actualDeviceIsCPU && !success) { + // llama_init_from_file returned nullptr + qWarning() << "embllm WARNING: Did not use GPU: GPU loading failed (out of VRAM?)"; + + if (backend == "cuda") { + // For CUDA, make sure we don't use the GPU at all - ngl=0 still offloads matmuls + try { + m_model = LLModel::Implementation::construct(filePath.toStdString(), "auto", n_ctx); + } catch (const std::exception &e) { + qWarning() << "embllm WARNING: Could not load embedding model:" << e.what(); + return false; + } + } + + success = m_model->loadModel(filePath.toStdString(), n_ctx, 0); + } + if (!success) { - qWarning() << "WARNING: Could not load embedding model"; + qWarning() << "embllm WARNING: Could not load embedding model"; delete m_model; m_model = nullptr; return false; } if (!m_model->supportsEmbedding()) { - qWarning() << "WARNING: Model type does not support embeddings"; + qWarning() << "embllm WARNING: Model type does not support embeddings"; delete m_model; m_model = nullptr; return false; @@ -128,7 +190,7 @@ std::vector EmbeddingLLMWorker::generateQueryEmbedding(const QString &tex std::vector embedding(m_model->embeddingSize()); try { - m_model->embed({text.toStdString()}, embedding.data(), true); + m_model->embed({text.toStdString()}, embedding.data(), /*isRetrieval*/ true); } catch (const std::exception &e) { qWarning() << "WARNING: LLModel::embed failed:" << e.what(); return {}; @@ -203,26 +265,34 @@ void EmbeddingLLMWorker::docEmbeddingsRequested(const QVector &c if (!isNomic) { QVector results; results.reserve(chunks.size()); + std::vector texts; + texts.reserve(chunks.size()); for (const auto &c: chunks) { EmbeddingResult result; result.model = c.model; result.folder_id = c.folder_id; result.chunk_id = c.chunk_id; - // TODO(cebtenzzre): take advantage of batched embeddings result.embedding.resize(m_model->embeddingSize()); - - { - QMutexLocker locker(&m_mutex); - try { - m_model->embed({c.chunk.toStdString()}, result.embedding.data(), false); - } catch (const std::exception &e) { - qWarning() << "WARNING: LLModel::embed failed:" << e.what(); - return; - } - } - results << result; + texts.push_back(c.chunk.toStdString()); } + + constexpr int BATCH_SIZE = 4; + std::vector result; + result.resize(chunks.size() * m_model->embeddingSize()); + for (int j = 0; j < chunks.size(); j += BATCH_SIZE) { + QMutexLocker locker(&m_mutex); + std::vector batchTexts(texts.begin() + j, texts.begin() + std::min(j + BATCH_SIZE, int(texts.size()))); + try { + m_model->embed(batchTexts, result.data() + j * m_model->embeddingSize(), /*isRetrieval*/ false); + } catch (const std::exception &e) { + qWarning() << "WARNING: LLModel::embed failed:" << e.what(); + return; + } + } + for (int i = 0; i < chunks.size(); i++) + memcpy(results[i].embedding.data(), &result[i * m_model->embeddingSize()], m_model->embeddingSize() * sizeof(float)); + emit embeddingsGenerated(results); return; }; diff --git a/gpt4all-chat/main.qml b/gpt4all-chat/main.qml index 397f90ef..2e3da744 100644 --- a/gpt4all-chat/main.qml +++ b/gpt4all-chat/main.qml @@ -204,7 +204,7 @@ Window { anchors.top: parent.top anchors.bottom: parent.bottom anchors.left: parent.left - width: MySettings.fontSize === "Small" ? 86 : 100 + width: 16 + 52 * theme.fontScale color: theme.viewBarBackground ColumnLayout { @@ -213,20 +213,20 @@ Window { anchors.topMargin: 30 anchors.horizontalCenter: parent.horizontalCenter Layout.margins: 0 - spacing: 18 + spacing: 16 MyToolButton { id: homeButton backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar backgroundColorHovered: theme.iconBackgroundViewBarHovered - Layout.preferredWidth: 48 - Layout.preferredHeight: 48 + Layout.preferredWidth: 38 * theme.fontScale + Layout.preferredHeight: 38 * theme.fontScale Layout.alignment: Qt.AlignCenter toggledWidth: 0 toggled: homeView.isShown() toggledColor: theme.iconBackgroundViewBarToggled - imageWidth: 34 - imageHeight: 34 + imageWidth: 25 * theme.fontScale + imageHeight: 25 * theme.fontScale source: "qrc:/gpt4all/icons/home.svg" Accessible.name: qsTr("Home view") Accessible.description: qsTr("Home view of application") @@ -238,10 +238,10 @@ Window { Text { Layout.topMargin: -20 text: qsTr("Home") - font.pixelSize: theme.fontSizeLargeCapped + font.pixelSize: theme.fontSizeMedium font.bold: true color: homeButton.hovered ? homeButton.backgroundColorHovered : homeButton.backgroundColor - Layout.preferredWidth: 48 + Layout.preferredWidth: 38 * theme.fontScale horizontalAlignment: Text.AlignHCenter TapHandler { onTapped: function(eventPoint, button) { @@ -254,14 +254,14 @@ Window { id: chatButton backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar backgroundColorHovered: theme.iconBackgroundViewBarHovered - Layout.preferredWidth: 48 - Layout.preferredHeight: 48 + Layout.preferredWidth: 38 * theme.fontScale + Layout.preferredHeight: 38 * theme.fontScale Layout.alignment: Qt.AlignCenter toggledWidth: 0 toggled: chatView.isShown() toggledColor: theme.iconBackgroundViewBarToggled - imageWidth: 34 - imageHeight: 34 + imageWidth: 25 * theme.fontScale + imageHeight: 25 * theme.fontScale source: "qrc:/gpt4all/icons/chat.svg" Accessible.name: qsTr("Chat view") Accessible.description: qsTr("Chat view to interact with models") @@ -273,10 +273,10 @@ Window { Text { Layout.topMargin: -20 text: qsTr("Chats") - font.pixelSize: theme.fontSizeLargeCapped + font.pixelSize: theme.fontSizeMedium font.bold: true color: chatButton.hovered ? chatButton.backgroundColorHovered : chatButton.backgroundColor - Layout.preferredWidth: 48 + Layout.preferredWidth: 38 * theme.fontScale horizontalAlignment: Text.AlignHCenter TapHandler { onTapped: function(eventPoint, button) { @@ -289,13 +289,13 @@ Window { id: modelsButton backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar backgroundColorHovered: theme.iconBackgroundViewBarHovered - Layout.preferredWidth: 48 - Layout.preferredHeight: 48 + Layout.preferredWidth: 38 * theme.fontScale + Layout.preferredHeight: 38 * theme.fontScale toggledWidth: 0 toggled: modelsView.isShown() toggledColor: theme.iconBackgroundViewBarToggled - imageWidth: 34 - imageHeight: 34 + imageWidth: 25 * theme.fontScale + imageHeight: 25 * theme.fontScale source: "qrc:/gpt4all/icons/models.svg" Accessible.name: qsTr("Models") Accessible.description: qsTr("Models view for installed models") @@ -307,10 +307,10 @@ Window { Text { Layout.topMargin: -20 text: qsTr("Models") - font.pixelSize: theme.fontSizeLargeCapped + font.pixelSize: theme.fontSizeMedium font.bold: true color: modelsButton.hovered ? modelsButton.backgroundColorHovered : modelsButton.backgroundColor - Layout.preferredWidth: 48 + Layout.preferredWidth: 38 * theme.fontScale horizontalAlignment: Text.AlignHCenter TapHandler { onTapped: function(eventPoint, button) { @@ -323,13 +323,13 @@ Window { id: localdocsButton backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar backgroundColorHovered: theme.iconBackgroundViewBarHovered - Layout.preferredWidth: 48 - Layout.preferredHeight: 48 + Layout.preferredWidth: 38 * theme.fontScale + Layout.preferredHeight: 38 * theme.fontScale toggledWidth: 0 toggledColor: theme.iconBackgroundViewBarToggled toggled: localDocsView.isShown() - imageWidth: 34 - imageHeight: 34 + imageWidth: 25 * theme.fontScale + imageHeight: 25 * theme.fontScale source: "qrc:/gpt4all/icons/db.svg" Accessible.name: qsTr("LocalDocs") Accessible.description: qsTr("LocalDocs view to configure and use local docs") @@ -341,10 +341,10 @@ Window { Text { Layout.topMargin: -20 text: qsTr("LocalDocs") - font.pixelSize: theme.fontSizeLargeCapped + font.pixelSize: theme.fontSizeMedium font.bold: true color: localdocsButton.hovered ? localdocsButton.backgroundColorHovered : localdocsButton.backgroundColor - Layout.preferredWidth: 48 + Layout.preferredWidth: 38 * theme.fontScale horizontalAlignment: Text.AlignHCenter TapHandler { onTapped: function(eventPoint, button) { @@ -357,13 +357,13 @@ Window { id: settingsButton backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar backgroundColorHovered: theme.iconBackgroundViewBarHovered - Layout.preferredWidth: 48 - Layout.preferredHeight: 48 + Layout.preferredWidth: 38 * theme.fontScale + Layout.preferredHeight: 38 * theme.fontScale toggledWidth: 0 toggledColor: theme.iconBackgroundViewBarToggled toggled: settingsView.isShown() - imageWidth: 34 - imageHeight: 34 + imageWidth: 25 * theme.fontScale + imageHeight: 25 * theme.fontScale source: "qrc:/gpt4all/icons/settings.svg" Accessible.name: qsTr("Settings") Accessible.description: qsTr("Settings view for application configuration") @@ -375,10 +375,10 @@ Window { Text { Layout.topMargin: -20 text: qsTr("Settings") - font.pixelSize: theme.fontSizeLargeCapped + font.pixelSize: theme.fontSizeMedium font.bold: true color: settingsButton.hovered ? settingsButton.backgroundColorHovered : settingsButton.backgroundColor - Layout.preferredWidth: 48 + Layout.preferredWidth: 38 * theme.fontScale horizontalAlignment: Text.AlignHCenter TapHandler { onTapped: function(eventPoint, button) { diff --git a/gpt4all-chat/mysettings.cpp b/gpt4all-chat/mysettings.cpp index 69d28ace..9b6badef 100644 --- a/gpt4all-chat/mysettings.cpp +++ b/gpt4all-chat/mysettings.cpp @@ -47,6 +47,7 @@ static const QVariantMap basicDefaults { { "localdocs/fileExtensions", QStringList { "txt", "pdf", "md", "rst" } }, { "localdocs/useRemoteEmbed", false }, { "localdocs/nomicAPIKey", "" }, + { "localdocs/embedDevice", "Auto" }, { "network/attribution", "" }, }; @@ -77,6 +78,22 @@ static QString defaultLocalModelsPath() return canonicalLocalPath; } +static QStringList getDevices(bool skipKompute = false) +{ + QStringList deviceList { "Auto" }; +#if defined(Q_OS_MAC) && defined(__aarch64__) + deviceList << "Metal"; +#else + std::vector devices = LLModel::Implementation::availableGPUDevices(); + for (LLModel::GPUDevice &d : devices) { + if (!skipKompute || strcmp(d.backend, "kompute")) + deviceList << QString::fromStdString(d.selectionName()); + } +#endif + deviceList << "CPU"; + return deviceList; +} + class MyPrivateSettings: public MySettings { }; Q_GLOBAL_STATIC(MyPrivateSettings, settingsInstance) MySettings *MySettings::globalInstance() @@ -85,18 +102,10 @@ MySettings *MySettings::globalInstance() } MySettings::MySettings() - : QObject{nullptr} + : QObject(nullptr) + , m_deviceList(getDevices()) + , m_embeddingsDeviceList(getDevices(/*skipKompute*/ true)) { - QVector deviceList{ "Auto" }; -#if defined(Q_OS_MAC) && defined(__aarch64__) - deviceList << "Metal"; -#else - std::vector devices = LLModel::Implementation::availableGPUDevices(); - for (LLModel::GPUDevice &d : devices) - deviceList << QString::fromStdString(d.selectionName()); -#endif - deviceList << "CPU"; - setDeviceList(deviceList); } QVariant MySettings::getBasicSetting(const QString &name) const @@ -113,17 +122,6 @@ void MySettings::setBasicSetting(const QString &name, const QVariant &value, std QMetaObject::invokeMethod(this, u"%1Changed"_s.arg(signal.value_or(name)).toLatin1().constData()); } -Q_INVOKABLE QVector MySettings::deviceList() const -{ - return m_deviceList; -} - -void MySettings::setDeviceList(const QVector &value) -{ - m_deviceList = value; - emit deviceListChanged(); -} - void MySettings::restoreModelDefaults(const ModelInfo &info) { setModelTemperature(info, info.m_temperature); @@ -162,6 +160,7 @@ void MySettings::restoreLocalDocsDefaults() setLocalDocsFileExtensions(basicDefaults.value("localdocs/fileExtensions").toStringList()); setLocalDocsUseRemoteEmbed(basicDefaults.value("localdocs/useRemoteEmbed").toBool()); setLocalDocsNomicAPIKey(basicDefaults.value("localdocs/nomicAPIKey").toString()); + setLocalDocsEmbedDevice(basicDefaults.value("localdocs/embedDevice").toString()); } void MySettings::eraseModel(const ModelInfo &info) @@ -382,6 +381,7 @@ bool MySettings::localDocsShowReferences() const { return getBasicSetting QStringList MySettings::localDocsFileExtensions() const { return getBasicSetting("localdocs/fileExtensions").toStringList(); } bool MySettings::localDocsUseRemoteEmbed() const { return getBasicSetting("localdocs/useRemoteEmbed").toBool(); } QString MySettings::localDocsNomicAPIKey() const { return getBasicSetting("localdocs/nomicAPIKey" ).toString(); } +QString MySettings::localDocsEmbedDevice() const { return getBasicSetting("localdocs/embedDevice" ).toString(); } QString MySettings::networkAttribution() const { return getBasicSetting("network/attribution" ).toString(); } void MySettings::setSaveChatsContext(bool value) { setBasicSetting("saveChatsContext", value); } @@ -397,6 +397,7 @@ void MySettings::setLocalDocsShowReferences(bool value) { setBasic void MySettings::setLocalDocsFileExtensions(const QStringList &value) { setBasicSetting("localdocs/fileExtensions", value, "localDocsFileExtensions"); } void MySettings::setLocalDocsUseRemoteEmbed(bool value) { setBasicSetting("localdocs/useRemoteEmbed", value, "localDocsUseRemoteEmbed"); } void MySettings::setLocalDocsNomicAPIKey(const QString &value) { setBasicSetting("localdocs/nomicAPIKey", value, "localDocsNomicAPIKey"); } +void MySettings::setLocalDocsEmbedDevice(const QString &value) { setBasicSetting("localdocs/embedDevice", value, "localDocsEmbedDevice"); } void MySettings::setNetworkAttribution(const QString &value) { setBasicSetting("network/attribution", value, "networkAttribution"); } QString MySettings::modelPath() @@ -446,11 +447,10 @@ QString MySettings::device() void MySettings::setDevice(const QString &value) { - if (device() == value) - return; - - m_settings.setValue("device", value); - emit deviceChanged(); + if (device() != value) { + m_settings.setValue("device", value); + emit deviceChanged(); + } } bool MySettings::forceMetal() const @@ -460,10 +460,10 @@ bool MySettings::forceMetal() const void MySettings::setForceMetal(bool value) { - if (m_forceMetal == value) - return; - m_forceMetal = value; - emit forceMetalChanged(value); + if (m_forceMetal != value) { + m_forceMetal = value; + emit forceMetalChanged(value); + } } bool MySettings::networkIsActive() const diff --git a/gpt4all-chat/mysettings.h b/gpt4all-chat/mysettings.h index fc845990..0fbc9033 100644 --- a/gpt4all-chat/mysettings.h +++ b/gpt4all-chat/mysettings.h @@ -31,11 +31,13 @@ class MySettings : public QObject Q_PROPERTY(QStringList localDocsFileExtensions READ localDocsFileExtensions WRITE setLocalDocsFileExtensions NOTIFY localDocsFileExtensionsChanged) Q_PROPERTY(bool localDocsUseRemoteEmbed READ localDocsUseRemoteEmbed WRITE setLocalDocsUseRemoteEmbed NOTIFY localDocsUseRemoteEmbedChanged) Q_PROPERTY(QString localDocsNomicAPIKey READ localDocsNomicAPIKey WRITE setLocalDocsNomicAPIKey NOTIFY localDocsNomicAPIKeyChanged) + Q_PROPERTY(QString localDocsEmbedDevice READ localDocsEmbedDevice WRITE setLocalDocsEmbedDevice NOTIFY localDocsEmbedDeviceChanged) Q_PROPERTY(QString networkAttribution READ networkAttribution WRITE setNetworkAttribution NOTIFY networkAttributionChanged) Q_PROPERTY(bool networkIsActive READ networkIsActive WRITE setNetworkIsActive NOTIFY networkIsActiveChanged) Q_PROPERTY(bool networkUsageStatsActive READ networkUsageStatsActive WRITE setNetworkUsageStatsActive NOTIFY networkUsageStatsActiveChanged) Q_PROPERTY(QString device READ device WRITE setDevice NOTIFY deviceChanged) - Q_PROPERTY(QVector deviceList READ deviceList NOTIFY deviceListChanged) + Q_PROPERTY(QStringList deviceList MEMBER m_deviceList CONSTANT) + Q_PROPERTY(QStringList embeddingsDeviceList MEMBER m_embeddingsDeviceList CONSTANT) Q_PROPERTY(int networkPort READ networkPort WRITE setNetworkPort NOTIFY networkPortChanged) public: @@ -138,6 +140,8 @@ public: void setLocalDocsUseRemoteEmbed(bool value); QString localDocsNomicAPIKey() const; void setLocalDocsNomicAPIKey(const QString &value); + QString localDocsEmbedDevice() const; + void setLocalDocsEmbedDevice(const QString &value); // Network settings QString networkAttribution() const; @@ -151,9 +155,6 @@ public: int networkPort() const; void setNetworkPort(int value); - QVector deviceList() const; - void setDeviceList(const QVector &value); - Q_SIGNALS: void nameChanged(const ModelInfo &info); void filenameChanged(const ModelInfo &info); @@ -185,18 +186,19 @@ Q_SIGNALS: void localDocsFileExtensionsChanged(); void localDocsUseRemoteEmbedChanged(); void localDocsNomicAPIKeyChanged(); + void localDocsEmbedDeviceChanged(); void networkAttributionChanged(); void networkIsActiveChanged(); void networkPortChanged(); void networkUsageStatsActiveChanged(); void attemptModelLoadChanged(); void deviceChanged(); - void deviceListChanged(); private: QSettings m_settings; bool m_forceMetal; - QVector m_deviceList; + const QStringList m_deviceList; + const QStringList m_embeddingsDeviceList; private: explicit MySettings(); diff --git a/gpt4all-chat/qml/AddModelView.qml b/gpt4all-chat/qml/AddModelView.qml index 7f402e20..d5a943aa 100644 --- a/gpt4all-chat/qml/AddModelView.qml +++ b/gpt4all-chat/qml/AddModelView.qml @@ -603,13 +603,13 @@ Rectangle { Layout.rightMargin: 20 Text { text: qsTr("File size") - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall color: theme.mutedDarkTextColor } Text { text: filesize color: theme.textColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall font.bold: true } } @@ -625,13 +625,13 @@ Rectangle { Layout.rightMargin: 20 Text { text: qsTr("RAM required") - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall color: theme.mutedDarkTextColor } Text { text: ramrequired >= 0 ? ramrequired + qsTr(" GB") : "?" color: theme.textColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall font.bold: true } } @@ -647,13 +647,13 @@ Rectangle { Layout.rightMargin: 20 Text { text: qsTr("Parameters") - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall color: theme.mutedDarkTextColor } Text { text: parameters !== "" ? parameters : "?" color: theme.textColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall font.bold: true } } @@ -669,13 +669,13 @@ Rectangle { Layout.rightMargin: 20 Text { text: qsTr("Quant") - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall color: theme.mutedDarkTextColor } Text { text: quant color: theme.textColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall font.bold: true } } @@ -691,13 +691,13 @@ Rectangle { Layout.rightMargin: 20 Text { text: qsTr("Type") - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall color: theme.mutedDarkTextColor } Text { text: type color: theme.textColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall font.bold: true } } diff --git a/gpt4all-chat/qml/ApplicationSettings.qml b/gpt4all-chat/qml/ApplicationSettings.qml index c0c3fbfa..2d302ce1 100644 --- a/gpt4all-chat/qml/ApplicationSettings.qml +++ b/gpt4all-chat/qml/ApplicationSettings.qml @@ -62,9 +62,19 @@ MySettingsTab { rowSpacing: 30 columnSpacing: 10 - ColumnLayout { + Label { Layout.row: 0 Layout.column: 0 + Layout.bottomMargin: 10 + color: theme.settingsTitleTextColor + font.pixelSize: theme.fontSizeBannerSmall + font.bold: true + text: qsTr("Application Settings") + } + + ColumnLayout { + Layout.row: 1 + Layout.column: 0 Layout.columnSpan: 3 Layout.fillWidth: true spacing: 10 @@ -72,7 +82,7 @@ MySettingsTab { color: theme.styledTextColor font.pixelSize: theme.fontSizeLarge font.bold: true - text: "General" + text: qsTr("General") } Rectangle { @@ -85,22 +95,21 @@ MySettingsTab { MySettingsLabel { id: themeLabel text: qsTr("Theme") - helpText: qsTr("Customize the colors of GPT4All") - Layout.row: 1 + helpText: qsTr("The application color scheme.") + Layout.row: 2 Layout.column: 0 } MyComboBox { id: themeBox - Layout.row: 1 + Layout.row: 2 Layout.column: 2 Layout.minimumWidth: 200 Layout.maximumWidth: 200 Layout.fillWidth: false Layout.alignment: Qt.AlignRight model: [qsTr("Dark"), qsTr("Light"), qsTr("LegacyDark")] - Accessible.role: Accessible.ComboBox - Accessible.name: qsTr("Color theme") - Accessible.description: qsTr("Color theme for the chat client to use") + Accessible.name: themeLabel.text + Accessible.description: themeLabel.helpText function updateModel() { themeBox.currentIndex = themeBox.indexOfValue(MySettings.chatTheme); } @@ -120,22 +129,21 @@ MySettingsTab { MySettingsLabel { id: fontLabel text: qsTr("Font Size") - helpText: qsTr("How big your font is displayed") - Layout.row: 2 + helpText: qsTr("The size of text in the application.") + Layout.row: 3 Layout.column: 0 } MyComboBox { id: fontBox - Layout.row: 2 + Layout.row: 3 Layout.column: 2 Layout.minimumWidth: 200 Layout.maximumWidth: 200 Layout.fillWidth: false Layout.alignment: Qt.AlignRight model: ["Small", "Medium", "Large"] - Accessible.role: Accessible.ComboBox - Accessible.name: qsTr("Font size") - Accessible.description: qsTr("Font size of the chat client") + Accessible.name: fontLabel.text + Accessible.description: fontLabel.helpText function updateModel() { fontBox.currentIndex = fontBox.indexOfValue(MySettings.fontSize); } @@ -155,59 +163,54 @@ MySettingsTab { MySettingsLabel { id: deviceLabel text: qsTr("Device") - helpText: qsTr("The hardware device used to load the model") - Layout.row: 3 + helpText: qsTr('The compute device used for text generation. "Auto" uses Vulkan or Metal.') + Layout.row: 4 Layout.column: 0 } MyComboBox { id: deviceBox - Layout.row: 3 + Layout.row: 4 Layout.column: 2 Layout.minimumWidth: 400 Layout.maximumWidth: 400 Layout.fillWidth: false Layout.alignment: Qt.AlignRight model: MySettings.deviceList - Accessible.role: Accessible.ComboBox - Accessible.name: qsTr("Device") - Accessible.description: qsTr("Device of the chat client") + Accessible.name: deviceLabel.text + Accessible.description: deviceLabel.helpText function updateModel() { deviceBox.currentIndex = deviceBox.indexOfValue(MySettings.device); } Component.onCompleted: { - deviceBox.updateModel() + deviceBox.updateModel(); } Connections { target: MySettings function onDeviceChanged() { - deviceBox.updateModel() - } - function onDeviceListChanged() { - deviceBox.updateModel() + deviceBox.updateModel(); } } onActivated: { - MySettings.device = deviceBox.currentText + MySettings.device = deviceBox.currentText; } } MySettingsLabel { id: defaultModelLabel - text: qsTr("Default model") - helpText: qsTr("The preferred default model") - Layout.row: 4 + text: qsTr("Default Model") + helpText: qsTr("The preferred model for new chats. Also used as the local server fallback.") + Layout.row: 5 Layout.column: 0 } MyComboBox { id: comboBox - Layout.row: 4 + Layout.row: 5 Layout.column: 2 Layout.minimumWidth: 400 Layout.maximumWidth: 400 Layout.alignment: Qt.AlignRight model: ModelList.userDefaultModelList - Accessible.role: Accessible.ComboBox - Accessible.name: qsTr("Default model") - Accessible.description: qsTr("Default model to use; the first item is the current default model") + Accessible.name: defaultModelLabel.text + Accessible.description: defaultModelLabel.helpText function updateModel() { comboBox.currentIndex = comboBox.indexOfValue(MySettings.userDefaultModel); } @@ -226,14 +229,14 @@ MySettingsTab { } MySettingsLabel { id: modelPathLabel - text: qsTr("Download path") - helpText: qsTr("The download folder for models") - Layout.row: 5 + text: qsTr("Download Path") + helpText: qsTr("Where to store local models and the LocalDocs database.") + Layout.row: 6 Layout.column: 0 } RowLayout { - Layout.row: 5 + Layout.row: 6 Layout.column: 2 Layout.alignment: Qt.AlignRight Layout.minimumWidth: 400 @@ -245,11 +248,8 @@ MySettingsTab { font.pixelSize: theme.fontSizeLarge implicitWidth: 300 Layout.fillWidth: true - ToolTip.text: qsTr("Path where model files will be downloaded to") - ToolTip.visible: hovered - Accessible.role: Accessible.ToolTip - Accessible.name: modelPathDisplayField.text - Accessible.description: ToolTip.text + Accessible.name: modelPathLabel.text + Accessible.description: modelPathLabel.helpText onEditingFinished: { if (isValid) { MySettings.modelPath = modelPathDisplayField.text @@ -271,29 +271,32 @@ MySettingsTab { MySettingsLabel { id: dataLakeLabel - text: qsTr("Opensource Datalake") - helpText: qsTr("Send your data to the GPT4All Open Source Datalake.") - Layout.row: 6 + text: qsTr("Enable Datalake") + helpText: qsTr("Send chats and feedback to the GPT4All Open-Source Datalake.") + Layout.row: 7 Layout.column: 0 } MyCheckBox { id: dataLakeBox - Layout.row: 6 + Layout.row: 7 Layout.column: 2 Layout.alignment: Qt.AlignRight - checked: MySettings.networkIsActive - onClicked: { - if (MySettings.networkIsActive) { - MySettings.networkIsActive = false - } else - networkDialog.open() + Component.onCompleted: { dataLakeBox.checked = MySettings.networkIsActive; } + Connections { + target: MySettings + function onNetworkIsActiveChanged() { dataLakeBox.checked = MySettings.networkIsActive; } + } + onClicked: { + if (MySettings.networkIsActive) + MySettings.networkIsActive = false; + else + networkDialog.open(); + dataLakeBox.checked = MySettings.networkIsActive; } - ToolTip.text: qsTr("Reveals a dialogue where you can opt-in for sharing data over network") - ToolTip.visible: hovered } ColumnLayout { - Layout.row: 7 + Layout.row: 8 Layout.column: 0 Layout.columnSpan: 3 Layout.fillWidth: true @@ -302,7 +305,7 @@ MySettingsTab { color: theme.styledTextColor font.pixelSize: theme.fontSizeLarge font.bold: true - text: "Advanced" + text: qsTr("Advanced") } Rectangle { @@ -315,18 +318,16 @@ MySettingsTab { MySettingsLabel { id: nThreadsLabel text: qsTr("CPU Threads") - helpText: qsTr("Number of CPU threads for inference and embedding") - Layout.row: 8 + helpText: qsTr("The number of CPU threads used for inference and embedding.") + Layout.row: 9 Layout.column: 0 } MyTextField { text: MySettings.threadCount color: theme.textColor font.pixelSize: theme.fontSizeLarge - ToolTip.text: qsTr("Amount of processing threads to use bounded by 1 and number of logical processors") - ToolTip.visible: hovered Layout.alignment: Qt.AlignRight - Layout.row: 8 + Layout.row: 9 Layout.column: 2 Layout.minimumWidth: 200 Layout.maximumWidth: 200 @@ -348,47 +349,43 @@ MySettingsTab { } MySettingsLabel { id: saveChatsContextLabel - text: qsTr("Save chat context") - helpText: qsTr("Save chat context to disk") - Layout.row: 9 + text: qsTr("Save Chat Context") + helpText: qsTr("Save the chat model's state to disk for faster loading. WARNING: Uses ~2GB per chat.") + Layout.row: 10 Layout.column: 0 } MyCheckBox { id: saveChatsContextBox - Layout.row: 9 + Layout.row: 10 Layout.column: 2 Layout.alignment: Qt.AlignRight checked: MySettings.saveChatsContext onClicked: { MySettings.saveChatsContext = !MySettings.saveChatsContext } - ToolTip.text: qsTr("WARNING: Saving chats to disk can be ~2GB per chat") - ToolTip.visible: hovered } MySettingsLabel { id: serverChatLabel - text: qsTr("Enable API server") - helpText: qsTr("A local http server running on local port") - Layout.row: 10 + text: qsTr("Enable Local Server") + helpText: qsTr("Expose an OpenAI-Compatible server to localhost. WARNING: Results in increased resource usage.") + Layout.row: 11 Layout.column: 0 } MyCheckBox { id: serverChatBox - Layout.row: 10 + Layout.row: 11 Layout.column: 2 Layout.alignment: Qt.AlignRight checked: MySettings.serverChat onClicked: { MySettings.serverChat = !MySettings.serverChat } - ToolTip.text: qsTr("WARNING: This enables the gui to act as a local REST web server(OpenAI API compliant) for API requests and will increase your RAM usage as well") - ToolTip.visible: hovered } MySettingsLabel { id: serverPortLabel - text: qsTr("API Server Port:") - helpText: qsTr("A local port to run the server (Requires restart") - Layout.row: 11 + text: qsTr("API Server Port") + helpText: qsTr("The port to use for the local server. Requires restart.") + Layout.row: 12 Layout.column: 0 } MyTextField { @@ -396,9 +393,7 @@ MySettingsTab { text: MySettings.networkPort color: theme.textColor font.pixelSize: theme.fontSizeLarge - ToolTip.text: qsTr("Api server port. WARNING: You need to restart the application for it to take effect") - ToolTip.visible: hovered - Layout.row: 11 + Layout.row: 12 Layout.column: 2 Layout.minimumWidth: 200 Layout.maximumWidth: 200 @@ -416,8 +411,8 @@ MySettingsTab { } } Accessible.role: Accessible.EditableText - Accessible.name: serverPortField.text - Accessible.description: ToolTip.text + Accessible.name: serverPortLabel.text + Accessible.description: serverPortLabel.helpText } /*MySettingsLabel { @@ -441,8 +436,8 @@ MySettingsTab { MySettingsLabel { id: updatesLabel - text: qsTr("Check for updates") - helpText: qsTr("Click to see if an update to the application is available"); + text: qsTr("Check For Updates") + helpText: qsTr("Manually check for an update to GPT4All."); Layout.row: 14 Layout.column: 0 } diff --git a/gpt4all-chat/qml/ChatDrawer.qml b/gpt4all-chat/qml/ChatDrawer.qml index f9f59c9b..3720d379 100644 --- a/gpt4all-chat/qml/ChatDrawer.qml +++ b/gpt4all-chat/qml/ChatDrawer.qml @@ -110,7 +110,7 @@ Rectangle { bottomPadding: 5 text: parent.section color: theme.chatDrawerSectionHeader - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmallest } } } diff --git a/gpt4all-chat/qml/ChatView.qml b/gpt4all-chat/qml/ChatView.qml index 76956141..deddce0c 100644 --- a/gpt4all-chat/qml/ChatView.qml +++ b/gpt4all-chat/qml/ChatView.qml @@ -365,7 +365,6 @@ Rectangle { } } - Accessible.role: Accessible.ComboBox Accessible.name: currentModelName() Accessible.description: qsTr("The top item is the current model") onActivated: function (index) { diff --git a/gpt4all-chat/qml/CollectionsDrawer.qml b/gpt4all-chat/qml/CollectionsDrawer.qml index 9331c082..62106a81 100644 --- a/gpt4all-chat/qml/CollectionsDrawer.qml +++ b/gpt4all-chat/qml/CollectionsDrawer.qml @@ -89,7 +89,7 @@ Rectangle { text: "%1 – %2".arg(qsTr("%n file(s)", "", model.totalDocs)).arg(qsTr("%n word(s)", "", model.totalWords)) elide: Text.ElideRight color: theme.mutedTextColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall } RowLayout { visible: model.updating @@ -105,7 +105,7 @@ Rectangle { text: qsTr("Updating") elide: Text.ElideRight color: theme.accentColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall font.bold: true } } diff --git a/gpt4all-chat/qml/HomeView.qml b/gpt4all-chat/qml/HomeView.qml index d4cc8e26..2ac03ad5 100644 --- a/gpt4all-chat/qml/HomeView.qml +++ b/gpt4all-chat/qml/HomeView.qml @@ -36,6 +36,7 @@ Rectangle { Layout.fillWidth: true Layout.maximumWidth: 1530 Layout.alignment: Qt.AlignCenter + Layout.topMargin: 20 spacing: 30 ColumnLayout { diff --git a/gpt4all-chat/qml/LocalDocsSettings.qml b/gpt4all-chat/qml/LocalDocsSettings.qml index 5873090a..30fef7b3 100644 --- a/gpt4all-chat/qml/LocalDocsSettings.qml +++ b/gpt4all-chat/qml/LocalDocsSettings.qml @@ -19,20 +19,30 @@ MySettingsTab { title: qsTr("LocalDocs") contentItem: ColumnLayout { id: root - spacing: 10 + spacing: 30 Label { - color: theme.styledTextColor - font.pixelSize: theme.fontSizeLarge + Layout.bottomMargin: 10 + color: theme.settingsTitleTextColor + font.pixelSize: theme.fontSizeBannerSmall font.bold: true - text: "Indexing" + text: qsTr("LocalDocs Settings") } - Rectangle { - Layout.bottomMargin: 15 - Layout.fillWidth: true - height: 1 - color: theme.settingsDivider + 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 + } } RowLayout { @@ -81,25 +91,26 @@ MySettingsTab { } } - Label { - Layout.topMargin: 15 - color: theme.grayRed900 - font.pixelSize: theme.fontSizeLarge - font.bold: true - text: "Embedding" - } + ColumnLayout { + spacing: 10 + Label { + color: theme.grayRed900 + font.pixelSize: theme.fontSizeLarge + font.bold: true + text: qsTr("Embedding") + } - Rectangle { - Layout.bottomMargin: 15 - Layout.fillWidth: true - height: 1 - color: theme.grayRed500 + Rectangle { + Layout.fillWidth: true + height: 1 + color: theme.grayRed500 + } } RowLayout { MySettingsLabel { text: qsTr("Use Nomic Embed API") - helpText: qsTr("Embed documents using the fast Nomic API instead of a private local model.") + helpText: qsTr("Embed documents using the fast Nomic API instead of a private local model. Requires restart.") } MyCheckBox { @@ -113,11 +124,45 @@ MySettingsTab { } } + 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; + } + } + } + RowLayout { MySettingsLabel { id: apiKeyLabel text: qsTr("Nomic API Key") - helpText: qsTr('API key to use for Nomic Embed. Get one from the Atlas API keys page.') + helpText: qsTr('API key to use for Nomic Embed. Get one from the Atlas API keys page. Requires restart.') onLinkActivated: function(link) { Qt.openUrlExternally(link) } } @@ -148,26 +193,27 @@ MySettingsTab { } } - Label { - Layout.topMargin: 15 - color: theme.grayRed900 - font.pixelSize: theme.fontSizeLarge - font.bold: true - text: "Display" - } + ColumnLayout { + spacing: 10 + Label { + color: theme.grayRed900 + font.pixelSize: theme.fontSizeLarge + font.bold: true + text: qsTr("Display") + } - Rectangle { - Layout.bottomMargin: 15 - Layout.fillWidth: true - height: 1 - color: theme.grayRed500 + Rectangle { + Layout.fillWidth: true + height: 1 + color: theme.grayRed500 + } } RowLayout { MySettingsLabel { id: showReferencesLabel - text: qsTr("Show sources") - helpText: qsTr("Shows sources in GUI generated by localdocs") + text: qsTr("Show Sources") + helpText: qsTr("Display the sources used for each response.") } MyCheckBox { id: showReferencesBox @@ -178,19 +224,20 @@ MySettingsTab { } } - Label { - Layout.topMargin: 15 - color: theme.styledTextColor - font.pixelSize: theme.fontSizeLarge - font.bold: true - text: "Advanced" - } + ColumnLayout { + spacing: 10 + Label { + color: theme.styledTextColor + font.pixelSize: theme.fontSizeLarge + font.bold: true + text: qsTr("Advanced") + } - Rectangle { - Layout.bottomMargin: 15 - Layout.fillWidth: true - height: 1 - color: theme.settingsDivider + Rectangle { + Layout.fillWidth: true + height: 1 + color: theme.settingsDivider + } } MySettingsLabel { diff --git a/gpt4all-chat/qml/LocalDocsView.qml b/gpt4all-chat/qml/LocalDocsView.qml index 9319e344..e7f6b8bf 100644 --- a/gpt4all-chat/qml/LocalDocsView.qml +++ b/gpt4all-chat/qml/LocalDocsView.qml @@ -307,7 +307,7 @@ Rectangle { } elide: Text.ElideRight color: theme.mutedDarkTextColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall } Text { visible: { @@ -322,7 +322,7 @@ Rectangle { elide: Text.ElideRight color: theme.mutedDarkTextColor font.family: "monospace" - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall } } @@ -332,21 +332,21 @@ Rectangle { text: "%1 – %2".arg(qsTr("%n file(s)", "", model.totalDocs)).arg(qsTr("%n word(s)", "", model.totalWords)) elide: Text.ElideRight color: theme.styledTextColor2 - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall } Text { text: model.embeddingModel elide: Text.ElideRight color: theme.mutedDarkTextColor font.bold: true - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall } Text { visible: Qt.formatDateTime(model.lastUpdate) !== "" text: Qt.formatDateTime(model.lastUpdate) elide: Text.ElideRight color: theme.mutedTextColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall } Text { visible: model.currentEmbeddingsToIndex !== 0 @@ -354,7 +354,7 @@ Rectangle { + model.totalEmbeddingsToIndex + " embeddings" elide: Text.ElideRight color: theme.mutedTextColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall } } @@ -400,53 +400,29 @@ Rectangle { Layout.fillWidth: true spacing: 30 Layout.leftMargin: 15 + Layout.rightMargin: 15 Layout.topMargin: 15 - Text { + MyTextButton { text: qsTr("Remove") - elide: Text.ElideRight color: theme.red500 - font.bold: true - font.pixelSize: theme.fontSizeSmall - TapHandler { - onTapped: { - LocalDocs.removeFolder(collection, folder_path) - } - } - } - Text { - Layout.alignment: Qt.AlignRight - visible: !model.forceIndexing && !model.indexing && model.currentEmbeddingsToIndex === 0 - text: qsTr("Rebuild") - elide: Text.ElideRight - color: theme.red500 - font.bold: true - font.pixelSize: theme.fontSizeSmall - TapHandler { - onTapped: { LocalDocs.forceRebuildFolder(folder_path); } - } - HoverHandler { id: hoverHandler1 } - ToolTip.text: qsTr("Reindex this folder from scratch. This is slow and usually not needed.") - ToolTip.visible: hoverHandler1.hovered - ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval + onClick: LocalDocs.removeFolder(collection, folder_path) } Item { Layout.fillWidth: true } - Text { - Layout.alignment: Qt.AlignRight + MyTextButton { + visible: !model.forceIndexing && !model.indexing && model.currentEmbeddingsToIndex === 0 + text: qsTr("Rebuild") + color: theme.green500 + onClick: { LocalDocs.forceRebuildFolder(folder_path); } + tooltip: qsTr("Reindex this folder from scratch. This is slow and usually not needed.") + } + MyTextButton { visible: model.forceIndexing text: qsTr("Update") - elide: Text.ElideRight - color: theme.red500 - font.bold: true - font.pixelSize: theme.fontSizeSmall - TapHandler { - onTapped: { LocalDocs.forceIndexing(collection); } - } - HoverHandler { id: hoverHandler2 } - ToolTip.text: qsTr("Update the collection to the new version. This is a slow operation.") - ToolTip.visible: hoverHandler2.hovered - ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval + color: theme.green500 + onClick: { LocalDocs.forceIndexing(collection); } + tooltip: qsTr("Update the collection to the new version. This is a slow operation.") } } } diff --git a/gpt4all-chat/qml/ModelSettings.qml b/gpt4all-chat/qml/ModelSettings.qml index f1ab3631..a20f1ef2 100644 --- a/gpt4all-chat/qml/ModelSettings.qml +++ b/gpt4all-chat/qml/ModelSettings.qml @@ -11,7 +11,7 @@ MySettingsTab { onRestoreDefaultsClicked: { MySettings.restoreModelDefaults(root.currentModelInfo); } - title: qsTr("Model/Character Settings") + title: qsTr("Model") contentItem: GridLayout { id: root columns: 3 @@ -23,32 +23,14 @@ MySettingsTab { property var currentModelId: comboBox.currentValue property var currentModelInfo: ModelList.modelInfo(root.currentModelId) - ColumnLayout { - Layout.row: 0 - Layout.column: 0 - Layout.columnSpan: 3 - Layout.fillWidth: true - spacing: 10 - Label { - color: theme.styledTextColor - font.pixelSize: theme.fontSizeLarge - font.bold: true - text: "General" - } - - Rectangle { - Layout.fillWidth: true - height: 1 - color: theme.settingsDivider - } - } - - MySettingsLabel { - id: label + Label { Layout.row: 1 Layout.column: 0 - text: qsTr("Model/Character") - helpText: qsTr("Select or clone a model and change its settings") + Layout.bottomMargin: 10 + color: theme.settingsTitleTextColor + font.pixelSize: theme.fontSizeBannerSmall + font.bold: true + text: qsTr("Model Settings") } RowLayout { @@ -56,7 +38,6 @@ MySettingsTab { Layout.row: 2 Layout.column: 0 Layout.columnSpan: 2 - height: label.height + 20 spacing: 10 MyComboBox { @@ -122,9 +103,7 @@ MySettingsTab { Layout.topMargin: 15 spacing: 10 MySettingsLabel { - id: uniqueNameLabel - text: qsTr("Unique Name") - helpText: qsTr("Must contain a non-empty unique name") + text: qsTr("Name") } } @@ -158,7 +137,6 @@ MySettingsTab { MySettingsLabel { text: qsTr("Model File") - helpText: qsTr("The filename of the selected model") Layout.row: 5 Layout.column: 0 Layout.topMargin: 15 @@ -177,7 +155,7 @@ MySettingsTab { MySettingsLabel { visible: !root.currentModelInfo.isOnline text: qsTr("System Prompt") - helpText: qsTr("Prefixed at the beginning of every conversation") + helpText: qsTr("Prefixed at the beginning of every conversation. Must contain the appropriate framing tokens.") Layout.row: 7 Layout.column: 0 Layout.topMargin: 15 @@ -212,9 +190,6 @@ MySettingsTab { MySettings.setModelSystemPrompt(root.currentModelInfo, text) } Accessible.role: Accessible.EditableText - ToolTip.text: qsTr("The systemPrompt allows instructions to the model at the beginning of a chat.\nNOTE: A longer, detailed system prompt can lead to higher quality answers, but can also slow down generation.") - ToolTip.visible: hovered - ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval } } @@ -227,7 +202,7 @@ MySettingsTab { MySettingsLabel { id: promptTemplateLabel text: qsTr("Prompt Template") - helpText: qsTr("The template that wraps every prompt") + helpText: qsTr("The template that wraps every prompt.") } MySettingsLabel { id: promptTemplateLabelHelp @@ -271,9 +246,6 @@ MySettingsTab { Accessible.role: Accessible.EditableText Accessible.name: promptTemplateLabel.text Accessible.description: promptTemplateLabelHelp.text - ToolTip.text: qsTr("The prompt template partially determines how models will respond to prompts.\nNOTE: A longer, detailed template can lead to higher quality answers, but can also slow down generation.") - ToolTip.visible: hovered - ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval } } @@ -328,7 +300,7 @@ MySettingsTab { id: contextLengthLabel visible: !root.currentModelInfo.isOnline text: qsTr("Context Length") - helpText: qsTr("Conversation context window") + helpText: qsTr("Number of input and output tokens the model sees.") Layout.row: 0 Layout.column: 0 } @@ -378,7 +350,7 @@ MySettingsTab { MySettingsLabel { id: tempLabel text: qsTr("Temperature") - helpText: qsTr("The temperature for model token generation") + helpText: qsTr("Randomness of model output. Higher -> more variation.") Layout.row: 1 Layout.column: 2 } @@ -422,8 +394,8 @@ MySettingsTab { } MySettingsLabel { id: topPLabel - text: qsTr("Top P") - helpText: qsTr("Prevents choosing highly unlikely tokens") + text: qsTr("Top-P") + helpText: qsTr("Nucleus Sampling factor. Lower -> more predicatable.") Layout.row: 2 Layout.column: 0 } @@ -432,7 +404,7 @@ MySettingsTab { text: root.currentModelInfo.topP color: theme.textColor font.pixelSize: theme.fontSizeLarge - ToolTip.text: qsTr("Only the most likely tokens up to a total probability of top_p can be chosen.\nNOTE: Prevents choosing highly unlikely tokens, aka Nucleus Sampling") + ToolTip.text: qsTr("Only the most likely tokens up to a total probability of top_p can be chosen.\nNOTE: Prevents choosing highly unlikely tokens.") ToolTip.visible: hovered Layout.row: 2 Layout.column: 1 @@ -466,8 +438,8 @@ MySettingsTab { } MySettingsLabel { id: minPLabel - text: qsTr("Min P") - helpText: qsTr("Minimum relative probability") + text: qsTr("Min-P") + helpText: qsTr("Minimum token probability. Higher -> more predictable.") Layout.row: 3 Layout.column: 0 } @@ -512,8 +484,8 @@ MySettingsTab { MySettingsLabel { id: topKLabel visible: !root.currentModelInfo.isOnline - text: qsTr("Top K") - helpText: qsTr("Size of selection pool for tokens") + text: qsTr("Top-K") + helpText: qsTr("Size of selection pool for tokens.") Layout.row: 2 Layout.column: 2 } @@ -523,7 +495,7 @@ MySettingsTab { text: root.currentModelInfo.topK color: theme.textColor font.pixelSize: theme.fontSizeLarge - ToolTip.text: qsTr("Only the top K most likely tokens will be chosen from") + ToolTip.text: qsTr("Only the top K most likely tokens will be chosen from.") ToolTip.visible: hovered Layout.row: 2 Layout.column: 3 @@ -559,7 +531,7 @@ MySettingsTab { id: maxLengthLabel visible: !root.currentModelInfo.isOnline text: qsTr("Max Length") - helpText: qsTr("Maximum length of response in tokens") + helpText: qsTr("Maximum response length, in tokens.") Layout.row: 0 Layout.column: 2 } @@ -569,8 +541,6 @@ MySettingsTab { text: root.currentModelInfo.maxLength color: theme.textColor font.pixelSize: theme.fontSizeLarge - ToolTip.text: qsTr("Maximum length of response in tokens") - ToolTip.visible: hovered Layout.row: 0 Layout.column: 3 validator: IntValidator { @@ -606,7 +576,7 @@ MySettingsTab { id: batchSizeLabel visible: !root.currentModelInfo.isOnline text: qsTr("Prompt Batch Size") - helpText: qsTr("Amount of prompt tokens to process at once") + helpText: qsTr("The batch size used for prompt processing.") Layout.row: 1 Layout.column: 0 } @@ -616,7 +586,7 @@ MySettingsTab { text: root.currentModelInfo.promptBatchSize color: theme.textColor font.pixelSize: theme.fontSizeLarge - ToolTip.text: qsTr("Amount of prompt tokens to process at once.\nNOTE: Higher values can speed up reading prompts but will use more RAM") + ToolTip.text: qsTr("Amount of prompt tokens to process at once.\nNOTE: Higher values can speed up reading prompts but will use more RAM.") ToolTip.visible: hovered Layout.row: 1 Layout.column: 1 @@ -652,7 +622,7 @@ MySettingsTab { id: repeatPenaltyLabel visible: !root.currentModelInfo.isOnline text: qsTr("Repeat Penalty") - helpText: qsTr("Penalize repetitiveness") + helpText: qsTr("Repetition penalty factor. Set to 1 to disable.") Layout.row: 4 Layout.column: 2 } @@ -662,8 +632,6 @@ MySettingsTab { text: root.currentModelInfo.repeatPenalty color: theme.textColor font.pixelSize: theme.fontSizeLarge - ToolTip.text: qsTr("Amount to penalize repetitiveness of the output") - ToolTip.visible: hovered Layout.row: 4 Layout.column: 3 validator: DoubleValidator { @@ -698,7 +666,7 @@ MySettingsTab { id: repeatPenaltyTokensLabel visible: !root.currentModelInfo.isOnline text: qsTr("Repeat Penalty Tokens") - helpText: qsTr("Length to apply penalty") + helpText: qsTr("Number of previous tokens used for penalty.") Layout.row: 3 Layout.column: 2 } @@ -708,8 +676,6 @@ MySettingsTab { text: root.currentModelInfo.repeatPenaltyTokens color: theme.textColor font.pixelSize: theme.fontSizeLarge - ToolTip.text: qsTr("How far back in output to apply repeat penalty") - ToolTip.visible: hovered Layout.row: 3 Layout.column: 3 validator: IntValidator { @@ -745,7 +711,7 @@ MySettingsTab { id: gpuLayersLabel visible: !root.currentModelInfo.isOnline text: qsTr("GPU Layers") - helpText: qsTr("How many GPU layers to load into VRAM") + helpText: qsTr("Number of model layers to load into VRAM.") Layout.row: 4 Layout.column: 0 } @@ -755,7 +721,7 @@ MySettingsTab { text: root.currentModelInfo.gpuLayers font.pixelSize: theme.fontSizeLarge color: theme.textColor - ToolTip.text: qsTr("How many GPU layers to load into VRAM. Decrease this if GPT4All runs out of VRAM while loading this model.\nLower values increase CPU load and RAM usage, and make inference slower.\nNOTE: Does not take effect until you reload the model.") + ToolTip.text: qsTr("How many model layers to load into VRAM. Decrease this if GPT4All runs out of VRAM while loading this model.\nLower values increase CPU load and RAM usage, and make inference slower.\nNOTE: Does not take effect until you reload the model.") ToolTip.visible: hovered Layout.row: 4 Layout.column: 1 diff --git a/gpt4all-chat/qml/ModelsView.qml b/gpt4all-chat/qml/ModelsView.qml index 6570edb5..b7e34f00 100644 --- a/gpt4all-chat/qml/ModelsView.qml +++ b/gpt4all-chat/qml/ModelsView.qml @@ -180,13 +180,13 @@ Rectangle { Layout.rightMargin: 20 Text { text: qsTr("File size") - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall color: theme.mutedDarkTextColor } Text { text: filesize color: theme.textColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall font.bold: true } } @@ -202,13 +202,13 @@ Rectangle { Layout.rightMargin: 20 Text { text: qsTr("RAM required") - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall color: theme.mutedDarkTextColor } Text { text: ramrequired + qsTr(" GB") color: theme.textColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall font.bold: true } } @@ -224,13 +224,13 @@ Rectangle { Layout.rightMargin: 20 Text { text: qsTr("Parameters") - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall color: theme.mutedDarkTextColor } Text { text: parameters color: theme.textColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall font.bold: true } } @@ -246,13 +246,13 @@ Rectangle { Layout.rightMargin: 20 Text { text: qsTr("Quant") - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall color: theme.mutedDarkTextColor } Text { text: quant color: theme.textColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall font.bold: true } } @@ -268,13 +268,13 @@ Rectangle { Layout.rightMargin: 20 Text { text: qsTr("Type") - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall color: theme.mutedDarkTextColor } Text { text: type color: theme.textColor - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeSmall font.bold: true } } diff --git a/gpt4all-chat/qml/MySettingsLabel.qml b/gpt4all-chat/qml/MySettingsLabel.qml index dd06b891..282bdc73 100644 --- a/gpt4all-chat/qml/MySettingsLabel.qml +++ b/gpt4all-chat/qml/MySettingsLabel.qml @@ -20,7 +20,7 @@ ColumnLayout { Label { id: mainTextLabel color: theme.settingsTitleTextColor - font.pixelSize: theme.fontSizeSmall + font.pixelSize: theme.fontSizeLarger font.bold: true onLinkActivated: function(link) { root.linkActivated(link); @@ -28,12 +28,13 @@ ColumnLayout { } Label { id: helpTextLabel + visible: text !== "" Layout.fillWidth: true wrapMode: Text.Wrap color: theme.settingsTitleTextColor - text: mainTextLabel.text - font.pixelSize: theme.fontSizeSmaller + font.pixelSize: theme.fontSizeLarge font.bold: false + onLinkActivated: function(link) { root.linkActivated(link); } diff --git a/gpt4all-chat/qml/MyTextButton.qml b/gpt4all-chat/qml/MyTextButton.qml new file mode 100644 index 00000000..5eb6ccca --- /dev/null +++ b/gpt4all-chat/qml/MyTextButton.qml @@ -0,0 +1,19 @@ +import QtQuick +import QtQuick.Controls + +Text { + id: text + + signal click() + property string tooltip + + HoverHandler { id: hoverHandler } + TapHandler { onTapped: { click() } } + + font.bold: true + font.underline: hoverHandler.hovered + font.pixelSize: theme.fontSizeSmall + ToolTip.text: tooltip + ToolTip.visible: tooltip !== "" && hoverHandler.hovered + ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval +} diff --git a/gpt4all-chat/qml/MyToolButton.qml b/gpt4all-chat/qml/MyToolButton.qml index db36914a..b9d8c544 100644 --- a/gpt4all-chat/qml/MyToolButton.qml +++ b/gpt4all-chat/qml/MyToolButton.qml @@ -33,7 +33,7 @@ Button { visible: myButton.toggled border.color: myButton.toggledColor border.width: myButton.toggledWidth - radius: 10 + radius: 8 } Image { id: image diff --git a/gpt4all-chat/qml/Theme.qml b/gpt4all-chat/qml/Theme.qml index 79a20ad4..1220c23c 100644 --- a/gpt4all-chat/qml/Theme.qml +++ b/gpt4all-chat/qml/Theme.qml @@ -1058,19 +1058,17 @@ QtObject { } } - property real fontSizeLargeCapped: MySettings.fontSize === "Small" ? 12 : 17 + property real fontScale: MySettings.fontSize === "Small" ? 1 : + MySettings.fontSize === "Medium" ? 1.3 : + /* "Large" */ 1.8 - property real fontSizeLarge: MySettings.fontSize === "Small" ? 12 : - MySettings.fontSize === "Medium" ? 17 : - 22 - - property real fontSizeLargest: MySettings.fontSize === "Small" ? 19 : - MySettings.fontSize === "Medium" ? 24 : - 26 - - property real fontSizeSmaller: fontSizeLarge - 4 - property real fontSizeSmall: fontSizeLarge - 2 - property real fontSizeLarger: fontSizeLarge + 2 - property real fontSizeBannerSmall: fontSizeLargest + 10 - property real fontSizeBanner: fontSizeLargest + 40 + property real fontSizeSmallest: 8 * fontScale + property real fontSizeSmaller: 9 * fontScale + property real fontSizeSmall: 10 * fontScale + property real fontSizeMedium: 11 * fontScale + property real fontSizeLarge: 12 * fontScale + property real fontSizeLarger: 14 * fontScale + property real fontSizeLargest: 18 * fontScale + property real fontSizeBannerSmall: 24 * fontScale**.8 + property real fontSizeBanner: 48 * fontScale**.8 }