mirror of
https://github.com/nomic-ai/gpt4all
synced 2024-11-18 03:25:46 +00:00
Huge change that completely revamps the settings dialog and implements
per model settings as well as the ability to clone a model into a "character." This also implements system prompts as well as quite a few bugfixes for instance this fixes chatgpt.
This commit is contained in:
parent
2a6c673c25
commit
6d9cdf228c
@ -99,7 +99,6 @@ qt_add_qml_module(chat
|
|||||||
qml/AboutDialog.qml
|
qml/AboutDialog.qml
|
||||||
qml/Theme.qml
|
qml/Theme.qml
|
||||||
qml/ModelSettings.qml
|
qml/ModelSettings.qml
|
||||||
qml/GenerationSettings.qml
|
|
||||||
qml/ApplicationSettings.qml
|
qml/ApplicationSettings.qml
|
||||||
qml/LocalDocsSettings.qml
|
qml/LocalDocsSettings.qml
|
||||||
qml/MySettingsTab.qml
|
qml/MySettingsTab.qml
|
||||||
@ -119,6 +118,7 @@ qt_add_qml_module(chat
|
|||||||
icons/db.svg
|
icons/db.svg
|
||||||
icons/settings.svg
|
icons/settings.svg
|
||||||
icons/edit.svg
|
icons/edit.svg
|
||||||
|
icons/image.svg
|
||||||
icons/trash.svg
|
icons/trash.svg
|
||||||
icons/network.svg
|
icons/network.svg
|
||||||
icons/thumbs_up.svg
|
icons/thumbs_up.svg
|
||||||
|
@ -67,6 +67,7 @@ void Chat::connectLLM()
|
|||||||
connect(this, &Chat::regenerateResponseRequested, m_llmodel, &ChatLLM::regenerateResponse, Qt::QueuedConnection);
|
connect(this, &Chat::regenerateResponseRequested, m_llmodel, &ChatLLM::regenerateResponse, Qt::QueuedConnection);
|
||||||
connect(this, &Chat::resetResponseRequested, m_llmodel, &ChatLLM::resetResponse, Qt::QueuedConnection);
|
connect(this, &Chat::resetResponseRequested, m_llmodel, &ChatLLM::resetResponse, Qt::QueuedConnection);
|
||||||
connect(this, &Chat::resetContextRequested, m_llmodel, &ChatLLM::resetContext, Qt::QueuedConnection);
|
connect(this, &Chat::resetContextRequested, m_llmodel, &ChatLLM::resetContext, Qt::QueuedConnection);
|
||||||
|
connect(this, &Chat::processSystemPromptRequested, m_llmodel, &ChatLLM::processSystemPrompt, Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(ModelList::globalInstance()->installedModels(), &InstalledModels::countChanged,
|
connect(ModelList::globalInstance()->installedModels(), &InstalledModels::countChanged,
|
||||||
this, &Chat::handleModelInstalled, Qt::QueuedConnection);
|
this, &Chat::handleModelInstalled, Qt::QueuedConnection);
|
||||||
@ -93,6 +94,11 @@ void Chat::reset()
|
|||||||
m_chatModel->clear();
|
m_chatModel->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Chat::processSystemPrompt()
|
||||||
|
{
|
||||||
|
emit processSystemPromptRequested();
|
||||||
|
}
|
||||||
|
|
||||||
bool Chat::isModelLoaded() const
|
bool Chat::isModelLoaded() const
|
||||||
{
|
{
|
||||||
return m_isModelLoaded;
|
return m_isModelLoaded;
|
||||||
@ -111,27 +117,10 @@ void Chat::resetResponseState()
|
|||||||
emit responseStateChanged();
|
emit responseStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chat::prompt(const QString &prompt, const QString &prompt_template, int32_t n_predict,
|
void Chat::prompt(const QString &prompt)
|
||||||
int32_t top_k, float top_p, float temp, int32_t n_batch, float repeat_penalty,
|
|
||||||
int32_t repeat_penalty_tokens)
|
|
||||||
{
|
{
|
||||||
resetResponseState();
|
resetResponseState();
|
||||||
int threadCount = MySettings::globalInstance()->threadCount();
|
emit promptRequested( m_collections, prompt);
|
||||||
if (threadCount <= 0)
|
|
||||||
threadCount = std::min(4, (int32_t) std::thread::hardware_concurrency());
|
|
||||||
|
|
||||||
emit promptRequested(
|
|
||||||
m_collections,
|
|
||||||
prompt,
|
|
||||||
prompt_template,
|
|
||||||
n_predict,
|
|
||||||
top_k,
|
|
||||||
top_p,
|
|
||||||
temp,
|
|
||||||
n_batch,
|
|
||||||
repeat_penalty,
|
|
||||||
repeat_penalty_tokens,
|
|
||||||
threadCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chat::regenerateResponse()
|
void Chat::regenerateResponse()
|
||||||
@ -386,7 +375,10 @@ bool Chat::serialize(QDataStream &stream, int version) const
|
|||||||
stream << m_id;
|
stream << m_id;
|
||||||
stream << m_name;
|
stream << m_name;
|
||||||
stream << m_userName;
|
stream << m_userName;
|
||||||
stream << m_modelInfo.filename;
|
if (version > 4)
|
||||||
|
stream << m_modelInfo.id();
|
||||||
|
else
|
||||||
|
stream << m_modelInfo.filename();
|
||||||
if (version > 2)
|
if (version > 2)
|
||||||
stream << m_collections;
|
stream << m_collections;
|
||||||
if (!m_llmodel->serialize(stream, version))
|
if (!m_llmodel->serialize(stream, version))
|
||||||
@ -405,16 +397,22 @@ bool Chat::deserialize(QDataStream &stream, int version)
|
|||||||
stream >> m_userName;
|
stream >> m_userName;
|
||||||
emit nameChanged();
|
emit nameChanged();
|
||||||
|
|
||||||
QString filename;
|
QString modelId;
|
||||||
stream >> filename;
|
stream >> modelId;
|
||||||
if (!ModelList::globalInstance()->contains(filename))
|
if (version > 4) {
|
||||||
|
if (!ModelList::globalInstance()->contains(modelId))
|
||||||
return false;
|
return false;
|
||||||
m_modelInfo = ModelList::globalInstance()->modelInfo(filename);
|
m_modelInfo = ModelList::globalInstance()->modelInfo(modelId);
|
||||||
|
} else {
|
||||||
|
if (!ModelList::globalInstance()->containsByFilename(modelId))
|
||||||
|
return false;
|
||||||
|
m_modelInfo = ModelList::globalInstance()->modelInfoByFilename(modelId);
|
||||||
|
}
|
||||||
emit modelInfoChanged();
|
emit modelInfoChanged();
|
||||||
|
|
||||||
// Prior to version 2 gptj models had a bug that fixed the kv_cache to F32 instead of F16 so
|
// Prior to version 2 gptj models had a bug that fixed the kv_cache to F32 instead of F16 so
|
||||||
// unfortunately, we cannot deserialize these
|
// unfortunately, we cannot deserialize these
|
||||||
if (version < 2 && m_modelInfo.filename.contains("gpt4all-j"))
|
if (version < 2 && m_modelInfo.filename().contains("gpt4all-j"))
|
||||||
return false;
|
return false;
|
||||||
if (version > 2) {
|
if (version > 2) {
|
||||||
stream >> m_collections;
|
stream >> m_collections;
|
||||||
|
@ -53,9 +53,9 @@ public:
|
|||||||
ChatModel *chatModel() { return m_chatModel; }
|
ChatModel *chatModel() { return m_chatModel; }
|
||||||
|
|
||||||
Q_INVOKABLE void reset();
|
Q_INVOKABLE void reset();
|
||||||
|
Q_INVOKABLE void processSystemPrompt();
|
||||||
Q_INVOKABLE bool isModelLoaded() const;
|
Q_INVOKABLE bool isModelLoaded() const;
|
||||||
Q_INVOKABLE void prompt(const QString &prompt, const QString &prompt_template, int32_t n_predict,
|
Q_INVOKABLE void prompt(const QString &prompt);
|
||||||
int32_t top_k, float top_p, float temp, int32_t n_batch, float repeat_penalty, int32_t repeat_penalty_tokens);
|
|
||||||
Q_INVOKABLE void regenerateResponse();
|
Q_INVOKABLE void regenerateResponse();
|
||||||
Q_INVOKABLE void stopGenerating();
|
Q_INVOKABLE void stopGenerating();
|
||||||
Q_INVOKABLE void newPromptResponsePair(const QString &prompt);
|
Q_INVOKABLE void newPromptResponsePair(const QString &prompt);
|
||||||
@ -102,12 +102,11 @@ Q_SIGNALS:
|
|||||||
void responseChanged();
|
void responseChanged();
|
||||||
void responseInProgressChanged();
|
void responseInProgressChanged();
|
||||||
void responseStateChanged();
|
void responseStateChanged();
|
||||||
void promptRequested(const QList<QString> &collectionList, const QString &prompt, const QString &prompt_template,
|
void promptRequested(const QList<QString> &collectionList, const QString &prompt);
|
||||||
int32_t n_predict, int32_t top_k, float top_p, float temp, int32_t n_batch, float repeat_penalty,
|
|
||||||
int32_t repeat_penalty_tokens, int32_t n_threads);
|
|
||||||
void regenerateResponseRequested();
|
void regenerateResponseRequested();
|
||||||
void resetResponseRequested();
|
void resetResponseRequested();
|
||||||
void resetContextRequested();
|
void resetContextRequested();
|
||||||
|
void processSystemPromptRequested();
|
||||||
void modelChangeRequested(const ModelInfo &modelInfo);
|
void modelChangeRequested(const ModelInfo &modelInfo);
|
||||||
void modelInfoChanged();
|
void modelInfoChanged();
|
||||||
void recalcChanged();
|
void recalcChanged();
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
|
|
||||||
#define CHAT_FORMAT_MAGIC 0xF5D553CC
|
#define CHAT_FORMAT_MAGIC 0xF5D553CC
|
||||||
#define CHAT_FORMAT_VERSION 4
|
#define CHAT_FORMAT_VERSION 5
|
||||||
|
|
||||||
class MyChatListModel: public ChatListModel { };
|
class MyChatListModel: public ChatListModel { };
|
||||||
Q_GLOBAL_STATIC(MyChatListModel, chatListModelInstance)
|
Q_GLOBAL_STATIC(MyChatListModel, chatListModelInstance)
|
||||||
|
@ -69,6 +69,7 @@ ChatLLM::ChatLLM(Chat *parent, bool isServer)
|
|||||||
, m_isServer(isServer)
|
, m_isServer(isServer)
|
||||||
, m_forceMetal(MySettings::globalInstance()->forceMetal())
|
, m_forceMetal(MySettings::globalInstance()->forceMetal())
|
||||||
, m_reloadingToChangeVariant(false)
|
, m_reloadingToChangeVariant(false)
|
||||||
|
, m_processedSystemPrompt(false)
|
||||||
{
|
{
|
||||||
moveToThread(&m_llmThread);
|
moveToThread(&m_llmThread);
|
||||||
connect(this, &ChatLLM::sendStartup, Network::globalInstance(), &Network::sendStartup);
|
connect(this, &ChatLLM::sendStartup, Network::globalInstance(), &Network::sendStartup);
|
||||||
@ -123,7 +124,7 @@ void ChatLLM::handleForceMetalChanged(bool forceMetal)
|
|||||||
bool ChatLLM::loadDefaultModel()
|
bool ChatLLM::loadDefaultModel()
|
||||||
{
|
{
|
||||||
ModelInfo defaultModel = ModelList::globalInstance()->defaultModelInfo();
|
ModelInfo defaultModel = ModelList::globalInstance()->defaultModelInfo();
|
||||||
if (defaultModel.filename.isEmpty()) {
|
if (defaultModel.filename().isEmpty()) {
|
||||||
emit modelLoadingError(QString("Could not find any model to load"));
|
emit modelLoadingError(QString("Could not find any model to load"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -145,7 +146,7 @@ bool ChatLLM::loadModel(const ModelInfo &modelInfo)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
bool isChatGPT = modelInfo.isChatGPT;
|
bool isChatGPT = modelInfo.isChatGPT;
|
||||||
QString filePath = modelInfo.dirpath + modelInfo.filename;
|
QString filePath = modelInfo.dirpath + modelInfo.filename();
|
||||||
QFileInfo fileInfo(filePath);
|
QFileInfo fileInfo(filePath);
|
||||||
|
|
||||||
// We have a live model, but it isn't the one we want
|
// We have a live model, but it isn't the one we want
|
||||||
@ -186,6 +187,11 @@ bool ChatLLM::loadModel(const ModelInfo &modelInfo)
|
|||||||
#endif
|
#endif
|
||||||
restoreState();
|
restoreState();
|
||||||
emit isModelLoadedChanged(true);
|
emit isModelLoadedChanged(true);
|
||||||
|
Q_ASSERT(!m_modelInfo.filename().isEmpty());
|
||||||
|
if (m_modelInfo.filename().isEmpty())
|
||||||
|
emit modelLoadingError(QString("Modelinfo is left null for %1").arg(modelInfo.filename()));
|
||||||
|
else
|
||||||
|
processSystemPrompt();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// Release the memory since we have to switch to a different model.
|
// Release the memory since we have to switch to a different model.
|
||||||
@ -237,7 +243,7 @@ bool ChatLLM::loadModel(const ModelInfo &modelInfo)
|
|||||||
if (!m_isServer)
|
if (!m_isServer)
|
||||||
LLModelStore::globalInstance()->releaseModel(m_llModelInfo); // release back into the store
|
LLModelStore::globalInstance()->releaseModel(m_llModelInfo); // release back into the store
|
||||||
m_llModelInfo = LLModelInfo();
|
m_llModelInfo = LLModelInfo();
|
||||||
emit modelLoadingError(QString("Could not load model due to invalid model file for %1").arg(modelInfo.filename));
|
emit modelLoadingError(QString("Could not load model due to invalid model file for %1").arg(modelInfo.filename()));
|
||||||
} else {
|
} else {
|
||||||
switch (m_llModelInfo.model->implementation().modelType[0]) {
|
switch (m_llModelInfo.model->implementation().modelType[0]) {
|
||||||
case 'L': m_llModelType = LLModelType::LLAMA_; break;
|
case 'L': m_llModelType = LLModelType::LLAMA_; break;
|
||||||
@ -251,7 +257,7 @@ bool ChatLLM::loadModel(const ModelInfo &modelInfo)
|
|||||||
if (!m_isServer)
|
if (!m_isServer)
|
||||||
LLModelStore::globalInstance()->releaseModel(m_llModelInfo); // release back into the store
|
LLModelStore::globalInstance()->releaseModel(m_llModelInfo); // release back into the store
|
||||||
m_llModelInfo = LLModelInfo();
|
m_llModelInfo = LLModelInfo();
|
||||||
emit modelLoadingError(QString("Could not determine model type for %1").arg(modelInfo.filename));
|
emit modelLoadingError(QString("Could not determine model type for %1").arg(modelInfo.filename()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,7 +265,7 @@ bool ChatLLM::loadModel(const ModelInfo &modelInfo)
|
|||||||
if (!m_isServer)
|
if (!m_isServer)
|
||||||
LLModelStore::globalInstance()->releaseModel(m_llModelInfo); // release back into the store
|
LLModelStore::globalInstance()->releaseModel(m_llModelInfo); // release back into the store
|
||||||
m_llModelInfo = LLModelInfo();
|
m_llModelInfo = LLModelInfo();
|
||||||
emit modelLoadingError(QString("Could not load model due to invalid format for %1").arg(modelInfo.filename));
|
emit modelLoadingError(QString("Could not load model due to invalid format for %1").arg(modelInfo.filename()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if defined(DEBUG_MODEL_LOADING)
|
#if defined(DEBUG_MODEL_LOADING)
|
||||||
@ -282,12 +288,13 @@ bool ChatLLM::loadModel(const ModelInfo &modelInfo)
|
|||||||
if (!m_isServer)
|
if (!m_isServer)
|
||||||
LLModelStore::globalInstance()->releaseModel(m_llModelInfo); // release back into the store
|
LLModelStore::globalInstance()->releaseModel(m_llModelInfo); // release back into the store
|
||||||
m_llModelInfo = LLModelInfo();
|
m_llModelInfo = LLModelInfo();
|
||||||
emit modelLoadingError(QString("Could not find file for model %1").arg(modelInfo.filename));
|
emit modelLoadingError(QString("Could not find file for model %1").arg(modelInfo.filename()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_llModelInfo.model)
|
if (m_llModelInfo.model)
|
||||||
setModelInfo(modelInfo);
|
setModelInfo(modelInfo);
|
||||||
|
|
||||||
|
processSystemPrompt();
|
||||||
return m_llModelInfo.model;
|
return m_llModelInfo.model;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,6 +330,7 @@ void ChatLLM::resetResponse()
|
|||||||
void ChatLLM::resetContext()
|
void ChatLLM::resetContext()
|
||||||
{
|
{
|
||||||
regenerateResponse();
|
regenerateResponse();
|
||||||
|
m_processedSystemPrompt = false;
|
||||||
m_ctx = LLModel::PromptContext();
|
m_ctx = LLModel::PromptContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,9 +420,25 @@ bool ChatLLM::handleRecalculate(bool isRecalc)
|
|||||||
}
|
}
|
||||||
return !m_stopGenerating;
|
return !m_stopGenerating;
|
||||||
}
|
}
|
||||||
|
bool ChatLLM::prompt(const QList<QString> &collectionList, const QString &prompt)
|
||||||
|
{
|
||||||
|
if (!m_processedSystemPrompt)
|
||||||
|
processSystemPrompt();
|
||||||
|
const QString promptTemplate = MySettings::globalInstance()->modelPromptTemplate(m_modelInfo);
|
||||||
|
const int32_t n_predict = MySettings::globalInstance()->modelMaxLength(m_modelInfo);
|
||||||
|
const int32_t top_k = MySettings::globalInstance()->modelTopK(m_modelInfo);
|
||||||
|
const float top_p = MySettings::globalInstance()->modelTopP(m_modelInfo);
|
||||||
|
const float temp = MySettings::globalInstance()->modelTemperature(m_modelInfo);
|
||||||
|
const int32_t n_batch = MySettings::globalInstance()->modelPromptBatchSize(m_modelInfo);
|
||||||
|
const float repeat_penalty = MySettings::globalInstance()->modelRepeatPenalty(m_modelInfo);
|
||||||
|
const int32_t repeat_penalty_tokens = MySettings::globalInstance()->modelRepeatPenaltyTokens(m_modelInfo);
|
||||||
|
return promptInternal(collectionList, prompt, promptTemplate, n_predict, top_k, top_p, temp, n_batch,
|
||||||
|
repeat_penalty, repeat_penalty_tokens);
|
||||||
|
}
|
||||||
|
|
||||||
bool ChatLLM::prompt(const QList<QString> &collectionList, const QString &prompt, const QString &prompt_template, int32_t n_predict, int32_t top_k,
|
bool ChatLLM::promptInternal(const QList<QString> &collectionList, const QString &prompt, const QString &promptTemplate,
|
||||||
float top_p, float temp, int32_t n_batch, float repeat_penalty, int32_t repeat_penalty_tokens, int n_threads)
|
int32_t n_predict, int32_t top_k, float top_p, float temp, int32_t n_batch, float repeat_penalty,
|
||||||
|
int32_t repeat_penalty_tokens)
|
||||||
{
|
{
|
||||||
if (!isModelLoaded())
|
if (!isModelLoaded())
|
||||||
return false;
|
return false;
|
||||||
@ -430,10 +454,14 @@ bool ChatLLM::prompt(const QList<QString> &collectionList, const QString &prompt
|
|||||||
augmentedTemplate.append("### Context:");
|
augmentedTemplate.append("### Context:");
|
||||||
for (const ResultInfo &info : databaseResults)
|
for (const ResultInfo &info : databaseResults)
|
||||||
augmentedTemplate.append(info.text);
|
augmentedTemplate.append(info.text);
|
||||||
augmentedTemplate.append(prompt_template);
|
augmentedTemplate.append(promptTemplate);
|
||||||
|
|
||||||
QString instructPrompt = augmentedTemplate.join("\n").arg(prompt);
|
QString instructPrompt = augmentedTemplate.join("\n").arg(prompt);
|
||||||
|
|
||||||
|
int n_threads = MySettings::globalInstance()->threadCount();
|
||||||
|
if (n_threads <= 0)
|
||||||
|
n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency());
|
||||||
|
|
||||||
m_stopGenerating = false;
|
m_stopGenerating = false;
|
||||||
auto promptFunc = std::bind(&ChatLLM::handlePrompt, this, std::placeholders::_1);
|
auto promptFunc = std::bind(&ChatLLM::handlePrompt, this, std::placeholders::_1);
|
||||||
auto responseFunc = std::bind(&ChatLLM::handleResponse, this, std::placeholders::_1,
|
auto responseFunc = std::bind(&ChatLLM::handleResponse, this, std::placeholders::_1,
|
||||||
@ -515,7 +543,7 @@ void ChatLLM::reloadModel()
|
|||||||
qDebug() << "reloadModel" << m_llmThread.objectName() << m_llModelInfo.model;
|
qDebug() << "reloadModel" << m_llmThread.objectName() << m_llModelInfo.model;
|
||||||
#endif
|
#endif
|
||||||
const ModelInfo m = modelInfo();
|
const ModelInfo m = modelInfo();
|
||||||
if (m.name.isEmpty())
|
if (m.name().isEmpty())
|
||||||
loadDefaultModel();
|
loadDefaultModel();
|
||||||
else
|
else
|
||||||
loadModel(m);
|
loadModel(m);
|
||||||
@ -581,6 +609,27 @@ bool ChatLLM::handleNameRecalculate(bool isRecalc)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ChatLLM::handleSystemPrompt(int32_t token)
|
||||||
|
{
|
||||||
|
Q_UNUSED(token);
|
||||||
|
qt_noop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChatLLM::handleSystemResponse(int32_t token, const std::string &response)
|
||||||
|
{
|
||||||
|
Q_UNUSED(token);
|
||||||
|
Q_UNUSED(response);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChatLLM::handleSystemRecalculate(bool isRecalc)
|
||||||
|
{
|
||||||
|
Q_UNUSED(isRecalc);
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ChatLLM::serialize(QDataStream &stream, int version)
|
bool ChatLLM::serialize(QDataStream &stream, int version)
|
||||||
{
|
{
|
||||||
if (version > 1) {
|
if (version > 1) {
|
||||||
@ -701,3 +750,45 @@ void ChatLLM::restoreState()
|
|||||||
m_state.clear();
|
m_state.clear();
|
||||||
m_state.resize(0);
|
m_state.resize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatLLM::processSystemPrompt()
|
||||||
|
{
|
||||||
|
Q_ASSERT(isModelLoaded());
|
||||||
|
if (!isModelLoaded() || m_processedSystemPrompt || m_isServer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto promptFunc = std::bind(&ChatLLM::handleSystemPrompt, this, std::placeholders::_1);
|
||||||
|
auto responseFunc = std::bind(&ChatLLM::handleSystemResponse, this, std::placeholders::_1,
|
||||||
|
std::placeholders::_2);
|
||||||
|
auto recalcFunc = std::bind(&ChatLLM::handleSystemRecalculate, this, std::placeholders::_1);
|
||||||
|
|
||||||
|
const std::string systemPrompt = MySettings::globalInstance()->modelSystemPrompt(m_modelInfo).toStdString();
|
||||||
|
const int32_t n_predict = MySettings::globalInstance()->modelMaxLength(m_modelInfo);
|
||||||
|
const int32_t top_k = MySettings::globalInstance()->modelTopK(m_modelInfo);
|
||||||
|
const float top_p = MySettings::globalInstance()->modelTopP(m_modelInfo);
|
||||||
|
const float temp = MySettings::globalInstance()->modelTemperature(m_modelInfo);
|
||||||
|
const int32_t n_batch = MySettings::globalInstance()->modelPromptBatchSize(m_modelInfo);
|
||||||
|
const float repeat_penalty = MySettings::globalInstance()->modelRepeatPenalty(m_modelInfo);
|
||||||
|
const int32_t repeat_penalty_tokens = MySettings::globalInstance()->modelRepeatPenaltyTokens(m_modelInfo);
|
||||||
|
int n_threads = MySettings::globalInstance()->threadCount();
|
||||||
|
if (n_threads <= 0)
|
||||||
|
n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency());
|
||||||
|
m_ctx.n_predict = n_predict;
|
||||||
|
m_ctx.top_k = top_k;
|
||||||
|
m_ctx.top_p = top_p;
|
||||||
|
m_ctx.temp = temp;
|
||||||
|
m_ctx.n_batch = n_batch;
|
||||||
|
m_ctx.repeat_penalty = repeat_penalty;
|
||||||
|
m_ctx.repeat_last_n = repeat_penalty_tokens;
|
||||||
|
m_llModelInfo.model->setThreadCount(n_threads);
|
||||||
|
#if defined(DEBUG)
|
||||||
|
printf("%s", qPrintable(QString::fromStdString(systemPrompt)));
|
||||||
|
fflush(stdout);
|
||||||
|
#endif
|
||||||
|
m_llModelInfo.model->prompt(systemPrompt, promptFunc, responseFunc, recalcFunc, m_ctx);
|
||||||
|
#if defined(DEBUG)
|
||||||
|
printf("\n");
|
||||||
|
fflush(stdout);
|
||||||
|
#endif
|
||||||
|
m_processedSystemPrompt = true;
|
||||||
|
}
|
@ -97,9 +97,7 @@ public:
|
|||||||
bool deserialize(QDataStream &stream, int version);
|
bool deserialize(QDataStream &stream, int version);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
bool prompt(const QList<QString> &collectionList, const QString &prompt, const QString &prompt_template,
|
bool prompt(const QList<QString> &collectionList, const QString &prompt);
|
||||||
int32_t n_predict, int32_t top_k, float top_p, float temp, int32_t n_batch, float repeat_penalty,
|
|
||||||
int32_t repeat_penalty_tokens, int32_t n_threads);
|
|
||||||
bool loadDefaultModel();
|
bool loadDefaultModel();
|
||||||
bool loadModel(const ModelInfo &modelInfo);
|
bool loadModel(const ModelInfo &modelInfo);
|
||||||
void modelChangeRequested(const ModelInfo &modelInfo);
|
void modelChangeRequested(const ModelInfo &modelInfo);
|
||||||
@ -111,6 +109,7 @@ public Q_SLOTS:
|
|||||||
void handleShouldBeLoadedChanged();
|
void handleShouldBeLoadedChanged();
|
||||||
void handleThreadStarted();
|
void handleThreadStarted();
|
||||||
void handleForceMetalChanged(bool forceMetal);
|
void handleForceMetalChanged(bool forceMetal);
|
||||||
|
void processSystemPrompt();
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void recalcChanged();
|
void recalcChanged();
|
||||||
@ -131,12 +130,18 @@ Q_SIGNALS:
|
|||||||
void modelInfoChanged(const ModelInfo &modelInfo);
|
void modelInfoChanged(const ModelInfo &modelInfo);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool promptInternal(const QList<QString> &collectionList, const QString &prompt, const QString &promptTemplate,
|
||||||
|
int32_t n_predict, int32_t top_k, float top_p, float temp, int32_t n_batch, float repeat_penalty,
|
||||||
|
int32_t repeat_penalty_tokens);
|
||||||
bool handlePrompt(int32_t token);
|
bool handlePrompt(int32_t token);
|
||||||
bool handleResponse(int32_t token, const std::string &response);
|
bool handleResponse(int32_t token, const std::string &response);
|
||||||
bool handleRecalculate(bool isRecalc);
|
bool handleRecalculate(bool isRecalc);
|
||||||
bool handleNamePrompt(int32_t token);
|
bool handleNamePrompt(int32_t token);
|
||||||
bool handleNameResponse(int32_t token, const std::string &response);
|
bool handleNameResponse(int32_t token, const std::string &response);
|
||||||
bool handleNameRecalculate(bool isRecalc);
|
bool handleNameRecalculate(bool isRecalc);
|
||||||
|
bool handleSystemPrompt(int32_t token);
|
||||||
|
bool handleSystemResponse(int32_t token, const std::string &response);
|
||||||
|
bool handleSystemRecalculate(bool isRecalc);
|
||||||
void saveState();
|
void saveState();
|
||||||
void restoreState();
|
void restoreState();
|
||||||
|
|
||||||
@ -160,6 +165,7 @@ private:
|
|||||||
bool m_isServer;
|
bool m_isServer;
|
||||||
bool m_forceMetal;
|
bool m_forceMetal;
|
||||||
bool m_reloadingToChangeVariant;
|
bool m_reloadingToChangeVariant;
|
||||||
|
bool m_processedSystemPrompt;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CHATLLM_H
|
#endif // CHATLLM_H
|
||||||
|
@ -175,7 +175,7 @@ void Download::installModel(const QString &modelFile, const QString &apiKey)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Network::globalInstance()->sendInstallModel(modelFile);
|
Network::globalInstance()->sendInstallModel(modelFile);
|
||||||
QString filePath = MySettings::globalInstance()->modelPath() + modelFile + ".txt";
|
QString filePath = MySettings::globalInstance()->modelPath() + modelFile;
|
||||||
QFile file(filePath);
|
QFile file(filePath);
|
||||||
if (file.open(QIODeviceBase::WriteOnly | QIODeviceBase::Text)) {
|
if (file.open(QIODeviceBase::WriteOnly | QIODeviceBase::Text)) {
|
||||||
QTextStream stream(&file);
|
QTextStream stream(&file);
|
||||||
|
6
gpt4all-chat/icons/image.svg
Normal file
6
gpt4all-chat/icons/image.svg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="#7d7d8e" viewBox="0 0 512 512"><path d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48z"/></svg>
|
||||||
|
<!--
|
||||||
|
Font Awesome Free 5.2.0 by @fontawesome - https://fontawesome.com
|
||||||
|
License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
-->
|
After Width: | Height: | Size: 606 B |
@ -204,12 +204,12 @@ Window {
|
|||||||
anchors.horizontalCenterOffset: window.width >= 950 ? 0 : Math.max(-((950 - window.width) / 2), -99.5)
|
anchors.horizontalCenterOffset: window.width >= 950 ? 0 : Math.max(-((950 - window.width) / 2), -99.5)
|
||||||
enabled: !currentChat.isServer
|
enabled: !currentChat.isServer
|
||||||
model: ModelList.installedModels
|
model: ModelList.installedModels
|
||||||
valueRole: "filename"
|
valueRole: "id"
|
||||||
textRole: "name"
|
textRole: "name"
|
||||||
property string currentModelName: ""
|
property string currentModelName: ""
|
||||||
function updateCurrentModelName() {
|
function updateCurrentModelName() {
|
||||||
var info = ModelList.modelInfo(currentChat.modelInfo.filename);
|
var info = ModelList.modelInfo(currentChat.modelInfo.id);
|
||||||
comboBox.currentModelName = info.name !== "" ? info.name : info.filename;
|
comboBox.currentModelName = info.name;
|
||||||
}
|
}
|
||||||
Connections {
|
Connections {
|
||||||
target: currentChat
|
target: currentChat
|
||||||
@ -217,6 +217,16 @@ Window {
|
|||||||
comboBox.updateCurrentModelName();
|
comboBox.updateCurrentModelName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Connections {
|
||||||
|
target: window
|
||||||
|
function onCurrentChatChanged() {
|
||||||
|
comboBox.updateCurrentModelName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
background: Rectangle {
|
||||||
|
color: theme.backgroundDark
|
||||||
|
radius: 10
|
||||||
|
}
|
||||||
contentItem: Text {
|
contentItem: Text {
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
@ -233,7 +243,7 @@ Window {
|
|||||||
delegate: ItemDelegate {
|
delegate: ItemDelegate {
|
||||||
width: comboBox.width
|
width: comboBox.width
|
||||||
contentItem: Text {
|
contentItem: Text {
|
||||||
text: name !== "" ? name : filename
|
text: name
|
||||||
color: theme.textColor
|
color: theme.textColor
|
||||||
font: comboBox.font
|
font: comboBox.font
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
@ -557,6 +567,7 @@ Window {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
Network.sendResetContext(chatModel.count)
|
Network.sendResetContext(chatModel.count)
|
||||||
currentChat.reset();
|
currentChat.reset();
|
||||||
|
currentChat.processSystemPrompt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -870,6 +881,7 @@ Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MyButton {
|
MyButton {
|
||||||
|
id: myButton
|
||||||
visible: chatModel.count && !currentChat.isServer
|
visible: chatModel.count && !currentChat.isServer
|
||||||
Image {
|
Image {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@ -894,19 +906,17 @@ Window {
|
|||||||
chatModel.updateThumbsUpState(index, false);
|
chatModel.updateThumbsUpState(index, false);
|
||||||
chatModel.updateThumbsDownState(index, false);
|
chatModel.updateThumbsDownState(index, false);
|
||||||
chatModel.updateNewResponse(index, "");
|
chatModel.updateNewResponse(index, "");
|
||||||
currentChat.prompt(listElement.prompt,
|
currentChat.prompt(listElement.prompt)
|
||||||
MySettings.promptTemplate,
|
|
||||||
MySettings.maxLength,
|
|
||||||
MySettings.topK,
|
|
||||||
MySettings.topP,
|
|
||||||
MySettings.temperature,
|
|
||||||
MySettings.promptBatchSize,
|
|
||||||
MySettings.repeatPenalty,
|
|
||||||
MySettings.repeatPenaltyTokens)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
background: Rectangle {
|
||||||
|
border.color: myButton.down ? theme.backgroundLightest : theme.buttonBorder
|
||||||
|
border.width: 2
|
||||||
|
radius: 10
|
||||||
|
color: myButton.hovered ? theme.backgroundLighter : theme.backgroundLight
|
||||||
|
}
|
||||||
anchors.bottom: textInputView.top
|
anchors.bottom: textInputView.top
|
||||||
anchors.horizontalCenter: textInputView.horizontalCenter
|
anchors.horizontalCenter: textInputView.horizontalCenter
|
||||||
anchors.bottomMargin: 20
|
anchors.bottomMargin: 20
|
||||||
|
@ -64,7 +64,9 @@
|
|||||||
"parameters": "7 billion",
|
"parameters": "7 billion",
|
||||||
"quant": "q4_0",
|
"quant": "q4_0",
|
||||||
"type": "MPT",
|
"type": "MPT",
|
||||||
"description": "<strong>Best overall smaller model</strong><br><ul><li>Fast responses<li>Chat based<li>Trained by Mosaic ML<li>Cannot be used commercially</ul>"
|
"description": "<strong>Best overall smaller model</strong><br><ul><li>Fast responses<li>Chat based<li>Trained by Mosaic ML<li>Cannot be used commercially</ul>",
|
||||||
|
"promptTemplate": "<|im_start|>user\n%1<|im_end|><|im_start|>assistant\n",
|
||||||
|
"systemPrompt": "<|im_start|>system\n- You are a helpful assistant chatbot trained by MosaicML.\n- You answer questions.\n- You are excited to be able to help the user, but will refuse to do anything that could be considered harmful to the user.\n- You are more than just an information source, you are also able to write poetry, short stories, and make jokes.<|im_end|>"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": "g",
|
"order": "g",
|
||||||
|
@ -1,10 +1,142 @@
|
|||||||
#include "modellist.h"
|
#include "modellist.h"
|
||||||
#include "mysettings.h"
|
#include "mysettings.h"
|
||||||
|
#include "network.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
//#define USE_LOCAL_MODELSJSON
|
//#define USE_LOCAL_MODELSJSON
|
||||||
|
|
||||||
|
QString ModelInfo::id() const
|
||||||
|
{
|
||||||
|
return m_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setId(const QString &id)
|
||||||
|
{
|
||||||
|
m_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ModelInfo::name() const
|
||||||
|
{
|
||||||
|
return MySettings::globalInstance()->modelName(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setName(const QString &name)
|
||||||
|
{
|
||||||
|
if (isClone) MySettings::globalInstance()->setModelName(*this, name, isClone /*force*/);
|
||||||
|
m_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ModelInfo::filename() const
|
||||||
|
{
|
||||||
|
return MySettings::globalInstance()->modelFilename(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setFilename(const QString &filename)
|
||||||
|
{
|
||||||
|
if (isClone) MySettings::globalInstance()->setModelFilename(*this, filename, isClone /*force*/);
|
||||||
|
m_filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ModelInfo::temperature() const
|
||||||
|
{
|
||||||
|
return MySettings::globalInstance()->modelTemperature(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setTemperature(double t)
|
||||||
|
{
|
||||||
|
if (isClone) MySettings::globalInstance()->setModelTemperature(*this, t, isClone /*force*/);
|
||||||
|
m_temperature = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ModelInfo::topP() const
|
||||||
|
{
|
||||||
|
return MySettings::globalInstance()->modelTopP(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setTopP(double p)
|
||||||
|
{
|
||||||
|
if (isClone) MySettings::globalInstance()->setModelTopP(*this, p, isClone /*force*/);
|
||||||
|
m_topP = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ModelInfo::topK() const
|
||||||
|
{
|
||||||
|
return MySettings::globalInstance()->modelTopK(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setTopK(int k)
|
||||||
|
{
|
||||||
|
if (isClone) MySettings::globalInstance()->setModelTopK(*this, k, isClone /*force*/);
|
||||||
|
m_topK = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ModelInfo::maxLength() const
|
||||||
|
{
|
||||||
|
return MySettings::globalInstance()->modelMaxLength(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setMaxLength(int l)
|
||||||
|
{
|
||||||
|
if (isClone) MySettings::globalInstance()->setModelMaxLength(*this, l, isClone /*force*/);
|
||||||
|
m_maxLength = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ModelInfo::promptBatchSize() const
|
||||||
|
{
|
||||||
|
return MySettings::globalInstance()->modelPromptBatchSize(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setPromptBatchSize(int s)
|
||||||
|
{
|
||||||
|
if (isClone) MySettings::globalInstance()->setModelPromptBatchSize(*this, s, isClone /*force*/);
|
||||||
|
m_promptBatchSize = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ModelInfo::repeatPenalty() const
|
||||||
|
{
|
||||||
|
return MySettings::globalInstance()->modelRepeatPenalty(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setRepeatPenalty(double p)
|
||||||
|
{
|
||||||
|
if (isClone) MySettings::globalInstance()->setModelRepeatPenalty(*this, p, isClone /*force*/);
|
||||||
|
m_repeatPenalty = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ModelInfo::repeatPenaltyTokens() const
|
||||||
|
{
|
||||||
|
return MySettings::globalInstance()->modelRepeatPenaltyTokens(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setRepeatPenaltyTokens(int t)
|
||||||
|
{
|
||||||
|
if (isClone) MySettings::globalInstance()->setModelRepeatPenaltyTokens(*this, t, isClone /*force*/);
|
||||||
|
m_repeatPenaltyTokens = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ModelInfo::promptTemplate() const
|
||||||
|
{
|
||||||
|
return MySettings::globalInstance()->modelPromptTemplate(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setPromptTemplate(const QString &t)
|
||||||
|
{
|
||||||
|
if (isClone) MySettings::globalInstance()->setModelPromptTemplate(*this, t, isClone /*force*/);
|
||||||
|
m_promptTemplate = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ModelInfo::systemPrompt() const
|
||||||
|
{
|
||||||
|
return MySettings::globalInstance()->modelSystemPrompt(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setSystemPrompt(const QString &p)
|
||||||
|
{
|
||||||
|
if (isClone) MySettings::globalInstance()->setModelSystemPrompt(*this, p, isClone /*force*/);
|
||||||
|
m_systemPrompt = p;
|
||||||
|
}
|
||||||
|
|
||||||
InstalledModels::InstalledModels(QObject *parent)
|
InstalledModels::InstalledModels(QObject *parent)
|
||||||
: QSortFilterProxyModel(parent)
|
: QSortFilterProxyModel(parent)
|
||||||
{
|
{
|
||||||
@ -27,11 +159,11 @@ int InstalledModels::count() const
|
|||||||
return rowCount();
|
return rowCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString InstalledModels::firstFilename() const
|
QString InstalledModels::firstId() const
|
||||||
{
|
{
|
||||||
if (rowCount() > 0) {
|
if (rowCount() > 0) {
|
||||||
QModelIndex firstIndex = index(0, 0);
|
QModelIndex firstIndex = index(0, 0);
|
||||||
return sourceModel()->data(firstIndex, ModelList::FilenameRole).toString();
|
return sourceModel()->data(firstIndex, ModelList::IdRole).toString();
|
||||||
} else {
|
} else {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
@ -96,9 +228,23 @@ ModelList::ModelList()
|
|||||||
m_watcher->addPath(exePath);
|
m_watcher->addPath(exePath);
|
||||||
m_watcher->addPath(MySettings::globalInstance()->modelPath());
|
m_watcher->addPath(MySettings::globalInstance()->modelPath());
|
||||||
connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &ModelList::updateModelsFromDirectory);
|
connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &ModelList::updateModelsFromDirectory);
|
||||||
connect(MySettings::globalInstance(), &MySettings::modelPathChanged, this, &ModelList::updateModelList);
|
connect(MySettings::globalInstance(), &MySettings::modelPathChanged, this, &ModelList::updateModelsFromDirectory);
|
||||||
|
connect(MySettings::globalInstance(), &MySettings::modelPathChanged, this, &ModelList::updateModelsFromJson);
|
||||||
|
connect(MySettings::globalInstance(), &MySettings::modelPathChanged, this, &ModelList::updateModelsFromSettings);
|
||||||
|
connect(MySettings::globalInstance(), &MySettings::nameChanged, this, &ModelList::updateDataForSettings);
|
||||||
|
connect(MySettings::globalInstance(), &MySettings::temperatureChanged, this, &ModelList::updateDataForSettings);
|
||||||
|
connect(MySettings::globalInstance(), &MySettings::topPChanged, this, &ModelList::updateDataForSettings);
|
||||||
|
connect(MySettings::globalInstance(), &MySettings::topKChanged, this, &ModelList::updateDataForSettings);
|
||||||
|
connect(MySettings::globalInstance(), &MySettings::maxLengthChanged, this, &ModelList::updateDataForSettings);
|
||||||
|
connect(MySettings::globalInstance(), &MySettings::promptBatchSizeChanged, this, &ModelList::updateDataForSettings);
|
||||||
|
connect(MySettings::globalInstance(), &MySettings::repeatPenaltyChanged, this, &ModelList::updateDataForSettings);
|
||||||
|
connect(MySettings::globalInstance(), &MySettings::repeatPenaltyTokensChanged, this, &ModelList::updateDataForSettings);;
|
||||||
|
connect(MySettings::globalInstance(), &MySettings::promptTemplateChanged, this, &ModelList::updateDataForSettings);
|
||||||
|
connect(MySettings::globalInstance(), &MySettings::systemPromptChanged, this, &ModelList::updateDataForSettings);
|
||||||
|
|
||||||
|
updateModelsFromJson();
|
||||||
|
updateModelsFromSettings();
|
||||||
updateModelsFromDirectory();
|
updateModelsFromDirectory();
|
||||||
updateModelList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ModelList::incompleteDownloadPath(const QString &modelFile)
|
QString ModelList::incompleteDownloadPath(const QString &modelFile)
|
||||||
@ -124,19 +270,19 @@ const QList<QString> ModelList::userDefaultModelList() const
|
|||||||
QList<QString> models;
|
QList<QString> models;
|
||||||
bool foundUserDefault = false;
|
bool foundUserDefault = false;
|
||||||
for (ModelInfo *info : m_models) {
|
for (ModelInfo *info : m_models) {
|
||||||
if (info->installed && (info->name == userDefaultModelName || info->filename == userDefaultModelName)) {
|
if (info->installed && info->id() == userDefaultModelName) {
|
||||||
foundUserDefault = true;
|
foundUserDefault = true;
|
||||||
models.prepend(info->name.isEmpty() ? info->filename : info->name);
|
models.prepend(info->name());
|
||||||
} else if (info->installed) {
|
} else if (info->installed) {
|
||||||
models.append(info->name.isEmpty() ? info->filename : info->name);
|
models.append(info->name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString defaultFileName = "Application default";
|
const QString defaultId = "Application default";
|
||||||
if (foundUserDefault)
|
if (foundUserDefault)
|
||||||
models.append(defaultFileName);
|
models.append(defaultId);
|
||||||
else
|
else
|
||||||
models.prepend(defaultFileName);
|
models.prepend(defaultId);
|
||||||
return models;
|
return models;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,11 +312,11 @@ ModelInfo ModelList::defaultModelInfo() const
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// If we don't have a user specified default, but *do* have a default setting and match, then use it
|
// If we don't have a user specified default, but *do* have a default setting and match, then use it
|
||||||
if (!hasUserDefaultName && hasDefaultName && (defaultModel->name == defaultModelName || defaultModel->filename == defaultModelName))
|
if (!hasUserDefaultName && hasDefaultName && (defaultModel->id() == defaultModelName))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// If we have a user specified default and match, then use it
|
// If we have a user specified default and match, then use it
|
||||||
if (hasUserDefaultName && (defaultModel->name == userDefaultModelName || defaultModel->filename == userDefaultModelName))
|
if (hasUserDefaultName && (defaultModel->id() == userDefaultModelName))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (defaultModel)
|
if (defaultModel)
|
||||||
@ -178,14 +324,28 @@ ModelInfo ModelList::defaultModelInfo() const
|
|||||||
return ModelInfo();
|
return ModelInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelList::contains(const QString &filename) const
|
bool ModelList::contains(const QString &id) const
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
return m_modelMap.contains(filename);
|
return m_modelMap.contains(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModelList::containsByFilename(const QString &filename) const
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
for (ModelInfo *info : m_models)
|
||||||
|
if (info->filename() == filename)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelList::lessThan(const ModelInfo* a, const ModelInfo* b)
|
bool ModelList::lessThan(const ModelInfo* a, const ModelInfo* b)
|
||||||
{
|
{
|
||||||
|
// Rule 0: Non-clone before clone
|
||||||
|
if (a->isClone != b->isClone) {
|
||||||
|
return !a->isClone;
|
||||||
|
}
|
||||||
|
|
||||||
// Rule 1: Non-empty 'order' before empty
|
// Rule 1: Non-empty 'order' before empty
|
||||||
if (a->order.isEmpty() != b->order.isEmpty()) {
|
if (a->order.isEmpty() != b->order.isEmpty()) {
|
||||||
return !a->order.isEmpty();
|
return !a->order.isEmpty();
|
||||||
@ -196,27 +356,32 @@ bool ModelList::lessThan(const ModelInfo* a, const ModelInfo* b)
|
|||||||
return a->order < b->order;
|
return a->order < b->order;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rule 3: Both 'order' are empty, sort by filename
|
// Rule 3: Both 'order' are empty, sort by id
|
||||||
return a->filename < b->filename;
|
return a->id() < b->id();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelList::addModel(const QString &filename)
|
void ModelList::addModel(const QString &id)
|
||||||
{
|
{
|
||||||
const bool hasModel = contains(filename);
|
const bool hasModel = contains(id);
|
||||||
Q_ASSERT(!hasModel);
|
Q_ASSERT(!hasModel);
|
||||||
if (hasModel) {
|
if (hasModel) {
|
||||||
qWarning() << "ERROR: model list already contains" << filename;
|
qWarning() << "ERROR: model list already contains" << id;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
beginInsertRows(QModelIndex(), m_models.size(), m_models.size());
|
int modelSizeBefore = 0;
|
||||||
int modelSizeAfter = 0;
|
int modelSizeAfter = 0;
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
modelSizeBefore = m_models.size();
|
||||||
|
}
|
||||||
|
beginInsertRows(QModelIndex(), modelSizeBefore, modelSizeBefore);
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
ModelInfo *info = new ModelInfo;
|
ModelInfo *info = new ModelInfo;
|
||||||
info->filename = filename;
|
info->setId(id);
|
||||||
m_models.append(info);
|
m_models.append(info);
|
||||||
m_modelMap.insert(filename, info);
|
m_modelMap.insert(id, info);
|
||||||
std::stable_sort(m_models.begin(), m_models.end(), ModelList::lessThan);
|
std::stable_sort(m_models.begin(), m_models.end(), ModelList::lessThan);
|
||||||
modelSizeAfter = m_models.size();
|
modelSizeAfter = m_models.size();
|
||||||
}
|
}
|
||||||
@ -235,10 +400,12 @@ int ModelList::rowCount(const QModelIndex &parent) const
|
|||||||
QVariant ModelList::dataInternal(const ModelInfo *info, int role) const
|
QVariant ModelList::dataInternal(const ModelInfo *info, int role) const
|
||||||
{
|
{
|
||||||
switch (role) {
|
switch (role) {
|
||||||
|
case IdRole:
|
||||||
|
return info->id();
|
||||||
case NameRole:
|
case NameRole:
|
||||||
return info->name;
|
return info->name();
|
||||||
case FilenameRole:
|
case FilenameRole:
|
||||||
return info->filename;
|
return info->filename();
|
||||||
case DirpathRole:
|
case DirpathRole:
|
||||||
return info->dirpath;
|
return info->dirpath;
|
||||||
case FilesizeRole:
|
case FilesizeRole:
|
||||||
@ -287,15 +454,35 @@ QVariant ModelList::dataInternal(const ModelInfo *info, int role) const
|
|||||||
return info->quant;
|
return info->quant;
|
||||||
case TypeRole:
|
case TypeRole:
|
||||||
return info->type;
|
return info->type;
|
||||||
|
case IsCloneRole:
|
||||||
|
return info->isClone;
|
||||||
|
case TemperatureRole:
|
||||||
|
return info->temperature();
|
||||||
|
case TopPRole:
|
||||||
|
return info->topP();
|
||||||
|
case TopKRole:
|
||||||
|
return info->topK();
|
||||||
|
case MaxLengthRole:
|
||||||
|
return info->maxLength();
|
||||||
|
case PromptBatchSizeRole:
|
||||||
|
return info->promptBatchSize();
|
||||||
|
case RepeatPenaltyRole:
|
||||||
|
return info->repeatPenalty();
|
||||||
|
case RepeatPenaltyTokensRole:
|
||||||
|
return info->repeatPenaltyTokens();
|
||||||
|
case PromptTemplateRole:
|
||||||
|
return info->promptTemplate();
|
||||||
|
case SystemPromptRole:
|
||||||
|
return info->systemPrompt();
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant ModelList::data(const QString &filename, int role) const
|
QVariant ModelList::data(const QString &id, int role) const
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
ModelInfo *info = m_modelMap.value(filename);
|
ModelInfo *info = m_modelMap.value(id);
|
||||||
return dataInternal(info, role);
|
return dataInternal(info, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +495,7 @@ QVariant ModelList::data(const QModelIndex &index, int role) const
|
|||||||
return dataInternal(info, role);
|
return dataInternal(info, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelList::updateData(const QString &filename, int role, const QVariant &value)
|
void ModelList::updateData(const QString &id, int role, const QVariant &value)
|
||||||
{
|
{
|
||||||
int modelSize;
|
int modelSize;
|
||||||
bool updateInstalled;
|
bool updateInstalled;
|
||||||
@ -316,23 +503,25 @@ void ModelList::updateData(const QString &filename, int role, const QVariant &va
|
|||||||
int index;
|
int index;
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
if (!m_modelMap.contains(filename)) {
|
if (!m_modelMap.contains(id)) {
|
||||||
qWarning() << "ERROR: cannot update as model map does not contain" << filename;
|
qWarning() << "ERROR: cannot update as model map does not contain" << id;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelInfo *info = m_modelMap.value(filename);
|
ModelInfo *info = m_modelMap.value(id);
|
||||||
index = m_models.indexOf(info);
|
index = m_models.indexOf(info);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
qWarning() << "ERROR: cannot update as model list does not contain" << filename;
|
qWarning() << "ERROR: cannot update as model list does not contain" << id;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
|
case IdRole:
|
||||||
|
info->setId(value.toString()); break;
|
||||||
case NameRole:
|
case NameRole:
|
||||||
info->name = value.toString(); break;
|
info->setName(value.toString()); break;
|
||||||
case FilenameRole:
|
case FilenameRole:
|
||||||
info->filename = value.toString(); break;
|
info->setFilename(value.toString()); break;
|
||||||
case DirpathRole:
|
case DirpathRole:
|
||||||
info->dirpath = value.toString(); break;
|
info->dirpath = value.toString(); break;
|
||||||
case FilesizeRole:
|
case FilesizeRole:
|
||||||
@ -381,15 +570,35 @@ void ModelList::updateData(const QString &filename, int role, const QVariant &va
|
|||||||
info->quant = value.toString(); break;
|
info->quant = value.toString(); break;
|
||||||
case TypeRole:
|
case TypeRole:
|
||||||
info->type = value.toString(); break;
|
info->type = value.toString(); break;
|
||||||
|
case IsCloneRole:
|
||||||
|
info->isClone = value.toBool(); break;
|
||||||
|
case TemperatureRole:
|
||||||
|
info->setTemperature(value.toDouble()); break;
|
||||||
|
case TopPRole:
|
||||||
|
info->setTopP(value.toDouble()); break;
|
||||||
|
case TopKRole:
|
||||||
|
info->setTopK(value.toInt()); break;
|
||||||
|
case MaxLengthRole:
|
||||||
|
info->setMaxLength(value.toInt()); break;
|
||||||
|
case PromptBatchSizeRole:
|
||||||
|
info->setPromptBatchSize(value.toInt()); break;
|
||||||
|
case RepeatPenaltyRole:
|
||||||
|
info->setRepeatPenalty(value.toDouble()); break;
|
||||||
|
case RepeatPenaltyTokensRole:
|
||||||
|
info->setRepeatPenaltyTokens(value.toInt()); break;
|
||||||
|
case PromptTemplateRole:
|
||||||
|
info->setPromptTemplate(value.toString()); break;
|
||||||
|
case SystemPromptRole:
|
||||||
|
info->setSystemPrompt(value.toString()); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra guarantee that these always remains in sync with filesystem
|
// Extra guarantee that these always remains in sync with filesystem
|
||||||
QFileInfo fileInfo(info->dirpath + info->filename);
|
QFileInfo fileInfo(info->dirpath + info->filename());
|
||||||
if (info->installed != fileInfo.exists()) {
|
if (info->installed != fileInfo.exists()) {
|
||||||
info->installed = fileInfo.exists();
|
info->installed = fileInfo.exists();
|
||||||
updateInstalled = true;
|
updateInstalled = true;
|
||||||
}
|
}
|
||||||
QFileInfo incompleteInfo(incompleteDownloadPath(info->filename));
|
QFileInfo incompleteInfo(incompleteDownloadPath(info->filename()));
|
||||||
if (info->isIncomplete != incompleteInfo.exists()) {
|
if (info->isIncomplete != incompleteInfo.exists()) {
|
||||||
info->isIncomplete = incompleteInfo.exists();
|
info->isIncomplete = incompleteInfo.exists();
|
||||||
updateIncomplete = true;
|
updateIncomplete = true;
|
||||||
@ -402,12 +611,120 @@ void ModelList::updateData(const QString &filename, int role, const QVariant &va
|
|||||||
emit userDefaultModelListChanged();
|
emit userDefaultModelListChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelInfo ModelList::modelInfo(const QString &filename) const
|
ModelInfo ModelList::modelInfo(const QString &id) const
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
if (!m_modelMap.contains(filename))
|
if (!m_modelMap.contains(id))
|
||||||
return ModelInfo();
|
return ModelInfo();
|
||||||
return *m_modelMap.value(filename);
|
return *m_modelMap.value(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelInfo ModelList::modelInfoByFilename(const QString &filename) const
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
for (ModelInfo *info : m_models)
|
||||||
|
if (info->filename() == filename)
|
||||||
|
return *info;
|
||||||
|
return ModelInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModelList::isUniqueName(const QString &name) const
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
for (const ModelInfo *info : m_models) {
|
||||||
|
if(info->name() == name)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ModelList::clone(const ModelInfo &model)
|
||||||
|
{
|
||||||
|
const QString id = Network::globalInstance()->generateUniqueId();
|
||||||
|
addModel(id);
|
||||||
|
updateData(id, ModelList::IsCloneRole, true);
|
||||||
|
updateData(id, ModelList::NameRole, uniqueModelName(model));
|
||||||
|
updateData(id, ModelList::FilenameRole, model.filename());
|
||||||
|
updateData(id, ModelList::DirpathRole, model.dirpath);
|
||||||
|
updateData(id, ModelList::InstalledRole, model.installed);
|
||||||
|
updateData(id, ModelList::ChatGPTRole, model.isChatGPT);
|
||||||
|
updateData(id, ModelList::TemperatureRole, model.temperature());
|
||||||
|
updateData(id, ModelList::TopPRole, model.topP());
|
||||||
|
updateData(id, ModelList::TopKRole, model.topK());
|
||||||
|
updateData(id, ModelList::MaxLengthRole, model.maxLength());
|
||||||
|
updateData(id, ModelList::PromptBatchSizeRole, model.promptBatchSize());
|
||||||
|
updateData(id, ModelList::RepeatPenaltyRole, model.repeatPenalty());
|
||||||
|
updateData(id, ModelList::RepeatPenaltyTokensRole, model.repeatPenaltyTokens());
|
||||||
|
updateData(id, ModelList::PromptTemplateRole, model.promptTemplate());
|
||||||
|
updateData(id, ModelList::SystemPromptRole, model.systemPrompt());
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelList::remove(const ModelInfo &model)
|
||||||
|
{
|
||||||
|
Q_ASSERT(model.isClone);
|
||||||
|
if (!model.isClone)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const bool hasModel = contains(model.id());
|
||||||
|
Q_ASSERT(hasModel);
|
||||||
|
if (!hasModel) {
|
||||||
|
qWarning() << "ERROR: model list does not contain" << model.id();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int indexOfModel = 0;
|
||||||
|
int modelSizeAfter = 0;
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
ModelInfo *info = m_modelMap.value(model.id());
|
||||||
|
indexOfModel = m_models.indexOf(info);
|
||||||
|
}
|
||||||
|
beginRemoveRows(QModelIndex(), indexOfModel, indexOfModel);
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
ModelInfo *info = m_models.takeAt(indexOfModel);
|
||||||
|
m_modelMap.remove(info->id());
|
||||||
|
delete info;
|
||||||
|
modelSizeAfter = m_models.size();
|
||||||
|
}
|
||||||
|
endRemoveRows();
|
||||||
|
emit dataChanged(index(0, 0), index(modelSizeAfter - 1, 0));
|
||||||
|
emit userDefaultModelListChanged();
|
||||||
|
MySettings::globalInstance()->eraseModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ModelList::uniqueModelName(const ModelInfo &model) const
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
QRegularExpression re("^(.*)~(\\d+)$");
|
||||||
|
QRegularExpressionMatch match = re.match(model.name());
|
||||||
|
QString baseName;
|
||||||
|
if (match.hasMatch())
|
||||||
|
baseName = match.captured(1);
|
||||||
|
else
|
||||||
|
baseName = model.name();
|
||||||
|
|
||||||
|
int maxSuffixNumber = 0;
|
||||||
|
bool baseNameExists = false;
|
||||||
|
|
||||||
|
for (const ModelInfo *info : m_models) {
|
||||||
|
if(info->name() == baseName)
|
||||||
|
baseNameExists = true;
|
||||||
|
|
||||||
|
QRegularExpressionMatch match = re.match(info->name());
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
QString currentBaseName = match.captured(1);
|
||||||
|
int currentSuffixNumber = match.captured(2).toInt();
|
||||||
|
if (currentBaseName == baseName && currentSuffixNumber > maxSuffixNumber)
|
||||||
|
maxSuffixNumber = currentSuffixNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baseNameExists)
|
||||||
|
return baseName + "~" + QString::number(maxSuffixNumber + 1);
|
||||||
|
|
||||||
|
return baseName;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ModelList::modelDirPath(const QString &modelName, bool isChatGPT)
|
QString ModelList::modelDirPath(const QString &modelName, bool isChatGPT)
|
||||||
@ -456,12 +773,25 @@ void ModelList::updateModelsFromDirectory()
|
|||||||
if (!info.exists())
|
if (!info.exists())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!contains(filename))
|
QVector<QString> modelsById;
|
||||||
addModel(filename);
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
for (ModelInfo *info : m_models)
|
||||||
|
if (info->filename() == filename)
|
||||||
|
modelsById.append(info->id());
|
||||||
|
}
|
||||||
|
|
||||||
updateData(filename, ChatGPTRole, filename.startsWith("chatgpt-"));
|
if (modelsById.isEmpty()) {
|
||||||
updateData(filename, DirpathRole, path);
|
addModel(filename);
|
||||||
updateData(filename, FilesizeRole, toFileSize(info.size()));
|
modelsById.append(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const QString &id : modelsById) {
|
||||||
|
updateData(id, FilenameRole, filename);
|
||||||
|
updateData(id, ChatGPTRole, filename.startsWith("chatgpt-"));
|
||||||
|
updateData(id, DirpathRole, path);
|
||||||
|
updateData(id, FilesizeRole, toFileSize(info.size()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,9 +800,17 @@ void ModelList::updateModelsFromDirectory()
|
|||||||
processDirectory(exePath);
|
processDirectory(exePath);
|
||||||
if (localPath != exePath)
|
if (localPath != exePath)
|
||||||
processDirectory(localPath);
|
processDirectory(localPath);
|
||||||
|
|
||||||
|
if (installedModels()->count()) {
|
||||||
|
const QString firstModel =
|
||||||
|
installedModels()->firstId();
|
||||||
|
QSettings settings;
|
||||||
|
settings.setValue("defaultModel", firstModel);
|
||||||
|
settings.sync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelList::updateModelList()
|
void ModelList::updateModelsFromJson()
|
||||||
{
|
{
|
||||||
#if defined(USE_LOCAL_MODELSJSON)
|
#if defined(USE_LOCAL_MODELSJSON)
|
||||||
QUrl jsonUrl("file://" + QDir::homePath() + "/dev/large_language_models/gpt4all/gpt4all-chat/metadata/models.json");
|
QUrl jsonUrl("file://" + QDir::homePath() + "/dev/large_language_models/gpt4all/gpt4all-chat/metadata/models.json");
|
||||||
@ -498,8 +836,9 @@ void ModelList::updateModelList()
|
|||||||
delete jsonReply;
|
delete jsonReply;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool operator==(const ModelInfo& lhs, const ModelInfo& rhs) {
|
void ModelList::updateDataForSettings()
|
||||||
return lhs.filename == rhs.filename && lhs.md5sum == rhs.md5sum;
|
{
|
||||||
|
emit dataChanged(index(0, 0), index(m_models.size() - 1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool compareVersions(const QString &a, const QString &b) {
|
static bool compareVersions(const QString &a, const QString &b) {
|
||||||
@ -566,24 +905,45 @@ void ModelList::parseModelsJsonFile(const QByteArray &jsonData)
|
|||||||
|
|
||||||
modelFilesize = ModelList::toFileSize(modelFilesize.toULongLong());
|
modelFilesize = ModelList::toFileSize(modelFilesize.toULongLong());
|
||||||
|
|
||||||
if (!contains(modelFilename))
|
const QString id = modelName;
|
||||||
addModel(modelFilename);
|
Q_ASSERT(!id.isEmpty());
|
||||||
|
|
||||||
if (!modelName.isEmpty())
|
if (!contains(id))
|
||||||
updateData(modelFilename, ModelList::NameRole, modelName);
|
addModel(id);
|
||||||
updateData(modelFilename, ModelList::FilesizeRole, modelFilesize);
|
|
||||||
updateData(modelFilename, ModelList::Md5sumRole, modelMd5sum);
|
updateData(id, ModelList::NameRole, modelName);
|
||||||
updateData(modelFilename, ModelList::DefaultRole, isDefault);
|
updateData(id, ModelList::FilenameRole, modelFilename);
|
||||||
updateData(modelFilename, ModelList::DescriptionRole, description);
|
updateData(id, ModelList::FilesizeRole, modelFilesize);
|
||||||
updateData(modelFilename, ModelList::RequiresVersionRole, requiresVersion);
|
updateData(id, ModelList::Md5sumRole, modelMd5sum);
|
||||||
updateData(modelFilename, ModelList::DeprecatedVersionRole, deprecatedVersion);
|
updateData(id, ModelList::DefaultRole, isDefault);
|
||||||
updateData(modelFilename, ModelList::UrlRole, url);
|
updateData(id, ModelList::DescriptionRole, description);
|
||||||
updateData(modelFilename, ModelList::DisableGUIRole, disableGUI);
|
updateData(id, ModelList::RequiresVersionRole, requiresVersion);
|
||||||
updateData(modelFilename, ModelList::OrderRole, order);
|
updateData(id, ModelList::DeprecatedVersionRole, deprecatedVersion);
|
||||||
updateData(modelFilename, ModelList::RamrequiredRole, ramrequired);
|
updateData(id, ModelList::UrlRole, url);
|
||||||
updateData(modelFilename, ModelList::ParametersRole, parameters);
|
updateData(id, ModelList::DisableGUIRole, disableGUI);
|
||||||
updateData(modelFilename, ModelList::QuantRole, quant);
|
updateData(id, ModelList::OrderRole, order);
|
||||||
updateData(modelFilename, ModelList::TypeRole, type);
|
updateData(id, ModelList::RamrequiredRole, ramrequired);
|
||||||
|
updateData(id, ModelList::ParametersRole, parameters);
|
||||||
|
updateData(id, ModelList::QuantRole, quant);
|
||||||
|
updateData(id, ModelList::TypeRole, type);
|
||||||
|
if (obj.contains("temperature"))
|
||||||
|
updateData(id, ModelList::TemperatureRole, obj["temperature"].toDouble());
|
||||||
|
if (obj.contains("topP"))
|
||||||
|
updateData(id, ModelList::TopPRole, obj["topP"].toDouble());
|
||||||
|
if (obj.contains("topK"))
|
||||||
|
updateData(id, ModelList::TopKRole, obj["topK"].toInt());
|
||||||
|
if (obj.contains("maxLength"))
|
||||||
|
updateData(id, ModelList::MaxLengthRole, obj["maxLength"].toInt());
|
||||||
|
if (obj.contains("promptBatchSize"))
|
||||||
|
updateData(id, ModelList::PromptBatchSizeRole, obj["promptBatchSize"].toInt());
|
||||||
|
if (obj.contains("repeatPenalty"))
|
||||||
|
updateData(id, ModelList::RepeatPenaltyRole, obj["repeatPenalty"].toDouble());
|
||||||
|
if (obj.contains("repeatPenaltyTokens"))
|
||||||
|
updateData(id, ModelList::RepeatPenaltyTokensRole, obj["repeatPenaltyTokens"].toInt());
|
||||||
|
if (obj.contains("promptTemplate"))
|
||||||
|
updateData(id, ModelList::PromptTemplateRole, obj["promptTemplate"].toString());
|
||||||
|
if (obj.contains("systemPrompt"))
|
||||||
|
updateData(id, ModelList::SystemPromptRole, obj["systemPrompt"].toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString chatGPTDesc = tr("<ul><li>Requires personal OpenAI API key.</li><li>WARNING: Will send"
|
const QString chatGPTDesc = tr("<ul><li>Requires personal OpenAI API key.</li><li>WARNING: Will send"
|
||||||
@ -592,44 +952,105 @@ void ModelList::parseModelsJsonFile(const QByteArray &jsonData)
|
|||||||
" <a href=\"https://platform.openai.com/account/api-keys\">here.</a></li>");
|
" <a href=\"https://platform.openai.com/account/api-keys\">here.</a></li>");
|
||||||
|
|
||||||
{
|
{
|
||||||
|
const QString modelName = "ChatGPT-3.5 Turbo";
|
||||||
|
const QString id = modelName;
|
||||||
const QString modelFilename = "chatgpt-gpt-3.5-turbo.txt";
|
const QString modelFilename = "chatgpt-gpt-3.5-turbo.txt";
|
||||||
if (!contains(modelFilename))
|
if (!contains(id))
|
||||||
addModel(modelFilename);
|
addModel(id);
|
||||||
updateData(modelFilename, ModelList::NameRole, "ChatGPT-3.5 Turbo");
|
updateData(id, ModelList::NameRole, modelName);
|
||||||
updateData(modelFilename, ModelList::FilesizeRole, "minimal");
|
updateData(id, ModelList::FilenameRole, modelFilename);
|
||||||
updateData(modelFilename, ModelList::ChatGPTRole, true);
|
updateData(id, ModelList::FilesizeRole, "minimal");
|
||||||
updateData(modelFilename, ModelList::DescriptionRole,
|
updateData(id, ModelList::ChatGPTRole, true);
|
||||||
|
updateData(id, ModelList::DescriptionRole,
|
||||||
tr("<strong>OpenAI's ChatGPT model GPT-3.5 Turbo</strong><br>") + chatGPTDesc);
|
tr("<strong>OpenAI's ChatGPT model GPT-3.5 Turbo</strong><br>") + chatGPTDesc);
|
||||||
updateData(modelFilename, ModelList::RequiresVersionRole, "2.4.2");
|
updateData(id, ModelList::RequiresVersionRole, "2.4.2");
|
||||||
updateData(modelFilename, ModelList::OrderRole, "ca");
|
updateData(id, ModelList::OrderRole, "ca");
|
||||||
updateData(modelFilename, ModelList::RamrequiredRole, 0);
|
updateData(id, ModelList::RamrequiredRole, 0);
|
||||||
updateData(modelFilename, ModelList::ParametersRole, "?");
|
updateData(id, ModelList::ParametersRole, "?");
|
||||||
updateData(modelFilename, ModelList::QuantRole, "NA");
|
updateData(id, ModelList::QuantRole, "NA");
|
||||||
updateData(modelFilename, ModelList::TypeRole, "GPT");
|
updateData(id, ModelList::TypeRole, "GPT");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
const QString modelName = "ChatGPT-4";
|
||||||
|
const QString id = modelName;
|
||||||
const QString modelFilename = "chatgpt-gpt-4.txt";
|
const QString modelFilename = "chatgpt-gpt-4.txt";
|
||||||
if (!contains(modelFilename))
|
if (!contains(id))
|
||||||
addModel(modelFilename);
|
addModel(id);
|
||||||
updateData(modelFilename, ModelList::NameRole, "ChatGPT-4");
|
updateData(id, ModelList::NameRole, modelName);
|
||||||
updateData(modelFilename, ModelList::FilesizeRole, "minimal");
|
updateData(id, ModelList::FilenameRole, modelFilename);
|
||||||
updateData(modelFilename, ModelList::ChatGPTRole, true);
|
updateData(id, ModelList::FilesizeRole, "minimal");
|
||||||
updateData(modelFilename, ModelList::DescriptionRole,
|
updateData(id, ModelList::ChatGPTRole, true);
|
||||||
|
updateData(id, ModelList::DescriptionRole,
|
||||||
tr("<strong>OpenAI's ChatGPT model GPT-4</strong><br>") + chatGPTDesc);
|
tr("<strong>OpenAI's ChatGPT model GPT-4</strong><br>") + chatGPTDesc);
|
||||||
updateData(modelFilename, ModelList::RequiresVersionRole, "2.4.2");
|
updateData(id, ModelList::RequiresVersionRole, "2.4.2");
|
||||||
updateData(modelFilename, ModelList::OrderRole, "cb");
|
updateData(id, ModelList::OrderRole, "cb");
|
||||||
updateData(modelFilename, ModelList::RamrequiredRole, 0);
|
updateData(id, ModelList::RamrequiredRole, 0);
|
||||||
updateData(modelFilename, ModelList::ParametersRole, "?");
|
updateData(id, ModelList::ParametersRole, "?");
|
||||||
updateData(modelFilename, ModelList::QuantRole, "NA");
|
updateData(id, ModelList::QuantRole, "NA");
|
||||||
updateData(modelFilename, ModelList::TypeRole, "GPT");
|
updateData(id, ModelList::TypeRole, "GPT");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (installedModels()->count()) {
|
if (installedModels()->count()) {
|
||||||
const QString firstModel =
|
const QString firstModel =
|
||||||
installedModels()->firstFilename();
|
installedModels()->firstId();
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.setValue("defaultModel", firstModel);
|
settings.setValue("defaultModel", firstModel);
|
||||||
settings.sync();
|
settings.sync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModelList::updateModelsFromSettings()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
settings.sync();
|
||||||
|
QStringList groups = settings.childGroups();
|
||||||
|
for (const QString g : groups) {
|
||||||
|
if (!g.startsWith("model-"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const QString id = g.sliced(6);
|
||||||
|
if (contains(id))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!settings.contains(g+ "/isClone"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Q_ASSERT(settings.contains(g + "/name"));
|
||||||
|
const QString name = settings.value(g + "/name").toString();
|
||||||
|
Q_ASSERT(settings.contains(g + "/filename"));
|
||||||
|
const QString filename = settings.value(g + "/filename").toString();
|
||||||
|
Q_ASSERT(settings.contains(g + "/temperature"));
|
||||||
|
const double temperature = settings.value(g + "/temperature").toDouble();
|
||||||
|
Q_ASSERT(settings.contains(g + "/topP"));
|
||||||
|
const double topP = settings.value(g + "/topP").toDouble();
|
||||||
|
Q_ASSERT(settings.contains(g + "/topK"));
|
||||||
|
const int topK = settings.value(g + "/topK").toInt();
|
||||||
|
Q_ASSERT(settings.contains(g + "/maxLength"));
|
||||||
|
const int maxLength = settings.value(g + "/maxLength").toInt();
|
||||||
|
Q_ASSERT(settings.contains(g + "/promptBatchSize"));
|
||||||
|
const int promptBatchSize = settings.value(g + "/promptBatchSize").toInt();
|
||||||
|
Q_ASSERT(settings.contains(g + "/repeatPenalty"));
|
||||||
|
const double repeatPenalty = settings.value(g + "/repeatPenalty").toDouble();
|
||||||
|
Q_ASSERT(settings.contains(g + "/repeatPenaltyTokens"));
|
||||||
|
const int repeatPenaltyTokens = settings.value(g + "/repeatPenaltyTokens").toInt();
|
||||||
|
Q_ASSERT(settings.contains(g + "/promptTemplate"));
|
||||||
|
const QString promptTemplate = settings.value(g + "/promptTemplate").toString();
|
||||||
|
Q_ASSERT(settings.contains(g + "/systemPrompt"));
|
||||||
|
const QString systemPrompt = settings.value(g + "/systemPrompt").toString();
|
||||||
|
|
||||||
|
addModel(id);
|
||||||
|
updateData(id, ModelList::IsCloneRole, true);
|
||||||
|
updateData(id, ModelList::NameRole, name);
|
||||||
|
updateData(id, ModelList::FilenameRole, filename);
|
||||||
|
updateData(id, ModelList::TemperatureRole, temperature);
|
||||||
|
updateData(id, ModelList::TopPRole, topP);
|
||||||
|
updateData(id, ModelList::TopKRole, topK);
|
||||||
|
updateData(id, ModelList::MaxLengthRole, maxLength);
|
||||||
|
updateData(id, ModelList::PromptBatchSizeRole, promptBatchSize);
|
||||||
|
updateData(id, ModelList::RepeatPenaltyRole, repeatPenalty);
|
||||||
|
updateData(id, ModelList::RepeatPenaltyTokensRole, repeatPenaltyTokens);
|
||||||
|
updateData(id, ModelList::PromptTemplateRole, promptTemplate);
|
||||||
|
updateData(id, ModelList::SystemPromptRole, systemPrompt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,8 +6,9 @@
|
|||||||
|
|
||||||
struct ModelInfo {
|
struct ModelInfo {
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
Q_PROPERTY(QString name MEMBER name)
|
Q_PROPERTY(QString id READ id WRITE setId)
|
||||||
Q_PROPERTY(QString filename MEMBER filename)
|
Q_PROPERTY(QString name READ name WRITE setName)
|
||||||
|
Q_PROPERTY(QString filename READ filename WRITE setFilename)
|
||||||
Q_PROPERTY(QString dirpath MEMBER dirpath)
|
Q_PROPERTY(QString dirpath MEMBER dirpath)
|
||||||
Q_PROPERTY(QString filesize MEMBER filesize)
|
Q_PROPERTY(QString filesize MEMBER filesize)
|
||||||
Q_PROPERTY(QByteArray md5sum MEMBER md5sum)
|
Q_PROPERTY(QByteArray md5sum MEMBER md5sum)
|
||||||
@ -32,10 +33,27 @@ struct ModelInfo {
|
|||||||
Q_PROPERTY(QString parameters MEMBER parameters)
|
Q_PROPERTY(QString parameters MEMBER parameters)
|
||||||
Q_PROPERTY(QString quant MEMBER quant)
|
Q_PROPERTY(QString quant MEMBER quant)
|
||||||
Q_PROPERTY(QString type MEMBER type)
|
Q_PROPERTY(QString type MEMBER type)
|
||||||
|
Q_PROPERTY(bool isClone MEMBER isClone)
|
||||||
|
Q_PROPERTY(double temperature READ temperature WRITE setTemperature)
|
||||||
|
Q_PROPERTY(double topP READ topP WRITE setTopP)
|
||||||
|
Q_PROPERTY(int topK READ topK WRITE setTopK)
|
||||||
|
Q_PROPERTY(int maxLength READ maxLength WRITE setMaxLength)
|
||||||
|
Q_PROPERTY(int promptBatchSize READ promptBatchSize WRITE setPromptBatchSize)
|
||||||
|
Q_PROPERTY(double repeatPenalty READ repeatPenalty WRITE setRepeatPenalty)
|
||||||
|
Q_PROPERTY(int repeatPenaltyTokens READ repeatPenaltyTokens WRITE setRepeatPenaltyTokens)
|
||||||
|
Q_PROPERTY(QString promptTemplate READ promptTemplate WRITE setPromptTemplate)
|
||||||
|
Q_PROPERTY(QString systemPrompt READ systemPrompt WRITE setSystemPrompt)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QString name;
|
QString id() const;
|
||||||
QString filename;
|
void setId(const QString &id);
|
||||||
|
|
||||||
|
QString name() const;
|
||||||
|
void setName(const QString &name);
|
||||||
|
|
||||||
|
QString filename() const;
|
||||||
|
void setFilename(const QString &name);
|
||||||
|
|
||||||
QString dirpath;
|
QString dirpath;
|
||||||
QString filesize;
|
QString filesize;
|
||||||
QByteArray md5sum;
|
QByteArray md5sum;
|
||||||
@ -60,9 +78,45 @@ public:
|
|||||||
QString parameters;
|
QString parameters;
|
||||||
QString quant;
|
QString quant;
|
||||||
QString type;
|
QString type;
|
||||||
|
bool isClone = false;
|
||||||
|
|
||||||
bool operator==(const ModelInfo &other) const {
|
bool operator==(const ModelInfo &other) const {
|
||||||
return filename == other.filename;
|
return m_id == other.m_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double temperature() const;
|
||||||
|
void setTemperature(double t);
|
||||||
|
double topP() const;
|
||||||
|
void setTopP(double p);
|
||||||
|
int topK() const;
|
||||||
|
void setTopK(int k);
|
||||||
|
int maxLength() const;
|
||||||
|
void setMaxLength(int l);
|
||||||
|
int promptBatchSize() const;
|
||||||
|
void setPromptBatchSize(int s);
|
||||||
|
double repeatPenalty() const;
|
||||||
|
void setRepeatPenalty(double p);
|
||||||
|
int repeatPenaltyTokens() const;
|
||||||
|
void setRepeatPenaltyTokens(int t);
|
||||||
|
QString promptTemplate() const;
|
||||||
|
void setPromptTemplate(const QString &t);
|
||||||
|
QString systemPrompt() const;
|
||||||
|
void setSystemPrompt(const QString &p);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_id;
|
||||||
|
QString m_name;
|
||||||
|
QString m_filename;
|
||||||
|
double m_temperature = 0.7;
|
||||||
|
double m_topP = 0.1;
|
||||||
|
int m_topK = 40;
|
||||||
|
int m_maxLength = 4096;
|
||||||
|
int m_promptBatchSize = 128;
|
||||||
|
double m_repeatPenalty = 1.18;
|
||||||
|
int m_repeatPenaltyTokens = 64;
|
||||||
|
QString m_promptTemplate = "### Human:\n%1\n### Assistant:\n";
|
||||||
|
QString m_systemPrompt = "### System:\nYou are an AI assistant who gives quality response to whatever humans ask of you.\n";
|
||||||
|
friend class MySettings;
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(ModelInfo)
|
Q_DECLARE_METATYPE(ModelInfo)
|
||||||
|
|
||||||
@ -73,7 +127,7 @@ class InstalledModels : public QSortFilterProxyModel
|
|||||||
public:
|
public:
|
||||||
explicit InstalledModels(QObject *parent);
|
explicit InstalledModels(QObject *parent);
|
||||||
int count() const;
|
int count() const;
|
||||||
QString firstFilename() const;
|
QString firstId() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void countChanged();
|
void countChanged();
|
||||||
@ -120,7 +174,8 @@ public:
|
|||||||
static ModelList *globalInstance();
|
static ModelList *globalInstance();
|
||||||
|
|
||||||
enum Roles {
|
enum Roles {
|
||||||
NameRole = Qt::UserRole + 1,
|
IdRole = Qt::UserRole + 1,
|
||||||
|
NameRole,
|
||||||
FilenameRole,
|
FilenameRole,
|
||||||
DirpathRole,
|
DirpathRole,
|
||||||
FilesizeRole,
|
FilesizeRole,
|
||||||
@ -145,12 +200,23 @@ public:
|
|||||||
RamrequiredRole,
|
RamrequiredRole,
|
||||||
ParametersRole,
|
ParametersRole,
|
||||||
QuantRole,
|
QuantRole,
|
||||||
TypeRole
|
TypeRole,
|
||||||
|
IsCloneRole,
|
||||||
|
TemperatureRole,
|
||||||
|
TopPRole,
|
||||||
|
TopKRole,
|
||||||
|
MaxLengthRole,
|
||||||
|
PromptBatchSizeRole,
|
||||||
|
RepeatPenaltyRole,
|
||||||
|
RepeatPenaltyTokensRole,
|
||||||
|
PromptTemplateRole,
|
||||||
|
SystemPromptRole,
|
||||||
};
|
};
|
||||||
|
|
||||||
QHash<int, QByteArray> roleNames() const override
|
QHash<int, QByteArray> roleNames() const override
|
||||||
{
|
{
|
||||||
QHash<int, QByteArray> roles;
|
QHash<int, QByteArray> roles;
|
||||||
|
roles[IdRole] = "id";
|
||||||
roles[NameRole] = "name";
|
roles[NameRole] = "name";
|
||||||
roles[FilenameRole] = "filename";
|
roles[FilenameRole] = "filename";
|
||||||
roles[DirpathRole] = "dirpath";
|
roles[DirpathRole] = "dirpath";
|
||||||
@ -177,21 +243,36 @@ public:
|
|||||||
roles[ParametersRole] = "parameters";
|
roles[ParametersRole] = "parameters";
|
||||||
roles[QuantRole] = "quant";
|
roles[QuantRole] = "quant";
|
||||||
roles[TypeRole] = "type";
|
roles[TypeRole] = "type";
|
||||||
|
roles[IsCloneRole] = "isClone";
|
||||||
|
roles[TemperatureRole] = "temperature";
|
||||||
|
roles[TopPRole] = "topP";
|
||||||
|
roles[TopKRole] = "topK";
|
||||||
|
roles[MaxLengthRole] = "maxLength";
|
||||||
|
roles[PromptBatchSizeRole] = "promptBatchSize";
|
||||||
|
roles[RepeatPenaltyRole] = "repeatPenalty";
|
||||||
|
roles[RepeatPenaltyTokensRole] = "repeatPenaltyTokens";
|
||||||
|
roles[PromptTemplateRole] = "promptTemplate";
|
||||||
|
roles[SystemPromptRole] = "systemPrompt";
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
QVariant data(const QString &filename, int role) const;
|
QVariant data(const QString &id, int role) const;
|
||||||
void updateData(const QString &filename, int role, const QVariant &value);
|
void updateData(const QString &id, int role, const QVariant &value);
|
||||||
|
|
||||||
int count() const { return m_models.size(); }
|
int count() const { return m_models.size(); }
|
||||||
|
|
||||||
bool contains(const QString &filename) const;
|
bool contains(const QString &id) const;
|
||||||
Q_INVOKABLE ModelInfo modelInfo(const QString &filename) const;
|
bool containsByFilename(const QString &filename) const;
|
||||||
|
Q_INVOKABLE ModelInfo modelInfo(const QString &id) const;
|
||||||
|
Q_INVOKABLE ModelInfo modelInfoByFilename(const QString &filename) const;
|
||||||
|
Q_INVOKABLE bool isUniqueName(const QString &name) const;
|
||||||
|
Q_INVOKABLE QString clone(const ModelInfo &model);
|
||||||
|
Q_INVOKABLE void remove(const ModelInfo &model);
|
||||||
ModelInfo defaultModelInfo() const;
|
ModelInfo defaultModelInfo() const;
|
||||||
|
|
||||||
void addModel(const QString &filename);
|
void addModel(const QString &id);
|
||||||
|
|
||||||
const QList<ModelInfo> exportModelList() const;
|
const QList<ModelInfo> exportModelList() const;
|
||||||
const QList<QString> userDefaultModelList() const;
|
const QList<QString> userDefaultModelList() const;
|
||||||
@ -220,8 +301,10 @@ Q_SIGNALS:
|
|||||||
void userDefaultModelListChanged();
|
void userDefaultModelListChanged();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
|
void updateModelsFromJson();
|
||||||
|
void updateModelsFromSettings();
|
||||||
void updateModelsFromDirectory();
|
void updateModelsFromDirectory();
|
||||||
void updateModelList();
|
void updateDataForSettings();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString modelDirPath(const QString &modelName, bool isChatGPT);
|
QString modelDirPath(const QString &modelName, bool isChatGPT);
|
||||||
@ -229,6 +312,7 @@ private:
|
|||||||
QVariant dataInternal(const ModelInfo *info, int role) const;
|
QVariant dataInternal(const ModelInfo *info, int role) const;
|
||||||
static bool lessThan(const ModelInfo* a, const ModelInfo* b);
|
static bool lessThan(const ModelInfo* a, const ModelInfo* b);
|
||||||
void parseModelsJsonFile(const QByteArray &jsonData);
|
void parseModelsJsonFile(const QByteArray &jsonData);
|
||||||
|
QString uniqueModelName(const ModelInfo &model) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable QMutex m_mutex;
|
mutable QMutex m_mutex;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "mysettings.h"
|
#include "mysettings.h"
|
||||||
|
#include "modellist.h"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
@ -7,14 +8,6 @@
|
|||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
static double default_temperature = 0.7;
|
|
||||||
static double default_topP = 0.1;
|
|
||||||
static int default_topK = 40;
|
|
||||||
static int default_maxLength = 4096;
|
|
||||||
static int default_promptBatchSize = 128;
|
|
||||||
static double default_repeatPenalty = 1.18;
|
|
||||||
static int default_repeatPenaltyTokens = 64;
|
|
||||||
static QString default_promptTemplate = "### Human:\n%1\n### Assistant:\n";
|
|
||||||
static int default_threadCount = 0;
|
static int default_threadCount = 0;
|
||||||
static bool default_saveChats = false;
|
static bool default_saveChats = false;
|
||||||
static bool default_saveChatGPTChats = true;
|
static bool default_saveChatGPTChats = true;
|
||||||
@ -68,16 +61,17 @@ MySettings::MySettings()
|
|||||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySettings::restoreGenerationDefaults()
|
void MySettings::restoreModelDefaults(const ModelInfo &model)
|
||||||
{
|
{
|
||||||
setTemperature(default_temperature);
|
setModelTemperature(model, model.m_temperature);
|
||||||
setTopP(default_topP);
|
setModelTopP(model, model.m_topP);
|
||||||
setTopK(default_topK);
|
setModelTopK(model, model.m_topK);;
|
||||||
setMaxLength(default_maxLength);
|
setModelMaxLength(model, model.m_maxLength);
|
||||||
setPromptBatchSize(default_promptBatchSize);
|
setModelPromptBatchSize(model, model.m_promptBatchSize);
|
||||||
setRepeatPenalty(default_repeatPenalty);
|
setModelRepeatPenalty(model, model.m_repeatPenalty);
|
||||||
setRepeatPenaltyTokens(default_repeatPenaltyTokens);
|
setModelRepeatPenaltyTokens(model, model.m_repeatPenaltyTokens);
|
||||||
setPromptTemplate(default_promptTemplate);
|
setModelPromptTemplate(model, model.m_promptTemplate);
|
||||||
|
setModelSystemPrompt(model, model.m_systemPrompt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySettings::restoreApplicationDefaults()
|
void MySettings::restoreApplicationDefaults()
|
||||||
@ -97,148 +91,256 @@ void MySettings::restoreLocalDocsDefaults()
|
|||||||
setLocalDocsRetrievalSize(default_localDocsRetrievalSize);
|
setLocalDocsRetrievalSize(default_localDocsRetrievalSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
double MySettings::temperature() const
|
void MySettings::eraseModel(const ModelInfo &m)
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
settings.remove(QString("model-%1").arg(m.id()));
|
||||||
|
settings.sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MySettings::modelName(const ModelInfo &m) const
|
||||||
{
|
{
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.sync();
|
setting.sync();
|
||||||
return setting.value("temperature", default_temperature).toDouble();
|
return setting.value(QString("model-%1").arg(m.id()) + "/name",
|
||||||
|
!m.m_name.isEmpty() ? m.m_name : m.m_filename).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySettings::setTemperature(double t)
|
void MySettings::setModelName(const ModelInfo &m, const QString &name, bool force)
|
||||||
{
|
{
|
||||||
if (temperature() == t)
|
if ((modelName(m) == name || m.id().isEmpty()) && !force)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.setValue("temperature", t);
|
if ((m.m_name == name || m.m_filename == name) && !m.isClone)
|
||||||
|
setting.remove(QString("model-%1").arg(m.id()) + "/name");
|
||||||
|
else
|
||||||
|
setting.setValue(QString("model-%1").arg(m.id()) + "/name", name);
|
||||||
|
if (m.isClone)
|
||||||
|
setting.setValue(QString("model-%1").arg(m.id()) + "/isClone", "true");
|
||||||
setting.sync();
|
setting.sync();
|
||||||
emit temperatureChanged();
|
if (!force)
|
||||||
|
emit nameChanged(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
double MySettings::topP() const
|
QString MySettings::modelFilename(const ModelInfo &m) const
|
||||||
{
|
{
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.sync();
|
setting.sync();
|
||||||
return setting.value("topP", default_topP).toDouble();
|
return setting.value(QString("model-%1").arg(m.id()) + "/filename", m.m_filename).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySettings::setTopP(double p)
|
void MySettings::setModelFilename(const ModelInfo &m, const QString &filename, bool force)
|
||||||
{
|
{
|
||||||
if (topP() == p)
|
if ((modelFilename(m) == filename || m.id().isEmpty()) && !force)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.setValue("topP", p);
|
if (m.m_filename == filename && !m.isClone)
|
||||||
|
setting.remove(QString("model-%1").arg(m.id()) + "/filename");
|
||||||
|
else
|
||||||
|
setting.setValue(QString("model-%1").arg(m.id()) + "/filename", filename);
|
||||||
setting.sync();
|
setting.sync();
|
||||||
emit topPChanged();
|
if (!force)
|
||||||
|
emit filenameChanged(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MySettings::topK() const
|
double MySettings::modelTemperature(const ModelInfo &m) const
|
||||||
{
|
{
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.sync();
|
setting.sync();
|
||||||
return setting.value("topK", default_topK).toInt();
|
return setting.value(QString("model-%1").arg(m.id()) + "/temperature", m.m_temperature).toDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySettings::setTopK(int k)
|
void MySettings::setModelTemperature(const ModelInfo &m, double t, bool force)
|
||||||
{
|
{
|
||||||
if (topK() == k)
|
if (modelTemperature(m) == t && !force)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.setValue("topK", k);
|
if (m.m_temperature == t && !m.isClone)
|
||||||
|
setting.remove(QString("model-%1").arg(m.id()) + "/temperature");
|
||||||
|
else
|
||||||
|
setting.setValue(QString("model-%1").arg(m.id()) + "/temperature", t);
|
||||||
setting.sync();
|
setting.sync();
|
||||||
emit topKChanged();
|
if (!force)
|
||||||
|
emit temperatureChanged(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MySettings::maxLength() const
|
double MySettings::modelTopP(const ModelInfo &m) const
|
||||||
{
|
{
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.sync();
|
setting.sync();
|
||||||
return setting.value("maxLength", default_maxLength).toInt();
|
return setting.value(QString("model-%1").arg(m.id()) + "/topP", m.m_topP).toDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySettings::setMaxLength(int l)
|
void MySettings::setModelTopP(const ModelInfo &m, double p, bool force)
|
||||||
{
|
{
|
||||||
if (maxLength() == l)
|
if (modelTopP(m) == p && !force)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.setValue("maxLength", l);
|
if (m.m_topP == p && !m.isClone)
|
||||||
|
setting.remove(QString("model-%1").arg(m.id()) + "/topP");
|
||||||
|
else
|
||||||
|
setting.setValue(QString("model-%1").arg(m.id()) + "/topP", p);
|
||||||
setting.sync();
|
setting.sync();
|
||||||
emit maxLengthChanged();
|
if (!force)
|
||||||
|
emit topPChanged(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MySettings::promptBatchSize() const
|
int MySettings::modelTopK(const ModelInfo &m) const
|
||||||
{
|
{
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.sync();
|
setting.sync();
|
||||||
return setting.value("promptBatchSize", default_promptBatchSize).toInt();
|
return setting.value(QString("model-%1").arg(m.id()) + "/topK", m.m_topK).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySettings::setPromptBatchSize(int s)
|
void MySettings::setModelTopK(const ModelInfo &m, int k, bool force)
|
||||||
{
|
{
|
||||||
if (promptBatchSize() == s)
|
if (modelTopK(m) == k && !force)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.setValue("promptBatchSize", s);
|
if (m.m_topK == k && !m.isClone)
|
||||||
|
setting.remove(QString("model-%1").arg(m.id()) + "/topK");
|
||||||
|
else
|
||||||
|
setting.setValue(QString("model-%1").arg(m.id()) + "/topK", k);
|
||||||
setting.sync();
|
setting.sync();
|
||||||
emit promptBatchSizeChanged();
|
if (!force)
|
||||||
|
emit topKChanged(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
double MySettings::repeatPenalty() const
|
int MySettings::modelMaxLength(const ModelInfo &m) const
|
||||||
{
|
{
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.sync();
|
setting.sync();
|
||||||
return setting.value("repeatPenalty", default_repeatPenalty).toDouble();
|
return setting.value(QString("model-%1").arg(m.id()) + "/maxLength", m.m_maxLength).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySettings::setRepeatPenalty(double p)
|
void MySettings::setModelMaxLength(const ModelInfo &m, int l, bool force)
|
||||||
{
|
{
|
||||||
if (repeatPenalty() == p)
|
if (modelMaxLength(m) == l && !force)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.setValue("repeatPenalty", p);
|
if (m.m_maxLength == l && !m.isClone)
|
||||||
|
setting.remove(QString("model-%1").arg(m.id()) + "/maxLength");
|
||||||
|
else
|
||||||
|
setting.setValue(QString("model-%1").arg(m.id()) + "/maxLength", l);
|
||||||
setting.sync();
|
setting.sync();
|
||||||
emit repeatPenaltyChanged();
|
if (!force)
|
||||||
|
emit maxLengthChanged(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MySettings::repeatPenaltyTokens() const
|
int MySettings::modelPromptBatchSize(const ModelInfo &m) const
|
||||||
{
|
{
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.sync();
|
setting.sync();
|
||||||
return setting.value("repeatPenaltyTokens", default_repeatPenaltyTokens).toInt();
|
return setting.value(QString("model-%1").arg(m.id()) + "/promptBatchSize", m.m_promptBatchSize).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySettings::setRepeatPenaltyTokens(int t)
|
void MySettings::setModelPromptBatchSize(const ModelInfo &m, int s, bool force)
|
||||||
{
|
{
|
||||||
if (repeatPenaltyTokens() == t)
|
if (modelPromptBatchSize(m) == s && !force)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.setValue("repeatPenaltyTokens", t);
|
if (m.m_promptBatchSize == s && !m.isClone)
|
||||||
|
setting.remove(QString("model-%1").arg(m.id()) + "/promptBatchSize");
|
||||||
|
else
|
||||||
|
setting.setValue(QString("model-%1").arg(m.id()) + "/promptBatchSize", s);
|
||||||
setting.sync();
|
setting.sync();
|
||||||
emit repeatPenaltyTokensChanged();
|
if (!force)
|
||||||
|
emit promptBatchSizeChanged(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MySettings::promptTemplate() const
|
double MySettings::modelRepeatPenalty(const ModelInfo &m) const
|
||||||
{
|
{
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.sync();
|
setting.sync();
|
||||||
return setting.value("promptTemplate", default_promptTemplate).toString();
|
return setting.value(QString("model-%1").arg(m.id()) + "/repeatPenalty", m.m_repeatPenalty).toDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySettings::setPromptTemplate(const QString &t)
|
void MySettings::setModelRepeatPenalty(const ModelInfo &m, double p, bool force)
|
||||||
{
|
{
|
||||||
if (promptTemplate() == t)
|
if (modelRepeatPenalty(m) == p && !force)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QSettings setting;
|
QSettings setting;
|
||||||
setting.setValue("promptTemplate", t);
|
if (m.m_repeatPenalty == p && !m.isClone)
|
||||||
|
setting.remove(QString("model-%1").arg(m.id()) + "/repeatPenalty");
|
||||||
|
else
|
||||||
|
setting.setValue(QString("model-%1").arg(m.id()) + "/repeatPenalty", p);
|
||||||
setting.sync();
|
setting.sync();
|
||||||
emit promptTemplateChanged();
|
if (!force)
|
||||||
|
emit repeatPenaltyChanged(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
int MySettings::modelRepeatPenaltyTokens(const ModelInfo &m) const
|
||||||
|
{
|
||||||
|
QSettings setting;
|
||||||
|
setting.sync();
|
||||||
|
return setting.value(QString("model-%1").arg(m.id()) + "/repeatPenaltyTokens", m.m_repeatPenaltyTokens).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySettings::setModelRepeatPenaltyTokens(const ModelInfo &m, int t, bool force)
|
||||||
|
{
|
||||||
|
if (modelRepeatPenaltyTokens(m) == t && !force)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QSettings setting;
|
||||||
|
if (m.m_repeatPenaltyTokens == t && !m.isClone)
|
||||||
|
setting.remove(QString("model-%1").arg(m.id()) + "/repeatPenaltyTokens");
|
||||||
|
else
|
||||||
|
setting.setValue(QString("model-%1").arg(m.id()) + "/repeatPenaltyTokens", t);
|
||||||
|
setting.sync();
|
||||||
|
if (!force)
|
||||||
|
emit repeatPenaltyTokensChanged(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MySettings::modelPromptTemplate(const ModelInfo &m) const
|
||||||
|
{
|
||||||
|
QSettings setting;
|
||||||
|
setting.sync();
|
||||||
|
return setting.value(QString("model-%1").arg(m.id()) + "/promptTemplate", m.m_promptTemplate).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySettings::setModelPromptTemplate(const ModelInfo &m, const QString &t, bool force)
|
||||||
|
{
|
||||||
|
if (modelPromptTemplate(m) == t && !force)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QSettings setting;
|
||||||
|
if (m.m_promptTemplate == t && !m.isClone)
|
||||||
|
setting.remove(QString("model-%1").arg(m.id()) + "/promptTemplate");
|
||||||
|
else
|
||||||
|
setting.setValue(QString("model-%1").arg(m.id()) + "/promptTemplate", t);
|
||||||
|
setting.sync();
|
||||||
|
if (!force)
|
||||||
|
emit promptTemplateChanged(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MySettings::modelSystemPrompt(const ModelInfo &m) const
|
||||||
|
{
|
||||||
|
QSettings setting;
|
||||||
|
setting.sync();
|
||||||
|
return setting.value(QString("model-%1").arg(m.id()) + "/systemPrompt", m.m_systemPrompt).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySettings::setModelSystemPrompt(const ModelInfo &m, const QString &p, bool force)
|
||||||
|
{
|
||||||
|
if (modelSystemPrompt(m) == p && !force)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QSettings setting;
|
||||||
|
if (m.m_systemPrompt == p && !m.isClone)
|
||||||
|
setting.remove(QString("model-%1").arg(m.id()) + "/systemPrompt");
|
||||||
|
else
|
||||||
|
setting.setValue(QString("model-%1").arg(m.id()) + "/systemPrompt", p);
|
||||||
|
setting.sync();
|
||||||
|
if (!force)
|
||||||
|
emit systemPromptChanged(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MySettings::threadCount() const
|
int MySettings::threadCount() const
|
||||||
|
@ -4,17 +4,10 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
|
|
||||||
|
class ModelInfo;
|
||||||
class MySettings : public QObject
|
class MySettings : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(double temperature READ temperature WRITE setTemperature NOTIFY temperatureChanged)
|
|
||||||
Q_PROPERTY(double topP READ topP WRITE setTopP NOTIFY topPChanged)
|
|
||||||
Q_PROPERTY(int topK READ topK WRITE setTopK NOTIFY topKChanged)
|
|
||||||
Q_PROPERTY(int maxLength READ maxLength WRITE setMaxLength NOTIFY maxLengthChanged)
|
|
||||||
Q_PROPERTY(int promptBatchSize READ promptBatchSize WRITE setPromptBatchSize NOTIFY promptBatchSizeChanged)
|
|
||||||
Q_PROPERTY(double repeatPenalty READ repeatPenalty WRITE setRepeatPenalty NOTIFY repeatPenaltyChanged)
|
|
||||||
Q_PROPERTY(int repeatPenaltyTokens READ repeatPenaltyTokens WRITE setRepeatPenaltyTokens NOTIFY repeatPenaltyTokensChanged)
|
|
||||||
Q_PROPERTY(QString promptTemplate READ promptTemplate WRITE setPromptTemplate NOTIFY promptTemplateChanged)
|
|
||||||
Q_PROPERTY(int threadCount READ threadCount WRITE setThreadCount NOTIFY threadCountChanged)
|
Q_PROPERTY(int threadCount READ threadCount WRITE setThreadCount NOTIFY threadCountChanged)
|
||||||
Q_PROPERTY(bool saveChats READ saveChats WRITE setSaveChats NOTIFY saveChatsChanged)
|
Q_PROPERTY(bool saveChats READ saveChats WRITE setSaveChats NOTIFY saveChatsChanged)
|
||||||
Q_PROPERTY(bool saveChatGPTChats READ saveChatGPTChats WRITE setSaveChatGPTChats NOTIFY saveChatGPTChatsChanged)
|
Q_PROPERTY(bool saveChatGPTChats READ saveChatGPTChats WRITE setSaveChatGPTChats NOTIFY saveChatGPTChatsChanged)
|
||||||
@ -33,27 +26,34 @@ public:
|
|||||||
static MySettings *globalInstance();
|
static MySettings *globalInstance();
|
||||||
|
|
||||||
// Restore methods
|
// Restore methods
|
||||||
Q_INVOKABLE void restoreGenerationDefaults();
|
Q_INVOKABLE void restoreModelDefaults(const ModelInfo &model);
|
||||||
Q_INVOKABLE void restoreApplicationDefaults();
|
Q_INVOKABLE void restoreApplicationDefaults();
|
||||||
Q_INVOKABLE void restoreLocalDocsDefaults();
|
Q_INVOKABLE void restoreLocalDocsDefaults();
|
||||||
|
|
||||||
// Generation settings
|
// Model/Character settings
|
||||||
double temperature() const;
|
void eraseModel(const ModelInfo &m);
|
||||||
void setTemperature(double t);
|
QString modelName(const ModelInfo &m) const;
|
||||||
double topP() const;
|
Q_INVOKABLE void setModelName(const ModelInfo &m, const QString &name, bool force = false);
|
||||||
void setTopP(double p);
|
QString modelFilename(const ModelInfo &m) const;
|
||||||
int topK() const;
|
Q_INVOKABLE void setModelFilename(const ModelInfo &m, const QString &filename, bool force = false);
|
||||||
void setTopK(int k);
|
double modelTemperature(const ModelInfo &m) const;
|
||||||
int maxLength() const;
|
Q_INVOKABLE void setModelTemperature(const ModelInfo &m, double t, bool force = false);
|
||||||
void setMaxLength(int l);
|
double modelTopP(const ModelInfo &m) const;
|
||||||
int promptBatchSize() const;
|
Q_INVOKABLE void setModelTopP(const ModelInfo &m, double p, bool force = false);
|
||||||
void setPromptBatchSize(int s);
|
int modelTopK(const ModelInfo &m) const;
|
||||||
double repeatPenalty() const;
|
Q_INVOKABLE void setModelTopK(const ModelInfo &m, int k, bool force = false);
|
||||||
void setRepeatPenalty(double p);
|
int modelMaxLength(const ModelInfo &m) const;
|
||||||
int repeatPenaltyTokens() const;
|
Q_INVOKABLE void setModelMaxLength(const ModelInfo &m, int l, bool force = false);
|
||||||
void setRepeatPenaltyTokens(int t);
|
int modelPromptBatchSize(const ModelInfo &m) const;
|
||||||
QString promptTemplate() const;
|
Q_INVOKABLE void setModelPromptBatchSize(const ModelInfo &m, int s, bool force = false);
|
||||||
void setPromptTemplate(const QString &t);
|
double modelRepeatPenalty(const ModelInfo &m) const;
|
||||||
|
Q_INVOKABLE void setModelRepeatPenalty(const ModelInfo &m, double p, bool force = false);
|
||||||
|
int modelRepeatPenaltyTokens(const ModelInfo &m) const;
|
||||||
|
Q_INVOKABLE void setModelRepeatPenaltyTokens(const ModelInfo &m, int t, bool force = false);
|
||||||
|
QString modelPromptTemplate(const ModelInfo &m) const;
|
||||||
|
Q_INVOKABLE void setModelPromptTemplate(const ModelInfo &m, const QString &t, bool force = false);
|
||||||
|
QString modelSystemPrompt(const ModelInfo &m) const;
|
||||||
|
Q_INVOKABLE void setModelSystemPrompt(const ModelInfo &m, const QString &p, bool force = false);
|
||||||
|
|
||||||
// Application settings
|
// Application settings
|
||||||
int threadCount() const;
|
int threadCount() const;
|
||||||
@ -90,14 +90,17 @@ public:
|
|||||||
void setNetworkUsageStatsActive(bool b);
|
void setNetworkUsageStatsActive(bool b);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void temperatureChanged();
|
void nameChanged(const ModelInfo &model);
|
||||||
void topPChanged();
|
void filenameChanged(const ModelInfo &model);
|
||||||
void topKChanged();
|
void temperatureChanged(const ModelInfo &model);
|
||||||
void maxLengthChanged();
|
void topPChanged(const ModelInfo &model);
|
||||||
void promptBatchSizeChanged();
|
void topKChanged(const ModelInfo &model);
|
||||||
void repeatPenaltyChanged();
|
void maxLengthChanged(const ModelInfo &model);
|
||||||
void repeatPenaltyTokensChanged();
|
void promptBatchSizeChanged(const ModelInfo &model);
|
||||||
void promptTemplateChanged();
|
void repeatPenaltyChanged(const ModelInfo &model);
|
||||||
|
void repeatPenaltyTokensChanged(const ModelInfo &model);
|
||||||
|
void promptTemplateChanged(const ModelInfo &model);
|
||||||
|
void systemPromptChanged(const ModelInfo &model);
|
||||||
void threadCountChanged();
|
void threadCountChanged();
|
||||||
void saveChatsChanged();
|
void saveChatsChanged();
|
||||||
void saveChatGPTChatsChanged();
|
void saveChatGPTChatsChanged();
|
||||||
|
@ -88,7 +88,7 @@ bool Network::packageAndSendJson(const QString &ingestId, const QString &json)
|
|||||||
Q_ASSERT(ChatListModel::globalInstance()->currentChat());
|
Q_ASSERT(ChatListModel::globalInstance()->currentChat());
|
||||||
QJsonObject object = doc.object();
|
QJsonObject object = doc.object();
|
||||||
object.insert("source", "gpt4all-chat");
|
object.insert("source", "gpt4all-chat");
|
||||||
object.insert("agent_id", ChatListModel::globalInstance()->currentChat()->modelInfo().filename);
|
object.insert("agent_id", ChatListModel::globalInstance()->currentChat()->modelInfo().filename());
|
||||||
object.insert("submitter_id", m_uniqueId);
|
object.insert("submitter_id", m_uniqueId);
|
||||||
object.insert("ingest_id", ingestId);
|
object.insert("ingest_id", ingestId);
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ bool Network::packageAndSendJson(const QString &ingestId, const QString &json)
|
|||||||
if (!attribution.isEmpty())
|
if (!attribution.isEmpty())
|
||||||
object.insert("network/attribution", attribution);
|
object.insert("network/attribution", attribution);
|
||||||
|
|
||||||
QString promptTemplate = MySettings::globalInstance()->promptTemplate();
|
QString promptTemplate = ChatListModel::globalInstance()->currentChat()->modelInfo().promptTemplate();
|
||||||
object.insert("prompt_template", promptTemplate);
|
object.insert("prompt_template", promptTemplate);
|
||||||
|
|
||||||
QJsonDocument newDoc;
|
QJsonDocument newDoc;
|
||||||
@ -391,7 +391,7 @@ void Network::sendMixpanelEvent(const QString &ev, const QVector<KeyValue> &valu
|
|||||||
properties.insert("ip", m_ipify);
|
properties.insert("ip", m_ipify);
|
||||||
properties.insert("name", QCoreApplication::applicationName() + " v"
|
properties.insert("name", QCoreApplication::applicationName() + " v"
|
||||||
+ QCoreApplication::applicationVersion());
|
+ QCoreApplication::applicationVersion());
|
||||||
properties.insert("model", ChatListModel::globalInstance()->currentChat()->modelInfo().filename);
|
properties.insert("model", ChatListModel::globalInstance()->currentChat()->modelInfo().filename());
|
||||||
|
|
||||||
// Some additional startup information
|
// Some additional startup information
|
||||||
if (ev == "startup") {
|
if (ev == "startup") {
|
||||||
|
@ -6,8 +6,12 @@ import QtQuick.Layouts
|
|||||||
import QtQuick.Dialogs
|
import QtQuick.Dialogs
|
||||||
import modellist
|
import modellist
|
||||||
import mysettings
|
import mysettings
|
||||||
|
import network
|
||||||
|
|
||||||
MySettingsTab {
|
MySettingsTab {
|
||||||
|
onRestoreDefaultsClicked: {
|
||||||
|
MySettings.restoreApplicationDefaults();
|
||||||
|
}
|
||||||
title: qsTr("Application")
|
title: qsTr("Application")
|
||||||
contentItem: GridLayout {
|
contentItem: GridLayout {
|
||||||
id: applicationSettingsTabInner
|
id: applicationSettingsTabInner
|
||||||
@ -26,7 +30,9 @@ MySettingsTab {
|
|||||||
id: comboBox
|
id: comboBox
|
||||||
Layout.row: 1
|
Layout.row: 1
|
||||||
Layout.column: 1
|
Layout.column: 1
|
||||||
|
Layout.columnSpan: 2
|
||||||
Layout.minimumWidth: 350
|
Layout.minimumWidth: 350
|
||||||
|
Layout.fillWidth: true
|
||||||
model: ModelList.userDefaultModelList
|
model: ModelList.userDefaultModelList
|
||||||
Accessible.role: Accessible.ComboBox
|
Accessible.role: Accessible.ComboBox
|
||||||
Accessible.name: qsTr("ComboBox for displaying/picking the default model")
|
Accessible.name: qsTr("ComboBox for displaying/picking the default model")
|
||||||
@ -178,25 +184,30 @@ MySettingsTab {
|
|||||||
Layout.columnSpan: 3
|
Layout.columnSpan: 3
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
height: 1
|
height: 1
|
||||||
color: theme.dialogBorder
|
color: theme.tabBorder
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
advancedSettings: GridLayout {
|
||||||
|
columns: 3
|
||||||
|
rowSpacing: 10
|
||||||
|
columnSpacing: 10
|
||||||
Rectangle {
|
Rectangle {
|
||||||
Layout.row: 9
|
Layout.row: 2
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.columnSpan: 3
|
Layout.columnSpan: 3
|
||||||
height: 1
|
height: 1
|
||||||
color: theme.dialogBorder
|
color: theme.tabBorder
|
||||||
}
|
}
|
||||||
Label {
|
Label {
|
||||||
id: gpuOverrideLabel
|
id: gpuOverrideLabel
|
||||||
text: qsTr("Force Metal (macOS+arm):")
|
text: qsTr("Force Metal (macOS+arm):")
|
||||||
color: theme.textColor
|
color: theme.textColor
|
||||||
Layout.row: 8
|
Layout.row: 1
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
}
|
}
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.row: 8
|
Layout.row: 1
|
||||||
Layout.column: 1
|
Layout.column: 1
|
||||||
Layout.columnSpan: 2
|
Layout.columnSpan: 2
|
||||||
MyCheckBox {
|
MyCheckBox {
|
||||||
@ -206,25 +217,19 @@ MySettingsTab {
|
|||||||
MySettings.forceMetal = !MySettings.forceMetal
|
MySettings.forceMetal = !MySettings.forceMetal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.minimumHeight: warningLabel.height
|
||||||
Label {
|
Label {
|
||||||
id: warningLabel
|
id: warningLabel
|
||||||
Layout.maximumWidth: 730
|
width: parent.width
|
||||||
Layout.alignment: Qt.AlignTop
|
|
||||||
color: theme.textErrorColor
|
color: theme.textErrorColor
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: qsTr("WARNING: On macOS with arm (M1+) this setting forces usage of the GPU. Can cause crashes if the model requires more RAM than the system supports. Because of crash possibility the setting will not persist across restarts of the application. This has no effect on non-macs or intel.")
|
text: qsTr("WARNING: On macOS with arm (M1+) this setting forces usage of the GPU. Can cause crashes if the model requires more RAM than the system supports. Because of crash possibility the setting will not persist across restarts of the application. This has no effect on non-macs or intel.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MyButton {
|
|
||||||
Layout.row: 10
|
|
||||||
Layout.column: 1
|
|
||||||
Layout.columnSpan: 2
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: qsTr("Restore Defaults")
|
|
||||||
Accessible.description: qsTr("Restores the settings dialog to a default state")
|
|
||||||
onClicked: {
|
|
||||||
MySettings.restoreApplicationDefaults();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,302 +0,0 @@
|
|||||||
import QtCore
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Controls.Basic
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import localdocs
|
|
||||||
import mysettings
|
|
||||||
|
|
||||||
MySettingsTab {
|
|
||||||
title: qsTr("Presets")
|
|
||||||
contentItem: GridLayout {
|
|
||||||
id: generationSettingsTabInner
|
|
||||||
columns: 2
|
|
||||||
rowSpacing: 10
|
|
||||||
columnSpacing: 10
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: tempLabel
|
|
||||||
text: qsTr("Temperature:")
|
|
||||||
color: theme.textColor
|
|
||||||
Layout.row: 0
|
|
||||||
Layout.column: 0
|
|
||||||
}
|
|
||||||
MyTextField {
|
|
||||||
text: MySettings.temperature
|
|
||||||
color: theme.textColor
|
|
||||||
ToolTip.text: qsTr("Temperature increases the chances of choosing less likely tokens.\nNOTE: Higher temperature gives more creative but less predictable outputs.")
|
|
||||||
ToolTip.visible: hovered
|
|
||||||
Layout.row: 0
|
|
||||||
Layout.column: 1
|
|
||||||
validator: DoubleValidator {
|
|
||||||
locale: "C"
|
|
||||||
}
|
|
||||||
onEditingFinished: {
|
|
||||||
var val = parseFloat(text)
|
|
||||||
if (!isNaN(val)) {
|
|
||||||
MySettings.temperature = val
|
|
||||||
focus = false
|
|
||||||
} else {
|
|
||||||
text = MySettings.temperature
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Accessible.role: Accessible.EditableText
|
|
||||||
Accessible.name: tempLabel.text
|
|
||||||
Accessible.description: ToolTip.text
|
|
||||||
}
|
|
||||||
Label {
|
|
||||||
id: topPLabel
|
|
||||||
text: qsTr("Top P:")
|
|
||||||
color: theme.textColor
|
|
||||||
Layout.row: 1
|
|
||||||
Layout.column: 0
|
|
||||||
}
|
|
||||||
MyTextField {
|
|
||||||
text: MySettings.topP
|
|
||||||
color: theme.textColor
|
|
||||||
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.visible: hovered
|
|
||||||
Layout.row: 1
|
|
||||||
Layout.column: 1
|
|
||||||
validator: DoubleValidator {
|
|
||||||
locale: "C"
|
|
||||||
}
|
|
||||||
onEditingFinished: {
|
|
||||||
var val = parseFloat(text)
|
|
||||||
if (!isNaN(val)) {
|
|
||||||
MySettings.topP = val
|
|
||||||
focus = false
|
|
||||||
} else {
|
|
||||||
text = MySettings.topP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Accessible.role: Accessible.EditableText
|
|
||||||
Accessible.name: topPLabel.text
|
|
||||||
Accessible.description: ToolTip.text
|
|
||||||
}
|
|
||||||
Label {
|
|
||||||
id: topKLabel
|
|
||||||
text: qsTr("Top K:")
|
|
||||||
color: theme.textColor
|
|
||||||
Layout.row: 2
|
|
||||||
Layout.column: 0
|
|
||||||
}
|
|
||||||
MyTextField {
|
|
||||||
text: MySettings.topK
|
|
||||||
color: theme.textColor
|
|
||||||
ToolTip.text: qsTr("Only the top K most likely tokens will be chosen from")
|
|
||||||
ToolTip.visible: hovered
|
|
||||||
Layout.row: 2
|
|
||||||
Layout.column: 1
|
|
||||||
validator: IntValidator {
|
|
||||||
bottom: 1
|
|
||||||
}
|
|
||||||
onEditingFinished: {
|
|
||||||
var val = parseInt(text)
|
|
||||||
if (!isNaN(val)) {
|
|
||||||
MySettings.topK = val
|
|
||||||
focus = false
|
|
||||||
} else {
|
|
||||||
text = MySettings.topK
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Accessible.role: Accessible.EditableText
|
|
||||||
Accessible.name: topKLabel.text
|
|
||||||
Accessible.description: ToolTip.text
|
|
||||||
}
|
|
||||||
Label {
|
|
||||||
id: maxLengthLabel
|
|
||||||
text: qsTr("Max Length:")
|
|
||||||
color: theme.textColor
|
|
||||||
Layout.row: 3
|
|
||||||
Layout.column: 0
|
|
||||||
}
|
|
||||||
MyTextField {
|
|
||||||
text: MySettings.maxLength
|
|
||||||
color: theme.textColor
|
|
||||||
ToolTip.text: qsTr("Maximum length of response in tokens")
|
|
||||||
ToolTip.visible: hovered
|
|
||||||
Layout.row: 3
|
|
||||||
Layout.column: 1
|
|
||||||
validator: IntValidator {
|
|
||||||
bottom: 1
|
|
||||||
}
|
|
||||||
onEditingFinished: {
|
|
||||||
var val = parseInt(text)
|
|
||||||
if (!isNaN(val)) {
|
|
||||||
MySettings.maxLength = val
|
|
||||||
focus = false
|
|
||||||
} else {
|
|
||||||
text = MySettings.maxLength
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Accessible.role: Accessible.EditableText
|
|
||||||
Accessible.name: maxLengthLabel.text
|
|
||||||
Accessible.description: ToolTip.text
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: batchSizeLabel
|
|
||||||
text: qsTr("Prompt Batch Size:")
|
|
||||||
color: theme.textColor
|
|
||||||
Layout.row: 4
|
|
||||||
Layout.column: 0
|
|
||||||
}
|
|
||||||
MyTextField {
|
|
||||||
text: MySettings.promptBatchSize
|
|
||||||
color: theme.textColor
|
|
||||||
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: 4
|
|
||||||
Layout.column: 1
|
|
||||||
validator: IntValidator {
|
|
||||||
bottom: 1
|
|
||||||
}
|
|
||||||
onEditingFinished: {
|
|
||||||
var val = parseInt(text)
|
|
||||||
if (!isNaN(val)) {
|
|
||||||
MySettings.promptBatchSize = val
|
|
||||||
focus = false
|
|
||||||
} else {
|
|
||||||
text = MySettings.promptBatchSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Accessible.role: Accessible.EditableText
|
|
||||||
Accessible.name: batchSizeLabel.text
|
|
||||||
Accessible.description: ToolTip.text
|
|
||||||
}
|
|
||||||
Label {
|
|
||||||
id: repeatPenaltyLabel
|
|
||||||
text: qsTr("Repeat Penalty:")
|
|
||||||
color: theme.textColor
|
|
||||||
Layout.row: 5
|
|
||||||
Layout.column: 0
|
|
||||||
}
|
|
||||||
MyTextField {
|
|
||||||
text: MySettings.repeatPenalty
|
|
||||||
color: theme.textColor
|
|
||||||
ToolTip.text: qsTr("Amount to penalize repetitiveness of the output")
|
|
||||||
ToolTip.visible: hovered
|
|
||||||
Layout.row: 5
|
|
||||||
Layout.column: 1
|
|
||||||
validator: DoubleValidator {
|
|
||||||
locale: "C"
|
|
||||||
}
|
|
||||||
onEditingFinished: {
|
|
||||||
var val = parseFloat(text)
|
|
||||||
if (!isNaN(val)) {
|
|
||||||
MySettings.repeatPenalty = val
|
|
||||||
focus = false
|
|
||||||
} else {
|
|
||||||
text = MySettings.repeatPenalty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Accessible.role: Accessible.EditableText
|
|
||||||
Accessible.name: repeatPenaltyLabel.text
|
|
||||||
Accessible.description: ToolTip.text
|
|
||||||
}
|
|
||||||
Label {
|
|
||||||
id: repeatPenaltyTokensLabel
|
|
||||||
text: qsTr("Repeat Penalty Tokens:")
|
|
||||||
color: theme.textColor
|
|
||||||
Layout.row: 6
|
|
||||||
Layout.column: 0
|
|
||||||
}
|
|
||||||
MyTextField {
|
|
||||||
text: MySettings.repeatPenaltyTokens
|
|
||||||
color: theme.textColor
|
|
||||||
ToolTip.text: qsTr("How far back in output to apply repeat penalty")
|
|
||||||
ToolTip.visible: hovered
|
|
||||||
Layout.row: 6
|
|
||||||
Layout.column: 1
|
|
||||||
validator: IntValidator {
|
|
||||||
bottom: 1
|
|
||||||
}
|
|
||||||
onEditingFinished: {
|
|
||||||
var val = parseInt(text)
|
|
||||||
if (!isNaN(val)) {
|
|
||||||
MySettings.repeatPenaltyTokens = val
|
|
||||||
focus = false
|
|
||||||
} else {
|
|
||||||
text = MySettings.repeatPenaltyTokens
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Accessible.role: Accessible.EditableText
|
|
||||||
Accessible.name: repeatPenaltyTokensLabel.text
|
|
||||||
Accessible.description: ToolTip.text
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.row: 7
|
|
||||||
Layout.column: 0
|
|
||||||
Layout.topMargin: 10
|
|
||||||
Layout.alignment: Qt.AlignTop
|
|
||||||
spacing: 20
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: promptTemplateLabel
|
|
||||||
text: qsTr("Prompt Template:")
|
|
||||||
color: theme.textColor
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: promptTemplateLabelHelp
|
|
||||||
Layout.maximumWidth: promptTemplateLabel.width
|
|
||||||
visible: templateTextArea.text.indexOf(
|
|
||||||
"%1") === -1
|
|
||||||
color: theme.textErrorColor
|
|
||||||
text: qsTr("Must contain the string \"%1\" to be replaced with the user's input.")
|
|
||||||
wrapMode: TextArea.Wrap
|
|
||||||
Accessible.role: Accessible.EditableText
|
|
||||||
Accessible.name: text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
Layout.row: 7
|
|
||||||
Layout.column: 1
|
|
||||||
Layout.fillWidth: true
|
|
||||||
height: 200
|
|
||||||
color: "transparent"
|
|
||||||
clip: true
|
|
||||||
ScrollView {
|
|
||||||
id: templateScrollView
|
|
||||||
anchors.fill: parent
|
|
||||||
TextArea {
|
|
||||||
id: templateTextArea
|
|
||||||
text: MySettings.promptTemplate
|
|
||||||
color: theme.textColor
|
|
||||||
background: Rectangle {
|
|
||||||
implicitWidth: 150
|
|
||||||
color: theme.backgroundLighter
|
|
||||||
radius: 10
|
|
||||||
}
|
|
||||||
padding: 10
|
|
||||||
wrapMode: TextArea.Wrap
|
|
||||||
onTextChanged: {
|
|
||||||
if (templateTextArea.text.indexOf("%1") !== -1) {
|
|
||||||
MySettings.promptTemplate = text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bottomPadding: 10
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MyButton {
|
|
||||||
Layout.row: 8
|
|
||||||
Layout.column: 1
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: qsTr("Restore Defaults")
|
|
||||||
Accessible.description: qsTr("Restores the settings dialog to a default state")
|
|
||||||
onClicked: {
|
|
||||||
MySettings.restoreGenerationDefaults();
|
|
||||||
templateTextArea.text = MySettings.promptTemplate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,8 +6,13 @@ import QtQuick.Layouts
|
|||||||
import QtQuick.Dialogs
|
import QtQuick.Dialogs
|
||||||
import localdocs
|
import localdocs
|
||||||
import mysettings
|
import mysettings
|
||||||
|
import network
|
||||||
|
|
||||||
MySettingsTab {
|
MySettingsTab {
|
||||||
|
onRestoreDefaultsClicked: {
|
||||||
|
MySettings.restoreLocalDocsDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
title: qsTr("LocalDocs Plugin (BETA)")
|
title: qsTr("LocalDocs Plugin (BETA)")
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
id: root
|
id: root
|
||||||
@ -25,9 +30,14 @@ MySettingsTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
Item {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
height: collection.height + 20
|
height: row.height
|
||||||
|
RowLayout {
|
||||||
|
id: row
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: collection.height
|
||||||
spacing: 10
|
spacing: 10
|
||||||
MyTextField {
|
MyTextField {
|
||||||
id: collection
|
id: collection
|
||||||
@ -98,28 +108,17 @@ MySettingsTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollView {
|
|
||||||
id: scrollView
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.bottomMargin: 10
|
|
||||||
clip: true
|
|
||||||
contentHeight: 300
|
|
||||||
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
color: theme.backgroundLighter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ColumnLayout {
|
||||||
id: listView
|
spacing: 0
|
||||||
|
Repeater {
|
||||||
model: LocalDocs.localDocsModel
|
model: LocalDocs.localDocsModel
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
id: item
|
id: item
|
||||||
width: listView.width
|
Layout.fillWidth: true
|
||||||
height: buttons.height + 20
|
height: buttons.height + 20
|
||||||
color: index % 2 === 0 ? theme.backgroundLight : theme.backgroundLighter
|
color: index % 2 === 0 ? theme.backgroundDark : theme.backgroundDarker
|
||||||
property bool removing: false
|
property bool removing: false
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
@ -136,6 +135,7 @@ MySettingsTab {
|
|||||||
Text {
|
Text {
|
||||||
id: folderId
|
id: folderId
|
||||||
anchors.left: collectionId.right
|
anchors.left: collectionId.right
|
||||||
|
anchors.right: buttons.left
|
||||||
anchors.margins: 20
|
anchors.margins: 20
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: folder_path
|
text: folder_path
|
||||||
@ -170,38 +170,25 @@ MySettingsTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GridLayout {
|
Rectangle {
|
||||||
id: gridLayout
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
height: 1
|
||||||
|
color: theme.tabBorder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
advancedSettings: GridLayout {
|
||||||
|
id: gridLayout
|
||||||
columns: 3
|
columns: 3
|
||||||
rowSpacing: 10
|
rowSpacing: 10
|
||||||
columnSpacing: 10
|
columnSpacing: 10
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
Layout.row: 0
|
|
||||||
Layout.column: 0
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.columnSpan: 3
|
|
||||||
height: 1
|
|
||||||
color: theme.dialogBorder
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
Layout.row: 3
|
Layout.row: 3
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.columnSpan: 3
|
Layout.columnSpan: 3
|
||||||
height: 1
|
height: 1
|
||||||
color: theme.dialogBorder
|
color: theme.tabBorder
|
||||||
}
|
|
||||||
|
|
||||||
// This is here just to stretch out the third column
|
|
||||||
Rectangle {
|
|
||||||
Layout.row: 3
|
|
||||||
Layout.column: 2
|
|
||||||
Layout.fillWidth: true
|
|
||||||
height: 1
|
|
||||||
color: theme.dialogBorder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
@ -261,33 +248,21 @@ MySettingsTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Item {
|
||||||
id: warningLabel
|
|
||||||
Layout.row: 1
|
Layout.row: 1
|
||||||
Layout.column: 2
|
Layout.column: 2
|
||||||
Layout.rowSpan: 2
|
Layout.rowSpan: 2
|
||||||
Layout.maximumWidth: 520
|
Layout.fillWidth: true
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.minimumHeight: warningLabel.height
|
||||||
|
Label {
|
||||||
|
id: warningLabel
|
||||||
|
width: parent.width
|
||||||
color: theme.textErrorColor
|
color: theme.textErrorColor
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: qsTr("Warning: Advanced usage only. Values too large may cause localdocs failure, extremely slow responses or failure to respond at all. Roughly speaking, the {N chars x N snippets} are added to the model's context window. More info <a href=\"https://docs.gpt4all.io/gpt4all_chat.html#localdocs-beta-plugin-chat-with-your-data\">here.</a>")
|
text: qsTr("Warning: Advanced usage only. Values too large may cause localdocs failure, extremely slow responses or failure to respond at all. Roughly speaking, the {N chars x N snippets} are added to the model's context window. More info <a href=\"https://docs.gpt4all.io/gpt4all_chat.html#localdocs-beta-plugin-chat-with-your-data\">here.</a>")
|
||||||
onLinkActivated: function(link) { Qt.openUrlExternally(link) }
|
onLinkActivated: function(link) { Qt.openUrlExternally(link) }
|
||||||
}
|
}
|
||||||
|
|
||||||
MyButton {
|
|
||||||
id: restoreDefaultsButton
|
|
||||||
Layout.row: 4
|
|
||||||
Layout.column: 1
|
|
||||||
Layout.columnSpan: 2
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: qsTr("Restore Defaults")
|
|
||||||
Accessible.role: Accessible.Button
|
|
||||||
Accessible.name: text
|
|
||||||
Accessible.description: qsTr("Restores the settings dialog to a default state")
|
|
||||||
onClicked: {
|
|
||||||
MySettings.restoreLocalDocsDefaults();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ Dialog {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
textFormat: Text.StyledText
|
textFormat: Text.StyledText
|
||||||
text: "<h2>" + (name !== "" ? name : filename) + "</h2>"
|
text: "<h2>" + name + "</h2>"
|
||||||
Layout.row: 0
|
Layout.row: 0
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
Layout.topMargin: 20
|
Layout.topMargin: 20
|
||||||
@ -329,12 +329,14 @@ Dialog {
|
|||||||
Layout.topMargin: 20
|
Layout.topMargin: 20
|
||||||
Layout.leftMargin: 20
|
Layout.leftMargin: 20
|
||||||
Layout.minimumWidth: 150
|
Layout.minimumWidth: 150
|
||||||
|
Layout.maximumWidth: textMetrics.width + 25
|
||||||
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||||
color: theme.textColor
|
color: theme.textColor
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: theme.backgroundLighter
|
color: theme.backgroundLighter
|
||||||
radius: 10
|
radius: 10
|
||||||
}
|
}
|
||||||
|
wrapMode: Text.WrapAnywhere
|
||||||
function showError() {
|
function showError() {
|
||||||
openaiKey.placeholderTextColor = theme.textErrorColor
|
openaiKey.placeholderTextColor = theme.textErrorColor
|
||||||
}
|
}
|
||||||
@ -346,6 +348,11 @@ Dialog {
|
|||||||
Accessible.role: Accessible.EditableText
|
Accessible.role: Accessible.EditableText
|
||||||
Accessible.name: placeholderText
|
Accessible.name: placeholderText
|
||||||
Accessible.description: qsTr("Whether the file hash is being calculated")
|
Accessible.description: qsTr("Whether the file hash is being calculated")
|
||||||
|
TextMetrics {
|
||||||
|
id: textMetrics
|
||||||
|
font: openaiKey.font
|
||||||
|
text: openaiKey.placeholderText
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,27 +3,665 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Controls.Basic
|
import QtQuick.Controls.Basic
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import localdocs
|
import modellist
|
||||||
import mysettings
|
import mysettings
|
||||||
|
|
||||||
MySettingsTab {
|
MySettingsTab {
|
||||||
title: qsTr("Models")
|
onRestoreDefaultsClicked: {
|
||||||
|
MySettings.restoreModelDefaults(root.currentModelInfo);
|
||||||
|
}
|
||||||
|
title: qsTr("Model/Character Settings")
|
||||||
contentItem: GridLayout {
|
contentItem: GridLayout {
|
||||||
id: generationSettingsTabInner
|
id: root
|
||||||
columns: 2
|
columns: 3
|
||||||
rowSpacing: 10
|
rowSpacing: 10
|
||||||
columnSpacing: 10
|
columnSpacing: 10
|
||||||
|
|
||||||
MyButton {
|
property var currentModelName: comboBox.currentText
|
||||||
Layout.row: 8
|
property var currentModelId: comboBox.currentValue
|
||||||
Layout.column: 1
|
property var currentModelInfo: ModelList.modelInfo(root.currentModelId)
|
||||||
Layout.fillWidth: true
|
|
||||||
text: qsTr("Restore Defaults")
|
Label {
|
||||||
Accessible.description: qsTr("Restores the settings dialog to a default state")
|
id: label
|
||||||
onClicked: {
|
Layout.row: 0
|
||||||
MySettings.restoreGenerationDefaults();
|
Layout.column: 0
|
||||||
templateTextArea.text = MySettings.promptTemplate
|
text: qsTr("Model/Character:")
|
||||||
|
color: theme.textColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.row: 1
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
height: label.height + 20
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
MyComboBox {
|
||||||
|
id: comboBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
model: ModelList.installedModels
|
||||||
|
valueRole: "id"
|
||||||
|
textRole: "name"
|
||||||
|
currentIndex: 0
|
||||||
|
contentItem: Text {
|
||||||
|
leftPadding: 10
|
||||||
|
rightPadding: 20
|
||||||
|
text: comboBox.currentText
|
||||||
|
font: comboBox.font
|
||||||
|
color: theme.textColor
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
delegate: ItemDelegate {
|
||||||
|
width: comboBox.width
|
||||||
|
contentItem: Text {
|
||||||
|
text: name
|
||||||
|
color: theme.textColor
|
||||||
|
font: comboBox.font
|
||||||
|
elide: Text.ElideRight
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
background: Rectangle {
|
||||||
|
color: highlighted ? theme.backgroundLight : theme.backgroundDark
|
||||||
|
}
|
||||||
|
highlighted: comboBox.highlightedIndex === index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MyButton {
|
||||||
|
id: cloneButton
|
||||||
|
text: qsTr("Clone")
|
||||||
|
onClicked: {
|
||||||
|
var id = ModelList.clone(root.currentModelInfo);
|
||||||
|
comboBox.currentIndex = comboBox.indexOfValue(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MyButton {
|
||||||
|
id: removeButton
|
||||||
|
enabled: root.currentModelInfo.isClone
|
||||||
|
text: qsTr("Remove")
|
||||||
|
onClicked: {
|
||||||
|
ModelList.remove(root.currentModelInfo);
|
||||||
|
comboBox.currentIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.row: 2
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.topMargin: 15
|
||||||
|
spacing: 10
|
||||||
|
Label {
|
||||||
|
id: uniqueNameLabel
|
||||||
|
text: qsTr("Unique Name:")
|
||||||
|
color: theme.textColor
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
id: uniqueNameLabelHelp
|
||||||
|
visible: false
|
||||||
|
text: qsTr("Must contain a non-empty unique name that does not match any existing model/character.")
|
||||||
|
color: theme.textErrorColor
|
||||||
|
wrapMode: TextArea.Wrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MyTextField {
|
||||||
|
id: uniqueNameField
|
||||||
|
text: root.currentModelName
|
||||||
|
enabled: root.currentModelInfo.isClone || root.currentModelInfo.description === ""
|
||||||
|
color: enabled ? theme.textColor : theme.mutedTextColor
|
||||||
|
Layout.row: 3
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Connections {
|
||||||
|
target: MySettings
|
||||||
|
function onNameChanged() {
|
||||||
|
uniqueNameField.text = root.currentModelInfo.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onCurrentModelInfoChanged() {
|
||||||
|
uniqueNameField.text = root.currentModelInfo.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onTextChanged: {
|
||||||
|
if (text !== "" && ModelList.isUniqueName(text)) {
|
||||||
|
MySettings.setModelName(root.currentModelInfo, text);
|
||||||
|
}
|
||||||
|
uniqueNameLabelHelp.visible = root.currentModelInfo.name !== "" &&
|
||||||
|
(text === "" || (text !== root.currentModelInfo.name && !ModelList.isUniqueName(text)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Model File:")
|
||||||
|
color: theme.textColor
|
||||||
|
Layout.row: 4
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.topMargin: 15
|
||||||
|
}
|
||||||
|
|
||||||
|
MyTextField {
|
||||||
|
text: root.currentModelInfo.filename
|
||||||
|
enabled: false
|
||||||
|
color: enabled ? theme.textColor : theme.mutedTextColor
|
||||||
|
Layout.row: 5
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
visible: !root.currentModelInfo.isChatGPT
|
||||||
|
text: qsTr("System Prompt:")
|
||||||
|
color: theme.textColor
|
||||||
|
Layout.row: 6
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.topMargin: 15
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: systemPrompt
|
||||||
|
visible: !root.currentModelInfo.isChatGPT
|
||||||
|
Layout.row: 7
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: "transparent"
|
||||||
|
Layout.minimumHeight: Math.max(150, systemPromptArea.contentHeight + 20)
|
||||||
|
TextArea {
|
||||||
|
id: systemPromptArea
|
||||||
|
anchors.fill: parent
|
||||||
|
text: root.currentModelInfo.systemPrompt
|
||||||
|
color: theme.textColor
|
||||||
|
background: Rectangle {
|
||||||
|
implicitWidth: 150
|
||||||
|
color: theme.backgroundDark
|
||||||
|
radius: 10
|
||||||
|
}
|
||||||
|
padding: 10
|
||||||
|
wrapMode: TextArea.Wrap
|
||||||
|
Connections {
|
||||||
|
target: MySettings
|
||||||
|
function onSystemPromptChanged() {
|
||||||
|
systemPromptArea.text = root.currentModelInfo.systemPrompt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onCurrentModelInfoChanged() {
|
||||||
|
systemPromptArea.text = root.currentModelInfo.systemPrompt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onTextChanged: {
|
||||||
|
MySettings.setModelSystemPrompt(root.currentModelInfo, text)
|
||||||
|
}
|
||||||
|
bottomPadding: 10
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.row: 8
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.topMargin: 15
|
||||||
|
spacing: 10
|
||||||
|
Label {
|
||||||
|
id: promptTemplateLabel
|
||||||
|
text: qsTr("Prompt Template:")
|
||||||
|
color: theme.textColor
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
id: promptTemplateLabelHelp
|
||||||
|
text: qsTr("Must contain the string \"%1\" to be replaced with the user's input.")
|
||||||
|
color: theme.textErrorColor
|
||||||
|
visible: templateTextArea.text.indexOf("%1") === -1
|
||||||
|
wrapMode: TextArea.Wrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: promptTemplate
|
||||||
|
Layout.row: 9
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumHeight: Math.max(150, templateTextArea.contentHeight + 20)
|
||||||
|
color: "transparent"
|
||||||
|
clip: true
|
||||||
|
TextArea {
|
||||||
|
id: templateTextArea
|
||||||
|
anchors.fill: parent
|
||||||
|
text: root.currentModelInfo.promptTemplate
|
||||||
|
color: theme.textColor
|
||||||
|
background: Rectangle {
|
||||||
|
implicitWidth: 150
|
||||||
|
color: theme.backgroundDark
|
||||||
|
radius: 10
|
||||||
|
}
|
||||||
|
padding: 10
|
||||||
|
wrapMode: TextArea.Wrap
|
||||||
|
Connections {
|
||||||
|
target: MySettings
|
||||||
|
function onPromptTemplateChanged() {
|
||||||
|
templateTextArea.text = root.currentModelInfo.promptTemplate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onCurrentModelInfoChanged() {
|
||||||
|
templateTextArea.text = root.currentModelInfo.promptTemplate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onTextChanged: {
|
||||||
|
if (templateTextArea.text.indexOf("%1") !== -1) {
|
||||||
|
MySettings.setModelPromptTemplate(root.currentModelInfo, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bottomPadding: 10
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: optionalImageRect
|
||||||
|
visible: false // FIXME: for later
|
||||||
|
Layout.row: 2
|
||||||
|
Layout.column: 1
|
||||||
|
Layout.rowSpan: 5
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.maximumWidth: height
|
||||||
|
Layout.topMargin: 35
|
||||||
|
Layout.bottomMargin: 35
|
||||||
|
Layout.leftMargin: 35
|
||||||
|
width: 3000
|
||||||
|
border.width: 1
|
||||||
|
border.color: theme.tabBorder
|
||||||
|
radius: 10
|
||||||
|
color: "transparent"
|
||||||
|
Item {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
height: childrenRect.height
|
||||||
|
Image {
|
||||||
|
id: img
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: 100
|
||||||
|
height: 100
|
||||||
|
source: "qrc:/gpt4all/icons/image.svg"
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: qsTr("Add\noptional image")
|
||||||
|
anchors.top: img.bottom
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
wrapMode: TextArea.Wrap
|
||||||
|
horizontalAlignment: Qt.AlignHCenter
|
||||||
|
color: theme.mutedTextColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Generation Settings")
|
||||||
|
color: theme.textColor
|
||||||
|
Layout.row: 10
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.topMargin: 15
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.minimumWidth: promptTemplate.width
|
||||||
|
horizontalAlignment: Qt.AlignHCenter
|
||||||
|
font.pixelSize: theme.fontSizeLarger
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
Layout.row: 11
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.topMargin: 15
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumWidth: promptTemplate.width
|
||||||
|
columns: 4
|
||||||
|
rowSpacing: 10
|
||||||
|
columnSpacing: 10
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: tempLabel
|
||||||
|
text: qsTr("Temperature:")
|
||||||
|
color: theme.textColor
|
||||||
|
Layout.row: 0
|
||||||
|
Layout.column: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
MyTextField {
|
||||||
|
id: temperatureField
|
||||||
|
text: root.currentModelInfo.temperature
|
||||||
|
color: theme.textColor
|
||||||
|
ToolTip.text: qsTr("Temperature increases the chances of choosing less likely tokens.\nNOTE: Higher temperature gives more creative but less predictable outputs.")
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
Layout.row: 0
|
||||||
|
Layout.column: 1
|
||||||
|
validator: DoubleValidator {
|
||||||
|
locale: "C"
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: MySettings
|
||||||
|
function onTemperatureChanged() {
|
||||||
|
temperatureField.text = root.currentModelInfo.temperature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onCurrentModelInfoChanged() {
|
||||||
|
temperatureField.text = root.currentModelInfo.temperature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onEditingFinished: {
|
||||||
|
var val = parseFloat(text)
|
||||||
|
if (!isNaN(val)) {
|
||||||
|
MySettings.setModelTemperature(root.currentModelInfo, val)
|
||||||
|
focus = false
|
||||||
|
} else {
|
||||||
|
text = root.currentModelInfo.temperature
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Accessible.role: Accessible.EditableText
|
||||||
|
Accessible.name: tempLabel.text
|
||||||
|
Accessible.description: ToolTip.text
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
id: topPLabel
|
||||||
|
text: qsTr("Top P:")
|
||||||
|
color: theme.textColor
|
||||||
|
Layout.row: 0
|
||||||
|
Layout.column: 2
|
||||||
|
}
|
||||||
|
MyTextField {
|
||||||
|
id: topPField
|
||||||
|
text: root.currentModelInfo.topP
|
||||||
|
color: theme.textColor
|
||||||
|
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.visible: hovered
|
||||||
|
Layout.row: 0
|
||||||
|
Layout.column: 3
|
||||||
|
validator: DoubleValidator {
|
||||||
|
locale: "C"
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: MySettings
|
||||||
|
function onTopPChanged() {
|
||||||
|
topPField.text = root.currentModelInfo.topP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onCurrentModelInfoChanged() {
|
||||||
|
topPField.text = root.currentModelInfo.topP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onEditingFinished: {
|
||||||
|
var val = parseFloat(text)
|
||||||
|
if (!isNaN(val)) {
|
||||||
|
MySettings.setModelTopP(root.currentModelInfo, val)
|
||||||
|
focus = false
|
||||||
|
} else {
|
||||||
|
text = root.currentModelInfo.topP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Accessible.role: Accessible.EditableText
|
||||||
|
Accessible.name: topPLabel.text
|
||||||
|
Accessible.description: ToolTip.text
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
id: topKLabel
|
||||||
|
visible: !root.currentModelInfo.isChatGPT
|
||||||
|
text: qsTr("Top K:")
|
||||||
|
color: theme.textColor
|
||||||
|
Layout.row: 1
|
||||||
|
Layout.column: 0
|
||||||
|
}
|
||||||
|
MyTextField {
|
||||||
|
id: topKField
|
||||||
|
visible: !root.currentModelInfo.isChatGPT
|
||||||
|
text: root.currentModelInfo.topK
|
||||||
|
color: theme.textColor
|
||||||
|
ToolTip.text: qsTr("Only the top K most likely tokens will be chosen from")
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
Layout.row: 1
|
||||||
|
Layout.column: 1
|
||||||
|
validator: IntValidator {
|
||||||
|
bottom: 1
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: MySettings
|
||||||
|
function onTopKChanged() {
|
||||||
|
topKField.text = root.currentModelInfo.topK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onCurrentModelInfoChanged() {
|
||||||
|
topKField.text = root.currentModelInfo.topK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onEditingFinished: {
|
||||||
|
var val = parseInt(text)
|
||||||
|
if (!isNaN(val)) {
|
||||||
|
MySettings.setModelTopK(root.currentModelInfo, val)
|
||||||
|
focus = false
|
||||||
|
} else {
|
||||||
|
text = root.currentModelInfo.topK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Accessible.role: Accessible.EditableText
|
||||||
|
Accessible.name: topKLabel.text
|
||||||
|
Accessible.description: ToolTip.text
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
id: maxLengthLabel
|
||||||
|
visible: !root.currentModelInfo.isChatGPT
|
||||||
|
text: qsTr("Max Length:")
|
||||||
|
color: theme.textColor
|
||||||
|
Layout.row: 1
|
||||||
|
Layout.column: 2
|
||||||
|
}
|
||||||
|
MyTextField {
|
||||||
|
id: maxLengthField
|
||||||
|
visible: !root.currentModelInfo.isChatGPT
|
||||||
|
text: root.currentModelInfo.maxLength
|
||||||
|
color: theme.textColor
|
||||||
|
ToolTip.text: qsTr("Maximum length of response in tokens")
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
Layout.row: 1
|
||||||
|
Layout.column: 3
|
||||||
|
validator: IntValidator {
|
||||||
|
bottom: 1
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: MySettings
|
||||||
|
function onMaxLengthChanged() {
|
||||||
|
maxLengthField.text = root.currentModelInfo.maxLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onCurrentModelInfoChanged() {
|
||||||
|
maxLengthField.text = root.currentModelInfo.maxLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onEditingFinished: {
|
||||||
|
var val = parseInt(text)
|
||||||
|
if (!isNaN(val)) {
|
||||||
|
MySettings.setModelMaxLength(root.currentModelInfo, val)
|
||||||
|
focus = false
|
||||||
|
} else {
|
||||||
|
text = root.currentModelInfo.maxLength
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Accessible.role: Accessible.EditableText
|
||||||
|
Accessible.name: maxLengthLabel.text
|
||||||
|
Accessible.description: ToolTip.text
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: batchSizeLabel
|
||||||
|
visible: !root.currentModelInfo.isChatGPT
|
||||||
|
text: qsTr("Prompt Batch Size:")
|
||||||
|
color: theme.textColor
|
||||||
|
Layout.row: 2
|
||||||
|
Layout.column: 0
|
||||||
|
}
|
||||||
|
MyTextField {
|
||||||
|
id: batchSizeField
|
||||||
|
visible: !root.currentModelInfo.isChatGPT
|
||||||
|
text: root.currentModelInfo.promptBatchSize
|
||||||
|
color: theme.textColor
|
||||||
|
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: 2
|
||||||
|
Layout.column: 1
|
||||||
|
validator: IntValidator {
|
||||||
|
bottom: 1
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: MySettings
|
||||||
|
function onPromptBatchSizeChanged() {
|
||||||
|
batchSizeField.text = root.currentModelInfo.promptBatchSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onCurrentModelInfoChanged() {
|
||||||
|
batchSizeField.text = root.currentModelInfo.promptBatchSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onEditingFinished: {
|
||||||
|
var val = parseInt(text)
|
||||||
|
if (!isNaN(val)) {
|
||||||
|
MySettings.setModelPromptBatchSize(root.currentModelInfo, val)
|
||||||
|
focus = false
|
||||||
|
} else {
|
||||||
|
text = root.currentModelInfo.promptBatchSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Accessible.role: Accessible.EditableText
|
||||||
|
Accessible.name: batchSizeLabel.text
|
||||||
|
Accessible.description: ToolTip.text
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
id: repeatPenaltyLabel
|
||||||
|
visible: !root.currentModelInfo.isChatGPT
|
||||||
|
text: qsTr("Repeat Penalty:")
|
||||||
|
color: theme.textColor
|
||||||
|
Layout.row: 2
|
||||||
|
Layout.column: 2
|
||||||
|
}
|
||||||
|
MyTextField {
|
||||||
|
id: repeatPenaltyField
|
||||||
|
visible: !root.currentModelInfo.isChatGPT
|
||||||
|
text: root.currentModelInfo.repeatPenalty
|
||||||
|
color: theme.textColor
|
||||||
|
ToolTip.text: qsTr("Amount to penalize repetitiveness of the output")
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
Layout.row: 2
|
||||||
|
Layout.column: 3
|
||||||
|
validator: DoubleValidator {
|
||||||
|
locale: "C"
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: MySettings
|
||||||
|
function onRepeatPenaltyChanged() {
|
||||||
|
repeatPenaltyField.text = root.currentModelInfo.repeatPenalty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onCurrentModelInfoChanged() {
|
||||||
|
repeatPenaltyField.text = root.currentModelInfo.repeatPenalty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onEditingFinished: {
|
||||||
|
var val = parseFloat(text)
|
||||||
|
if (!isNaN(val)) {
|
||||||
|
MySettings.setModelRepeatPenalty(root.currentModelInfo, val)
|
||||||
|
focus = false
|
||||||
|
} else {
|
||||||
|
text = root.currentModelInfo.repeatPenalty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Accessible.role: Accessible.EditableText
|
||||||
|
Accessible.name: repeatPenaltyLabel.text
|
||||||
|
Accessible.description: ToolTip.text
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
id: repeatPenaltyTokensLabel
|
||||||
|
visible: !root.currentModelInfo.isChatGPT
|
||||||
|
text: qsTr("Repeat Penalty Tokens:")
|
||||||
|
color: theme.textColor
|
||||||
|
Layout.row: 3
|
||||||
|
Layout.column: 0
|
||||||
|
}
|
||||||
|
MyTextField {
|
||||||
|
id: repeatPenaltyTokenField
|
||||||
|
visible: !root.currentModelInfo.isChatGPT
|
||||||
|
text: root.currentModelInfo.repeatPenaltyTokens
|
||||||
|
color: theme.textColor
|
||||||
|
ToolTip.text: qsTr("How far back in output to apply repeat penalty")
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
Layout.row: 3
|
||||||
|
Layout.column: 1
|
||||||
|
validator: IntValidator {
|
||||||
|
bottom: 1
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: MySettings
|
||||||
|
function onRepeatPenaltyTokensChanged() {
|
||||||
|
repeatPenaltyTokenField.text = root.currentModelInfo.repeatPenaltyTokens;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onCurrentModelInfoChanged() {
|
||||||
|
repeatPenaltyTokenField.text = root.currentModelInfo.repeatPenaltyTokens;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onEditingFinished: {
|
||||||
|
var val = parseInt(text)
|
||||||
|
if (!isNaN(val)) {
|
||||||
|
MySettings.setModelRepeatPenaltyTokens(root.currentModelInfo, val)
|
||||||
|
focus = false
|
||||||
|
} else {
|
||||||
|
text = root.currentModelInfo.repeatPenaltyTokens
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Accessible.role: Accessible.EditableText
|
||||||
|
Accessible.name: repeatPenaltyTokensLabel.text
|
||||||
|
Accessible.description: ToolTip.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.row: 12
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.topMargin: 15
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumWidth: promptTemplate.width
|
||||||
|
height: 1
|
||||||
|
color: theme.tabBorder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,7 +17,7 @@ Button {
|
|||||||
border.color: myButton.down ? theme.backgroundLightest : theme.buttonBorder
|
border.color: myButton.down ? theme.backgroundLightest : theme.buttonBorder
|
||||||
border.width: 2
|
border.width: 2
|
||||||
radius: 10
|
radius: 10
|
||||||
color: myButton.hovered ? theme.backgroundLighter : theme.backgroundLight
|
color: myButton.hovered ? theme.backgroundDark : theme.backgroundDarkest
|
||||||
}
|
}
|
||||||
Accessible.role: Accessible.Button
|
Accessible.role: Accessible.Button
|
||||||
Accessible.name: text
|
Accessible.name: text
|
||||||
|
@ -9,14 +9,13 @@ ComboBox {
|
|||||||
padding: 10
|
padding: 10
|
||||||
Accessible.role: Accessible.ComboBox
|
Accessible.role: Accessible.ComboBox
|
||||||
contentItem: Text {
|
contentItem: Text {
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
id: text
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
rightPadding: 20
|
rightPadding: 20
|
||||||
text: comboBox.displayText
|
text: comboBox.displayText
|
||||||
font: comboBox.font
|
font: comboBox.font
|
||||||
color: theme.textColor
|
color: theme.textColor
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
delegate: ItemDelegate {
|
delegate: ItemDelegate {
|
||||||
|
@ -11,7 +11,7 @@ TextField {
|
|||||||
color: text === "" || isValid ? theme.textColor : theme.textErrorColor
|
color: text === "" || isValid ? theme.textColor : theme.textErrorColor
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
implicitWidth: 150
|
implicitWidth: 150
|
||||||
color: theme.backgroundLighter
|
color: theme.backgroundDark
|
||||||
radius: 10
|
radius: 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,71 +12,56 @@ Item {
|
|||||||
id: theme
|
id: theme
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property alias title: titleLabel.text
|
||||||
property ListModel tabTitlesModel: ListModel { }
|
property ListModel tabTitlesModel: ListModel { }
|
||||||
property list<Component> tabs: [ ]
|
property list<Component> tabs: [ ]
|
||||||
|
|
||||||
Canvas {
|
Label {
|
||||||
id: canvas
|
id: titleLabel
|
||||||
anchors.fill: parent
|
anchors.top: parent.top
|
||||||
contextType: "2d"
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
onPaint: {
|
color: theme.textColor
|
||||||
var context = getContext("2d");
|
padding: 10
|
||||||
context.reset();
|
font.bold: true
|
||||||
context.lineWidth = 2;
|
font.pixelSize: theme.fontSizeLarger
|
||||||
context.moveTo(stackLayout.x, stackLayout.y);
|
|
||||||
context.lineTo(stackLayout.x, stackLayout.y + stackLayout.height);
|
|
||||||
context.lineTo(stackLayout.x + stackLayout.width, stackLayout.y + stackLayout.height);
|
|
||||||
context.lineTo(stackLayout.x + stackLayout.width, stackLayout.y);
|
|
||||||
context.lineTo(/*settingsTabBar.currentItem.x + */settingsTabBar.currentItem.width, stackLayout.y);
|
|
||||||
context.strokeStyle = theme.tabBorder;
|
|
||||||
context.stroke();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.top: titleLabel.bottom
|
||||||
|
anchors.leftMargin: 15
|
||||||
|
anchors.rightMargin: 15
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: 1
|
||||||
|
color: theme.tabBorder
|
||||||
}
|
}
|
||||||
|
|
||||||
TabBar {
|
TabBar {
|
||||||
id: settingsTabBar
|
id: settingsTabBar
|
||||||
width: parent.width / 1.25
|
anchors.top: titleLabel.bottom
|
||||||
|
anchors.topMargin: 15
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: parent.width / 1.75
|
||||||
z: 200
|
z: 200
|
||||||
visible: tabTitlesModel.count > 1
|
visible: tabTitlesModel.count > 1
|
||||||
|
background: Rectangle {
|
||||||
|
color: "transparent"
|
||||||
|
}
|
||||||
Repeater {
|
Repeater {
|
||||||
model: settingsStack.tabTitlesModel
|
model: settingsStack.tabTitlesModel
|
||||||
TabButton {
|
TabButton {
|
||||||
id: tabButton
|
id: tabButton
|
||||||
|
padding: 10
|
||||||
contentItem: IconLabel {
|
contentItem: IconLabel {
|
||||||
color: theme.textColor
|
color: theme.textColor
|
||||||
font.bold: tabButton.checked
|
font.bold: tabButton.checked
|
||||||
text: model.title
|
text: model.title
|
||||||
}
|
}
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: tabButton.checked ? theme.backgroundDarkest : theme.backgroundLight
|
color: "transparent"
|
||||||
// Rectangle {
|
border.width: 1
|
||||||
// anchors.top: parent.top
|
border.color: tabButton.checked ? theme.tabBorder : "transparent"
|
||||||
// anchors.left: parent.left
|
radius: 10
|
||||||
// anchors.right: parent.right
|
|
||||||
// height: tabButton.checked
|
|
||||||
// color: theme.tabBorder
|
|
||||||
// }
|
|
||||||
// Rectangle {
|
|
||||||
// anchors.bottom: parent.bottom
|
|
||||||
// anchors.left: parent.left
|
|
||||||
// anchors.right: parent.right
|
|
||||||
// height: !tabButton.checked
|
|
||||||
// color: theme.tabBorder
|
|
||||||
// }
|
|
||||||
// Rectangle {
|
|
||||||
// anchors.top: parent.top
|
|
||||||
// anchors.bottom: parent.bottom
|
|
||||||
// anchors.left: parent.left
|
|
||||||
// width: tabButton.checked
|
|
||||||
// color: theme.tabBorder
|
|
||||||
// }
|
|
||||||
// Rectangle {
|
|
||||||
// anchors.top: parent.top
|
|
||||||
// anchors.bottom: parent.bottom
|
|
||||||
// anchors.right: parent.right
|
|
||||||
// width: tabButton.checked
|
|
||||||
// color: theme.tabBorder
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
Accessible.role: Accessible.Button
|
Accessible.role: Accessible.Button
|
||||||
Accessible.name: model.title
|
Accessible.name: model.title
|
||||||
@ -84,9 +69,31 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: dividerTabBar
|
||||||
|
visible: tabTitlesModel.count > 1
|
||||||
|
anchors.top: settingsTabBar.bottom
|
||||||
|
anchors.topMargin: 15
|
||||||
|
anchors.bottomMargin: 15
|
||||||
|
anchors.leftMargin: 15
|
||||||
|
anchors.rightMargin: 15
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: 1
|
||||||
|
color: theme.tabBorder
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "transparent"
|
||||||
|
radius: 10
|
||||||
|
border.width: 1
|
||||||
|
border.color: theme.tabBorder
|
||||||
|
}
|
||||||
|
|
||||||
StackLayout {
|
StackLayout {
|
||||||
id: stackLayout
|
id: stackLayout
|
||||||
anchors.top: tabTitlesModel.count > 1 ? settingsTabBar.bottom : parent.top
|
anchors.top: tabTitlesModel.count > 1 ? dividerTabBar.bottom : titleLabel.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
@ -5,42 +5,87 @@ import QtQuick.Controls.Basic
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
id: root
|
||||||
property string title: ""
|
property string title: ""
|
||||||
property Item contentItem: null
|
property Item contentItem: null
|
||||||
|
property Item advancedSettings: null
|
||||||
|
signal restoreDefaultsClicked
|
||||||
|
|
||||||
onContentItemChanged: function() {
|
onContentItemChanged: function() {
|
||||||
if (contentItem) {
|
if (contentItem) {
|
||||||
contentItem.parent = tabInner;
|
contentItem.parent = contentInner;
|
||||||
contentItem.anchors.left = tabInner.left;
|
contentItem.anchors.left = contentInner.left;
|
||||||
contentItem.anchors.right = tabInner.right;
|
contentItem.anchors.right = contentInner.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAdvancedSettingsChanged: function() {
|
||||||
|
if (advancedSettings) {
|
||||||
|
advancedSettings.parent = advancedInner;
|
||||||
|
advancedSettings.anchors.left = advancedInner.left;
|
||||||
|
advancedSettings.anchors.right = advancedInner.right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollView {
|
ScrollView {
|
||||||
id: root
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height
|
height: parent.height
|
||||||
padding: 15
|
padding: 15
|
||||||
rightPadding: 20
|
rightPadding: 20
|
||||||
contentWidth: availableWidth
|
contentWidth: availableWidth
|
||||||
contentHeight: tabInner.height
|
contentHeight: innerColumn.height
|
||||||
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
|
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
|
||||||
|
|
||||||
Theme {
|
Theme {
|
||||||
id: theme
|
id: theme
|
||||||
}
|
}
|
||||||
|
|
||||||
// background: Rectangle {
|
ColumnLayout {
|
||||||
// color: 'transparent'
|
id: innerColumn
|
||||||
// border.color: theme.tabBorder
|
|
||||||
// border.width: 1
|
|
||||||
// radius: 10
|
|
||||||
// }
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: tabInner
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
anchors.margins: 15
|
||||||
|
spacing: 10
|
||||||
|
Column {
|
||||||
|
id: contentInner
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: advancedInner
|
||||||
|
visible: false
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: restoreDefaultsButton.height
|
||||||
|
MyButton {
|
||||||
|
id: restoreDefaultsButton
|
||||||
|
anchors.left: parent.left
|
||||||
|
width: implicitWidth
|
||||||
|
text: qsTr("Restore Defaults")
|
||||||
|
Accessible.role: Accessible.Button
|
||||||
|
Accessible.name: text
|
||||||
|
Accessible.description: qsTr("Restores the settings dialog to a default state")
|
||||||
|
onClicked: {
|
||||||
|
root.restoreDefaultsClicked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MyButton {
|
||||||
|
id: advancedSettingsButton
|
||||||
|
anchors.right: parent.right
|
||||||
|
visible: root.advancedSettings
|
||||||
|
width: implicitWidth
|
||||||
|
text: !advancedInner.visible ? qsTr("Advanced Settings") : qsTr("Hide Advanced Settings")
|
||||||
|
Accessible.role: Accessible.Button
|
||||||
|
Accessible.name: text
|
||||||
|
Accessible.description: qsTr("Shows/hides the advanced settings")
|
||||||
|
onClicked: {
|
||||||
|
advancedInner.visible = !advancedInner.visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ TextField {
|
|||||||
padding: 10
|
padding: 10
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
implicitWidth: 150
|
implicitWidth: 150
|
||||||
color: theme.backgroundLighter
|
color: theme.backgroundDark
|
||||||
radius: 10
|
radius: 10
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,7 +14,6 @@ import mysettings
|
|||||||
Dialog {
|
Dialog {
|
||||||
id: settingsDialog
|
id: settingsDialog
|
||||||
modal: true
|
modal: true
|
||||||
opacity: 0.9
|
|
||||||
padding: 20
|
padding: 20
|
||||||
bottomPadding: 30
|
bottomPadding: 30
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
@ -38,7 +37,7 @@ Dialog {
|
|||||||
ListModel {
|
ListModel {
|
||||||
id: stacksModel
|
id: stacksModel
|
||||||
ListElement {
|
ListElement {
|
||||||
title: "Generation"
|
title: "Models"
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
title: "Application"
|
title: "Application"
|
||||||
@ -67,7 +66,6 @@ Dialog {
|
|||||||
id: item
|
id: item
|
||||||
width: listView.width
|
width: listView.width
|
||||||
height: titleLabel.height + 25
|
height: titleLabel.height + 25
|
||||||
// color: index % 2 === 0 ? theme.backgroundLight : theme.backgroundLighter
|
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
border.color: theme.backgroundLighter
|
border.color: theme.backgroundLighter
|
||||||
border.width: index == listView.currentIndex ? 1 : 0
|
border.width: index == listView.currentIndex ? 1 : 0
|
||||||
@ -78,6 +76,7 @@ Dialog {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.margins: 20
|
anchors.margins: 20
|
||||||
|
font.bold: index == listView.currentIndex
|
||||||
text: title
|
text: title
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
color: theme.textColor
|
color: theme.textColor
|
||||||
@ -101,19 +100,21 @@ Dialog {
|
|||||||
currentIndex: listView.currentIndex
|
currentIndex: listView.currentIndex
|
||||||
|
|
||||||
MySettingsStack {
|
MySettingsStack {
|
||||||
|
title: qsTr("Model/Character Settings")
|
||||||
tabs: [
|
tabs: [
|
||||||
Component { ModelSettings { } },
|
Component { ModelSettings { } }
|
||||||
Component { GenerationSettings { } }
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
MySettingsStack {
|
MySettingsStack {
|
||||||
|
title: qsTr("Application General Settings")
|
||||||
tabs: [
|
tabs: [
|
||||||
Component { ApplicationSettings { } }
|
Component { ApplicationSettings { } }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
MySettingsStack {
|
MySettingsStack {
|
||||||
|
title: qsTr("LocalDocs Plugin (BETA) Settings")
|
||||||
tabs: [
|
tabs: [
|
||||||
Component { LocalDocsSettings { } }
|
Component { LocalDocsSettings { } }
|
||||||
]
|
]
|
||||||
|
@ -7,9 +7,9 @@ QtObject {
|
|||||||
property color textAccent: "#8e8ea0"
|
property color textAccent: "#8e8ea0"
|
||||||
property color mutedTextColor: backgroundLightest
|
property color mutedTextColor: backgroundLightest
|
||||||
property color textErrorColor: "red"
|
property color textErrorColor: "red"
|
||||||
property color backgroundDarkest: "#202123"
|
property color backgroundDarkest: "#1c1f21"
|
||||||
property color backgroundDarker: "#222326"
|
property color backgroundDarker: "#1e2123"
|
||||||
property color backgroundDark: "#242528"
|
property color backgroundDark: "#222527"
|
||||||
property color backgroundLight: "#343541"
|
property color backgroundLight: "#343541"
|
||||||
property color backgroundLighter: "#444654"
|
property color backgroundLighter: "#444654"
|
||||||
property color backgroundLightest: "#7d7d8e"
|
property color backgroundLightest: "#7d7d8e"
|
||||||
|
@ -120,6 +120,74 @@ static QVector<HighlightingRule> pythonHighlightingRules()
|
|||||||
return highlightingRules;
|
return highlightingRules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QVector<HighlightingRule> csharpHighlightingRules()
|
||||||
|
{
|
||||||
|
static QVector<HighlightingRule> highlightingRules;
|
||||||
|
if (highlightingRules.isEmpty()) {
|
||||||
|
|
||||||
|
HighlightingRule rule;
|
||||||
|
|
||||||
|
// Function call highlighting
|
||||||
|
QTextCharFormat functionCallFormat;
|
||||||
|
functionCallFormat.setForeground(functionCallColor);
|
||||||
|
rule.pattern = QRegularExpression("\\b(\\w+)\\s*(?=\\()");
|
||||||
|
rule.format = functionCallFormat;
|
||||||
|
highlightingRules.append(rule);
|
||||||
|
|
||||||
|
// Function definition highlighting
|
||||||
|
QTextCharFormat functionFormat;
|
||||||
|
functionFormat.setForeground(functionColor);
|
||||||
|
rule.pattern = QRegularExpression("\\bvoid|int|double|string|bool\\s+(\\w+)\\s*(?=\\()");
|
||||||
|
rule.format = functionFormat;
|
||||||
|
highlightingRules.append(rule);
|
||||||
|
|
||||||
|
// Number highlighting
|
||||||
|
QTextCharFormat numberFormat;
|
||||||
|
numberFormat.setForeground(numberColor);
|
||||||
|
rule.pattern = QRegularExpression("\\b[0-9]*\\.?[0-9]+\\b");
|
||||||
|
rule.format = numberFormat;
|
||||||
|
highlightingRules.append(rule);
|
||||||
|
|
||||||
|
// Keyword highlighting
|
||||||
|
QTextCharFormat keywordFormat;
|
||||||
|
keywordFormat.setForeground(keywordColor);
|
||||||
|
QStringList keywordPatterns = {
|
||||||
|
"\\bvoid\\b", "\\bint\\b", "\\bdouble\\b", "\\bstring\\b", "\\bbool\\b",
|
||||||
|
"\\bclass\\b", "\\bif\\b", "\\belse\\b", "\\bwhile\\b", "\\bfor\\b",
|
||||||
|
"\\breturn\\b", "\\bnew\\b", "\\bthis\\b", "\\bpublic\\b", "\\bprivate\\b",
|
||||||
|
"\\bprotected\\b", "\\bstatic\\b", "\\btrue\\b", "\\bfalse\\b", "\\bnull\\b",
|
||||||
|
"\\bnamespace\\b", "\\busing\\b", "\\btry\\b", "\\bcatch\\b", "\\bfinally\\b",
|
||||||
|
"\\bthrow\\b", "\\bvar\\b"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const QString &pattern : keywordPatterns) {
|
||||||
|
rule.pattern = QRegularExpression(pattern);
|
||||||
|
rule.format = keywordFormat;
|
||||||
|
highlightingRules.append(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
// String highlighting
|
||||||
|
QTextCharFormat stringFormat;
|
||||||
|
stringFormat.setForeground(stringColor);
|
||||||
|
rule.pattern = QRegularExpression("\".*?\"");
|
||||||
|
rule.format = stringFormat;
|
||||||
|
highlightingRules.append(rule);
|
||||||
|
|
||||||
|
// Single-line comment highlighting
|
||||||
|
QTextCharFormat commentFormat;
|
||||||
|
commentFormat.setForeground(commentColor);
|
||||||
|
rule.pattern = QRegularExpression("//[^\n]*");
|
||||||
|
rule.format = commentFormat;
|
||||||
|
highlightingRules.append(rule);
|
||||||
|
|
||||||
|
// Multi-line comment highlighting
|
||||||
|
rule.pattern = QRegularExpression("/\\*.*?\\*/");
|
||||||
|
rule.format = commentFormat;
|
||||||
|
highlightingRules.append(rule);
|
||||||
|
}
|
||||||
|
return highlightingRules;
|
||||||
|
}
|
||||||
|
|
||||||
static QVector<HighlightingRule> cppHighlightingRules()
|
static QVector<HighlightingRule> cppHighlightingRules()
|
||||||
{
|
{
|
||||||
static QVector<HighlightingRule> highlightingRules;
|
static QVector<HighlightingRule> highlightingRules;
|
||||||
|
@ -14,11 +14,11 @@
|
|||||||
static inline QJsonObject modelToJson(const ModelInfo &info)
|
static inline QJsonObject modelToJson(const ModelInfo &info)
|
||||||
{
|
{
|
||||||
QJsonObject model;
|
QJsonObject model;
|
||||||
model.insert("id", info.name);
|
model.insert("id", info.name());
|
||||||
model.insert("object", "model");
|
model.insert("object", "model");
|
||||||
model.insert("created", "who can keep track?");
|
model.insert("created", "who can keep track?");
|
||||||
model.insert("owned_by", "humanity");
|
model.insert("owned_by", "humanity");
|
||||||
model.insert("root", info.name);
|
model.insert("root", info.name());
|
||||||
model.insert("parent", QJsonValue::Null);
|
model.insert("parent", QJsonValue::Null);
|
||||||
|
|
||||||
QJsonArray permissions;
|
QJsonArray permissions;
|
||||||
@ -106,7 +106,7 @@ void Server::start()
|
|||||||
if (!info.installed)
|
if (!info.installed)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (model == info.name) {
|
if (model == info.name()) {
|
||||||
object = modelToJson(info);
|
object = modelToJson(info);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -173,7 +173,7 @@ QHttpServerResponse Server::handleCompletionRequest(const QHttpServerRequest &re
|
|||||||
for (const ModelInfo &info : modelList) {
|
for (const ModelInfo &info : modelList) {
|
||||||
if (!info.installed)
|
if (!info.installed)
|
||||||
continue;
|
continue;
|
||||||
if (modelRequested == info.name || modelRequested == info.filename) {
|
if (modelRequested == info.name() || modelRequested == info.filename()) {
|
||||||
modelInfo = info;
|
modelInfo = info;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -284,32 +284,28 @@ QHttpServerResponse Server::handleCompletionRequest(const QHttpServerRequest &re
|
|||||||
// load the new model if necessary
|
// load the new model if necessary
|
||||||
setShouldBeLoaded(true);
|
setShouldBeLoaded(true);
|
||||||
|
|
||||||
if (modelInfo.filename.isEmpty()) {
|
if (modelInfo.filename().isEmpty()) {
|
||||||
std::cerr << "ERROR: couldn't load default model " << modelRequested.toStdString() << std::endl;
|
std::cerr << "ERROR: couldn't load default model " << modelRequested.toStdString() << std::endl;
|
||||||
return QHttpServerResponse(QHttpServerResponder::StatusCode::BadRequest);
|
return QHttpServerResponse(QHttpServerResponder::StatusCode::BadRequest);
|
||||||
} else if (!loadModel(modelInfo)) {
|
} else if (!loadModel(modelInfo)) {
|
||||||
std::cerr << "ERROR: couldn't load model " << modelInfo.name.toStdString() << std::endl;
|
std::cerr << "ERROR: couldn't load model " << modelInfo.name().toStdString() << std::endl;
|
||||||
return QHttpServerResponse(QHttpServerResponder::StatusCode::InternalServerError);
|
return QHttpServerResponse(QHttpServerResponder::StatusCode::InternalServerError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't remember any context
|
// don't remember any context
|
||||||
resetContext();
|
resetContext();
|
||||||
|
|
||||||
const QString promptTemplate = MySettings::globalInstance()->promptTemplate();
|
const QString promptTemplate = modelInfo.promptTemplate();
|
||||||
const float top_k = MySettings::globalInstance()->topK();
|
const float top_k = modelInfo.topK();
|
||||||
const int n_batch = MySettings::globalInstance()->promptBatchSize();
|
const int n_batch = modelInfo.promptBatchSize();
|
||||||
const float repeat_penalty = MySettings::globalInstance()->repeatPenalty();
|
const float repeat_penalty = modelInfo.repeatPenalty();
|
||||||
const int repeat_last_n = MySettings::globalInstance()->repeatPenaltyTokens();
|
const int repeat_last_n = modelInfo.repeatPenaltyTokens();
|
||||||
|
|
||||||
int threadCount = MySettings::globalInstance()->threadCount();
|
|
||||||
if (threadCount <= 0)
|
|
||||||
threadCount = std::min(4, (int32_t) std::thread::hardware_concurrency());
|
|
||||||
|
|
||||||
int promptTokens = 0;
|
int promptTokens = 0;
|
||||||
int responseTokens = 0;
|
int responseTokens = 0;
|
||||||
QList<QPair<QString, QList<ResultInfo>>> responses;
|
QList<QPair<QString, QList<ResultInfo>>> responses;
|
||||||
for (int i = 0; i < n; ++i) {
|
for (int i = 0; i < n; ++i) {
|
||||||
if (!prompt(
|
if (!promptInternal(
|
||||||
m_collections,
|
m_collections,
|
||||||
actualPrompt,
|
actualPrompt,
|
||||||
promptTemplate,
|
promptTemplate,
|
||||||
@ -319,10 +315,9 @@ QHttpServerResponse Server::handleCompletionRequest(const QHttpServerRequest &re
|
|||||||
temperature,
|
temperature,
|
||||||
n_batch,
|
n_batch,
|
||||||
repeat_penalty,
|
repeat_penalty,
|
||||||
repeat_last_n,
|
repeat_last_n)) {
|
||||||
threadCount)) {
|
|
||||||
|
|
||||||
std::cerr << "ERROR: couldn't prompt model " << modelInfo.name.toStdString() << std::endl;
|
std::cerr << "ERROR: couldn't prompt model " << modelInfo.name().toStdString() << std::endl;
|
||||||
return QHttpServerResponse(QHttpServerResponder::StatusCode::InternalServerError);
|
return QHttpServerResponse(QHttpServerResponder::StatusCode::InternalServerError);
|
||||||
}
|
}
|
||||||
QString echoedPrompt = actualPrompt;
|
QString echoedPrompt = actualPrompt;
|
||||||
@ -340,7 +335,7 @@ QHttpServerResponse Server::handleCompletionRequest(const QHttpServerRequest &re
|
|||||||
responseObject.insert("id", "foobarbaz");
|
responseObject.insert("id", "foobarbaz");
|
||||||
responseObject.insert("object", "text_completion");
|
responseObject.insert("object", "text_completion");
|
||||||
responseObject.insert("created", QDateTime::currentSecsSinceEpoch());
|
responseObject.insert("created", QDateTime::currentSecsSinceEpoch());
|
||||||
responseObject.insert("model", modelInfo.name);
|
responseObject.insert("model", modelInfo.name());
|
||||||
|
|
||||||
QJsonArray choices;
|
QJsonArray choices;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user