mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-07-01 17:51:57 +00:00
Serialize the source excerpts from and to pure json
Signed-off-by: Adam Treat <treat.adam@gmail.com>
This commit is contained in:
parent
01f67c74ea
commit
27b86dae21
@ -787,10 +787,8 @@ bool ChatLLM::promptInternal(const QList<QString> &collectionList, const QString
|
|||||||
QString docsContext;
|
QString docsContext;
|
||||||
if (!localDocsExcerpts.isEmpty()) {
|
if (!localDocsExcerpts.isEmpty()) {
|
||||||
// FIXME(adam): we should be using the new tool template if available otherwise this I guess
|
// FIXME(adam): we should be using the new tool template if available otherwise this I guess
|
||||||
QStringList results;
|
QString json = SourceExcerpt::toJson(localDocsExcerpts);
|
||||||
for (const SourceExcerpt &info : localDocsExcerpts)
|
docsContext = u"### Context:\n%1\n\n"_s.arg(json);
|
||||||
results << u"Collection: %1\nPath: %2\nExcerpt: %3"_s.arg(info.collection, info.path, info.text);
|
|
||||||
docsContext = u"### Context:\n%1\n\n"_s.arg(results.join("\n\n"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int n_threads = MySettings::globalInstance()->threadCount();
|
int n_threads = MySettings::globalInstance()->threadCount();
|
||||||
@ -900,9 +898,6 @@ bool ChatLLM::promptInternal(const QList<QString> &collectionList, const QString
|
|||||||
emit sourceExcerptsChanged(sourceExcerpts);
|
emit sourceExcerptsChanged(sourceExcerpts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Erase the context of the tool call
|
|
||||||
m_ctx.n_past = std::max(0, m_ctx.n_past);
|
|
||||||
m_ctx.tokens.erase(m_ctx.tokens.end() - m_promptResponseTokens, m_ctx.tokens.end());
|
|
||||||
m_promptResponseTokens = 0;
|
m_promptResponseTokens = 0;
|
||||||
m_promptTokens = 0;
|
m_promptTokens = 0;
|
||||||
m_response = std::string();
|
m_response = std::string();
|
||||||
|
@ -29,7 +29,6 @@ struct ChatItem
|
|||||||
Q_PROPERTY(bool thumbsUpState MEMBER thumbsUpState)
|
Q_PROPERTY(bool thumbsUpState MEMBER thumbsUpState)
|
||||||
Q_PROPERTY(bool thumbsDownState MEMBER thumbsDownState)
|
Q_PROPERTY(bool thumbsDownState MEMBER thumbsDownState)
|
||||||
Q_PROPERTY(QList<SourceExcerpt> sources MEMBER sources)
|
Q_PROPERTY(QList<SourceExcerpt> sources MEMBER sources)
|
||||||
Q_PROPERTY(QList<SourceExcerpt> consolidatedSources MEMBER consolidatedSources)
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// TODO: Maybe we should include the model name here as well as timestamp?
|
// TODO: Maybe we should include the model name here as well as timestamp?
|
||||||
@ -39,7 +38,6 @@ public:
|
|||||||
QString prompt;
|
QString prompt;
|
||||||
QString newResponse;
|
QString newResponse;
|
||||||
QList<SourceExcerpt> sources;
|
QList<SourceExcerpt> sources;
|
||||||
QList<SourceExcerpt> consolidatedSources;
|
|
||||||
bool currentResponse = false;
|
bool currentResponse = false;
|
||||||
bool stopped = false;
|
bool stopped = false;
|
||||||
bool thumbsUpState = false;
|
bool thumbsUpState = false;
|
||||||
@ -65,8 +63,7 @@ public:
|
|||||||
StoppedRole,
|
StoppedRole,
|
||||||
ThumbsUpStateRole,
|
ThumbsUpStateRole,
|
||||||
ThumbsDownStateRole,
|
ThumbsDownStateRole,
|
||||||
SourcesRole,
|
SourcesRole
|
||||||
ConsolidatedSourcesRole
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||||
@ -102,8 +99,6 @@ public:
|
|||||||
return item.thumbsDownState;
|
return item.thumbsDownState;
|
||||||
case SourcesRole:
|
case SourcesRole:
|
||||||
return QVariant::fromValue(item.sources);
|
return QVariant::fromValue(item.sources);
|
||||||
case ConsolidatedSourcesRole:
|
|
||||||
return QVariant::fromValue(item.consolidatedSources);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@ -122,7 +117,6 @@ public:
|
|||||||
roles[ThumbsUpStateRole] = "thumbsUpState";
|
roles[ThumbsUpStateRole] = "thumbsUpState";
|
||||||
roles[ThumbsDownStateRole] = "thumbsDownState";
|
roles[ThumbsDownStateRole] = "thumbsDownState";
|
||||||
roles[SourcesRole] = "sources";
|
roles[SourcesRole] = "sources";
|
||||||
roles[ConsolidatedSourcesRole] = "consolidatedSources";
|
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,20 +194,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<SourceExcerpt> consolidateSources(const QList<SourceExcerpt> &sources) {
|
|
||||||
QMap<QString, SourceExcerpt> groupedData;
|
|
||||||
for (const SourceExcerpt &info : sources) {
|
|
||||||
QString key = !info.file.isEmpty() ? info.file : info.url;
|
|
||||||
if (groupedData.contains(key)) {
|
|
||||||
groupedData[key].text += "\n---\n" + info.text;
|
|
||||||
} else {
|
|
||||||
groupedData[key] = info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QList<SourceExcerpt> consolidatedSources = groupedData.values();
|
|
||||||
return consolidatedSources;
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_INVOKABLE void updateSources(int index, const QList<SourceExcerpt> &sources)
|
Q_INVOKABLE void updateSources(int index, const QList<SourceExcerpt> &sources)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= m_chatItems.size()) return;
|
if (index < 0 || index >= m_chatItems.size()) return;
|
||||||
@ -221,13 +201,10 @@ public:
|
|||||||
ChatItem &item = m_chatItems[index];
|
ChatItem &item = m_chatItems[index];
|
||||||
if (sources.isEmpty()) {
|
if (sources.isEmpty()) {
|
||||||
item.sources.clear();
|
item.sources.clear();
|
||||||
item.consolidatedSources.clear();
|
|
||||||
} else {
|
} else {
|
||||||
item.sources << sources;
|
item.sources << sources;
|
||||||
item.consolidatedSources << consolidateSources(sources);
|
|
||||||
}
|
}
|
||||||
emit dataChanged(createIndex(index, 0), createIndex(index, 0), {SourcesRole});
|
emit dataChanged(createIndex(index, 0), createIndex(index, 0), {SourcesRole});
|
||||||
emit dataChanged(createIndex(index, 0), createIndex(index, 0), {ConsolidatedSourcesRole});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_INVOKABLE void updateThumbsUpState(int index, bool b)
|
Q_INVOKABLE void updateThumbsUpState(int index, bool b)
|
||||||
@ -278,61 +255,7 @@ public:
|
|||||||
stream << c.stopped;
|
stream << c.stopped;
|
||||||
stream << c.thumbsUpState;
|
stream << c.thumbsUpState;
|
||||||
stream << c.thumbsDownState;
|
stream << c.thumbsDownState;
|
||||||
if (version > 7) {
|
stream << SourceExcerpt::toJson(c.sources);
|
||||||
stream << c.sources.size();
|
|
||||||
for (const SourceExcerpt &info : c.sources) {
|
|
||||||
Q_ASSERT(!info.file.isEmpty());
|
|
||||||
stream << info.collection;
|
|
||||||
stream << info.path;
|
|
||||||
stream << info.file;
|
|
||||||
stream << info.title;
|
|
||||||
stream << info.author;
|
|
||||||
stream << info.date;
|
|
||||||
stream << info.text;
|
|
||||||
stream << info.page;
|
|
||||||
stream << info.from;
|
|
||||||
stream << info.to;
|
|
||||||
if (version > 9) {
|
|
||||||
stream << info.url;
|
|
||||||
stream << info.favicon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (version > 2) {
|
|
||||||
QList<QString> references;
|
|
||||||
QList<QString> referencesContext;
|
|
||||||
int validReferenceNumber = 1;
|
|
||||||
for (const SourceExcerpt &info : c.sources) {
|
|
||||||
if (info.file.isEmpty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
QString reference;
|
|
||||||
{
|
|
||||||
QTextStream stream(&reference);
|
|
||||||
stream << (validReferenceNumber++) << ". ";
|
|
||||||
if (!info.title.isEmpty())
|
|
||||||
stream << "\"" << info.title << "\". ";
|
|
||||||
if (!info.author.isEmpty())
|
|
||||||
stream << "By " << info.author << ". ";
|
|
||||||
if (!info.date.isEmpty())
|
|
||||||
stream << "Date: " << info.date << ". ";
|
|
||||||
stream << "In " << info.file << ". ";
|
|
||||||
if (info.page != -1)
|
|
||||||
stream << "Page " << info.page << ". ";
|
|
||||||
if (info.from != -1) {
|
|
||||||
stream << "Lines " << info.from;
|
|
||||||
if (info.to != -1)
|
|
||||||
stream << "-" << info.to;
|
|
||||||
stream << ". ";
|
|
||||||
}
|
|
||||||
stream << "[Context](context://" << validReferenceNumber - 1 << ")";
|
|
||||||
}
|
|
||||||
references.append(reference);
|
|
||||||
referencesContext.append(info.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream << references.join("\n");
|
|
||||||
stream << referencesContext;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return stream.status() == QDataStream::Ok;
|
return stream.status() == QDataStream::Ok;
|
||||||
}
|
}
|
||||||
@ -352,30 +275,35 @@ public:
|
|||||||
stream >> c.stopped;
|
stream >> c.stopped;
|
||||||
stream >> c.thumbsUpState;
|
stream >> c.thumbsUpState;
|
||||||
stream >> c.thumbsDownState;
|
stream >> c.thumbsDownState;
|
||||||
if (version > 7) {
|
if (version > 9) {
|
||||||
|
QList<SourceExcerpt> sources;
|
||||||
|
QString json;
|
||||||
|
stream >> json;
|
||||||
|
QString errorString;
|
||||||
|
sources = SourceExcerpt::fromJson(json, errorString);
|
||||||
|
Q_ASSERT(errorString.isEmpty());
|
||||||
|
c.sources = sources;
|
||||||
|
} else if (version > 7) {
|
||||||
qsizetype count;
|
qsizetype count;
|
||||||
stream >> count;
|
stream >> count;
|
||||||
QList<SourceExcerpt> sources;
|
QList<SourceExcerpt> sources;
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
SourceExcerpt info;
|
SourceExcerpt source;
|
||||||
stream >> info.collection;
|
stream >> source.collection;
|
||||||
stream >> info.path;
|
stream >> source.path;
|
||||||
stream >> info.file;
|
stream >> source.file;
|
||||||
stream >> info.title;
|
stream >> source.title;
|
||||||
stream >> info.author;
|
stream >> source.author;
|
||||||
stream >> info.date;
|
stream >> source.date;
|
||||||
stream >> info.text;
|
Excerpt excerpt;
|
||||||
stream >> info.page;
|
stream >> excerpt.text;
|
||||||
stream >> info.from;
|
stream >> excerpt.page;
|
||||||
stream >> info.to;
|
stream >> excerpt.from;
|
||||||
if (version > 9) {
|
stream >> excerpt.to;
|
||||||
stream >> info.url;
|
source.excerpts = QList{ excerpt };
|
||||||
stream >> info.favicon;
|
sources.append(source);
|
||||||
}
|
|
||||||
sources.append(info);
|
|
||||||
}
|
}
|
||||||
c.sources = sources;
|
c.sources = sources;
|
||||||
c.consolidatedSources = consolidateSources(sources);
|
|
||||||
} else if (version > 2) {
|
} else if (version > 2) {
|
||||||
QString references;
|
QString references;
|
||||||
QList<QString> referencesContext;
|
QList<QString> referencesContext;
|
||||||
@ -398,7 +326,8 @@ public:
|
|||||||
for (int j = 0; j < referenceList.size(); ++j) {
|
for (int j = 0; j < referenceList.size(); ++j) {
|
||||||
QString reference = referenceList[j];
|
QString reference = referenceList[j];
|
||||||
QString context = referencesContext[j];
|
QString context = referencesContext[j];
|
||||||
SourceExcerpt info;
|
SourceExcerpt source;
|
||||||
|
Excerpt excerpt;
|
||||||
QTextStream refStream(&reference);
|
QTextStream refStream(&reference);
|
||||||
QString dummy;
|
QString dummy;
|
||||||
int validReferenceNumber;
|
int validReferenceNumber;
|
||||||
@ -407,28 +336,28 @@ public:
|
|||||||
if (reference.contains("\"")) {
|
if (reference.contains("\"")) {
|
||||||
int startIndex = reference.indexOf('"') + 1;
|
int startIndex = reference.indexOf('"') + 1;
|
||||||
int endIndex = reference.indexOf('"', startIndex);
|
int endIndex = reference.indexOf('"', startIndex);
|
||||||
info.title = reference.mid(startIndex, endIndex - startIndex);
|
source.title = reference.mid(startIndex, endIndex - startIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract author (after "By " and before the next period)
|
// Extract author (after "By " and before the next period)
|
||||||
if (reference.contains("By ")) {
|
if (reference.contains("By ")) {
|
||||||
int startIndex = reference.indexOf("By ") + 3;
|
int startIndex = reference.indexOf("By ") + 3;
|
||||||
int endIndex = reference.indexOf('.', startIndex);
|
int endIndex = reference.indexOf('.', startIndex);
|
||||||
info.author = reference.mid(startIndex, endIndex - startIndex).trimmed();
|
source.author = reference.mid(startIndex, endIndex - startIndex).trimmed();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract date (after "Date: " and before the next period)
|
// Extract date (after "Date: " and before the next period)
|
||||||
if (reference.contains("Date: ")) {
|
if (reference.contains("Date: ")) {
|
||||||
int startIndex = reference.indexOf("Date: ") + 6;
|
int startIndex = reference.indexOf("Date: ") + 6;
|
||||||
int endIndex = reference.indexOf('.', startIndex);
|
int endIndex = reference.indexOf('.', startIndex);
|
||||||
info.date = reference.mid(startIndex, endIndex - startIndex).trimmed();
|
source.date = reference.mid(startIndex, endIndex - startIndex).trimmed();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract file name (after "In " and before the "[Context]")
|
// Extract file name (after "In " and before the "[Context]")
|
||||||
if (reference.contains("In ") && reference.contains(". [Context]")) {
|
if (reference.contains("In ") && reference.contains(". [Context]")) {
|
||||||
int startIndex = reference.indexOf("In ") + 3;
|
int startIndex = reference.indexOf("In ") + 3;
|
||||||
int endIndex = reference.indexOf(". [Context]", startIndex);
|
int endIndex = reference.indexOf(". [Context]", startIndex);
|
||||||
info.file = reference.mid(startIndex, endIndex - startIndex).trimmed();
|
source.file = reference.mid(startIndex, endIndex - startIndex).trimmed();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract page number (after "Page " and before the next space)
|
// Extract page number (after "Page " and before the next space)
|
||||||
@ -436,7 +365,7 @@ public:
|
|||||||
int startIndex = reference.indexOf("Page ") + 5;
|
int startIndex = reference.indexOf("Page ") + 5;
|
||||||
int endIndex = reference.indexOf(' ', startIndex);
|
int endIndex = reference.indexOf(' ', startIndex);
|
||||||
if (endIndex == -1) endIndex = reference.length();
|
if (endIndex == -1) endIndex = reference.length();
|
||||||
info.page = reference.mid(startIndex, endIndex - startIndex).toInt();
|
excerpt.page = reference.mid(startIndex, endIndex - startIndex).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract lines (after "Lines " and before the next space or hyphen)
|
// Extract lines (after "Lines " and before the next space or hyphen)
|
||||||
@ -446,18 +375,18 @@ public:
|
|||||||
if (endIndex == -1) endIndex = reference.length();
|
if (endIndex == -1) endIndex = reference.length();
|
||||||
int hyphenIndex = reference.indexOf('-', startIndex);
|
int hyphenIndex = reference.indexOf('-', startIndex);
|
||||||
if (hyphenIndex != -1 && hyphenIndex < endIndex) {
|
if (hyphenIndex != -1 && hyphenIndex < endIndex) {
|
||||||
info.from = reference.mid(startIndex, hyphenIndex - startIndex).toInt();
|
excerpt.from = reference.mid(startIndex, hyphenIndex - startIndex).toInt();
|
||||||
info.to = reference.mid(hyphenIndex + 1, endIndex - hyphenIndex - 1).toInt();
|
excerpt.to = reference.mid(hyphenIndex + 1, endIndex - hyphenIndex - 1).toInt();
|
||||||
} else {
|
} else {
|
||||||
info.from = reference.mid(startIndex, endIndex - startIndex).toInt();
|
excerpt.from = reference.mid(startIndex, endIndex - startIndex).toInt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info.text = context;
|
excerpt.text = context;
|
||||||
sources.append(info);
|
source.excerpts = QList{ excerpt };
|
||||||
|
sources.append(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
c.sources = sources;
|
c.sources = sources;
|
||||||
c.consolidatedSources = consolidateSources(sources);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
beginInsertRows(QModelIndex(), m_chatItems.size(), m_chatItems.size());
|
beginInsertRows(QModelIndex(), m_chatItems.size(), m_chatItems.size());
|
||||||
|
@ -1106,7 +1106,7 @@ Rectangle {
|
|||||||
Layout.preferredWidth: childrenRect.width
|
Layout.preferredWidth: childrenRect.width
|
||||||
Layout.preferredHeight: childrenRect.height
|
Layout.preferredHeight: childrenRect.height
|
||||||
visible: {
|
visible: {
|
||||||
if (consolidatedSources.length === 0)
|
if (sources.length === 0)
|
||||||
return false
|
return false
|
||||||
if (!MySettings.localDocsShowReferences)
|
if (!MySettings.localDocsShowReferences)
|
||||||
return false
|
return false
|
||||||
@ -1134,9 +1134,9 @@ Rectangle {
|
|||||||
sourceSize.height: 24
|
sourceSize.height: 24
|
||||||
mipmap: true
|
mipmap: true
|
||||||
source: {
|
source: {
|
||||||
if (typeof consolidatedSources === 'undefined'
|
if (typeof sources === 'undefined'
|
||||||
|| typeof consolidatedSources[0] === 'undefined'
|
|| typeof sources[0] === 'undefined'
|
||||||
|| consolidatedSources[0].url === "")
|
|| sources[0].url === "")
|
||||||
return "qrc:/gpt4all/icons/db.svg";
|
return "qrc:/gpt4all/icons/db.svg";
|
||||||
else
|
else
|
||||||
return "qrc:/gpt4all/icons/globe.svg";
|
return "qrc:/gpt4all/icons/globe.svg";
|
||||||
@ -1151,7 +1151,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: qsTr("%1 Sources").arg(consolidatedSources.length)
|
text: qsTr("%1 Sources").arg(sources.length)
|
||||||
padding: 0
|
padding: 0
|
||||||
font.pixelSize: theme.fontSizeLarge
|
font.pixelSize: theme.fontSizeLarge
|
||||||
font.bold: true
|
font.bold: true
|
||||||
@ -1199,7 +1199,7 @@ Rectangle {
|
|||||||
Layout.column: 1
|
Layout.column: 1
|
||||||
Layout.topMargin: 5
|
Layout.topMargin: 5
|
||||||
visible: {
|
visible: {
|
||||||
if (consolidatedSources.length === 0)
|
if (sources.length === 0)
|
||||||
return false
|
return false
|
||||||
if (!MySettings.localDocsShowReferences)
|
if (!MySettings.localDocsShowReferences)
|
||||||
return false
|
return false
|
||||||
@ -1240,9 +1240,9 @@ Rectangle {
|
|||||||
id: flow
|
id: flow
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: 10
|
spacing: 10
|
||||||
visible: consolidatedSources.length !== 0
|
visible: sources.length !== 0
|
||||||
Repeater {
|
Repeater {
|
||||||
model: consolidatedSources
|
model: sources
|
||||||
|
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
radius: 10
|
radius: 10
|
||||||
@ -1361,7 +1361,7 @@ Rectangle {
|
|||||||
return false;
|
return false;
|
||||||
if (MySettings.suggestionMode === 2) // Off
|
if (MySettings.suggestionMode === 2) // Off
|
||||||
return false;
|
return false;
|
||||||
if (MySettings.suggestionMode === 0 && consolidatedSources.length === 0) // LocalDocs only
|
if (MySettings.suggestionMode === 0 && sources.length === 0) // LocalDocs only
|
||||||
return false;
|
return false;
|
||||||
return currentChat.responseState === Chat.GeneratingQuestions || currentChat.generatedQuestions.length !== 0;
|
return currentChat.responseState === Chat.GeneratingQuestions || currentChat.generatedQuestions.length !== 0;
|
||||||
}
|
}
|
||||||
|
@ -408,12 +408,8 @@ QHttpServerResponse Server::handleCompletionRequest(const QHttpServerRequest &re
|
|||||||
message.insert("role", "assistant");
|
message.insert("role", "assistant");
|
||||||
message.insert("content", result);
|
message.insert("content", result);
|
||||||
choice.insert("message", message);
|
choice.insert("message", message);
|
||||||
if (MySettings::globalInstance()->localDocsShowReferences()) {
|
if (MySettings::globalInstance()->localDocsShowReferences())
|
||||||
QJsonArray references;
|
choice.insert("references", SourceExcerpt::toJson(infos));
|
||||||
for (const auto &ref : infos)
|
|
||||||
references.append(ref.toJson());
|
|
||||||
choice.insert("references", references);
|
|
||||||
}
|
|
||||||
choices.append(choice);
|
choices.append(choice);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -426,12 +422,8 @@ QHttpServerResponse Server::handleCompletionRequest(const QHttpServerRequest &re
|
|||||||
choice.insert("index", index++);
|
choice.insert("index", index++);
|
||||||
choice.insert("logprobs", QJsonValue::Null); // We don't support
|
choice.insert("logprobs", QJsonValue::Null); // We don't support
|
||||||
choice.insert("finish_reason", responseTokens == max_tokens ? "length" : "stop");
|
choice.insert("finish_reason", responseTokens == max_tokens ? "length" : "stop");
|
||||||
if (MySettings::globalInstance()->localDocsShowReferences()) {
|
if (MySettings::globalInstance()->localDocsShowReferences())
|
||||||
QJsonArray references;
|
choice.insert("references", SourceExcerpt::toJson(infos));
|
||||||
for (const auto &ref : infos)
|
|
||||||
references.append(ref.toJson());
|
|
||||||
choice.insert("references", references);
|
|
||||||
}
|
|
||||||
choices.append(choice);
|
choices.append(choice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,53 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonValue>
|
#include <QJsonValue>
|
||||||
|
|
||||||
|
QString SourceExcerpt::toJson(const QList<SourceExcerpt> &sources)
|
||||||
|
{
|
||||||
|
if (sources.isEmpty())
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
QJsonArray resultsArray;
|
||||||
|
for (const auto &source : sources) {
|
||||||
|
QJsonObject sourceObj;
|
||||||
|
sourceObj["date"] = source.date;
|
||||||
|
sourceObj["collection"] = source.collection;
|
||||||
|
sourceObj["path"] = source.path;
|
||||||
|
sourceObj["file"] = source.file;
|
||||||
|
sourceObj["url"] = source.url;
|
||||||
|
sourceObj["favicon"] = source.favicon;
|
||||||
|
sourceObj["title"] = source.title;
|
||||||
|
sourceObj["author"] = source.author;
|
||||||
|
sourceObj["description"] = source.description;
|
||||||
|
|
||||||
|
QJsonArray excerptsArray;
|
||||||
|
for (const auto &excerpt : source.excerpts) {
|
||||||
|
QJsonObject excerptObj;
|
||||||
|
excerptObj["text"] = excerpt.text;
|
||||||
|
if (excerpt.page != -1)
|
||||||
|
excerptObj["page"] = excerpt.page;
|
||||||
|
if (excerpt.from != -1)
|
||||||
|
excerptObj["from"] = excerpt.from;
|
||||||
|
if (excerpt.to != -1)
|
||||||
|
excerptObj["to"] = excerpt.to;
|
||||||
|
excerptsArray.append(excerptObj);
|
||||||
|
}
|
||||||
|
sourceObj["excerpts"] = excerptsArray;
|
||||||
|
|
||||||
|
resultsArray.append(sourceObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject jsonObj;
|
||||||
|
jsonObj["results"] = resultsArray;
|
||||||
|
|
||||||
|
QJsonDocument doc(jsonObj);
|
||||||
|
return doc.toJson(QJsonDocument::Compact);
|
||||||
|
}
|
||||||
|
|
||||||
QList<SourceExcerpt> SourceExcerpt::fromJson(const QString &json, QString &errorString)
|
QList<SourceExcerpt> SourceExcerpt::fromJson(const QString &json, QString &errorString)
|
||||||
{
|
{
|
||||||
|
if (json.isEmpty())
|
||||||
|
return QList<SourceExcerpt>();
|
||||||
|
|
||||||
QJsonParseError err;
|
QJsonParseError err;
|
||||||
QJsonDocument document = QJsonDocument::fromJson(json.toUtf8(), &err);
|
QJsonDocument document = QJsonDocument::fromJson(json.toUtf8(), &err);
|
||||||
if (err.error != QJsonParseError::NoError) {
|
if (err.error != QJsonParseError::NoError) {
|
||||||
@ -44,7 +89,7 @@ QList<SourceExcerpt> SourceExcerpt::fromJson(const QString &json, QString &error
|
|||||||
SourceExcerpt source;
|
SourceExcerpt source;
|
||||||
source.date = result["date"].toString();
|
source.date = result["date"].toString();
|
||||||
if (result.contains("collection"))
|
if (result.contains("collection"))
|
||||||
source.collection = result["text"].toString();
|
source.collection = result["collection"].toString();
|
||||||
if (result.contains("path"))
|
if (result.contains("path"))
|
||||||
source.path = result["path"].toString();
|
source.path = result["path"].toString();
|
||||||
if (result.contains("file"))
|
if (result.contains("file"))
|
||||||
@ -61,15 +106,6 @@ QList<SourceExcerpt> SourceExcerpt::fromJson(const QString &json, QString &error
|
|||||||
source.author = result["description"].toString();
|
source.author = result["description"].toString();
|
||||||
|
|
||||||
for (int i = 0; i < textExcerpts.size(); ++i) {
|
for (int i = 0; i < textExcerpts.size(); ++i) {
|
||||||
SourceExcerpt excerpt;
|
|
||||||
excerpt.date = source.date;
|
|
||||||
excerpt.collection = source.collection;
|
|
||||||
excerpt.path = source.path;
|
|
||||||
excerpt.file = source.file;
|
|
||||||
excerpt.url = source.url;
|
|
||||||
excerpt.favicon = source.favicon;
|
|
||||||
excerpt.title = source.title;
|
|
||||||
excerpt.author = source.author;
|
|
||||||
if (!textExcerpts[i].isObject()) {
|
if (!textExcerpts[i].isObject()) {
|
||||||
errorString = "result excerpt is not an object";
|
errorString = "result excerpt is not an object";
|
||||||
return QList<SourceExcerpt>();
|
return QList<SourceExcerpt>();
|
||||||
@ -79,6 +115,7 @@ QList<SourceExcerpt> SourceExcerpt::fromJson(const QString &json, QString &error
|
|||||||
errorString = "result excerpt is does not have text field";
|
errorString = "result excerpt is does not have text field";
|
||||||
return QList<SourceExcerpt>();
|
return QList<SourceExcerpt>();
|
||||||
}
|
}
|
||||||
|
Excerpt excerpt;
|
||||||
excerpt.text = excerptObj["text"].toString();
|
excerpt.text = excerptObj["text"].toString();
|
||||||
if (excerptObj.contains("page"))
|
if (excerptObj.contains("page"))
|
||||||
excerpt.page = excerptObj["page"].toInt();
|
excerpt.page = excerptObj["page"].toInt();
|
||||||
@ -86,8 +123,9 @@ QList<SourceExcerpt> SourceExcerpt::fromJson(const QString &json, QString &error
|
|||||||
excerpt.from = excerptObj["from"].toInt();
|
excerpt.from = excerptObj["from"].toInt();
|
||||||
if (excerptObj.contains("to"))
|
if (excerptObj.contains("to"))
|
||||||
excerpt.to = excerptObj["to"].toInt();
|
excerpt.to = excerptObj["to"].toInt();
|
||||||
excerpts.append(excerpt);
|
source.excerpts.append(excerpt);
|
||||||
}
|
}
|
||||||
|
excerpts.append(source);
|
||||||
}
|
}
|
||||||
return excerpts;
|
return excerpts;
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,23 @@
|
|||||||
|
|
||||||
using namespace Qt::Literals::StringLiterals;
|
using namespace Qt::Literals::StringLiterals;
|
||||||
|
|
||||||
|
struct Excerpt {
|
||||||
|
QString text; // [Required] The text actually used in the augmented context
|
||||||
|
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
|
||||||
|
bool operator==(const Excerpt &other) const {
|
||||||
|
return text == other.text && page == other.page && from == other.from && to == other.to;
|
||||||
|
}
|
||||||
|
bool operator!=(const Excerpt &other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Q_DECLARE_METATYPE(Excerpt)
|
||||||
|
|
||||||
struct SourceExcerpt {
|
struct SourceExcerpt {
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
Q_PROPERTY(QString date MEMBER date)
|
Q_PROPERTY(QString date MEMBER date)
|
||||||
Q_PROPERTY(QString text MEMBER text)
|
|
||||||
Q_PROPERTY(QString collection MEMBER collection)
|
Q_PROPERTY(QString collection MEMBER collection)
|
||||||
Q_PROPERTY(QString path MEMBER path)
|
Q_PROPERTY(QString path MEMBER path)
|
||||||
Q_PROPERTY(QString file MEMBER file)
|
Q_PROPERTY(QString file MEMBER file)
|
||||||
@ -20,14 +33,12 @@ struct SourceExcerpt {
|
|||||||
Q_PROPERTY(QString title MEMBER title)
|
Q_PROPERTY(QString title MEMBER title)
|
||||||
Q_PROPERTY(QString author MEMBER author)
|
Q_PROPERTY(QString author MEMBER author)
|
||||||
Q_PROPERTY(QString description MEMBER description)
|
Q_PROPERTY(QString description MEMBER description)
|
||||||
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)
|
Q_PROPERTY(QString fileUri READ fileUri STORED false)
|
||||||
|
Q_PROPERTY(QString text READ text STORED false)
|
||||||
|
Q_PROPERTY(QList<Excerpt> excerpts MEMBER excerpts)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QString date; // [Required] The creation or the last modification date whichever is latest
|
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 collection; // [Optional] The name of the collection
|
||||||
QString path; // [Optional] The full path
|
QString path; // [Optional] The full path
|
||||||
QString file; // [Optional] The name of the file, but not the full path
|
QString file; // [Optional] The name of the file, but not the full path
|
||||||
@ -36,9 +47,26 @@ public:
|
|||||||
QString title; // [Optional] The title of the document
|
QString title; // [Optional] The title of the document
|
||||||
QString author; // [Optional] The author of the document
|
QString author; // [Optional] The author of the document
|
||||||
QString description; // [Optional] The description of the source
|
QString description; // [Optional] The description of the source
|
||||||
int page = -1; // [Optional] The page where the text was found
|
QList<Excerpt> excerpts;// [Required] The list of excerpts
|
||||||
int from = -1; // [Optional] The line number where the text begins
|
|
||||||
int to = -1; // [Optional] The line number where the text ends
|
// Returns a human readable string containing all the excerpts
|
||||||
|
QString text() const {
|
||||||
|
QStringList formattedExcerpts;
|
||||||
|
for (const auto& excerpt : excerpts) {
|
||||||
|
QString formattedExcerpt = excerpt.text;
|
||||||
|
if (excerpt.page != -1) {
|
||||||
|
formattedExcerpt += QStringLiteral(" (Page: %1").arg(excerpt.page);
|
||||||
|
if (excerpt.from != -1 && excerpt.to != -1) {
|
||||||
|
formattedExcerpt += QStringLiteral(", Lines: %1-%2").arg(excerpt.from).arg(excerpt.to);
|
||||||
|
}
|
||||||
|
formattedExcerpt += QStringLiteral(")");
|
||||||
|
} else if (excerpt.from != -1 && excerpt.to != -1) {
|
||||||
|
formattedExcerpt += QStringLiteral(" (Lines: %1-%2)").arg(excerpt.from).arg(excerpt.to);
|
||||||
|
}
|
||||||
|
formattedExcerpts.append(formattedExcerpt);
|
||||||
|
}
|
||||||
|
return formattedExcerpts.join(QStringLiteral("\n---\n"));
|
||||||
|
}
|
||||||
|
|
||||||
QString fileUri() const {
|
QString fileUri() const {
|
||||||
// QUrl reserved chars that are not UNSAFE_PATH according to glib/gconvert.c
|
// QUrl reserved chars that are not UNSAFE_PATH according to glib/gconvert.c
|
||||||
@ -55,25 +83,7 @@ public:
|
|||||||
return u"file://"_s + escaped;
|
return u"file://"_s + escaped;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject toJson() const
|
static QString toJson(const QList<SourceExcerpt> &sources);
|
||||||
{
|
|
||||||
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("description", description);
|
|
||||||
result.insert("page", page);
|
|
||||||
result.insert("from", from);
|
|
||||||
result.insert("to", to);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QList<SourceExcerpt> fromJson(const QString &json, QString &errorString);
|
static QList<SourceExcerpt> fromJson(const QString &json, QString &errorString);
|
||||||
|
|
||||||
bool operator==(const SourceExcerpt &other) const {
|
bool operator==(const SourceExcerpt &other) const {
|
||||||
|
Loading…
Reference in New Issue
Block a user