mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2024-10-01 01:06:10 -04:00
chat: generate follow-up questions after response (#2634)
* user can configure the prompt and when they appear * also make the name generation prompt configurable Signed-off-by: Adam Treat <treat.adam@gmail.com> Signed-off-by: Jared Van Bortel <jared@nomic.ai> Co-authored-by: Jared Van Bortel <jared@nomic.ai>
This commit is contained in:
parent
ef4e362d92
commit
66bc04aa8e
@ -210,11 +210,13 @@ qt_add_qml_module(chat
|
|||||||
icons/network.svg
|
icons/network.svg
|
||||||
icons/nomic_logo.svg
|
icons/nomic_logo.svg
|
||||||
icons/notes.svg
|
icons/notes.svg
|
||||||
|
icons/plus.svg
|
||||||
icons/recycle.svg
|
icons/recycle.svg
|
||||||
icons/regenerate.svg
|
icons/regenerate.svg
|
||||||
icons/search.svg
|
icons/search.svg
|
||||||
icons/send_message.svg
|
icons/send_message.svg
|
||||||
icons/settings.svg
|
icons/settings.svg
|
||||||
|
icons/stack.svg
|
||||||
icons/stop_generating.svg
|
icons/stop_generating.svg
|
||||||
icons/thumbs_down.svg
|
icons/thumbs_down.svg
|
||||||
icons/thumbs_up.svg
|
icons/thumbs_up.svg
|
||||||
|
@ -58,11 +58,13 @@ void Chat::connectLLM()
|
|||||||
connect(m_llmodel, &ChatLLM::modelLoadingPercentageChanged, this, &Chat::handleModelLoadingPercentageChanged, Qt::QueuedConnection);
|
connect(m_llmodel, &ChatLLM::modelLoadingPercentageChanged, this, &Chat::handleModelLoadingPercentageChanged, Qt::QueuedConnection);
|
||||||
connect(m_llmodel, &ChatLLM::responseChanged, this, &Chat::handleResponseChanged, Qt::QueuedConnection);
|
connect(m_llmodel, &ChatLLM::responseChanged, this, &Chat::handleResponseChanged, Qt::QueuedConnection);
|
||||||
connect(m_llmodel, &ChatLLM::promptProcessing, this, &Chat::promptProcessing, Qt::QueuedConnection);
|
connect(m_llmodel, &ChatLLM::promptProcessing, this, &Chat::promptProcessing, Qt::QueuedConnection);
|
||||||
|
connect(m_llmodel, &ChatLLM::generatingQuestions, this, &Chat::generatingQuestions, Qt::QueuedConnection);
|
||||||
connect(m_llmodel, &ChatLLM::responseStopped, this, &Chat::responseStopped, Qt::QueuedConnection);
|
connect(m_llmodel, &ChatLLM::responseStopped, this, &Chat::responseStopped, Qt::QueuedConnection);
|
||||||
connect(m_llmodel, &ChatLLM::modelLoadingError, this, &Chat::handleModelLoadingError, Qt::QueuedConnection);
|
connect(m_llmodel, &ChatLLM::modelLoadingError, this, &Chat::handleModelLoadingError, Qt::QueuedConnection);
|
||||||
connect(m_llmodel, &ChatLLM::modelLoadingWarning, this, &Chat::modelLoadingWarning, Qt::QueuedConnection);
|
connect(m_llmodel, &ChatLLM::modelLoadingWarning, this, &Chat::modelLoadingWarning, Qt::QueuedConnection);
|
||||||
connect(m_llmodel, &ChatLLM::recalcChanged, this, &Chat::handleRecalculating, Qt::QueuedConnection);
|
connect(m_llmodel, &ChatLLM::recalcChanged, this, &Chat::handleRecalculating, Qt::QueuedConnection);
|
||||||
connect(m_llmodel, &ChatLLM::generatedNameChanged, this, &Chat::generatedNameChanged, Qt::QueuedConnection);
|
connect(m_llmodel, &ChatLLM::generatedNameChanged, this, &Chat::generatedNameChanged, Qt::QueuedConnection);
|
||||||
|
connect(m_llmodel, &ChatLLM::generatedQuestionFinished, this, &Chat::generatedQuestionFinished, Qt::QueuedConnection);
|
||||||
connect(m_llmodel, &ChatLLM::reportSpeed, this, &Chat::handleTokenSpeedChanged, Qt::QueuedConnection);
|
connect(m_llmodel, &ChatLLM::reportSpeed, this, &Chat::handleTokenSpeedChanged, Qt::QueuedConnection);
|
||||||
connect(m_llmodel, &ChatLLM::loadedModelInfoChanged, this, &Chat::loadedModelInfoChanged, Qt::QueuedConnection);
|
connect(m_llmodel, &ChatLLM::loadedModelInfoChanged, this, &Chat::loadedModelInfoChanged, Qt::QueuedConnection);
|
||||||
connect(m_llmodel, &ChatLLM::databaseResultsChanged, this, &Chat::handleDatabaseResultsChanged, Qt::QueuedConnection);
|
connect(m_llmodel, &ChatLLM::databaseResultsChanged, this, &Chat::handleDatabaseResultsChanged, Qt::QueuedConnection);
|
||||||
@ -113,6 +115,8 @@ void Chat::resetResponseState()
|
|||||||
if (m_responseInProgress && m_responseState == Chat::LocalDocsRetrieval)
|
if (m_responseInProgress && m_responseState == Chat::LocalDocsRetrieval)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
m_generatedQuestions = QList<QString>();
|
||||||
|
emit generatedQuestionsChanged();
|
||||||
m_tokenSpeed = QString();
|
m_tokenSpeed = QString();
|
||||||
emit tokenSpeedChanged();
|
emit tokenSpeedChanged();
|
||||||
m_responseInProgress = true;
|
m_responseInProgress = true;
|
||||||
@ -189,6 +193,12 @@ void Chat::promptProcessing()
|
|||||||
emit responseStateChanged();
|
emit responseStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Chat::generatingQuestions()
|
||||||
|
{
|
||||||
|
m_responseState = Chat::GeneratingQuestions;
|
||||||
|
emit responseStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void Chat::responseStopped(qint64 promptResponseMs)
|
void Chat::responseStopped(qint64 promptResponseMs)
|
||||||
{
|
{
|
||||||
m_tokenSpeed = QString();
|
m_tokenSpeed = QString();
|
||||||
@ -304,6 +314,12 @@ void Chat::generatedNameChanged(const QString &name)
|
|||||||
emit nameChanged();
|
emit nameChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Chat::generatedQuestionFinished(const QString &question)
|
||||||
|
{
|
||||||
|
m_generatedQuestions << question;
|
||||||
|
emit generatedQuestionsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void Chat::handleRecalculating()
|
void Chat::handleRecalculating()
|
||||||
{
|
{
|
||||||
Network::globalInstance()->trackChatEvent("recalc_context", { {"length", m_chatModel->count()} });
|
Network::globalInstance()->trackChatEvent("recalc_context", { {"length", m_chatModel->count()} });
|
||||||
|
@ -39,6 +39,7 @@ class Chat : public QObject
|
|||||||
Q_PROPERTY(LocalDocsCollectionsModel *collectionModel READ collectionModel NOTIFY collectionModelChanged)
|
Q_PROPERTY(LocalDocsCollectionsModel *collectionModel READ collectionModel NOTIFY collectionModelChanged)
|
||||||
// 0=no, 1=waiting, 2=working
|
// 0=no, 1=waiting, 2=working
|
||||||
Q_PROPERTY(int trySwitchContextInProgress READ trySwitchContextInProgress NOTIFY trySwitchContextInProgressChanged)
|
Q_PROPERTY(int trySwitchContextInProgress READ trySwitchContextInProgress NOTIFY trySwitchContextInProgressChanged)
|
||||||
|
Q_PROPERTY(QList<QString> generatedQuestions READ generatedQuestions NOTIFY generatedQuestionsChanged)
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
QML_UNCREATABLE("Only creatable from c++!")
|
QML_UNCREATABLE("Only creatable from c++!")
|
||||||
|
|
||||||
@ -48,6 +49,7 @@ public:
|
|||||||
LocalDocsRetrieval,
|
LocalDocsRetrieval,
|
||||||
LocalDocsProcessing,
|
LocalDocsProcessing,
|
||||||
PromptProcessing,
|
PromptProcessing,
|
||||||
|
GeneratingQuestions,
|
||||||
ResponseGeneration
|
ResponseGeneration
|
||||||
};
|
};
|
||||||
Q_ENUM(ResponseState)
|
Q_ENUM(ResponseState)
|
||||||
@ -119,6 +121,8 @@ public:
|
|||||||
|
|
||||||
int trySwitchContextInProgress() const { return m_trySwitchContextInProgress; }
|
int trySwitchContextInProgress() const { return m_trySwitchContextInProgress; }
|
||||||
|
|
||||||
|
QList<QString> generatedQuestions() const { return m_generatedQuestions; }
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void serverNewPromptResponsePair(const QString &prompt);
|
void serverNewPromptResponsePair(const QString &prompt);
|
||||||
|
|
||||||
@ -153,13 +157,16 @@ Q_SIGNALS:
|
|||||||
void collectionModelChanged();
|
void collectionModelChanged();
|
||||||
void trySwitchContextInProgressChanged();
|
void trySwitchContextInProgressChanged();
|
||||||
void loadedModelInfoChanged();
|
void loadedModelInfoChanged();
|
||||||
|
void generatedQuestionsChanged();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void handleResponseChanged(const QString &response);
|
void handleResponseChanged(const QString &response);
|
||||||
void handleModelLoadingPercentageChanged(float);
|
void handleModelLoadingPercentageChanged(float);
|
||||||
void promptProcessing();
|
void promptProcessing();
|
||||||
|
void generatingQuestions();
|
||||||
void responseStopped(qint64 promptResponseMs);
|
void responseStopped(qint64 promptResponseMs);
|
||||||
void generatedNameChanged(const QString &name);
|
void generatedNameChanged(const QString &name);
|
||||||
|
void generatedQuestionFinished(const QString &question);
|
||||||
void handleRecalculating();
|
void handleRecalculating();
|
||||||
void handleModelLoadingError(const QString &error);
|
void handleModelLoadingError(const QString &error);
|
||||||
void handleTokenSpeedChanged(const QString &tokenSpeed);
|
void handleTokenSpeedChanged(const QString &tokenSpeed);
|
||||||
@ -179,6 +186,7 @@ private:
|
|||||||
QString m_fallbackReason;
|
QString m_fallbackReason;
|
||||||
QString m_response;
|
QString m_response;
|
||||||
QList<QString> m_collections;
|
QList<QString> m_collections;
|
||||||
|
QList<QString> m_generatedQuestions;
|
||||||
ChatModel *m_chatModel;
|
ChatModel *m_chatModel;
|
||||||
bool m_responseInProgress = false;
|
bool m_responseInProgress = false;
|
||||||
ResponseState m_responseState;
|
ResponseState m_responseState;
|
||||||
|
@ -750,7 +750,7 @@ bool ChatLLM::promptInternal(const QList<QString> &collectionList, const QString
|
|||||||
if (!databaseResults.isEmpty()) {
|
if (!databaseResults.isEmpty()) {
|
||||||
QStringList results;
|
QStringList results;
|
||||||
for (const ResultInfo &info : databaseResults)
|
for (const ResultInfo &info : databaseResults)
|
||||||
results << u"Collection: %1\nPath: %2\nSnippet: %3"_s.arg(info.collection, info.path, info.text);
|
results << u"Collection: %1\nPath: %2\nExcerpt: %3"_s.arg(info.collection, info.path, info.text);
|
||||||
|
|
||||||
// FIXME(jared): use a Jinja prompt template instead of hardcoded Alpaca-style localdocs template
|
// FIXME(jared): use a Jinja prompt template instead of hardcoded Alpaca-style localdocs template
|
||||||
docsContext = u"### Context:\n%1\n\n"_s.arg(results.join("\n\n"));
|
docsContext = u"### Context:\n%1\n\n"_s.arg(results.join("\n\n"));
|
||||||
@ -797,7 +797,13 @@ bool ChatLLM::promptInternal(const QList<QString> &collectionList, const QString
|
|||||||
m_response = trimmed;
|
m_response = trimmed;
|
||||||
emit responseChanged(QString::fromStdString(m_response));
|
emit responseChanged(QString::fromStdString(m_response));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SuggestionMode mode = MySettings::globalInstance()->suggestionMode();
|
||||||
|
if (mode == SuggestionMode::On || (!databaseResults.isEmpty() && mode == SuggestionMode::LocalDocsOnly))
|
||||||
|
generateQuestions(elapsed);
|
||||||
|
else
|
||||||
emit responseStopped(elapsed);
|
emit responseStopped(elapsed);
|
||||||
|
|
||||||
m_pristineLoadedState = false;
|
m_pristineLoadedState = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -875,13 +881,19 @@ void ChatLLM::generateName()
|
|||||||
if (!isModelLoaded())
|
if (!isModelLoaded())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const QString chatNamePrompt = MySettings::globalInstance()->modelChatNamePrompt(m_modelInfo);
|
||||||
|
if (chatNamePrompt.trimmed().isEmpty()) {
|
||||||
|
qWarning() << "ChatLLM: not generating chat name because prompt is empty";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto promptTemplate = MySettings::globalInstance()->modelPromptTemplate(m_modelInfo);
|
auto promptTemplate = MySettings::globalInstance()->modelPromptTemplate(m_modelInfo);
|
||||||
auto promptFunc = std::bind(&ChatLLM::handleNamePrompt, this, std::placeholders::_1);
|
auto promptFunc = std::bind(&ChatLLM::handleNamePrompt, this, std::placeholders::_1);
|
||||||
auto responseFunc = std::bind(&ChatLLM::handleNameResponse, this, std::placeholders::_1, std::placeholders::_2);
|
auto responseFunc = std::bind(&ChatLLM::handleNameResponse, this, std::placeholders::_1, std::placeholders::_2);
|
||||||
auto recalcFunc = std::bind(&ChatLLM::handleNameRecalculate, this, std::placeholders::_1);
|
auto recalcFunc = std::bind(&ChatLLM::handleNameRecalculate, this, std::placeholders::_1);
|
||||||
LLModel::PromptContext ctx = m_ctx;
|
LLModel::PromptContext ctx = m_ctx;
|
||||||
m_llModelInfo.model->prompt("Describe the above conversation in seven words or less.",
|
m_llModelInfo.model->prompt(chatNamePrompt.toStdString(), promptTemplate.toStdString(),
|
||||||
promptTemplate.toStdString(), promptFunc, responseFunc, recalcFunc, ctx);
|
promptFunc, responseFunc, recalcFunc, ctx);
|
||||||
std::string trimmed = trim_whitespace(m_nameResponse);
|
std::string trimmed = trim_whitespace(m_nameResponse);
|
||||||
if (trimmed != m_nameResponse) {
|
if (trimmed != m_nameResponse) {
|
||||||
m_nameResponse = trimmed;
|
m_nameResponse = trimmed;
|
||||||
@ -901,7 +913,6 @@ bool ChatLLM::handleNamePrompt(int32_t token)
|
|||||||
qDebug() << "name prompt" << m_llmThread.objectName() << token;
|
qDebug() << "name prompt" << m_llmThread.objectName() << token;
|
||||||
#endif
|
#endif
|
||||||
Q_UNUSED(token);
|
Q_UNUSED(token);
|
||||||
qt_noop();
|
|
||||||
return !m_stopGenerating;
|
return !m_stopGenerating;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -925,10 +936,84 @@ bool ChatLLM::handleNameRecalculate(bool isRecalc)
|
|||||||
qDebug() << "name recalc" << m_llmThread.objectName() << isRecalc;
|
qDebug() << "name recalc" << m_llmThread.objectName() << isRecalc;
|
||||||
#endif
|
#endif
|
||||||
Q_UNUSED(isRecalc);
|
Q_UNUSED(isRecalc);
|
||||||
qt_noop();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ChatLLM::handleQuestionPrompt(int32_t token)
|
||||||
|
{
|
||||||
|
#if defined(DEBUG)
|
||||||
|
qDebug() << "question prompt" << m_llmThread.objectName() << token;
|
||||||
|
#endif
|
||||||
|
Q_UNUSED(token);
|
||||||
|
return !m_stopGenerating;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChatLLM::handleQuestionResponse(int32_t token, const std::string &response)
|
||||||
|
{
|
||||||
|
#if defined(DEBUG)
|
||||||
|
qDebug() << "question response" << m_llmThread.objectName() << token << response;
|
||||||
|
#endif
|
||||||
|
Q_UNUSED(token);
|
||||||
|
|
||||||
|
// add token to buffer
|
||||||
|
m_questionResponse.append(response);
|
||||||
|
|
||||||
|
// match whole question sentences
|
||||||
|
static const QRegularExpression reQuestion(R"(\b(What|Where|How|Why|When|Who|Which|Whose|Whom)\b[^?]*\?)");
|
||||||
|
|
||||||
|
// extract all questions from response
|
||||||
|
int lastMatchEnd = -1;
|
||||||
|
for (const auto &match : reQuestion.globalMatch(m_questionResponse)) {
|
||||||
|
lastMatchEnd = match.capturedEnd();
|
||||||
|
emit generatedQuestionFinished(match.captured());
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove processed input from buffer
|
||||||
|
if (lastMatchEnd != -1)
|
||||||
|
m_questionResponse.erase(m_questionResponse.cbegin(), m_questionResponse.cbegin() + lastMatchEnd);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChatLLM::handleQuestionRecalculate(bool isRecalc)
|
||||||
|
{
|
||||||
|
#if defined(DEBUG)
|
||||||
|
qDebug() << "name recalc" << m_llmThread.objectName() << isRecalc;
|
||||||
|
#endif
|
||||||
|
Q_UNUSED(isRecalc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatLLM::generateQuestions(qint64 elapsed)
|
||||||
|
{
|
||||||
|
Q_ASSERT(isModelLoaded());
|
||||||
|
if (!isModelLoaded()) {
|
||||||
|
emit responseStopped(elapsed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string suggestedFollowUpPrompt = MySettings::globalInstance()->modelSuggestedFollowUpPrompt(m_modelInfo).toStdString();
|
||||||
|
if (QString::fromStdString(suggestedFollowUpPrompt).trimmed().isEmpty()) {
|
||||||
|
emit responseStopped(elapsed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit generatingQuestions();
|
||||||
|
m_questionResponse.clear();
|
||||||
|
auto promptTemplate = MySettings::globalInstance()->modelPromptTemplate(m_modelInfo);
|
||||||
|
auto promptFunc = std::bind(&ChatLLM::handleQuestionPrompt, this, std::placeholders::_1);
|
||||||
|
auto responseFunc = std::bind(&ChatLLM::handleQuestionResponse, this, std::placeholders::_1, std::placeholders::_2);
|
||||||
|
auto recalcFunc = std::bind(&ChatLLM::handleQuestionRecalculate, this, std::placeholders::_1);
|
||||||
|
LLModel::PromptContext ctx = m_ctx;
|
||||||
|
QElapsedTimer totalTime;
|
||||||
|
totalTime.start();
|
||||||
|
m_llModelInfo.model->prompt(suggestedFollowUpPrompt,
|
||||||
|
promptTemplate.toStdString(), promptFunc, responseFunc, recalcFunc, ctx);
|
||||||
|
elapsed += totalTime.elapsed();
|
||||||
|
emit responseStopped(elapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ChatLLM::handleSystemPrompt(int32_t token)
|
bool ChatLLM::handleSystemPrompt(int32_t token)
|
||||||
{
|
{
|
||||||
#if defined(DEBUG)
|
#if defined(DEBUG)
|
||||||
|
@ -160,6 +160,7 @@ public Q_SLOTS:
|
|||||||
void unloadModel();
|
void unloadModel();
|
||||||
void reloadModel();
|
void reloadModel();
|
||||||
void generateName();
|
void generateName();
|
||||||
|
void generateQuestions(qint64 elapsed);
|
||||||
void handleChatIdChanged(const QString &id);
|
void handleChatIdChanged(const QString &id);
|
||||||
void handleShouldBeLoadedChanged();
|
void handleShouldBeLoadedChanged();
|
||||||
void handleThreadStarted();
|
void handleThreadStarted();
|
||||||
@ -176,8 +177,10 @@ Q_SIGNALS:
|
|||||||
void modelLoadingWarning(const QString &warning);
|
void modelLoadingWarning(const QString &warning);
|
||||||
void responseChanged(const QString &response);
|
void responseChanged(const QString &response);
|
||||||
void promptProcessing();
|
void promptProcessing();
|
||||||
|
void generatingQuestions();
|
||||||
void responseStopped(qint64 promptResponseMs);
|
void responseStopped(qint64 promptResponseMs);
|
||||||
void generatedNameChanged(const QString &name);
|
void generatedNameChanged(const QString &name);
|
||||||
|
void generatedQuestionFinished(const QString &generatedQuestion);
|
||||||
void stateChanged();
|
void stateChanged();
|
||||||
void threadStarted();
|
void threadStarted();
|
||||||
void shouldBeLoadedChanged();
|
void shouldBeLoadedChanged();
|
||||||
@ -206,6 +209,9 @@ protected:
|
|||||||
bool handleRestoreStateFromTextPrompt(int32_t token);
|
bool handleRestoreStateFromTextPrompt(int32_t token);
|
||||||
bool handleRestoreStateFromTextResponse(int32_t token, const std::string &response);
|
bool handleRestoreStateFromTextResponse(int32_t token, const std::string &response);
|
||||||
bool handleRestoreStateFromTextRecalculate(bool isRecalc);
|
bool handleRestoreStateFromTextRecalculate(bool isRecalc);
|
||||||
|
bool handleQuestionPrompt(int32_t token);
|
||||||
|
bool handleQuestionResponse(int32_t token, const std::string &response);
|
||||||
|
bool handleQuestionRecalculate(bool isRecalc);
|
||||||
void saveState();
|
void saveState();
|
||||||
void restoreState();
|
void restoreState();
|
||||||
|
|
||||||
@ -219,6 +225,7 @@ private:
|
|||||||
|
|
||||||
std::string m_response;
|
std::string m_response;
|
||||||
std::string m_nameResponse;
|
std::string m_nameResponse;
|
||||||
|
QString m_questionResponse;
|
||||||
LLModelInfo m_llModelInfo;
|
LLModelInfo m_llModelInfo;
|
||||||
LLModelType m_llModelType;
|
LLModelType m_llModelType;
|
||||||
ModelInfo m_modelInfo;
|
ModelInfo m_modelInfo;
|
||||||
|
1
gpt4all-chat/icons/plus.svg
Normal file
1
gpt4all-chat/icons/plus.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M224,128a8,8,0,0,1-8,8H136v80a8,8,0,0,1-16,0V136H40a8,8,0,0,1,0-16h80V40a8,8,0,0,1,16,0v80h80A8,8,0,0,1,224,128Z"></path></svg>
|
After Width: | Height: | Size: 236 B |
1
gpt4all-chat/icons/stack.svg
Normal file
1
gpt4all-chat/icons/stack.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M230.91,124A8,8,0,0,1,228,134.91l-96,56a8,8,0,0,1-8.06,0l-96-56A8,8,0,0,1,36,121.09l92,53.65,92-53.65A8,8,0,0,1,230.91,124ZM24,80a8,8,0,0,1,4-6.91l96-56a8,8,0,0,1,8.06,0l96,56a8,8,0,0,1,0,13.82l-96,56a8,8,0,0,1-8.06,0l-96-56A8,8,0,0,1,24,80Zm23.88,0L128,126.74,208.12,80,128,33.26ZM232,192H216V176a8,8,0,0,0-16,0v16H184a8,8,0,0,0,0,16h16v16a8,8,0,0,0,16,0V208h16a8,8,0,0,0,0-16Zm-92,23.76-12,7L36,169.09A8,8,0,0,0,28,182.91l96,56a8,8,0,0,0,8.06,0l16-9.33A8,8,0,1,0,140,215.76Z"></path></svg>
|
After Width: | Height: | Size: 600 B |
@ -334,6 +334,28 @@ void ModelInfo::setSystemPrompt(const QString &p)
|
|||||||
m_systemPrompt = p;
|
m_systemPrompt = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ModelInfo::chatNamePrompt() const
|
||||||
|
{
|
||||||
|
return MySettings::globalInstance()->modelChatNamePrompt(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setChatNamePrompt(const QString &p)
|
||||||
|
{
|
||||||
|
if (shouldSaveMetadata()) MySettings::globalInstance()->setModelChatNamePrompt(*this, p, true /*force*/);
|
||||||
|
m_chatNamePrompt = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ModelInfo::suggestedFollowUpPrompt() const
|
||||||
|
{
|
||||||
|
return MySettings::globalInstance()->modelSuggestedFollowUpPrompt(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInfo::setSuggestedFollowUpPrompt(const QString &p)
|
||||||
|
{
|
||||||
|
if (shouldSaveMetadata()) MySettings::globalInstance()->setModelSuggestedFollowUpPrompt(*this, p, true /*force*/);
|
||||||
|
m_suggestedFollowUpPrompt = p;
|
||||||
|
}
|
||||||
|
|
||||||
bool ModelInfo::shouldSaveMetadata() const
|
bool ModelInfo::shouldSaveMetadata() const
|
||||||
{
|
{
|
||||||
return installed && (isClone() || isDiscovered() || description() == "" /*indicates sideloaded*/);
|
return installed && (isClone() || isDiscovered() || description() == "" /*indicates sideloaded*/);
|
||||||
@ -364,6 +386,8 @@ QVariantMap ModelInfo::getFields() const
|
|||||||
{ "repeatPenaltyTokens", m_repeatPenaltyTokens },
|
{ "repeatPenaltyTokens", m_repeatPenaltyTokens },
|
||||||
{ "promptTemplate", m_promptTemplate },
|
{ "promptTemplate", m_promptTemplate },
|
||||||
{ "systemPrompt", m_systemPrompt },
|
{ "systemPrompt", m_systemPrompt },
|
||||||
|
{ "chatNamePrompt", m_chatNamePrompt },
|
||||||
|
{ "suggestedFollowUpPrompt", m_suggestedFollowUpPrompt },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -758,6 +782,10 @@ QVariant ModelList::dataInternal(const ModelInfo *info, int role) const
|
|||||||
return info->promptTemplate();
|
return info->promptTemplate();
|
||||||
case SystemPromptRole:
|
case SystemPromptRole:
|
||||||
return info->systemPrompt();
|
return info->systemPrompt();
|
||||||
|
case ChatNamePromptRole:
|
||||||
|
return info->chatNamePrompt();
|
||||||
|
case SuggestedFollowUpPromptRole:
|
||||||
|
return info->suggestedFollowUpPrompt();
|
||||||
case LikesRole:
|
case LikesRole:
|
||||||
return info->likes();
|
return info->likes();
|
||||||
case DownloadsRole:
|
case DownloadsRole:
|
||||||
@ -928,6 +956,10 @@ void ModelList::updateData(const QString &id, const QVector<QPair<int, QVariant>
|
|||||||
info->setPromptTemplate(value.toString()); break;
|
info->setPromptTemplate(value.toString()); break;
|
||||||
case SystemPromptRole:
|
case SystemPromptRole:
|
||||||
info->setSystemPrompt(value.toString()); break;
|
info->setSystemPrompt(value.toString()); break;
|
||||||
|
case ChatNamePromptRole:
|
||||||
|
info->setChatNamePrompt(value.toString()); break;
|
||||||
|
case SuggestedFollowUpPromptRole:
|
||||||
|
info->setSuggestedFollowUpPrompt(value.toString()); break;
|
||||||
case LikesRole:
|
case LikesRole:
|
||||||
{
|
{
|
||||||
if (info->likes() != value.toInt()) {
|
if (info->likes() != value.toInt()) {
|
||||||
@ -1077,6 +1109,8 @@ QString ModelList::clone(const ModelInfo &model)
|
|||||||
{ ModelList::RepeatPenaltyTokensRole, model.repeatPenaltyTokens() },
|
{ ModelList::RepeatPenaltyTokensRole, model.repeatPenaltyTokens() },
|
||||||
{ ModelList::PromptTemplateRole, model.promptTemplate() },
|
{ ModelList::PromptTemplateRole, model.promptTemplate() },
|
||||||
{ ModelList::SystemPromptRole, model.systemPrompt() },
|
{ ModelList::SystemPromptRole, model.systemPrompt() },
|
||||||
|
{ ModelList::ChatNamePromptRole, model.chatNamePrompt() },
|
||||||
|
{ ModelList::SuggestedFollowUpPromptRole, model.suggestedFollowUpPrompt() },
|
||||||
};
|
};
|
||||||
updateData(id, data);
|
updateData(id, data);
|
||||||
return id;
|
return id;
|
||||||
@ -1772,6 +1806,14 @@ void ModelList::updateModelsFromSettings()
|
|||||||
const QString systemPrompt = settings.value(g + "/systemPrompt").toString();
|
const QString systemPrompt = settings.value(g + "/systemPrompt").toString();
|
||||||
data.append({ ModelList::SystemPromptRole, systemPrompt });
|
data.append({ ModelList::SystemPromptRole, systemPrompt });
|
||||||
}
|
}
|
||||||
|
if (settings.contains(g + "/chatNamePrompt")) {
|
||||||
|
const QString chatNamePrompt = settings.value(g + "/chatNamePrompt").toString();
|
||||||
|
data.append({ ModelList::ChatNamePromptRole, chatNamePrompt });
|
||||||
|
}
|
||||||
|
if (settings.contains(g + "/suggestedFollowUpPrompt")) {
|
||||||
|
const QString suggestedFollowUpPrompt = settings.value(g + "/suggestedFollowUpPrompt").toString();
|
||||||
|
data.append({ ModelList::SuggestedFollowUpPromptRole, suggestedFollowUpPrompt });
|
||||||
|
}
|
||||||
updateData(id, data);
|
updateData(id, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,8 @@ struct ModelInfo {
|
|||||||
Q_PROPERTY(int repeatPenaltyTokens READ repeatPenaltyTokens WRITE setRepeatPenaltyTokens)
|
Q_PROPERTY(int repeatPenaltyTokens READ repeatPenaltyTokens WRITE setRepeatPenaltyTokens)
|
||||||
Q_PROPERTY(QString promptTemplate READ promptTemplate WRITE setPromptTemplate)
|
Q_PROPERTY(QString promptTemplate READ promptTemplate WRITE setPromptTemplate)
|
||||||
Q_PROPERTY(QString systemPrompt READ systemPrompt WRITE setSystemPrompt)
|
Q_PROPERTY(QString systemPrompt READ systemPrompt WRITE setSystemPrompt)
|
||||||
|
Q_PROPERTY(QString chatNamePrompt READ chatNamePrompt WRITE setChatNamePrompt)
|
||||||
|
Q_PROPERTY(QString suggestedFollowUpPrompt READ suggestedFollowUpPrompt WRITE setSuggestedFollowUpPrompt)
|
||||||
Q_PROPERTY(int likes READ likes WRITE setLikes)
|
Q_PROPERTY(int likes READ likes WRITE setLikes)
|
||||||
Q_PROPERTY(int downloads READ downloads WRITE setDownloads)
|
Q_PROPERTY(int downloads READ downloads WRITE setDownloads)
|
||||||
Q_PROPERTY(QDateTime recency READ recency WRITE setRecency)
|
Q_PROPERTY(QDateTime recency READ recency WRITE setRecency)
|
||||||
@ -167,6 +169,10 @@ public:
|
|||||||
void setPromptTemplate(const QString &t);
|
void setPromptTemplate(const QString &t);
|
||||||
QString systemPrompt() const;
|
QString systemPrompt() const;
|
||||||
void setSystemPrompt(const QString &p);
|
void setSystemPrompt(const QString &p);
|
||||||
|
QString chatNamePrompt() const;
|
||||||
|
void setChatNamePrompt(const QString &p);
|
||||||
|
QString suggestedFollowUpPrompt() const;
|
||||||
|
void setSuggestedFollowUpPrompt(const QString &p);
|
||||||
|
|
||||||
bool shouldSaveMetadata() const;
|
bool shouldSaveMetadata() const;
|
||||||
|
|
||||||
@ -199,6 +205,8 @@ private:
|
|||||||
int m_repeatPenaltyTokens = 64;
|
int m_repeatPenaltyTokens = 64;
|
||||||
QString m_promptTemplate = "### Human:\n%1\n\n### Assistant:\n";
|
QString m_promptTemplate = "### Human:\n%1\n\n### Assistant:\n";
|
||||||
QString m_systemPrompt = "### System:\nYou are an AI assistant who gives a quality response to whatever humans ask of you.\n\n";
|
QString m_systemPrompt = "### System:\nYou are an AI assistant who gives a quality response to whatever humans ask of you.\n\n";
|
||||||
|
QString m_chatNamePrompt = "Describe the above conversation in seven words or less.";
|
||||||
|
QString m_suggestedFollowUpPrompt = "Suggest three very short factual follow-up questions that have not been answered yet or cannot be found inspired by the previous conversation and excerpts.";
|
||||||
friend class MySettings;
|
friend class MySettings;
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(ModelInfo)
|
Q_DECLARE_METATYPE(ModelInfo)
|
||||||
@ -317,6 +325,8 @@ public:
|
|||||||
RepeatPenaltyTokensRole,
|
RepeatPenaltyTokensRole,
|
||||||
PromptTemplateRole,
|
PromptTemplateRole,
|
||||||
SystemPromptRole,
|
SystemPromptRole,
|
||||||
|
ChatNamePromptRole,
|
||||||
|
SuggestedFollowUpPromptRole,
|
||||||
MinPRole,
|
MinPRole,
|
||||||
LikesRole,
|
LikesRole,
|
||||||
DownloadsRole,
|
DownloadsRole,
|
||||||
@ -368,6 +378,8 @@ public:
|
|||||||
roles[RepeatPenaltyTokensRole] = "repeatPenaltyTokens";
|
roles[RepeatPenaltyTokensRole] = "repeatPenaltyTokens";
|
||||||
roles[PromptTemplateRole] = "promptTemplate";
|
roles[PromptTemplateRole] = "promptTemplate";
|
||||||
roles[SystemPromptRole] = "systemPrompt";
|
roles[SystemPromptRole] = "systemPrompt";
|
||||||
|
roles[ChatNamePromptRole] = "chatNamePrompt";
|
||||||
|
roles[SuggestedFollowUpPromptRole] = "suggestedFollowUpPrompt";
|
||||||
roles[LikesRole] = "likes";
|
roles[LikesRole] = "likes";
|
||||||
roles[DownloadsRole] = "downloads";
|
roles[DownloadsRole] = "downloads";
|
||||||
roles[RecencyRole] = "recency";
|
roles[RecencyRole] = "recency";
|
||||||
|
@ -41,6 +41,7 @@ static const QVariantMap basicDefaults {
|
|||||||
{ "saveChatsContext", false },
|
{ "saveChatsContext", false },
|
||||||
{ "serverChat", false },
|
{ "serverChat", false },
|
||||||
{ "userDefaultModel", "Application default" },
|
{ "userDefaultModel", "Application default" },
|
||||||
|
{ "suggestionMode", QVariant::fromValue(SuggestionMode::LocalDocsOnly) },
|
||||||
{ "localdocs/chunkSize", 512 },
|
{ "localdocs/chunkSize", 512 },
|
||||||
{ "localdocs/retrievalSize", 3 },
|
{ "localdocs/retrievalSize", 3 },
|
||||||
{ "localdocs/showReferences", true },
|
{ "localdocs/showReferences", true },
|
||||||
@ -136,6 +137,8 @@ void MySettings::restoreModelDefaults(const ModelInfo &info)
|
|||||||
setModelRepeatPenaltyTokens(info, info.m_repeatPenaltyTokens);
|
setModelRepeatPenaltyTokens(info, info.m_repeatPenaltyTokens);
|
||||||
setModelPromptTemplate(info, info.m_promptTemplate);
|
setModelPromptTemplate(info, info.m_promptTemplate);
|
||||||
setModelSystemPrompt(info, info.m_systemPrompt);
|
setModelSystemPrompt(info, info.m_systemPrompt);
|
||||||
|
setModelChatNamePrompt(info, info.m_chatNamePrompt);
|
||||||
|
setModelSuggestedFollowUpPrompt(info, info.m_suggestedFollowUpPrompt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySettings::restoreApplicationDefaults()
|
void MySettings::restoreApplicationDefaults()
|
||||||
@ -150,6 +153,7 @@ void MySettings::restoreApplicationDefaults()
|
|||||||
setModelPath(defaultLocalModelsPath());
|
setModelPath(defaultLocalModelsPath());
|
||||||
setUserDefaultModel(basicDefaults.value("userDefaultModel").toString());
|
setUserDefaultModel(basicDefaults.value("userDefaultModel").toString());
|
||||||
setForceMetal(defaults::forceMetal);
|
setForceMetal(defaults::forceMetal);
|
||||||
|
setSuggestionMode(basicDefaults.value("suggestionMode").value<SuggestionMode>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySettings::restoreLocalDocsDefaults()
|
void MySettings::restoreLocalDocsDefaults()
|
||||||
@ -231,9 +235,11 @@ int MySettings::modelPromptBatchSize (const ModelInfo &info) const { re
|
|||||||
int MySettings::modelContextLength (const ModelInfo &info) const { return getModelSetting("contextLength", info).toInt(); }
|
int MySettings::modelContextLength (const ModelInfo &info) const { return getModelSetting("contextLength", info).toInt(); }
|
||||||
int MySettings::modelGpuLayers (const ModelInfo &info) const { return getModelSetting("gpuLayers", info).toInt(); }
|
int MySettings::modelGpuLayers (const ModelInfo &info) const { return getModelSetting("gpuLayers", info).toInt(); }
|
||||||
double MySettings::modelRepeatPenalty (const ModelInfo &info) const { return getModelSetting("repeatPenalty", info).toDouble(); }
|
double MySettings::modelRepeatPenalty (const ModelInfo &info) const { return getModelSetting("repeatPenalty", info).toDouble(); }
|
||||||
int MySettings::modelRepeatPenaltyTokens(const ModelInfo &info) const { return getModelSetting("repeatPenaltyTokens", info).toInt(); }
|
int MySettings::modelRepeatPenaltyTokens (const ModelInfo &info) const { return getModelSetting("repeatPenaltyTokens", info).toInt(); }
|
||||||
QString MySettings::modelPromptTemplate (const ModelInfo &info) const { return getModelSetting("promptTemplate", info).toString(); }
|
QString MySettings::modelPromptTemplate (const ModelInfo &info) const { return getModelSetting("promptTemplate", info).toString(); }
|
||||||
QString MySettings::modelSystemPrompt (const ModelInfo &info) const { return getModelSetting("systemPrompt", info).toString(); }
|
QString MySettings::modelSystemPrompt (const ModelInfo &info) const { return getModelSetting("systemPrompt", info).toString(); }
|
||||||
|
QString MySettings::modelChatNamePrompt (const ModelInfo &info) const { return getModelSetting("chatNamePrompt", info).toString(); }
|
||||||
|
QString MySettings::modelSuggestedFollowUpPrompt(const ModelInfo &info) const { return getModelSetting("suggestedFollowUpPrompt", info).toString(); }
|
||||||
|
|
||||||
void MySettings::setModelFilename(const ModelInfo &info, const QString &value, bool force)
|
void MySettings::setModelFilename(const ModelInfo &info, const QString &value, bool force)
|
||||||
{
|
{
|
||||||
@ -345,6 +351,16 @@ void MySettings::setModelSystemPrompt(const ModelInfo &info, const QString &valu
|
|||||||
setModelSetting("systemPrompt", info, value, force, true);
|
setModelSetting("systemPrompt", info, value, force, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MySettings::setModelChatNamePrompt(const ModelInfo &info, const QString &value, bool force)
|
||||||
|
{
|
||||||
|
setModelSetting("chatNamePrompt", info, value, force, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySettings::setModelSuggestedFollowUpPrompt(const ModelInfo &info, const QString &value, bool force)
|
||||||
|
{
|
||||||
|
setModelSetting("suggestedFollowUpPrompt", info, value, force, true);
|
||||||
|
}
|
||||||
|
|
||||||
int MySettings::threadCount() const
|
int MySettings::threadCount() const
|
||||||
{
|
{
|
||||||
int c = m_settings.value("threadCount", defaults::threadCount).toInt();
|
int c = m_settings.value("threadCount", defaults::threadCount).toInt();
|
||||||
@ -383,6 +399,7 @@ bool MySettings::localDocsUseRemoteEmbed() const { return getBasicSetting
|
|||||||
QString MySettings::localDocsNomicAPIKey() const { return getBasicSetting("localdocs/nomicAPIKey" ).toString(); }
|
QString MySettings::localDocsNomicAPIKey() const { return getBasicSetting("localdocs/nomicAPIKey" ).toString(); }
|
||||||
QString MySettings::localDocsEmbedDevice() const { return getBasicSetting("localdocs/embedDevice" ).toString(); }
|
QString MySettings::localDocsEmbedDevice() const { return getBasicSetting("localdocs/embedDevice" ).toString(); }
|
||||||
QString MySettings::networkAttribution() const { return getBasicSetting("network/attribution" ).toString(); }
|
QString MySettings::networkAttribution() const { return getBasicSetting("network/attribution" ).toString(); }
|
||||||
|
SuggestionMode MySettings::suggestionMode() const { return getBasicSetting("suggestionMode").value<SuggestionMode>(); };
|
||||||
|
|
||||||
void MySettings::setSaveChatsContext(bool value) { setBasicSetting("saveChatsContext", value); }
|
void MySettings::setSaveChatsContext(bool value) { setBasicSetting("saveChatsContext", value); }
|
||||||
void MySettings::setServerChat(bool value) { setBasicSetting("serverChat", value); }
|
void MySettings::setServerChat(bool value) { setBasicSetting("serverChat", value); }
|
||||||
@ -399,6 +416,7 @@ void MySettings::setLocalDocsUseRemoteEmbed(bool value) { setBasic
|
|||||||
void MySettings::setLocalDocsNomicAPIKey(const QString &value) { setBasicSetting("localdocs/nomicAPIKey", value, "localDocsNomicAPIKey"); }
|
void MySettings::setLocalDocsNomicAPIKey(const QString &value) { setBasicSetting("localdocs/nomicAPIKey", value, "localDocsNomicAPIKey"); }
|
||||||
void MySettings::setLocalDocsEmbedDevice(const QString &value) { setBasicSetting("localdocs/embedDevice", value, "localDocsEmbedDevice"); }
|
void MySettings::setLocalDocsEmbedDevice(const QString &value) { setBasicSetting("localdocs/embedDevice", value, "localDocsEmbedDevice"); }
|
||||||
void MySettings::setNetworkAttribution(const QString &value) { setBasicSetting("network/attribution", value, "networkAttribution"); }
|
void MySettings::setNetworkAttribution(const QString &value) { setBasicSetting("network/attribution", value, "networkAttribution"); }
|
||||||
|
void MySettings::setSuggestionMode(SuggestionMode value) { setBasicSetting("suggestionMode", int(value)); }
|
||||||
|
|
||||||
QString MySettings::modelPath()
|
QString MySettings::modelPath()
|
||||||
{
|
{
|
||||||
|
@ -13,6 +13,18 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
namespace MySettingsEnums {
|
||||||
|
Q_NAMESPACE
|
||||||
|
|
||||||
|
enum class SuggestionMode {
|
||||||
|
LocalDocsOnly = 0,
|
||||||
|
On = 1,
|
||||||
|
Off = 2,
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(SuggestionMode)
|
||||||
|
}
|
||||||
|
using namespace MySettingsEnums;
|
||||||
|
|
||||||
class MySettings : public QObject
|
class MySettings : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -39,6 +51,7 @@ class MySettings : public QObject
|
|||||||
Q_PROPERTY(QStringList deviceList MEMBER m_deviceList CONSTANT)
|
Q_PROPERTY(QStringList deviceList MEMBER m_deviceList CONSTANT)
|
||||||
Q_PROPERTY(QStringList embeddingsDeviceList MEMBER m_embeddingsDeviceList CONSTANT)
|
Q_PROPERTY(QStringList embeddingsDeviceList MEMBER m_embeddingsDeviceList CONSTANT)
|
||||||
Q_PROPERTY(int networkPort READ networkPort WRITE setNetworkPort NOTIFY networkPortChanged)
|
Q_PROPERTY(int networkPort READ networkPort WRITE setNetworkPort NOTIFY networkPortChanged)
|
||||||
|
Q_PROPERTY(SuggestionMode suggestionMode READ suggestionMode WRITE setSuggestionMode NOTIFY suggestionModeChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static MySettings *globalInstance();
|
static MySettings *globalInstance();
|
||||||
@ -98,6 +111,10 @@ public:
|
|||||||
Q_INVOKABLE void setModelContextLength(const ModelInfo &info, int value, bool force = false);
|
Q_INVOKABLE void setModelContextLength(const ModelInfo &info, int value, bool force = false);
|
||||||
int modelGpuLayers(const ModelInfo &info) const;
|
int modelGpuLayers(const ModelInfo &info) const;
|
||||||
Q_INVOKABLE void setModelGpuLayers(const ModelInfo &info, int value, bool force = false);
|
Q_INVOKABLE void setModelGpuLayers(const ModelInfo &info, int value, bool force = false);
|
||||||
|
QString modelChatNamePrompt(const ModelInfo &info) const;
|
||||||
|
Q_INVOKABLE void setModelChatNamePrompt(const ModelInfo &info, const QString &value, bool force = false);
|
||||||
|
QString modelSuggestedFollowUpPrompt(const ModelInfo &info) const;
|
||||||
|
Q_INVOKABLE void setModelSuggestedFollowUpPrompt(const ModelInfo &info, const QString &value, bool force = false);
|
||||||
|
|
||||||
// Application settings
|
// Application settings
|
||||||
int threadCount() const;
|
int threadCount() const;
|
||||||
@ -122,6 +139,8 @@ public:
|
|||||||
void setContextLength(int32_t value);
|
void setContextLength(int32_t value);
|
||||||
int32_t gpuLayers() const;
|
int32_t gpuLayers() const;
|
||||||
void setGpuLayers(int32_t value);
|
void setGpuLayers(int32_t value);
|
||||||
|
SuggestionMode suggestionMode() const;
|
||||||
|
void setSuggestionMode(SuggestionMode mode);
|
||||||
|
|
||||||
// Release/Download settings
|
// Release/Download settings
|
||||||
QString lastVersionStarted() const;
|
QString lastVersionStarted() const;
|
||||||
@ -171,6 +190,8 @@ Q_SIGNALS:
|
|||||||
void repeatPenaltyTokensChanged(const ModelInfo &info);
|
void repeatPenaltyTokensChanged(const ModelInfo &info);
|
||||||
void promptTemplateChanged(const ModelInfo &info);
|
void promptTemplateChanged(const ModelInfo &info);
|
||||||
void systemPromptChanged(const ModelInfo &info);
|
void systemPromptChanged(const ModelInfo &info);
|
||||||
|
void chatNamePromptChanged(const ModelInfo &info);
|
||||||
|
void suggestedFollowUpPromptChanged(const ModelInfo &info);
|
||||||
void threadCountChanged();
|
void threadCountChanged();
|
||||||
void saveChatsContextChanged();
|
void saveChatsContextChanged();
|
||||||
void serverChatChanged();
|
void serverChatChanged();
|
||||||
@ -193,6 +214,7 @@ Q_SIGNALS:
|
|||||||
void networkUsageStatsActiveChanged();
|
void networkUsageStatsActiveChanged();
|
||||||
void attemptModelLoadChanged();
|
void attemptModelLoadChanged();
|
||||||
void deviceChanged();
|
void deviceChanged();
|
||||||
|
void suggestionModeChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSettings m_settings;
|
QSettings m_settings;
|
||||||
|
@ -227,16 +227,40 @@ MySettingsTab {
|
|||||||
MySettings.userDefaultModel = comboBox.currentText
|
MySettings.userDefaultModel = comboBox.currentText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
MySettingsLabel {
|
||||||
|
id: suggestionModeLabel
|
||||||
|
text: qsTr("Suggestion Mode")
|
||||||
|
helpText: qsTr("Generate suggested follow-up questions at the end of responses.")
|
||||||
|
Layout.row: 6
|
||||||
|
Layout.column: 0
|
||||||
|
}
|
||||||
|
MyComboBox {
|
||||||
|
id: suggestionModeBox
|
||||||
|
Layout.row: 6
|
||||||
|
Layout.column: 2
|
||||||
|
Layout.minimumWidth: 400
|
||||||
|
Layout.maximumWidth: 400
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
model: [ qsTr("When chatting with LocalDocs"), qsTr("Whenever possible"), qsTr("Never") ]
|
||||||
|
Accessible.name: suggestionModeLabel.text
|
||||||
|
Accessible.description: suggestionModeLabel.helpText
|
||||||
|
onActivated: {
|
||||||
|
MySettings.suggestionMode = suggestionModeBox.currentIndex;
|
||||||
|
}
|
||||||
|
Component.onCompleted: {
|
||||||
|
suggestionModeBox.currentIndex = MySettings.suggestionMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
MySettingsLabel {
|
MySettingsLabel {
|
||||||
id: modelPathLabel
|
id: modelPathLabel
|
||||||
text: qsTr("Download Path")
|
text: qsTr("Download Path")
|
||||||
helpText: qsTr("Where to store local models and the LocalDocs database.")
|
helpText: qsTr("Where to store local models and the LocalDocs database.")
|
||||||
Layout.row: 6
|
Layout.row: 7
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.row: 6
|
Layout.row: 7
|
||||||
Layout.column: 2
|
Layout.column: 2
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
Layout.minimumWidth: 400
|
Layout.minimumWidth: 400
|
||||||
@ -273,12 +297,12 @@ MySettingsTab {
|
|||||||
id: dataLakeLabel
|
id: dataLakeLabel
|
||||||
text: qsTr("Enable Datalake")
|
text: qsTr("Enable Datalake")
|
||||||
helpText: qsTr("Send chats and feedback to the GPT4All Open-Source Datalake.")
|
helpText: qsTr("Send chats and feedback to the GPT4All Open-Source Datalake.")
|
||||||
Layout.row: 7
|
Layout.row: 8
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
}
|
}
|
||||||
MyCheckBox {
|
MyCheckBox {
|
||||||
id: dataLakeBox
|
id: dataLakeBox
|
||||||
Layout.row: 7
|
Layout.row: 8
|
||||||
Layout.column: 2
|
Layout.column: 2
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
Component.onCompleted: { dataLakeBox.checked = MySettings.networkIsActive; }
|
Component.onCompleted: { dataLakeBox.checked = MySettings.networkIsActive; }
|
||||||
@ -296,7 +320,7 @@ MySettingsTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Layout.row: 8
|
Layout.row: 9
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
Layout.columnSpan: 3
|
Layout.columnSpan: 3
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@ -319,7 +343,7 @@ MySettingsTab {
|
|||||||
id: nThreadsLabel
|
id: nThreadsLabel
|
||||||
text: qsTr("CPU Threads")
|
text: qsTr("CPU Threads")
|
||||||
helpText: qsTr("The number of CPU threads used for inference and embedding.")
|
helpText: qsTr("The number of CPU threads used for inference and embedding.")
|
||||||
Layout.row: 9
|
Layout.row: 10
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
}
|
}
|
||||||
MyTextField {
|
MyTextField {
|
||||||
@ -327,7 +351,7 @@ MySettingsTab {
|
|||||||
color: theme.textColor
|
color: theme.textColor
|
||||||
font.pixelSize: theme.fontSizeLarge
|
font.pixelSize: theme.fontSizeLarge
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
Layout.row: 9
|
Layout.row: 10
|
||||||
Layout.column: 2
|
Layout.column: 2
|
||||||
Layout.minimumWidth: 200
|
Layout.minimumWidth: 200
|
||||||
Layout.maximumWidth: 200
|
Layout.maximumWidth: 200
|
||||||
@ -351,12 +375,12 @@ MySettingsTab {
|
|||||||
id: saveChatsContextLabel
|
id: saveChatsContextLabel
|
||||||
text: qsTr("Save Chat Context")
|
text: qsTr("Save Chat Context")
|
||||||
helpText: qsTr("Save the chat model's state to disk for faster loading. WARNING: Uses ~2GB per chat.")
|
helpText: qsTr("Save the chat model's state to disk for faster loading. WARNING: Uses ~2GB per chat.")
|
||||||
Layout.row: 10
|
Layout.row: 11
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
}
|
}
|
||||||
MyCheckBox {
|
MyCheckBox {
|
||||||
id: saveChatsContextBox
|
id: saveChatsContextBox
|
||||||
Layout.row: 10
|
Layout.row: 11
|
||||||
Layout.column: 2
|
Layout.column: 2
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
checked: MySettings.saveChatsContext
|
checked: MySettings.saveChatsContext
|
||||||
@ -368,12 +392,12 @@ MySettingsTab {
|
|||||||
id: serverChatLabel
|
id: serverChatLabel
|
||||||
text: qsTr("Enable Local Server")
|
text: qsTr("Enable Local Server")
|
||||||
helpText: qsTr("Expose an OpenAI-Compatible server to localhost. WARNING: Results in increased resource usage.")
|
helpText: qsTr("Expose an OpenAI-Compatible server to localhost. WARNING: Results in increased resource usage.")
|
||||||
Layout.row: 11
|
Layout.row: 12
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
}
|
}
|
||||||
MyCheckBox {
|
MyCheckBox {
|
||||||
id: serverChatBox
|
id: serverChatBox
|
||||||
Layout.row: 11
|
Layout.row: 12
|
||||||
Layout.column: 2
|
Layout.column: 2
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
checked: MySettings.serverChat
|
checked: MySettings.serverChat
|
||||||
@ -385,7 +409,7 @@ MySettingsTab {
|
|||||||
id: serverPortLabel
|
id: serverPortLabel
|
||||||
text: qsTr("API Server Port")
|
text: qsTr("API Server Port")
|
||||||
helpText: qsTr("The port to use for the local server. Requires restart.")
|
helpText: qsTr("The port to use for the local server. Requires restart.")
|
||||||
Layout.row: 12
|
Layout.row: 13
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
}
|
}
|
||||||
MyTextField {
|
MyTextField {
|
||||||
@ -393,7 +417,7 @@ MySettingsTab {
|
|||||||
text: MySettings.networkPort
|
text: MySettings.networkPort
|
||||||
color: theme.textColor
|
color: theme.textColor
|
||||||
font.pixelSize: theme.fontSizeLarge
|
font.pixelSize: theme.fontSizeLarge
|
||||||
Layout.row: 12
|
Layout.row: 13
|
||||||
Layout.column: 2
|
Layout.column: 2
|
||||||
Layout.minimumWidth: 200
|
Layout.minimumWidth: 200
|
||||||
Layout.maximumWidth: 200
|
Layout.maximumWidth: 200
|
||||||
|
@ -797,7 +797,7 @@ Rectangle {
|
|||||||
|
|
||||||
delegate: GridLayout {
|
delegate: GridLayout {
|
||||||
width: listView.contentItem.width - 15
|
width: listView.contentItem.width - 15
|
||||||
rows: 3
|
rows: 5
|
||||||
columns: 2
|
columns: 2
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@ -850,6 +850,8 @@ Rectangle {
|
|||||||
font.pixelSize: theme.fontSizeLarger
|
font.pixelSize: theme.fontSizeLarger
|
||||||
font.bold: true
|
font.bold: true
|
||||||
color: theme.conversationHeader
|
color: theme.conversationHeader
|
||||||
|
enabled: false
|
||||||
|
focus: false
|
||||||
readOnly: true
|
readOnly: true
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
@ -872,6 +874,7 @@ Rectangle {
|
|||||||
case Chat.LocalDocsProcessing: return qsTr("searching localdocs: ") + currentChat.collectionList.join(", ") + " ...";
|
case Chat.LocalDocsProcessing: return qsTr("searching localdocs: ") + currentChat.collectionList.join(", ") + " ...";
|
||||||
case Chat.PromptProcessing: return qsTr("processing ...")
|
case Chat.PromptProcessing: return qsTr("processing ...")
|
||||||
case Chat.ResponseGeneration: return qsTr("generating response ...");
|
case Chat.ResponseGeneration: return qsTr("generating response ...");
|
||||||
|
case Chat.GeneratingQuestions: return qsTr("generating questions ...");
|
||||||
default: return ""; // handle unexpected values
|
default: return ""; // handle unexpected values
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1094,7 +1097,16 @@ Rectangle {
|
|||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
Layout.preferredWidth: childrenRect.width
|
Layout.preferredWidth: childrenRect.width
|
||||||
Layout.preferredHeight: childrenRect.height
|
Layout.preferredHeight: childrenRect.height
|
||||||
visible: consolidatedSources.length !== 0 && MySettings.localDocsShowReferences && (!currentResponse || !currentChat.responseInProgress)
|
visible: {
|
||||||
|
if (consolidatedSources.length === 0)
|
||||||
|
return false
|
||||||
|
if (!MySettings.localDocsShowReferences)
|
||||||
|
return false
|
||||||
|
if (currentResponse && currentChat.responseInProgress
|
||||||
|
&& currentChat.responseState !== Chat.GeneratingQuestions )
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
MyButton {
|
MyButton {
|
||||||
backgroundColor: theme.sourcesBackground
|
backgroundColor: theme.sourcesBackground
|
||||||
@ -1171,7 +1183,16 @@ Rectangle {
|
|||||||
Layout.row: 3
|
Layout.row: 3
|
||||||
Layout.column: 1
|
Layout.column: 1
|
||||||
Layout.topMargin: 5
|
Layout.topMargin: 5
|
||||||
visible: consolidatedSources.length !== 0 && MySettings.localDocsShowReferences && (!currentResponse || !currentChat.responseInProgress)
|
visible: {
|
||||||
|
if (consolidatedSources.length === 0)
|
||||||
|
return false
|
||||||
|
if (!MySettings.localDocsShowReferences)
|
||||||
|
return false
|
||||||
|
if (currentResponse && currentChat.responseInProgress
|
||||||
|
&& currentChat.responseState !== Chat.GeneratingQuestions )
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
clip: true
|
clip: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: 0
|
Layout.preferredHeight: 0
|
||||||
@ -1310,45 +1331,250 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldShowSuggestions() {
|
||||||
|
if (!currentResponse)
|
||||||
|
return false;
|
||||||
|
if (MySettings.suggestionMode === 2) // Off
|
||||||
|
return false;
|
||||||
|
if (MySettings.suggestionMode === 0 && consolidatedSources.length === 0) // LocalDocs only
|
||||||
|
return false;
|
||||||
|
return currentChat.responseState === Chat.GeneratingQuestions || currentChat.generatedQuestions.length !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
property bool shouldAutoScroll: true
|
Item {
|
||||||
property bool isAutoScrolling: false
|
visible: shouldShowSuggestions()
|
||||||
|
Layout.row: 4
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.topMargin: 20
|
||||||
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
||||||
|
Layout.preferredWidth: 28
|
||||||
|
Layout.preferredHeight: 28
|
||||||
|
Image {
|
||||||
|
id: stack
|
||||||
|
sourceSize: Qt.size(28, 28)
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
mipmap: true
|
||||||
|
visible: false
|
||||||
|
source: "qrc:/gpt4all/icons/stack.svg"
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
ColorOverlay {
|
||||||
target: currentChat
|
anchors.fill: stack
|
||||||
function onResponseChanged() {
|
source: stack
|
||||||
listView.scrollToEnd()
|
color: theme.conversationHeader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
visible: shouldShowSuggestions()
|
||||||
|
Layout.row: 4
|
||||||
|
Layout.column: 1
|
||||||
|
Layout.topMargin: 20
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 38
|
||||||
|
RowLayout {
|
||||||
|
spacing: 5
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
TextArea {
|
||||||
|
text: qsTr("Suggested follow-ups")
|
||||||
|
padding: 0
|
||||||
|
font.pixelSize: theme.fontSizeLarger
|
||||||
|
font.bold: true
|
||||||
|
color: theme.conversationHeader
|
||||||
|
enabled: false
|
||||||
|
focus: false
|
||||||
|
readOnly: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
visible: shouldShowSuggestions()
|
||||||
|
Layout.row: 5
|
||||||
|
Layout.column: 1
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumHeight: 1
|
||||||
|
spacing: 10
|
||||||
|
Repeater {
|
||||||
|
model: currentChat.generatedQuestions
|
||||||
|
TextArea {
|
||||||
|
id: followUpText
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
rightPadding: 40
|
||||||
|
topPadding: 10
|
||||||
|
leftPadding: 20
|
||||||
|
bottomPadding: 10
|
||||||
|
text: modelData
|
||||||
|
focus: false
|
||||||
|
readOnly: true
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
hoverEnabled: !currentChat.responseInProgress
|
||||||
|
color: theme.textColor
|
||||||
|
font.pixelSize: theme.fontSizeLarge
|
||||||
|
background: Rectangle {
|
||||||
|
color: hovered ? theme.sourcesBackgroundHovered : theme.sourcesBackground
|
||||||
|
radius: 10
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
id: maFollowUp
|
||||||
|
anchors.fill: parent
|
||||||
|
enabled: !currentChat.responseInProgress
|
||||||
|
onClicked: function() {
|
||||||
|
var chat = window.currentChat
|
||||||
|
var followup = modelData
|
||||||
|
chat.stopGenerating()
|
||||||
|
chat.newPromptResponsePair(followup);
|
||||||
|
chat.prompt(followup,
|
||||||
|
MySettings.promptTemplate,
|
||||||
|
MySettings.maxLength,
|
||||||
|
MySettings.topK,
|
||||||
|
MySettings.topP,
|
||||||
|
MySettings.minP,
|
||||||
|
MySettings.temperature,
|
||||||
|
MySettings.promptBatchSize,
|
||||||
|
MySettings.repeatPenalty,
|
||||||
|
MySettings.repeatPenaltyTokens)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: 40
|
||||||
|
height: 40
|
||||||
|
visible: !currentChat.responseInProgress
|
||||||
|
Image {
|
||||||
|
id: plusImage
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
sourceSize.width: 20
|
||||||
|
sourceSize.height: 20
|
||||||
|
mipmap: true
|
||||||
|
visible: false
|
||||||
|
source: "qrc:/gpt4all/icons/plus.svg"
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorOverlay {
|
||||||
|
anchors.fill: plusImage
|
||||||
|
source: plusImage
|
||||||
|
color: theme.styledTextColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: "transparent"
|
||||||
|
radius: 10
|
||||||
|
Layout.preferredHeight: currentChat.responseInProgress ? 40 : 0
|
||||||
|
clip: true
|
||||||
|
ColumnLayout {
|
||||||
|
id: followUpLayout
|
||||||
|
anchors.fill: parent
|
||||||
|
Rectangle {
|
||||||
|
id: myRect1
|
||||||
|
Layout.preferredWidth: 0
|
||||||
|
Layout.minimumWidth: 0
|
||||||
|
Layout.maximumWidth: parent.width
|
||||||
|
height: 12
|
||||||
|
color: theme.sourcesBackgroundHovered
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: myRect2
|
||||||
|
Layout.preferredWidth: 0
|
||||||
|
Layout.minimumWidth: 0
|
||||||
|
Layout.maximumWidth: parent.width
|
||||||
|
height: 12
|
||||||
|
color: theme.sourcesBackgroundHovered
|
||||||
|
}
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
id: followUpProgressAnimation
|
||||||
|
ParallelAnimation {
|
||||||
|
PropertyAnimation {
|
||||||
|
target: myRect1
|
||||||
|
property: "Layout.preferredWidth"
|
||||||
|
from: 0
|
||||||
|
to: followUpLayout.width
|
||||||
|
duration: 1000
|
||||||
|
}
|
||||||
|
PropertyAnimation {
|
||||||
|
target: myRect2
|
||||||
|
property: "Layout.preferredWidth"
|
||||||
|
from: 0
|
||||||
|
to: followUpLayout.width / 2
|
||||||
|
duration: 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SequentialAnimation {
|
||||||
|
loops: Animation.Infinite
|
||||||
|
ParallelAnimation {
|
||||||
|
PropertyAnimation {
|
||||||
|
target: myRect1
|
||||||
|
property: "opacity"
|
||||||
|
from: 1
|
||||||
|
to: 0.2
|
||||||
|
duration: 1500
|
||||||
|
}
|
||||||
|
PropertyAnimation {
|
||||||
|
target: myRect2
|
||||||
|
property: "opacity"
|
||||||
|
from: 1
|
||||||
|
to: 0.2
|
||||||
|
duration: 1500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ParallelAnimation {
|
||||||
|
PropertyAnimation {
|
||||||
|
target: myRect1
|
||||||
|
property: "opacity"
|
||||||
|
from: 0.2
|
||||||
|
to: 1
|
||||||
|
duration: 1500
|
||||||
|
}
|
||||||
|
PropertyAnimation {
|
||||||
|
target: myRect2
|
||||||
|
property: "opacity"
|
||||||
|
from: 0.2
|
||||||
|
to: 1
|
||||||
|
duration: 1500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onVisibleChanged: {
|
||||||
|
if (visible)
|
||||||
|
followUpProgressAnimation.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on Layout.preferredHeight {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 300
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollToEnd() {
|
function scrollToEnd() {
|
||||||
if (listView.shouldAutoScroll) {
|
|
||||||
listView.isAutoScrolling = true
|
|
||||||
listView.positionViewAtEnd()
|
listView.positionViewAtEnd()
|
||||||
listView.isAutoScrolling = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onContentYChanged: {
|
onContentHeightChanged: {
|
||||||
if (!isAutoScrolling)
|
if (atYEnd)
|
||||||
shouldAutoScroll = atYEnd
|
scrollToEnd()
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
shouldAutoScroll = true
|
|
||||||
positionViewAtEnd()
|
|
||||||
}
|
|
||||||
|
|
||||||
footer: Item {
|
|
||||||
id: bottomPadding
|
|
||||||
width: parent.width
|
|
||||||
height: 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -250,45 +250,64 @@ MySettingsTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MySettingsLabel {
|
||||||
|
id: chatNamePromptLabel
|
||||||
|
text: qsTr("Chat Name Prompt")
|
||||||
|
helpText: qsTr("Prompt used to automatically generate chat names.")
|
||||||
|
Layout.row: 11
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.topMargin: 15
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: optionalImageRect
|
id: chatNamePrompt
|
||||||
visible: false // FIXME: for later
|
Layout.row: 12
|
||||||
Layout.row: 2
|
Layout.column: 0
|
||||||
Layout.column: 1
|
Layout.columnSpan: 2
|
||||||
Layout.rowSpan: 5
|
Layout.fillWidth: true
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.minimumHeight: Math.max(100, chatNamePromptTextArea.contentHeight + 20)
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.maximumWidth: height
|
|
||||||
Layout.topMargin: 35
|
|
||||||
Layout.bottomMargin: 35
|
|
||||||
Layout.leftMargin: 35
|
|
||||||
width: 3000
|
|
||||||
radius: 10
|
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
Item {
|
clip: true
|
||||||
anchors.centerIn: parent
|
MyTextArea {
|
||||||
height: childrenRect.height
|
id: chatNamePromptTextArea
|
||||||
Image {
|
anchors.fill: parent
|
||||||
id: img
|
text: root.currentModelInfo.chatNamePrompt
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
Accessible.role: Accessible.EditableText
|
||||||
width: 100
|
Accessible.name: chatNamePromptLabel.text
|
||||||
height: 100
|
Accessible.description: chatNamePromptLabel.text
|
||||||
source: "qrc:/gpt4all/icons/image.svg"
|
|
||||||
}
|
}
|
||||||
Text {
|
|
||||||
text: qsTr("Add\noptional image")
|
|
||||||
font.pixelSize: theme.fontSizeLarge
|
|
||||||
anchors.top: img.bottom
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
wrapMode: TextArea.Wrap
|
|
||||||
horizontalAlignment: Qt.AlignHCenter
|
|
||||||
color: theme.mutedTextColor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MySettingsLabel {
|
||||||
|
id: suggestedFollowUpPromptLabel
|
||||||
|
text: qsTr("Suggested FollowUp Prompt")
|
||||||
|
helpText: qsTr("Prompt used to generate suggested follow-up questions.")
|
||||||
|
Layout.row: 13
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.topMargin: 15
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: suggestedFollowUpPrompt
|
||||||
|
Layout.row: 14
|
||||||
|
Layout.column: 0
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumHeight: Math.max(100, suggestedFollowUpPromptTextArea.contentHeight + 20)
|
||||||
|
color: "transparent"
|
||||||
|
clip: true
|
||||||
|
MyTextArea {
|
||||||
|
id: suggestedFollowUpPromptTextArea
|
||||||
|
anchors.fill: parent
|
||||||
|
text: root.currentModelInfo.suggestedFollowUpPrompt
|
||||||
|
Accessible.role: Accessible.EditableText
|
||||||
|
Accessible.name: suggestedFollowUpPromptLabel.text
|
||||||
|
Accessible.description: suggestedFollowUpPromptLabel.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GridLayout {
|
GridLayout {
|
||||||
Layout.row: 11
|
Layout.row: 15
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
Layout.columnSpan: 2
|
Layout.columnSpan: 2
|
||||||
Layout.topMargin: 15
|
Layout.topMargin: 15
|
||||||
@ -784,7 +803,7 @@ MySettingsTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
Layout.row: 12
|
Layout.row: 16
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
Layout.columnSpan: 2
|
Layout.columnSpan: 2
|
||||||
Layout.topMargin: 15
|
Layout.topMargin: 15
|
||||||
|
Loading…
Reference in New Issue
Block a user