UI and embedding device changes for GPT4All v3.0.0-rc3 (#2477)

Signed-off-by: Jared Van Bortel <jared@nomic.ai>
This commit is contained in:
Jared Van Bortel 2024-06-28 12:57:57 -04:00 committed by GitHub
parent 426aa5eb47
commit 2c8d634b5b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 661 additions and 562 deletions

View File

@ -132,39 +132,40 @@ qt_add_qml_module(chat
main.qml main.qml
qml/AddCollectionView.qml qml/AddCollectionView.qml
qml/AddModelView.qml qml/AddModelView.qml
qml/ApplicationSettings.qml
qml/ChatDrawer.qml qml/ChatDrawer.qml
qml/ChatView.qml qml/ChatView.qml
qml/CollectionsDrawer.qml qml/CollectionsDrawer.qml
qml/HomeView.qml qml/HomeView.qml
qml/LocalDocsSettings.qml
qml/LocalDocsView.qml
qml/ModelSettings.qml
qml/ModelsView.qml qml/ModelsView.qml
qml/NetworkDialog.qml qml/NetworkDialog.qml
qml/NewVersionDialog.qml qml/NewVersionDialog.qml
qml/ThumbsDownDialog.qml qml/PopupDialog.qml
qml/SettingsView.qml qml/SettingsView.qml
qml/StartupDialog.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/SwitchModelDialog.qml
qml/MySettingsTab.qml qml/Theme.qml
qml/MySettingsStack.qml qml/ThumbsDownDialog.qml
qml/MySettingsDestructiveButton.qml qml/MyBusyIndicator.qml
qml/MySettingsButton.qml
qml/MySettingsLabel.qml
qml/MySlug.qml
qml/MyButton.qml qml/MyButton.qml
qml/MyCheckBox.qml
qml/MyComboBox.qml qml/MyComboBox.qml
qml/MyDialog.qml qml/MyDialog.qml
qml/MyDirectoryField.qml qml/MyDirectoryField.qml
qml/MyFancyLink.qml qml/MyFancyLink.qml
qml/MyTextArea.qml
qml/MyTextField.qml
qml/MyCheckBox.qml
qml/MyBusyIndicator.qml
qml/MyMiniButton.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/MyToolButton.qml
qml/MyWelcomeButton.qml qml/MyWelcomeButton.qml
RESOURCES RESOURCES

View File

@ -17,7 +17,6 @@
#include <QMutexLocker> #include <QMutexLocker>
#include <QSet> #include <QSet>
#include <QStringList> #include <QStringList>
#include <QVariantMap>
#include <QWaitCondition> #include <QWaitCondition>
#include <Qt> #include <Qt>
#include <QtLogging> #include <QtLogging>
@ -340,181 +339,8 @@ bool ChatLLM::loadModel(const ModelInfo &modelInfo)
model->setRequestURL(modelInfo.url()); model->setRequestURL(modelInfo.url());
model->setAPIKey(apiKey); model->setAPIKey(apiKey);
m_llModelInfo.resetModel(this, model); m_llModelInfo.resetModel(this, model);
} else { } else if (!loadNewModel(modelInfo, modelLoadProps)) {
QElapsedTimer modelLoadTimer; return false; // m_shouldBeLoaded became false
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<QString> 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<float>::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<LLModel::GPUDevice> 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));
}
} }
#if defined(DEBUG_MODEL_LOADING) #if defined(DEBUG_MODEL_LOADING)
qDebug() << "new model" << m_llmThread.objectName() << m_llModelInfo.model.get(); 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); 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<float>::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<QString> 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<LLModel::GPUDevice> 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 bool ChatLLM::isModelLoaded() const
{ {
return m_llModelInfo.model && m_llModelInfo.model->isModelLoaded(); return m_llModelInfo.model && m_llModelInfo.model->isModelLoaded();

View File

@ -14,6 +14,7 @@
#include <QPair> #include <QPair>
#include <QString> #include <QString>
#include <QThread> #include <QThread>
#include <QVariantMap>
#include <QVector> #include <QVector>
#include <QtGlobal> #include <QtGlobal>
@ -214,6 +215,8 @@ protected:
quint32 m_promptResponseTokens; quint32 m_promptResponseTokens;
private: private:
bool loadNewModel(const ModelInfo &modelInfo, QVariantMap &modelLoadProps);
std::string m_response; std::string m_response;
std::string m_nameResponse; std::string m_nameResponse;
LLModelInfo m_llModelInfo; LLModelInfo m_llModelInfo;

View File

@ -26,6 +26,7 @@
#include <exception> #include <exception>
#include <utility> #include <utility>
#include <vector>
using namespace Qt::Literals::StringLiterals; using namespace Qt::Literals::StringLiterals;
@ -63,9 +64,13 @@ void EmbeddingLLMWorker::wait()
bool EmbeddingLLMWorker::loadModel() bool EmbeddingLLMWorker::loadModel()
{ {
constexpr int n_ctx = 2048;
m_nomicAPIKey.clear(); m_nomicAPIKey.clear();
m_model = nullptr; m_model = nullptr;
// TODO(jared): react to setting changes without restarting
if (MySettings::globalInstance()->localDocsUseRemoteEmbed()) { if (MySettings::globalInstance()->localDocsUseRemoteEmbed()) {
m_nomicAPIKey = MySettings::globalInstance()->localDocsNomicAPIKey(); m_nomicAPIKey = MySettings::globalInstance()->localDocsNomicAPIKey();
return true; return true;
@ -79,29 +84,86 @@ bool EmbeddingLLMWorker::loadModel()
QString filePath = embPathFmt.arg(QCoreApplication::applicationDirPath(), LOCAL_EMBEDDING_MODEL); QString filePath = embPathFmt.arg(QCoreApplication::applicationDirPath(), LOCAL_EMBEDDING_MODEL);
if (!QFileInfo::exists(filePath)) { if (!QFileInfo::exists(filePath)) {
qWarning() << "WARNING: Local embedding model not found"; qWarning() << "embllm WARNING: Local embedding model not found";
return false; 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 { try {
m_model = LLModel::Implementation::construct(filePath.toStdString()); m_model = LLModel::Implementation::construct(filePath.toStdString(), backend, n_ctx);
} catch (const std::exception &e) { } 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; return false;
} }
// NOTE: explicitly loads model on CPU to avoid GPU OOM bool actualDeviceIsCPU = true;
// TODO(cebtenzzre): support GPU-accelerated embeddings
bool success = m_model->loadModel(filePath.toStdString(), 2048, 0); #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<LLModel::GPUDevice> 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) { if (!success) {
qWarning() << "WARNING: Could not load embedding model"; qWarning() << "embllm WARNING: Could not load embedding model";
delete m_model; delete m_model;
m_model = nullptr; m_model = nullptr;
return false; return false;
} }
if (!m_model->supportsEmbedding()) { if (!m_model->supportsEmbedding()) {
qWarning() << "WARNING: Model type does not support embeddings"; qWarning() << "embllm WARNING: Model type does not support embeddings";
delete m_model; delete m_model;
m_model = nullptr; m_model = nullptr;
return false; return false;
@ -128,7 +190,7 @@ std::vector<float> EmbeddingLLMWorker::generateQueryEmbedding(const QString &tex
std::vector<float> embedding(m_model->embeddingSize()); std::vector<float> embedding(m_model->embeddingSize());
try { try {
m_model->embed({text.toStdString()}, embedding.data(), true); m_model->embed({text.toStdString()}, embedding.data(), /*isRetrieval*/ true);
} catch (const std::exception &e) { } catch (const std::exception &e) {
qWarning() << "WARNING: LLModel::embed failed:" << e.what(); qWarning() << "WARNING: LLModel::embed failed:" << e.what();
return {}; return {};
@ -203,26 +265,34 @@ void EmbeddingLLMWorker::docEmbeddingsRequested(const QVector<EmbeddingChunk> &c
if (!isNomic) { if (!isNomic) {
QVector<EmbeddingResult> results; QVector<EmbeddingResult> results;
results.reserve(chunks.size()); results.reserve(chunks.size());
std::vector<std::string> texts;
texts.reserve(chunks.size());
for (const auto &c: chunks) { for (const auto &c: chunks) {
EmbeddingResult result; EmbeddingResult result;
result.model = c.model; result.model = c.model;
result.folder_id = c.folder_id; result.folder_id = c.folder_id;
result.chunk_id = c.chunk_id; result.chunk_id = c.chunk_id;
// TODO(cebtenzzre): take advantage of batched embeddings
result.embedding.resize(m_model->embeddingSize()); 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; results << result;
texts.push_back(c.chunk.toStdString());
} }
constexpr int BATCH_SIZE = 4;
std::vector<float> 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); emit embeddingsGenerated(results);
return; return;
}; };

View File

@ -204,7 +204,7 @@ Window {
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
width: MySettings.fontSize === "Small" ? 86 : 100 width: 16 + 52 * theme.fontScale
color: theme.viewBarBackground color: theme.viewBarBackground
ColumnLayout { ColumnLayout {
@ -213,20 +213,20 @@ Window {
anchors.topMargin: 30 anchors.topMargin: 30
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
Layout.margins: 0 Layout.margins: 0
spacing: 18 spacing: 16
MyToolButton { MyToolButton {
id: homeButton id: homeButton
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
backgroundColorHovered: theme.iconBackgroundViewBarHovered backgroundColorHovered: theme.iconBackgroundViewBarHovered
Layout.preferredWidth: 48 Layout.preferredWidth: 38 * theme.fontScale
Layout.preferredHeight: 48 Layout.preferredHeight: 38 * theme.fontScale
Layout.alignment: Qt.AlignCenter Layout.alignment: Qt.AlignCenter
toggledWidth: 0 toggledWidth: 0
toggled: homeView.isShown() toggled: homeView.isShown()
toggledColor: theme.iconBackgroundViewBarToggled toggledColor: theme.iconBackgroundViewBarToggled
imageWidth: 34 imageWidth: 25 * theme.fontScale
imageHeight: 34 imageHeight: 25 * theme.fontScale
source: "qrc:/gpt4all/icons/home.svg" source: "qrc:/gpt4all/icons/home.svg"
Accessible.name: qsTr("Home view") Accessible.name: qsTr("Home view")
Accessible.description: qsTr("Home view of application") Accessible.description: qsTr("Home view of application")
@ -238,10 +238,10 @@ Window {
Text { Text {
Layout.topMargin: -20 Layout.topMargin: -20
text: qsTr("Home") text: qsTr("Home")
font.pixelSize: theme.fontSizeLargeCapped font.pixelSize: theme.fontSizeMedium
font.bold: true font.bold: true
color: homeButton.hovered ? homeButton.backgroundColorHovered : homeButton.backgroundColor color: homeButton.hovered ? homeButton.backgroundColorHovered : homeButton.backgroundColor
Layout.preferredWidth: 48 Layout.preferredWidth: 38 * theme.fontScale
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
TapHandler { TapHandler {
onTapped: function(eventPoint, button) { onTapped: function(eventPoint, button) {
@ -254,14 +254,14 @@ Window {
id: chatButton id: chatButton
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
backgroundColorHovered: theme.iconBackgroundViewBarHovered backgroundColorHovered: theme.iconBackgroundViewBarHovered
Layout.preferredWidth: 48 Layout.preferredWidth: 38 * theme.fontScale
Layout.preferredHeight: 48 Layout.preferredHeight: 38 * theme.fontScale
Layout.alignment: Qt.AlignCenter Layout.alignment: Qt.AlignCenter
toggledWidth: 0 toggledWidth: 0
toggled: chatView.isShown() toggled: chatView.isShown()
toggledColor: theme.iconBackgroundViewBarToggled toggledColor: theme.iconBackgroundViewBarToggled
imageWidth: 34 imageWidth: 25 * theme.fontScale
imageHeight: 34 imageHeight: 25 * theme.fontScale
source: "qrc:/gpt4all/icons/chat.svg" source: "qrc:/gpt4all/icons/chat.svg"
Accessible.name: qsTr("Chat view") Accessible.name: qsTr("Chat view")
Accessible.description: qsTr("Chat view to interact with models") Accessible.description: qsTr("Chat view to interact with models")
@ -273,10 +273,10 @@ Window {
Text { Text {
Layout.topMargin: -20 Layout.topMargin: -20
text: qsTr("Chats") text: qsTr("Chats")
font.pixelSize: theme.fontSizeLargeCapped font.pixelSize: theme.fontSizeMedium
font.bold: true font.bold: true
color: chatButton.hovered ? chatButton.backgroundColorHovered : chatButton.backgroundColor color: chatButton.hovered ? chatButton.backgroundColorHovered : chatButton.backgroundColor
Layout.preferredWidth: 48 Layout.preferredWidth: 38 * theme.fontScale
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
TapHandler { TapHandler {
onTapped: function(eventPoint, button) { onTapped: function(eventPoint, button) {
@ -289,13 +289,13 @@ Window {
id: modelsButton id: modelsButton
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
backgroundColorHovered: theme.iconBackgroundViewBarHovered backgroundColorHovered: theme.iconBackgroundViewBarHovered
Layout.preferredWidth: 48 Layout.preferredWidth: 38 * theme.fontScale
Layout.preferredHeight: 48 Layout.preferredHeight: 38 * theme.fontScale
toggledWidth: 0 toggledWidth: 0
toggled: modelsView.isShown() toggled: modelsView.isShown()
toggledColor: theme.iconBackgroundViewBarToggled toggledColor: theme.iconBackgroundViewBarToggled
imageWidth: 34 imageWidth: 25 * theme.fontScale
imageHeight: 34 imageHeight: 25 * theme.fontScale
source: "qrc:/gpt4all/icons/models.svg" source: "qrc:/gpt4all/icons/models.svg"
Accessible.name: qsTr("Models") Accessible.name: qsTr("Models")
Accessible.description: qsTr("Models view for installed models") Accessible.description: qsTr("Models view for installed models")
@ -307,10 +307,10 @@ Window {
Text { Text {
Layout.topMargin: -20 Layout.topMargin: -20
text: qsTr("Models") text: qsTr("Models")
font.pixelSize: theme.fontSizeLargeCapped font.pixelSize: theme.fontSizeMedium
font.bold: true font.bold: true
color: modelsButton.hovered ? modelsButton.backgroundColorHovered : modelsButton.backgroundColor color: modelsButton.hovered ? modelsButton.backgroundColorHovered : modelsButton.backgroundColor
Layout.preferredWidth: 48 Layout.preferredWidth: 38 * theme.fontScale
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
TapHandler { TapHandler {
onTapped: function(eventPoint, button) { onTapped: function(eventPoint, button) {
@ -323,13 +323,13 @@ Window {
id: localdocsButton id: localdocsButton
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
backgroundColorHovered: theme.iconBackgroundViewBarHovered backgroundColorHovered: theme.iconBackgroundViewBarHovered
Layout.preferredWidth: 48 Layout.preferredWidth: 38 * theme.fontScale
Layout.preferredHeight: 48 Layout.preferredHeight: 38 * theme.fontScale
toggledWidth: 0 toggledWidth: 0
toggledColor: theme.iconBackgroundViewBarToggled toggledColor: theme.iconBackgroundViewBarToggled
toggled: localDocsView.isShown() toggled: localDocsView.isShown()
imageWidth: 34 imageWidth: 25 * theme.fontScale
imageHeight: 34 imageHeight: 25 * theme.fontScale
source: "qrc:/gpt4all/icons/db.svg" source: "qrc:/gpt4all/icons/db.svg"
Accessible.name: qsTr("LocalDocs") Accessible.name: qsTr("LocalDocs")
Accessible.description: qsTr("LocalDocs view to configure and use local docs") Accessible.description: qsTr("LocalDocs view to configure and use local docs")
@ -341,10 +341,10 @@ Window {
Text { Text {
Layout.topMargin: -20 Layout.topMargin: -20
text: qsTr("LocalDocs") text: qsTr("LocalDocs")
font.pixelSize: theme.fontSizeLargeCapped font.pixelSize: theme.fontSizeMedium
font.bold: true font.bold: true
color: localdocsButton.hovered ? localdocsButton.backgroundColorHovered : localdocsButton.backgroundColor color: localdocsButton.hovered ? localdocsButton.backgroundColorHovered : localdocsButton.backgroundColor
Layout.preferredWidth: 48 Layout.preferredWidth: 38 * theme.fontScale
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
TapHandler { TapHandler {
onTapped: function(eventPoint, button) { onTapped: function(eventPoint, button) {
@ -357,13 +357,13 @@ Window {
id: settingsButton id: settingsButton
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
backgroundColorHovered: theme.iconBackgroundViewBarHovered backgroundColorHovered: theme.iconBackgroundViewBarHovered
Layout.preferredWidth: 48 Layout.preferredWidth: 38 * theme.fontScale
Layout.preferredHeight: 48 Layout.preferredHeight: 38 * theme.fontScale
toggledWidth: 0 toggledWidth: 0
toggledColor: theme.iconBackgroundViewBarToggled toggledColor: theme.iconBackgroundViewBarToggled
toggled: settingsView.isShown() toggled: settingsView.isShown()
imageWidth: 34 imageWidth: 25 * theme.fontScale
imageHeight: 34 imageHeight: 25 * theme.fontScale
source: "qrc:/gpt4all/icons/settings.svg" source: "qrc:/gpt4all/icons/settings.svg"
Accessible.name: qsTr("Settings") Accessible.name: qsTr("Settings")
Accessible.description: qsTr("Settings view for application configuration") Accessible.description: qsTr("Settings view for application configuration")
@ -375,10 +375,10 @@ Window {
Text { Text {
Layout.topMargin: -20 Layout.topMargin: -20
text: qsTr("Settings") text: qsTr("Settings")
font.pixelSize: theme.fontSizeLargeCapped font.pixelSize: theme.fontSizeMedium
font.bold: true font.bold: true
color: settingsButton.hovered ? settingsButton.backgroundColorHovered : settingsButton.backgroundColor color: settingsButton.hovered ? settingsButton.backgroundColorHovered : settingsButton.backgroundColor
Layout.preferredWidth: 48 Layout.preferredWidth: 38 * theme.fontScale
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
TapHandler { TapHandler {
onTapped: function(eventPoint, button) { onTapped: function(eventPoint, button) {

View File

@ -47,6 +47,7 @@ static const QVariantMap basicDefaults {
{ "localdocs/fileExtensions", QStringList { "txt", "pdf", "md", "rst" } }, { "localdocs/fileExtensions", QStringList { "txt", "pdf", "md", "rst" } },
{ "localdocs/useRemoteEmbed", false }, { "localdocs/useRemoteEmbed", false },
{ "localdocs/nomicAPIKey", "" }, { "localdocs/nomicAPIKey", "" },
{ "localdocs/embedDevice", "Auto" },
{ "network/attribution", "" }, { "network/attribution", "" },
}; };
@ -77,6 +78,22 @@ static QString defaultLocalModelsPath()
return canonicalLocalPath; return canonicalLocalPath;
} }
static QStringList getDevices(bool skipKompute = false)
{
QStringList deviceList { "Auto" };
#if defined(Q_OS_MAC) && defined(__aarch64__)
deviceList << "Metal";
#else
std::vector<LLModel::GPUDevice> 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 { }; class MyPrivateSettings: public MySettings { };
Q_GLOBAL_STATIC(MyPrivateSettings, settingsInstance) Q_GLOBAL_STATIC(MyPrivateSettings, settingsInstance)
MySettings *MySettings::globalInstance() MySettings *MySettings::globalInstance()
@ -85,18 +102,10 @@ MySettings *MySettings::globalInstance()
} }
MySettings::MySettings() MySettings::MySettings()
: QObject{nullptr} : QObject(nullptr)
, m_deviceList(getDevices())
, m_embeddingsDeviceList(getDevices(/*skipKompute*/ true))
{ {
QVector<QString> deviceList{ "Auto" };
#if defined(Q_OS_MAC) && defined(__aarch64__)
deviceList << "Metal";
#else
std::vector<LLModel::GPUDevice> 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 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()); QMetaObject::invokeMethod(this, u"%1Changed"_s.arg(signal.value_or(name)).toLatin1().constData());
} }
Q_INVOKABLE QVector<QString> MySettings::deviceList() const
{
return m_deviceList;
}
void MySettings::setDeviceList(const QVector<QString> &value)
{
m_deviceList = value;
emit deviceListChanged();
}
void MySettings::restoreModelDefaults(const ModelInfo &info) void MySettings::restoreModelDefaults(const ModelInfo &info)
{ {
setModelTemperature(info, info.m_temperature); setModelTemperature(info, info.m_temperature);
@ -162,6 +160,7 @@ void MySettings::restoreLocalDocsDefaults()
setLocalDocsFileExtensions(basicDefaults.value("localdocs/fileExtensions").toStringList()); setLocalDocsFileExtensions(basicDefaults.value("localdocs/fileExtensions").toStringList());
setLocalDocsUseRemoteEmbed(basicDefaults.value("localdocs/useRemoteEmbed").toBool()); setLocalDocsUseRemoteEmbed(basicDefaults.value("localdocs/useRemoteEmbed").toBool());
setLocalDocsNomicAPIKey(basicDefaults.value("localdocs/nomicAPIKey").toString()); setLocalDocsNomicAPIKey(basicDefaults.value("localdocs/nomicAPIKey").toString());
setLocalDocsEmbedDevice(basicDefaults.value("localdocs/embedDevice").toString());
} }
void MySettings::eraseModel(const ModelInfo &info) 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(); } QStringList MySettings::localDocsFileExtensions() const { return getBasicSetting("localdocs/fileExtensions").toStringList(); }
bool MySettings::localDocsUseRemoteEmbed() const { return getBasicSetting("localdocs/useRemoteEmbed").toBool(); } bool MySettings::localDocsUseRemoteEmbed() const { return getBasicSetting("localdocs/useRemoteEmbed").toBool(); }
QString MySettings::localDocsNomicAPIKey() const { return getBasicSetting("localdocs/nomicAPIKey" ).toString(); } 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(); } QString MySettings::networkAttribution() const { return getBasicSetting("network/attribution" ).toString(); }
void MySettings::setSaveChatsContext(bool value) { setBasicSetting("saveChatsContext", value); } 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::setLocalDocsFileExtensions(const QStringList &value) { setBasicSetting("localdocs/fileExtensions", value, "localDocsFileExtensions"); }
void MySettings::setLocalDocsUseRemoteEmbed(bool value) { setBasicSetting("localdocs/useRemoteEmbed", value, "localDocsUseRemoteEmbed"); } void MySettings::setLocalDocsUseRemoteEmbed(bool value) { setBasicSetting("localdocs/useRemoteEmbed", value, "localDocsUseRemoteEmbed"); }
void MySettings::setLocalDocsNomicAPIKey(const QString &value) { setBasicSetting("localdocs/nomicAPIKey", value, "localDocsNomicAPIKey"); } 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"); } void MySettings::setNetworkAttribution(const QString &value) { setBasicSetting("network/attribution", value, "networkAttribution"); }
QString MySettings::modelPath() QString MySettings::modelPath()
@ -446,11 +447,10 @@ QString MySettings::device()
void MySettings::setDevice(const QString &value) void MySettings::setDevice(const QString &value)
{ {
if (device() == value) if (device() != value) {
return; m_settings.setValue("device", value);
emit deviceChanged();
m_settings.setValue("device", value); }
emit deviceChanged();
} }
bool MySettings::forceMetal() const bool MySettings::forceMetal() const
@ -460,10 +460,10 @@ bool MySettings::forceMetal() const
void MySettings::setForceMetal(bool value) void MySettings::setForceMetal(bool value)
{ {
if (m_forceMetal == value) if (m_forceMetal != value) {
return; m_forceMetal = value;
m_forceMetal = value; emit forceMetalChanged(value);
emit forceMetalChanged(value); }
} }
bool MySettings::networkIsActive() const bool MySettings::networkIsActive() const

View File

@ -31,11 +31,13 @@ class MySettings : public QObject
Q_PROPERTY(QStringList localDocsFileExtensions READ localDocsFileExtensions WRITE setLocalDocsFileExtensions NOTIFY localDocsFileExtensionsChanged) Q_PROPERTY(QStringList localDocsFileExtensions READ localDocsFileExtensions WRITE setLocalDocsFileExtensions NOTIFY localDocsFileExtensionsChanged)
Q_PROPERTY(bool localDocsUseRemoteEmbed READ localDocsUseRemoteEmbed WRITE setLocalDocsUseRemoteEmbed NOTIFY localDocsUseRemoteEmbedChanged) Q_PROPERTY(bool localDocsUseRemoteEmbed READ localDocsUseRemoteEmbed WRITE setLocalDocsUseRemoteEmbed NOTIFY localDocsUseRemoteEmbedChanged)
Q_PROPERTY(QString localDocsNomicAPIKey READ localDocsNomicAPIKey WRITE setLocalDocsNomicAPIKey NOTIFY localDocsNomicAPIKeyChanged) 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(QString networkAttribution READ networkAttribution WRITE setNetworkAttribution NOTIFY networkAttributionChanged)
Q_PROPERTY(bool networkIsActive READ networkIsActive WRITE setNetworkIsActive NOTIFY networkIsActiveChanged) Q_PROPERTY(bool networkIsActive READ networkIsActive WRITE setNetworkIsActive NOTIFY networkIsActiveChanged)
Q_PROPERTY(bool networkUsageStatsActive READ networkUsageStatsActive WRITE setNetworkUsageStatsActive NOTIFY networkUsageStatsActiveChanged) Q_PROPERTY(bool networkUsageStatsActive READ networkUsageStatsActive WRITE setNetworkUsageStatsActive NOTIFY networkUsageStatsActiveChanged)
Q_PROPERTY(QString device READ device WRITE setDevice NOTIFY deviceChanged) Q_PROPERTY(QString device READ device WRITE setDevice NOTIFY deviceChanged)
Q_PROPERTY(QVector<QString> 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) Q_PROPERTY(int networkPort READ networkPort WRITE setNetworkPort NOTIFY networkPortChanged)
public: public:
@ -138,6 +140,8 @@ public:
void setLocalDocsUseRemoteEmbed(bool value); void setLocalDocsUseRemoteEmbed(bool value);
QString localDocsNomicAPIKey() const; QString localDocsNomicAPIKey() const;
void setLocalDocsNomicAPIKey(const QString &value); void setLocalDocsNomicAPIKey(const QString &value);
QString localDocsEmbedDevice() const;
void setLocalDocsEmbedDevice(const QString &value);
// Network settings // Network settings
QString networkAttribution() const; QString networkAttribution() const;
@ -151,9 +155,6 @@ public:
int networkPort() const; int networkPort() const;
void setNetworkPort(int value); void setNetworkPort(int value);
QVector<QString> deviceList() const;
void setDeviceList(const QVector<QString> &value);
Q_SIGNALS: Q_SIGNALS:
void nameChanged(const ModelInfo &info); void nameChanged(const ModelInfo &info);
void filenameChanged(const ModelInfo &info); void filenameChanged(const ModelInfo &info);
@ -185,18 +186,19 @@ Q_SIGNALS:
void localDocsFileExtensionsChanged(); void localDocsFileExtensionsChanged();
void localDocsUseRemoteEmbedChanged(); void localDocsUseRemoteEmbedChanged();
void localDocsNomicAPIKeyChanged(); void localDocsNomicAPIKeyChanged();
void localDocsEmbedDeviceChanged();
void networkAttributionChanged(); void networkAttributionChanged();
void networkIsActiveChanged(); void networkIsActiveChanged();
void networkPortChanged(); void networkPortChanged();
void networkUsageStatsActiveChanged(); void networkUsageStatsActiveChanged();
void attemptModelLoadChanged(); void attemptModelLoadChanged();
void deviceChanged(); void deviceChanged();
void deviceListChanged();
private: private:
QSettings m_settings; QSettings m_settings;
bool m_forceMetal; bool m_forceMetal;
QVector<QString> m_deviceList; const QStringList m_deviceList;
const QStringList m_embeddingsDeviceList;
private: private:
explicit MySettings(); explicit MySettings();

View File

@ -603,13 +603,13 @@ Rectangle {
Layout.rightMargin: 20 Layout.rightMargin: 20
Text { Text {
text: qsTr("File size") text: qsTr("File size")
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
color: theme.mutedDarkTextColor color: theme.mutedDarkTextColor
} }
Text { Text {
text: filesize text: filesize
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
font.bold: true font.bold: true
} }
} }
@ -625,13 +625,13 @@ Rectangle {
Layout.rightMargin: 20 Layout.rightMargin: 20
Text { Text {
text: qsTr("RAM required") text: qsTr("RAM required")
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
color: theme.mutedDarkTextColor color: theme.mutedDarkTextColor
} }
Text { Text {
text: ramrequired >= 0 ? ramrequired + qsTr(" GB") : "?" text: ramrequired >= 0 ? ramrequired + qsTr(" GB") : "?"
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
font.bold: true font.bold: true
} }
} }
@ -647,13 +647,13 @@ Rectangle {
Layout.rightMargin: 20 Layout.rightMargin: 20
Text { Text {
text: qsTr("Parameters") text: qsTr("Parameters")
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
color: theme.mutedDarkTextColor color: theme.mutedDarkTextColor
} }
Text { Text {
text: parameters !== "" ? parameters : "?" text: parameters !== "" ? parameters : "?"
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
font.bold: true font.bold: true
} }
} }
@ -669,13 +669,13 @@ Rectangle {
Layout.rightMargin: 20 Layout.rightMargin: 20
Text { Text {
text: qsTr("Quant") text: qsTr("Quant")
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
color: theme.mutedDarkTextColor color: theme.mutedDarkTextColor
} }
Text { Text {
text: quant text: quant
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
font.bold: true font.bold: true
} }
} }
@ -691,13 +691,13 @@ Rectangle {
Layout.rightMargin: 20 Layout.rightMargin: 20
Text { Text {
text: qsTr("Type") text: qsTr("Type")
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
color: theme.mutedDarkTextColor color: theme.mutedDarkTextColor
} }
Text { Text {
text: type text: type
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
font.bold: true font.bold: true
} }
} }

View File

@ -62,9 +62,19 @@ MySettingsTab {
rowSpacing: 30 rowSpacing: 30
columnSpacing: 10 columnSpacing: 10
ColumnLayout { Label {
Layout.row: 0 Layout.row: 0
Layout.column: 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.columnSpan: 3
Layout.fillWidth: true Layout.fillWidth: true
spacing: 10 spacing: 10
@ -72,7 +82,7 @@ MySettingsTab {
color: theme.styledTextColor color: theme.styledTextColor
font.pixelSize: theme.fontSizeLarge font.pixelSize: theme.fontSizeLarge
font.bold: true font.bold: true
text: "General" text: qsTr("General")
} }
Rectangle { Rectangle {
@ -85,22 +95,21 @@ MySettingsTab {
MySettingsLabel { MySettingsLabel {
id: themeLabel id: themeLabel
text: qsTr("Theme") text: qsTr("Theme")
helpText: qsTr("Customize the colors of GPT4All") helpText: qsTr("The application color scheme.")
Layout.row: 1 Layout.row: 2
Layout.column: 0 Layout.column: 0
} }
MyComboBox { MyComboBox {
id: themeBox id: themeBox
Layout.row: 1 Layout.row: 2
Layout.column: 2 Layout.column: 2
Layout.minimumWidth: 200 Layout.minimumWidth: 200
Layout.maximumWidth: 200 Layout.maximumWidth: 200
Layout.fillWidth: false Layout.fillWidth: false
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
model: [qsTr("Dark"), qsTr("Light"), qsTr("LegacyDark")] model: [qsTr("Dark"), qsTr("Light"), qsTr("LegacyDark")]
Accessible.role: Accessible.ComboBox Accessible.name: themeLabel.text
Accessible.name: qsTr("Color theme") Accessible.description: themeLabel.helpText
Accessible.description: qsTr("Color theme for the chat client to use")
function updateModel() { function updateModel() {
themeBox.currentIndex = themeBox.indexOfValue(MySettings.chatTheme); themeBox.currentIndex = themeBox.indexOfValue(MySettings.chatTheme);
} }
@ -120,22 +129,21 @@ MySettingsTab {
MySettingsLabel { MySettingsLabel {
id: fontLabel id: fontLabel
text: qsTr("Font Size") text: qsTr("Font Size")
helpText: qsTr("How big your font is displayed") helpText: qsTr("The size of text in the application.")
Layout.row: 2 Layout.row: 3
Layout.column: 0 Layout.column: 0
} }
MyComboBox { MyComboBox {
id: fontBox id: fontBox
Layout.row: 2 Layout.row: 3
Layout.column: 2 Layout.column: 2
Layout.minimumWidth: 200 Layout.minimumWidth: 200
Layout.maximumWidth: 200 Layout.maximumWidth: 200
Layout.fillWidth: false Layout.fillWidth: false
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
model: ["Small", "Medium", "Large"] model: ["Small", "Medium", "Large"]
Accessible.role: Accessible.ComboBox Accessible.name: fontLabel.text
Accessible.name: qsTr("Font size") Accessible.description: fontLabel.helpText
Accessible.description: qsTr("Font size of the chat client")
function updateModel() { function updateModel() {
fontBox.currentIndex = fontBox.indexOfValue(MySettings.fontSize); fontBox.currentIndex = fontBox.indexOfValue(MySettings.fontSize);
} }
@ -155,59 +163,54 @@ MySettingsTab {
MySettingsLabel { MySettingsLabel {
id: deviceLabel id: deviceLabel
text: qsTr("Device") text: qsTr("Device")
helpText: qsTr("The hardware device used to load the model") helpText: qsTr('The compute device used for text generation. "Auto" uses Vulkan or Metal.')
Layout.row: 3 Layout.row: 4
Layout.column: 0 Layout.column: 0
} }
MyComboBox { MyComboBox {
id: deviceBox id: deviceBox
Layout.row: 3 Layout.row: 4
Layout.column: 2 Layout.column: 2
Layout.minimumWidth: 400 Layout.minimumWidth: 400
Layout.maximumWidth: 400 Layout.maximumWidth: 400
Layout.fillWidth: false Layout.fillWidth: false
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
model: MySettings.deviceList model: MySettings.deviceList
Accessible.role: Accessible.ComboBox Accessible.name: deviceLabel.text
Accessible.name: qsTr("Device") Accessible.description: deviceLabel.helpText
Accessible.description: qsTr("Device of the chat client")
function updateModel() { function updateModel() {
deviceBox.currentIndex = deviceBox.indexOfValue(MySettings.device); deviceBox.currentIndex = deviceBox.indexOfValue(MySettings.device);
} }
Component.onCompleted: { Component.onCompleted: {
deviceBox.updateModel() deviceBox.updateModel();
} }
Connections { Connections {
target: MySettings target: MySettings
function onDeviceChanged() { function onDeviceChanged() {
deviceBox.updateModel() deviceBox.updateModel();
}
function onDeviceListChanged() {
deviceBox.updateModel()
} }
} }
onActivated: { onActivated: {
MySettings.device = deviceBox.currentText MySettings.device = deviceBox.currentText;
} }
} }
MySettingsLabel { MySettingsLabel {
id: defaultModelLabel id: defaultModelLabel
text: qsTr("Default model") text: qsTr("Default Model")
helpText: qsTr("The preferred default model") helpText: qsTr("The preferred model for new chats. Also used as the local server fallback.")
Layout.row: 4 Layout.row: 5
Layout.column: 0 Layout.column: 0
} }
MyComboBox { MyComboBox {
id: comboBox id: comboBox
Layout.row: 4 Layout.row: 5
Layout.column: 2 Layout.column: 2
Layout.minimumWidth: 400 Layout.minimumWidth: 400
Layout.maximumWidth: 400 Layout.maximumWidth: 400
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
model: ModelList.userDefaultModelList model: ModelList.userDefaultModelList
Accessible.role: Accessible.ComboBox Accessible.name: defaultModelLabel.text
Accessible.name: qsTr("Default model") Accessible.description: defaultModelLabel.helpText
Accessible.description: qsTr("Default model to use; the first item is the current default model")
function updateModel() { function updateModel() {
comboBox.currentIndex = comboBox.indexOfValue(MySettings.userDefaultModel); comboBox.currentIndex = comboBox.indexOfValue(MySettings.userDefaultModel);
} }
@ -226,14 +229,14 @@ MySettingsTab {
} }
MySettingsLabel { MySettingsLabel {
id: modelPathLabel id: modelPathLabel
text: qsTr("Download path") text: qsTr("Download Path")
helpText: qsTr("The download folder for models") helpText: qsTr("Where to store local models and the LocalDocs database.")
Layout.row: 5 Layout.row: 6
Layout.column: 0 Layout.column: 0
} }
RowLayout { RowLayout {
Layout.row: 5 Layout.row: 6
Layout.column: 2 Layout.column: 2
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
Layout.minimumWidth: 400 Layout.minimumWidth: 400
@ -245,11 +248,8 @@ MySettingsTab {
font.pixelSize: theme.fontSizeLarge font.pixelSize: theme.fontSizeLarge
implicitWidth: 300 implicitWidth: 300
Layout.fillWidth: true Layout.fillWidth: true
ToolTip.text: qsTr("Path where model files will be downloaded to") Accessible.name: modelPathLabel.text
ToolTip.visible: hovered Accessible.description: modelPathLabel.helpText
Accessible.role: Accessible.ToolTip
Accessible.name: modelPathDisplayField.text
Accessible.description: ToolTip.text
onEditingFinished: { onEditingFinished: {
if (isValid) { if (isValid) {
MySettings.modelPath = modelPathDisplayField.text MySettings.modelPath = modelPathDisplayField.text
@ -271,29 +271,32 @@ MySettingsTab {
MySettingsLabel { MySettingsLabel {
id: dataLakeLabel id: dataLakeLabel
text: qsTr("Opensource Datalake") text: qsTr("Enable Datalake")
helpText: qsTr("Send your data to the GPT4All Open Source Datalake.") helpText: qsTr("Send chats and feedback to the GPT4All Open-Source Datalake.")
Layout.row: 6 Layout.row: 7
Layout.column: 0 Layout.column: 0
} }
MyCheckBox { MyCheckBox {
id: dataLakeBox id: dataLakeBox
Layout.row: 6 Layout.row: 7
Layout.column: 2 Layout.column: 2
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
checked: MySettings.networkIsActive Component.onCompleted: { dataLakeBox.checked = MySettings.networkIsActive; }
onClicked: { Connections {
if (MySettings.networkIsActive) { target: MySettings
MySettings.networkIsActive = false function onNetworkIsActiveChanged() { dataLakeBox.checked = MySettings.networkIsActive; }
} else }
networkDialog.open() 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 { ColumnLayout {
Layout.row: 7 Layout.row: 8
Layout.column: 0 Layout.column: 0
Layout.columnSpan: 3 Layout.columnSpan: 3
Layout.fillWidth: true Layout.fillWidth: true
@ -302,7 +305,7 @@ MySettingsTab {
color: theme.styledTextColor color: theme.styledTextColor
font.pixelSize: theme.fontSizeLarge font.pixelSize: theme.fontSizeLarge
font.bold: true font.bold: true
text: "Advanced" text: qsTr("Advanced")
} }
Rectangle { Rectangle {
@ -315,18 +318,16 @@ MySettingsTab {
MySettingsLabel { MySettingsLabel {
id: nThreadsLabel id: nThreadsLabel
text: qsTr("CPU Threads") text: qsTr("CPU Threads")
helpText: qsTr("Number of CPU threads for inference and embedding") helpText: qsTr("The number of CPU threads used for inference and embedding.")
Layout.row: 8 Layout.row: 9
Layout.column: 0 Layout.column: 0
} }
MyTextField { MyTextField {
text: MySettings.threadCount text: MySettings.threadCount
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeLarge 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.alignment: Qt.AlignRight
Layout.row: 8 Layout.row: 9
Layout.column: 2 Layout.column: 2
Layout.minimumWidth: 200 Layout.minimumWidth: 200
Layout.maximumWidth: 200 Layout.maximumWidth: 200
@ -348,47 +349,43 @@ MySettingsTab {
} }
MySettingsLabel { MySettingsLabel {
id: saveChatsContextLabel id: saveChatsContextLabel
text: qsTr("Save chat context") text: qsTr("Save Chat Context")
helpText: qsTr("Save chat context to disk") helpText: qsTr("Save the chat model's state to disk for faster loading. WARNING: Uses ~2GB per chat.")
Layout.row: 9 Layout.row: 10
Layout.column: 0 Layout.column: 0
} }
MyCheckBox { MyCheckBox {
id: saveChatsContextBox id: saveChatsContextBox
Layout.row: 9 Layout.row: 10
Layout.column: 2 Layout.column: 2
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
checked: MySettings.saveChatsContext checked: MySettings.saveChatsContext
onClicked: { onClicked: {
MySettings.saveChatsContext = !MySettings.saveChatsContext MySettings.saveChatsContext = !MySettings.saveChatsContext
} }
ToolTip.text: qsTr("WARNING: Saving chats to disk can be ~2GB per chat")
ToolTip.visible: hovered
} }
MySettingsLabel { MySettingsLabel {
id: serverChatLabel id: serverChatLabel
text: qsTr("Enable API server") text: qsTr("Enable Local Server")
helpText: qsTr("A local http server running on local port") helpText: qsTr("Expose an OpenAI-Compatible server to localhost. WARNING: Results in increased resource usage.")
Layout.row: 10 Layout.row: 11
Layout.column: 0 Layout.column: 0
} }
MyCheckBox { MyCheckBox {
id: serverChatBox id: serverChatBox
Layout.row: 10 Layout.row: 11
Layout.column: 2 Layout.column: 2
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
checked: MySettings.serverChat checked: MySettings.serverChat
onClicked: { onClicked: {
MySettings.serverChat = !MySettings.serverChat 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 { MySettingsLabel {
id: serverPortLabel id: serverPortLabel
text: qsTr("API Server Port:") text: qsTr("API Server Port")
helpText: qsTr("A local port to run the server (Requires restart") helpText: qsTr("The port to use for the local server. Requires restart.")
Layout.row: 11 Layout.row: 12
Layout.column: 0 Layout.column: 0
} }
MyTextField { MyTextField {
@ -396,9 +393,7 @@ MySettingsTab {
text: MySettings.networkPort text: MySettings.networkPort
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeLarge font.pixelSize: theme.fontSizeLarge
ToolTip.text: qsTr("Api server port. WARNING: You need to restart the application for it to take effect") Layout.row: 12
ToolTip.visible: hovered
Layout.row: 11
Layout.column: 2 Layout.column: 2
Layout.minimumWidth: 200 Layout.minimumWidth: 200
Layout.maximumWidth: 200 Layout.maximumWidth: 200
@ -416,8 +411,8 @@ MySettingsTab {
} }
} }
Accessible.role: Accessible.EditableText Accessible.role: Accessible.EditableText
Accessible.name: serverPortField.text Accessible.name: serverPortLabel.text
Accessible.description: ToolTip.text Accessible.description: serverPortLabel.helpText
} }
/*MySettingsLabel { /*MySettingsLabel {
@ -441,8 +436,8 @@ MySettingsTab {
MySettingsLabel { MySettingsLabel {
id: updatesLabel id: updatesLabel
text: qsTr("Check for updates") text: qsTr("Check For Updates")
helpText: qsTr("Click to see if an update to the application is available"); helpText: qsTr("Manually check for an update to GPT4All.");
Layout.row: 14 Layout.row: 14
Layout.column: 0 Layout.column: 0
} }

View File

@ -110,7 +110,7 @@ Rectangle {
bottomPadding: 5 bottomPadding: 5
text: parent.section text: parent.section
color: theme.chatDrawerSectionHeader color: theme.chatDrawerSectionHeader
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmallest
} }
} }
} }

View File

@ -365,7 +365,6 @@ Rectangle {
} }
} }
Accessible.role: Accessible.ComboBox
Accessible.name: currentModelName() Accessible.name: currentModelName()
Accessible.description: qsTr("The top item is the current model") Accessible.description: qsTr("The top item is the current model")
onActivated: function (index) { onActivated: function (index) {

View File

@ -89,7 +89,7 @@ Rectangle {
text: "%1 %2".arg(qsTr("%n file(s)", "", model.totalDocs)).arg(qsTr("%n word(s)", "", model.totalWords)) text: "%1 %2".arg(qsTr("%n file(s)", "", model.totalDocs)).arg(qsTr("%n word(s)", "", model.totalWords))
elide: Text.ElideRight elide: Text.ElideRight
color: theme.mutedTextColor color: theme.mutedTextColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
} }
RowLayout { RowLayout {
visible: model.updating visible: model.updating
@ -105,7 +105,7 @@ Rectangle {
text: qsTr("Updating") text: qsTr("Updating")
elide: Text.ElideRight elide: Text.ElideRight
color: theme.accentColor color: theme.accentColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
font.bold: true font.bold: true
} }
} }

View File

@ -36,6 +36,7 @@ Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.maximumWidth: 1530 Layout.maximumWidth: 1530
Layout.alignment: Qt.AlignCenter Layout.alignment: Qt.AlignCenter
Layout.topMargin: 20
spacing: 30 spacing: 30
ColumnLayout { ColumnLayout {

View File

@ -19,20 +19,30 @@ MySettingsTab {
title: qsTr("LocalDocs") title: qsTr("LocalDocs")
contentItem: ColumnLayout { contentItem: ColumnLayout {
id: root id: root
spacing: 10 spacing: 30
Label { Label {
color: theme.styledTextColor Layout.bottomMargin: 10
font.pixelSize: theme.fontSizeLarge color: theme.settingsTitleTextColor
font.pixelSize: theme.fontSizeBannerSmall
font.bold: true font.bold: true
text: "Indexing" text: qsTr("LocalDocs Settings")
} }
Rectangle { ColumnLayout {
Layout.bottomMargin: 15 spacing: 10
Layout.fillWidth: true Label {
height: 1 color: theme.styledTextColor
color: theme.settingsDivider font.pixelSize: theme.fontSizeLarge
font.bold: true
text: qsTr("Indexing")
}
Rectangle {
Layout.fillWidth: true
height: 1
color: theme.settingsDivider
}
} }
RowLayout { RowLayout {
@ -81,25 +91,26 @@ MySettingsTab {
} }
} }
Label { ColumnLayout {
Layout.topMargin: 15 spacing: 10
color: theme.grayRed900 Label {
font.pixelSize: theme.fontSizeLarge color: theme.grayRed900
font.bold: true font.pixelSize: theme.fontSizeLarge
text: "Embedding" font.bold: true
} text: qsTr("Embedding")
}
Rectangle { Rectangle {
Layout.bottomMargin: 15 Layout.fillWidth: true
Layout.fillWidth: true height: 1
height: 1 color: theme.grayRed500
color: theme.grayRed500 }
} }
RowLayout { RowLayout {
MySettingsLabel { MySettingsLabel {
text: qsTr("Use Nomic Embed API") 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 { 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 { RowLayout {
MySettingsLabel { MySettingsLabel {
id: apiKeyLabel id: apiKeyLabel
text: qsTr("Nomic API Key") text: qsTr("Nomic API Key")
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>.') 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.')
onLinkActivated: function(link) { Qt.openUrlExternally(link) } onLinkActivated: function(link) { Qt.openUrlExternally(link) }
} }
@ -148,26 +193,27 @@ MySettingsTab {
} }
} }
Label { ColumnLayout {
Layout.topMargin: 15 spacing: 10
color: theme.grayRed900 Label {
font.pixelSize: theme.fontSizeLarge color: theme.grayRed900
font.bold: true font.pixelSize: theme.fontSizeLarge
text: "Display" font.bold: true
} text: qsTr("Display")
}
Rectangle { Rectangle {
Layout.bottomMargin: 15 Layout.fillWidth: true
Layout.fillWidth: true height: 1
height: 1 color: theme.grayRed500
color: theme.grayRed500 }
} }
RowLayout { RowLayout {
MySettingsLabel { MySettingsLabel {
id: showReferencesLabel id: showReferencesLabel
text: qsTr("Show sources") text: qsTr("Show Sources")
helpText: qsTr("Shows sources in GUI generated by localdocs") helpText: qsTr("Display the sources used for each response.")
} }
MyCheckBox { MyCheckBox {
id: showReferencesBox id: showReferencesBox
@ -178,19 +224,20 @@ MySettingsTab {
} }
} }
Label { ColumnLayout {
Layout.topMargin: 15 spacing: 10
color: theme.styledTextColor Label {
font.pixelSize: theme.fontSizeLarge color: theme.styledTextColor
font.bold: true font.pixelSize: theme.fontSizeLarge
text: "Advanced" font.bold: true
} text: qsTr("Advanced")
}
Rectangle { Rectangle {
Layout.bottomMargin: 15 Layout.fillWidth: true
Layout.fillWidth: true height: 1
height: 1 color: theme.settingsDivider
color: theme.settingsDivider }
} }
MySettingsLabel { MySettingsLabel {

View File

@ -307,7 +307,7 @@ Rectangle {
} }
elide: Text.ElideRight elide: Text.ElideRight
color: theme.mutedDarkTextColor color: theme.mutedDarkTextColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
} }
Text { Text {
visible: { visible: {
@ -322,7 +322,7 @@ Rectangle {
elide: Text.ElideRight elide: Text.ElideRight
color: theme.mutedDarkTextColor color: theme.mutedDarkTextColor
font.family: "monospace" 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)) text: "%1 %2".arg(qsTr("%n file(s)", "", model.totalDocs)).arg(qsTr("%n word(s)", "", model.totalWords))
elide: Text.ElideRight elide: Text.ElideRight
color: theme.styledTextColor2 color: theme.styledTextColor2
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
} }
Text { Text {
text: model.embeddingModel text: model.embeddingModel
elide: Text.ElideRight elide: Text.ElideRight
color: theme.mutedDarkTextColor color: theme.mutedDarkTextColor
font.bold: true font.bold: true
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
} }
Text { Text {
visible: Qt.formatDateTime(model.lastUpdate) !== "" visible: Qt.formatDateTime(model.lastUpdate) !== ""
text: Qt.formatDateTime(model.lastUpdate) text: Qt.formatDateTime(model.lastUpdate)
elide: Text.ElideRight elide: Text.ElideRight
color: theme.mutedTextColor color: theme.mutedTextColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
} }
Text { Text {
visible: model.currentEmbeddingsToIndex !== 0 visible: model.currentEmbeddingsToIndex !== 0
@ -354,7 +354,7 @@ Rectangle {
+ model.totalEmbeddingsToIndex + " embeddings" + model.totalEmbeddingsToIndex + " embeddings"
elide: Text.ElideRight elide: Text.ElideRight
color: theme.mutedTextColor color: theme.mutedTextColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
} }
} }
@ -400,53 +400,29 @@ Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
spacing: 30 spacing: 30
Layout.leftMargin: 15 Layout.leftMargin: 15
Layout.rightMargin: 15
Layout.topMargin: 15 Layout.topMargin: 15
Text { MyTextButton {
text: qsTr("Remove") text: qsTr("Remove")
elide: Text.ElideRight
color: theme.red500 color: theme.red500
font.bold: true onClick: LocalDocs.removeFolder(collection, folder_path)
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
} }
Item { Item {
Layout.fillWidth: true Layout.fillWidth: true
} }
Text { MyTextButton {
Layout.alignment: Qt.AlignRight 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 visible: model.forceIndexing
text: qsTr("Update") text: qsTr("Update")
elide: Text.ElideRight color: theme.green500
color: theme.red500 onClick: { LocalDocs.forceIndexing(collection); }
font.bold: true tooltip: qsTr("Update the collection to the new version. This is a slow operation.")
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
} }
} }
} }

View File

@ -11,7 +11,7 @@ MySettingsTab {
onRestoreDefaultsClicked: { onRestoreDefaultsClicked: {
MySettings.restoreModelDefaults(root.currentModelInfo); MySettings.restoreModelDefaults(root.currentModelInfo);
} }
title: qsTr("Model/Character Settings") title: qsTr("Model")
contentItem: GridLayout { contentItem: GridLayout {
id: root id: root
columns: 3 columns: 3
@ -23,32 +23,14 @@ MySettingsTab {
property var currentModelId: comboBox.currentValue property var currentModelId: comboBox.currentValue
property var currentModelInfo: ModelList.modelInfo(root.currentModelId) property var currentModelInfo: ModelList.modelInfo(root.currentModelId)
ColumnLayout { Label {
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
Layout.row: 1 Layout.row: 1
Layout.column: 0 Layout.column: 0
text: qsTr("Model/Character") Layout.bottomMargin: 10
helpText: qsTr("Select or clone a model and change its settings") color: theme.settingsTitleTextColor
font.pixelSize: theme.fontSizeBannerSmall
font.bold: true
text: qsTr("Model Settings")
} }
RowLayout { RowLayout {
@ -56,7 +38,6 @@ MySettingsTab {
Layout.row: 2 Layout.row: 2
Layout.column: 0 Layout.column: 0
Layout.columnSpan: 2 Layout.columnSpan: 2
height: label.height + 20
spacing: 10 spacing: 10
MyComboBox { MyComboBox {
@ -122,9 +103,7 @@ MySettingsTab {
Layout.topMargin: 15 Layout.topMargin: 15
spacing: 10 spacing: 10
MySettingsLabel { MySettingsLabel {
id: uniqueNameLabel text: qsTr("Name")
text: qsTr("Unique Name")
helpText: qsTr("Must contain a non-empty unique name")
} }
} }
@ -158,7 +137,6 @@ MySettingsTab {
MySettingsLabel { MySettingsLabel {
text: qsTr("Model File") text: qsTr("Model File")
helpText: qsTr("The filename of the selected model")
Layout.row: 5 Layout.row: 5
Layout.column: 0 Layout.column: 0
Layout.topMargin: 15 Layout.topMargin: 15
@ -177,7 +155,7 @@ MySettingsTab {
MySettingsLabel { MySettingsLabel {
visible: !root.currentModelInfo.isOnline visible: !root.currentModelInfo.isOnline
text: qsTr("System Prompt") 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.row: 7
Layout.column: 0 Layout.column: 0
Layout.topMargin: 15 Layout.topMargin: 15
@ -212,9 +190,6 @@ MySettingsTab {
MySettings.setModelSystemPrompt(root.currentModelInfo, text) MySettings.setModelSystemPrompt(root.currentModelInfo, text)
} }
Accessible.role: Accessible.EditableText 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 { MySettingsLabel {
id: promptTemplateLabel id: promptTemplateLabel
text: qsTr("Prompt Template") text: qsTr("Prompt Template")
helpText: qsTr("The template that wraps every prompt") helpText: qsTr("The template that wraps every prompt.")
} }
MySettingsLabel { MySettingsLabel {
id: promptTemplateLabelHelp id: promptTemplateLabelHelp
@ -271,9 +246,6 @@ MySettingsTab {
Accessible.role: Accessible.EditableText Accessible.role: Accessible.EditableText
Accessible.name: promptTemplateLabel.text Accessible.name: promptTemplateLabel.text
Accessible.description: promptTemplateLabelHelp.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 id: contextLengthLabel
visible: !root.currentModelInfo.isOnline visible: !root.currentModelInfo.isOnline
text: qsTr("Context Length") text: qsTr("Context Length")
helpText: qsTr("Conversation context window") helpText: qsTr("Number of input and output tokens the model sees.")
Layout.row: 0 Layout.row: 0
Layout.column: 0 Layout.column: 0
} }
@ -378,7 +350,7 @@ MySettingsTab {
MySettingsLabel { MySettingsLabel {
id: tempLabel id: tempLabel
text: qsTr("Temperature") text: qsTr("Temperature")
helpText: qsTr("The temperature for model token generation") helpText: qsTr("Randomness of model output. Higher -> more variation.")
Layout.row: 1 Layout.row: 1
Layout.column: 2 Layout.column: 2
} }
@ -422,8 +394,8 @@ MySettingsTab {
} }
MySettingsLabel { MySettingsLabel {
id: topPLabel id: topPLabel
text: qsTr("Top P") text: qsTr("Top-P")
helpText: qsTr("Prevents choosing highly unlikely tokens") helpText: qsTr("Nucleus Sampling factor. Lower -> more predicatable.")
Layout.row: 2 Layout.row: 2
Layout.column: 0 Layout.column: 0
} }
@ -432,7 +404,7 @@ MySettingsTab {
text: root.currentModelInfo.topP text: root.currentModelInfo.topP
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeLarge 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 ToolTip.visible: hovered
Layout.row: 2 Layout.row: 2
Layout.column: 1 Layout.column: 1
@ -466,8 +438,8 @@ MySettingsTab {
} }
MySettingsLabel { MySettingsLabel {
id: minPLabel id: minPLabel
text: qsTr("Min P") text: qsTr("Min-P")
helpText: qsTr("Minimum relative probability") helpText: qsTr("Minimum token probability. Higher -> more predictable.")
Layout.row: 3 Layout.row: 3
Layout.column: 0 Layout.column: 0
} }
@ -512,8 +484,8 @@ MySettingsTab {
MySettingsLabel { MySettingsLabel {
id: topKLabel id: topKLabel
visible: !root.currentModelInfo.isOnline visible: !root.currentModelInfo.isOnline
text: qsTr("Top K") text: qsTr("Top-K")
helpText: qsTr("Size of selection pool for tokens") helpText: qsTr("Size of selection pool for tokens.")
Layout.row: 2 Layout.row: 2
Layout.column: 2 Layout.column: 2
} }
@ -523,7 +495,7 @@ MySettingsTab {
text: root.currentModelInfo.topK text: root.currentModelInfo.topK
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeLarge 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 ToolTip.visible: hovered
Layout.row: 2 Layout.row: 2
Layout.column: 3 Layout.column: 3
@ -559,7 +531,7 @@ MySettingsTab {
id: maxLengthLabel id: maxLengthLabel
visible: !root.currentModelInfo.isOnline visible: !root.currentModelInfo.isOnline
text: qsTr("Max Length") text: qsTr("Max Length")
helpText: qsTr("Maximum length of response in tokens") helpText: qsTr("Maximum response length, in tokens.")
Layout.row: 0 Layout.row: 0
Layout.column: 2 Layout.column: 2
} }
@ -569,8 +541,6 @@ MySettingsTab {
text: root.currentModelInfo.maxLength text: root.currentModelInfo.maxLength
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeLarge font.pixelSize: theme.fontSizeLarge
ToolTip.text: qsTr("Maximum length of response in tokens")
ToolTip.visible: hovered
Layout.row: 0 Layout.row: 0
Layout.column: 3 Layout.column: 3
validator: IntValidator { validator: IntValidator {
@ -606,7 +576,7 @@ MySettingsTab {
id: batchSizeLabel id: batchSizeLabel
visible: !root.currentModelInfo.isOnline visible: !root.currentModelInfo.isOnline
text: qsTr("Prompt Batch Size") 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.row: 1
Layout.column: 0 Layout.column: 0
} }
@ -616,7 +586,7 @@ MySettingsTab {
text: root.currentModelInfo.promptBatchSize text: root.currentModelInfo.promptBatchSize
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeLarge 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 ToolTip.visible: hovered
Layout.row: 1 Layout.row: 1
Layout.column: 1 Layout.column: 1
@ -652,7 +622,7 @@ MySettingsTab {
id: repeatPenaltyLabel id: repeatPenaltyLabel
visible: !root.currentModelInfo.isOnline visible: !root.currentModelInfo.isOnline
text: qsTr("Repeat Penalty") text: qsTr("Repeat Penalty")
helpText: qsTr("Penalize repetitiveness") helpText: qsTr("Repetition penalty factor. Set to 1 to disable.")
Layout.row: 4 Layout.row: 4
Layout.column: 2 Layout.column: 2
} }
@ -662,8 +632,6 @@ MySettingsTab {
text: root.currentModelInfo.repeatPenalty text: root.currentModelInfo.repeatPenalty
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeLarge font.pixelSize: theme.fontSizeLarge
ToolTip.text: qsTr("Amount to penalize repetitiveness of the output")
ToolTip.visible: hovered
Layout.row: 4 Layout.row: 4
Layout.column: 3 Layout.column: 3
validator: DoubleValidator { validator: DoubleValidator {
@ -698,7 +666,7 @@ MySettingsTab {
id: repeatPenaltyTokensLabel id: repeatPenaltyTokensLabel
visible: !root.currentModelInfo.isOnline visible: !root.currentModelInfo.isOnline
text: qsTr("Repeat Penalty Tokens") text: qsTr("Repeat Penalty Tokens")
helpText: qsTr("Length to apply penalty") helpText: qsTr("Number of previous tokens used for penalty.")
Layout.row: 3 Layout.row: 3
Layout.column: 2 Layout.column: 2
} }
@ -708,8 +676,6 @@ MySettingsTab {
text: root.currentModelInfo.repeatPenaltyTokens text: root.currentModelInfo.repeatPenaltyTokens
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeLarge font.pixelSize: theme.fontSizeLarge
ToolTip.text: qsTr("How far back in output to apply repeat penalty")
ToolTip.visible: hovered
Layout.row: 3 Layout.row: 3
Layout.column: 3 Layout.column: 3
validator: IntValidator { validator: IntValidator {
@ -745,7 +711,7 @@ MySettingsTab {
id: gpuLayersLabel id: gpuLayersLabel
visible: !root.currentModelInfo.isOnline visible: !root.currentModelInfo.isOnline
text: qsTr("GPU Layers") 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.row: 4
Layout.column: 0 Layout.column: 0
} }
@ -755,7 +721,7 @@ MySettingsTab {
text: root.currentModelInfo.gpuLayers text: root.currentModelInfo.gpuLayers
font.pixelSize: theme.fontSizeLarge font.pixelSize: theme.fontSizeLarge
color: theme.textColor 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 ToolTip.visible: hovered
Layout.row: 4 Layout.row: 4
Layout.column: 1 Layout.column: 1

View File

@ -180,13 +180,13 @@ Rectangle {
Layout.rightMargin: 20 Layout.rightMargin: 20
Text { Text {
text: qsTr("File size") text: qsTr("File size")
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
color: theme.mutedDarkTextColor color: theme.mutedDarkTextColor
} }
Text { Text {
text: filesize text: filesize
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
font.bold: true font.bold: true
} }
} }
@ -202,13 +202,13 @@ Rectangle {
Layout.rightMargin: 20 Layout.rightMargin: 20
Text { Text {
text: qsTr("RAM required") text: qsTr("RAM required")
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
color: theme.mutedDarkTextColor color: theme.mutedDarkTextColor
} }
Text { Text {
text: ramrequired + qsTr(" GB") text: ramrequired + qsTr(" GB")
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
font.bold: true font.bold: true
} }
} }
@ -224,13 +224,13 @@ Rectangle {
Layout.rightMargin: 20 Layout.rightMargin: 20
Text { Text {
text: qsTr("Parameters") text: qsTr("Parameters")
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
color: theme.mutedDarkTextColor color: theme.mutedDarkTextColor
} }
Text { Text {
text: parameters text: parameters
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
font.bold: true font.bold: true
} }
} }
@ -246,13 +246,13 @@ Rectangle {
Layout.rightMargin: 20 Layout.rightMargin: 20
Text { Text {
text: qsTr("Quant") text: qsTr("Quant")
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
color: theme.mutedDarkTextColor color: theme.mutedDarkTextColor
} }
Text { Text {
text: quant text: quant
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
font.bold: true font.bold: true
} }
} }
@ -268,13 +268,13 @@ Rectangle {
Layout.rightMargin: 20 Layout.rightMargin: 20
Text { Text {
text: qsTr("Type") text: qsTr("Type")
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
color: theme.mutedDarkTextColor color: theme.mutedDarkTextColor
} }
Text { Text {
text: type text: type
color: theme.textColor color: theme.textColor
font.pixelSize: theme.fontSizeSmaller font.pixelSize: theme.fontSizeSmall
font.bold: true font.bold: true
} }
} }

View File

@ -20,7 +20,7 @@ ColumnLayout {
Label { Label {
id: mainTextLabel id: mainTextLabel
color: theme.settingsTitleTextColor color: theme.settingsTitleTextColor
font.pixelSize: theme.fontSizeSmall font.pixelSize: theme.fontSizeLarger
font.bold: true font.bold: true
onLinkActivated: function(link) { onLinkActivated: function(link) {
root.linkActivated(link); root.linkActivated(link);
@ -28,12 +28,13 @@ ColumnLayout {
} }
Label { Label {
id: helpTextLabel id: helpTextLabel
visible: text !== ""
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.Wrap wrapMode: Text.Wrap
color: theme.settingsTitleTextColor color: theme.settingsTitleTextColor
text: mainTextLabel.text font.pixelSize: theme.fontSizeLarge
font.pixelSize: theme.fontSizeSmaller
font.bold: false font.bold: false
onLinkActivated: function(link) { onLinkActivated: function(link) {
root.linkActivated(link); root.linkActivated(link);
} }

View File

@ -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
}

View File

@ -33,7 +33,7 @@ Button {
visible: myButton.toggled visible: myButton.toggled
border.color: myButton.toggledColor border.color: myButton.toggledColor
border.width: myButton.toggledWidth border.width: myButton.toggledWidth
radius: 10 radius: 8
} }
Image { Image {
id: image id: image

View File

@ -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 : property real fontSizeSmallest: 8 * fontScale
MySettings.fontSize === "Medium" ? 17 : property real fontSizeSmaller: 9 * fontScale
22 property real fontSizeSmall: 10 * fontScale
property real fontSizeMedium: 11 * fontScale
property real fontSizeLargest: MySettings.fontSize === "Small" ? 19 : property real fontSizeLarge: 12 * fontScale
MySettings.fontSize === "Medium" ? 24 : property real fontSizeLarger: 14 * fontScale
26 property real fontSizeLargest: 18 * fontScale
property real fontSizeBannerSmall: 24 * fontScale**.8
property real fontSizeSmaller: fontSizeLarge - 4 property real fontSizeBanner: 48 * fontScale**.8
property real fontSizeSmall: fontSizeLarge - 2
property real fontSizeLarger: fontSizeLarge + 2
property real fontSizeBannerSmall: fontSizeLargest + 10
property real fontSizeBanner: fontSizeLargest + 40
} }