mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-06-29 08:47:39 +00:00
Move the jinja processing to mysettings and validation.
Signed-off-by: Adam Treat <treat.adam@gmail.com>
This commit is contained in:
parent
227dbfd18b
commit
48117cda46
@ -31,7 +31,6 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <jinja2cpp/template.h>
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
@ -1337,34 +1336,14 @@ void ChatLLM::processSystemPrompt()
|
|||||||
if (!isModelLoaded() || m_processedSystemPrompt || m_restoreStateFromText || m_isServer)
|
if (!isModelLoaded() || m_processedSystemPrompt || m_restoreStateFromText || m_isServer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const std::string systemPromptTemplate = MySettings::globalInstance()->modelSystemPromptTemplate(m_modelInfo).toStdString();
|
QString error;
|
||||||
|
const std::string systemPrompt = MySettings::globalInstance()->modelSystemPrompt(m_modelInfo, error).toStdString();
|
||||||
// FIXME: This needs to be moved to settings probably and the same code used for validation
|
|
||||||
jinja2::ValuesMap params;
|
|
||||||
params.insert({"currentDate", QDate::currentDate().toString().toStdString()});
|
|
||||||
|
|
||||||
jinja2::ValuesList toolList;
|
|
||||||
int c = ToolModel::globalInstance()->count();
|
|
||||||
for (int i = 0; i < c; ++i) {
|
|
||||||
Tool *t = ToolModel::globalInstance()->get(i);
|
|
||||||
if (t->usageMode() == ToolEnums::UsageMode::Enabled)
|
|
||||||
toolList.push_back(t->jinjaValue());
|
|
||||||
}
|
|
||||||
params.insert({"toolList", toolList});
|
|
||||||
|
|
||||||
std::string systemPrompt;
|
|
||||||
|
|
||||||
jinja2::Template t;
|
|
||||||
t.Load(systemPromptTemplate);
|
|
||||||
const auto renderResult = t.RenderAsString(params);
|
|
||||||
|
|
||||||
// The GUI should not allow setting an improper template, but it is always possible someone hand
|
// The GUI should not allow setting an improper template, but it is always possible someone hand
|
||||||
// edits the settings file to produce an improper one.
|
// edits the settings file to produce an improper one.
|
||||||
Q_ASSERT(renderResult);
|
Q_ASSERT(error.isEmpty());
|
||||||
if (renderResult)
|
if (!error.isEmpty())
|
||||||
systemPrompt = renderResult.value();
|
qWarning() << "ERROR: Could not parse system prompt template:" << error;
|
||||||
else
|
|
||||||
qWarning() << "ERROR: Could not parse system prompt template:" << renderResult.error().ToString();
|
|
||||||
|
|
||||||
if (QString::fromStdString(systemPrompt).trimmed().isEmpty()) {
|
if (QString::fromStdString(systemPrompt).trimmed().isEmpty()) {
|
||||||
m_processedSystemPrompt = true;
|
m_processedSystemPrompt = true;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "mysettings.h"
|
#include "mysettings.h"
|
||||||
|
|
||||||
#include "../gpt4all-backend/llmodel.h"
|
#include "../gpt4all-backend/llmodel.h"
|
||||||
|
#include "tool.h"
|
||||||
|
#include "toolmodel.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@ -18,6 +20,7 @@
|
|||||||
#include <QtLogging>
|
#include <QtLogging>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <jinja2cpp/template.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -676,3 +679,45 @@ void MySettings::setLanguageAndLocale(const QString &bcp47Name)
|
|||||||
QLocale::setDefault(locale);
|
QLocale::setDefault(locale);
|
||||||
emit languageAndLocaleChanged();
|
emit languageAndLocaleChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString MySettings::validateModelSystemPromptTemplate(const QString &proposedTemplate)
|
||||||
|
{
|
||||||
|
QString error;
|
||||||
|
systemPromptInternal(proposedTemplate, error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MySettings::modelSystemPrompt(const ModelInfo &info, QString &error)
|
||||||
|
{
|
||||||
|
return systemPromptInternal(modelSystemPromptTemplate(info), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MySettings::systemPromptInternal(const QString &proposedTemplate, QString &error)
|
||||||
|
{
|
||||||
|
jinja2::ValuesMap params;
|
||||||
|
params.insert({"currentDate", QDate::currentDate().toString().toStdString()});
|
||||||
|
|
||||||
|
jinja2::ValuesList toolList;
|
||||||
|
int c = ToolModel::globalInstance()->count();
|
||||||
|
for (int i = 0; i < c; ++i) {
|
||||||
|
Tool *t = ToolModel::globalInstance()->get(i);
|
||||||
|
if (t->usageMode() == ToolEnums::UsageMode::Enabled)
|
||||||
|
toolList.push_back(t->jinjaValue());
|
||||||
|
}
|
||||||
|
params.insert({"toolList", toolList});
|
||||||
|
|
||||||
|
QString systemPrompt;
|
||||||
|
jinja2::Template t;
|
||||||
|
const auto loadResult = t.Load(proposedTemplate.toStdString(), "systemPromptTemplate" /*Used in error messages*/);
|
||||||
|
if (!loadResult) {
|
||||||
|
error = QString::fromStdString(loadResult.error().ToString());
|
||||||
|
return systemPrompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto renderResult = t.RenderAsString(params);
|
||||||
|
if (renderResult)
|
||||||
|
systemPrompt = QString::fromStdString(renderResult.value());
|
||||||
|
else
|
||||||
|
error = QString::fromStdString(renderResult.error().ToString());
|
||||||
|
return systemPrompt;
|
||||||
|
}
|
||||||
|
@ -204,6 +204,10 @@ public:
|
|||||||
int networkPort() const;
|
int networkPort() const;
|
||||||
void setNetworkPort(int value);
|
void setNetworkPort(int value);
|
||||||
|
|
||||||
|
// Jinja aware methods for validating and parsing/rendering the system prompt
|
||||||
|
Q_INVOKABLE QString validateModelSystemPromptTemplate(const QString &proposedTemplate);
|
||||||
|
QString modelSystemPrompt(const ModelInfo &info, QString &error);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void nameChanged(const ModelInfo &info);
|
void nameChanged(const ModelInfo &info);
|
||||||
void filenameChanged(const ModelInfo &info);
|
void filenameChanged(const ModelInfo &info);
|
||||||
@ -269,6 +273,8 @@ private:
|
|||||||
void setModelSetting(const QString &name, const ModelInfo &info, const QVariant &value, bool force,
|
void setModelSetting(const QString &name, const ModelInfo &info, const QVariant &value, bool force,
|
||||||
bool signal = false);
|
bool signal = false);
|
||||||
QString filePathForLocale(const QLocale &locale);
|
QString filePathForLocale(const QLocale &locale);
|
||||||
|
QString systemPromptInternal(const QString &proposedTemplate, QString &error);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MYSETTINGS_H
|
#endif // MYSETTINGS_H
|
||||||
|
@ -153,13 +153,30 @@ MySettingsTab {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
|
|
||||||
MySettingsLabel {
|
RowLayout {
|
||||||
visible: !root.currentModelInfo.isOnline
|
|
||||||
text: qsTr("System Prompt")
|
|
||||||
helpText: qsTr("Prefixed at the beginning of every conversation. Must contain the appropriate framing tokens.")
|
|
||||||
Layout.row: 7
|
Layout.row: 7
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
|
Layout.columnSpan: 2
|
||||||
Layout.topMargin: 15
|
Layout.topMargin: 15
|
||||||
|
spacing: 10
|
||||||
|
MySettingsLabel {
|
||||||
|
text: qsTr("System Prompt Template")
|
||||||
|
helpText: qsTr("Prefixed at the beginning of every conversation. Must contain the appropriate framing tokens.")
|
||||||
|
}
|
||||||
|
MySettingsLabel {
|
||||||
|
id: systemPromptTemplateError
|
||||||
|
color: theme.textErrorColor
|
||||||
|
wrapMode: TextArea.Wrap
|
||||||
|
Timer {
|
||||||
|
id: errorTimer
|
||||||
|
interval: 500 // 500 ms delay
|
||||||
|
repeat: false
|
||||||
|
property string text: ""
|
||||||
|
onTriggered: {
|
||||||
|
systemPromptTemplateError.text = errorTimer.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@ -188,7 +205,15 @@ MySettingsTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
MySettings.setModelSystemPromptTemplate(root.currentModelInfo, text)
|
var errorString = MySettings.validateModelSystemPromptTemplate(text);
|
||||||
|
if (errorString === "") {
|
||||||
|
errorTimer.stop();
|
||||||
|
systemPromptTemplateError.text = ""; // Clear any previous error
|
||||||
|
MySettings.setModelSystemPromptTemplate(root.currentModelInfo, text);
|
||||||
|
} else {
|
||||||
|
errorTimer.text = errorString;
|
||||||
|
errorTimer.restart();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Accessible.role: Accessible.EditableText
|
Accessible.role: Accessible.EditableText
|
||||||
}
|
}
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
#ifndef SOURCEEXCERT_H
|
|
||||||
#define SOURCEEXCERT_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
using namespace Qt::Literals::StringLiterals;
|
|
||||||
|
|
||||||
struct SourceExcerpt {
|
|
||||||
Q_GADGET
|
|
||||||
Q_PROPERTY(QString date MEMBER date)
|
|
||||||
Q_PROPERTY(QString text MEMBER text)
|
|
||||||
Q_PROPERTY(QString collection MEMBER collection)
|
|
||||||
Q_PROPERTY(QString path MEMBER path)
|
|
||||||
Q_PROPERTY(QString file MEMBER file)
|
|
||||||
Q_PROPERTY(QString url MEMBER url)
|
|
||||||
Q_PROPERTY(QString favicon MEMBER favicon)
|
|
||||||
Q_PROPERTY(QString title MEMBER title)
|
|
||||||
Q_PROPERTY(QString author MEMBER author)
|
|
||||||
Q_PROPERTY(int page MEMBER page)
|
|
||||||
Q_PROPERTY(int from MEMBER from)
|
|
||||||
Q_PROPERTY(int to MEMBER to)
|
|
||||||
Q_PROPERTY(QString fileUri READ fileUri STORED false)
|
|
||||||
|
|
||||||
public:
|
|
||||||
QString date; // [Required] The creation or the last modification date whichever is latest
|
|
||||||
QString text; // [Required] The text actually used in the augmented context
|
|
||||||
QString collection; // [Optional] The name of the collection
|
|
||||||
QString path; // [Optional] The full path
|
|
||||||
QString file; // [Optional] The name of the file, but not the full path
|
|
||||||
QString url; // [Optional] The name of the remote url
|
|
||||||
QString favicon; // [Optional] The favicon
|
|
||||||
QString title; // [Optional] The title of the document
|
|
||||||
QString author; // [Optional] The author of the document
|
|
||||||
int page = -1; // [Optional] The page where the text was found
|
|
||||||
int from = -1; // [Optional] The line number where the text begins
|
|
||||||
int to = -1; // [Optional] The line number where the text ends
|
|
||||||
|
|
||||||
QString fileUri() const {
|
|
||||||
// QUrl reserved chars that are not UNSAFE_PATH according to glib/gconvert.c
|
|
||||||
static const QByteArray s_exclude = "!$&'()*+,/:=@~"_ba;
|
|
||||||
|
|
||||||
Q_ASSERT(!QFileInfo(path).isRelative());
|
|
||||||
#ifdef Q_OS_WINDOWS
|
|
||||||
Q_ASSERT(!path.contains('\\')); // Qt normally uses forward slash as path separator
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto escaped = QString::fromUtf8(QUrl::toPercentEncoding(path, s_exclude));
|
|
||||||
if (escaped.front() != '/')
|
|
||||||
escaped = '/' + escaped;
|
|
||||||
return u"file://"_s + escaped;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject toJson() const
|
|
||||||
{
|
|
||||||
QJsonObject result;
|
|
||||||
result.insert("date", date);
|
|
||||||
result.insert("text", text);
|
|
||||||
result.insert("collection", collection);
|
|
||||||
result.insert("path", path);
|
|
||||||
result.insert("file", file);
|
|
||||||
result.insert("url", url);
|
|
||||||
result.insert("favicon", favicon);
|
|
||||||
result.insert("title", title);
|
|
||||||
result.insert("author", author);
|
|
||||||
result.insert("page", page);
|
|
||||||
result.insert("from", from);
|
|
||||||
result.insert("to", to);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const SourceExcerpt &other) const {
|
|
||||||
return date == other.date &&
|
|
||||||
text == other.text &&
|
|
||||||
collection == other.collection &&
|
|
||||||
path == other.path &&
|
|
||||||
file == other.file &&
|
|
||||||
url == other.url &&
|
|
||||||
favicon == other.favicon &&
|
|
||||||
title == other.title &&
|
|
||||||
author == other.author &&
|
|
||||||
page == other.page &&
|
|
||||||
from == other.from &&
|
|
||||||
to == other.to;
|
|
||||||
}
|
|
||||||
bool operator!=(const SourceExcerpt &other) const {
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(SourceExcerpt)
|
|
||||||
|
|
||||||
#endif // SOURCEEXCERT_H
|
|
Loading…
Reference in New Issue
Block a user