fix: Create _content folder only when there is an attachment (#297)

This commit is contained in:
Dinesh Bala
2025-12-16 18:04:10 +05:45
committed by GitHub
parent e86e58337a
commit e3f464c54e

View File

@ -38,14 +38,6 @@ SerializationResult ChatSerializer::saveToFile(const ChatModel *model, const QSt
return {false, "Failed to create directory structure"}; return {false, "Failed to create directory structure"};
} }
QString contentFolder = getChatContentFolder(filePath);
QDir dir;
if (!dir.exists(contentFolder)) {
if (!dir.mkpath(contentFolder)) {
LOG_MESSAGE(QString("Warning: Failed to create content folder: %1").arg(contentFolder));
}
}
QFile file(filePath); QFile file(filePath);
if (!file.open(QIODevice::WriteOnly)) { if (!file.open(QIODevice::WriteOnly)) {
return {false, QString("Failed to open file for writing: %1").arg(filePath)}; return {false, QString("Failed to open file for writing: %1").arg(filePath)};
@ -88,21 +80,22 @@ SerializationResult ChatSerializer::loadFromFile(ChatModel *model, const QString
return {true, QString()}; return {true, QString()};
} }
QJsonObject ChatSerializer::serializeMessage(const ChatModel::Message &message, const QString &chatFilePath) QJsonObject ChatSerializer::serializeMessage(
const ChatModel::Message &message, const QString &chatFilePath)
{ {
QJsonObject messageObj; QJsonObject messageObj;
messageObj["role"] = static_cast<int>(message.role); messageObj["role"] = static_cast<int>(message.role);
messageObj["content"] = message.content; messageObj["content"] = message.content;
messageObj["id"] = message.id; messageObj["id"] = message.id;
if (message.isRedacted) { if (message.isRedacted) {
messageObj["isRedacted"] = true; messageObj["isRedacted"] = true;
} }
if (!message.signature.isEmpty()) { if (!message.signature.isEmpty()) {
messageObj["signature"] = message.signature; messageObj["signature"] = message.signature;
} }
if (!message.attachments.isEmpty()) { if (!message.attachments.isEmpty()) {
QJsonArray attachmentsArray; QJsonArray attachmentsArray;
for (const auto &attachment : message.attachments) { for (const auto &attachment : message.attachments) {
@ -113,7 +106,7 @@ QJsonObject ChatSerializer::serializeMessage(const ChatModel::Message &message,
} }
messageObj["attachments"] = attachmentsArray; messageObj["attachments"] = attachmentsArray;
} }
if (!message.images.isEmpty()) { if (!message.images.isEmpty()) {
QJsonArray imagesArray; QJsonArray imagesArray;
for (const auto &image : message.images) { for (const auto &image : message.images) {
@ -125,11 +118,12 @@ QJsonObject ChatSerializer::serializeMessage(const ChatModel::Message &message,
} }
messageObj["images"] = imagesArray; messageObj["images"] = imagesArray;
} }
return messageObj; return messageObj;
} }
ChatModel::Message ChatSerializer::deserializeMessage(const QJsonObject &json, const QString &chatFilePath) ChatModel::Message ChatSerializer::deserializeMessage(
const QJsonObject &json, const QString &chatFilePath)
{ {
ChatModel::Message message; ChatModel::Message message;
message.role = static_cast<ChatModel::ChatRole>(json["role"].toInt()); message.role = static_cast<ChatModel::ChatRole>(json["role"].toInt());
@ -137,7 +131,7 @@ ChatModel::Message ChatSerializer::deserializeMessage(const QJsonObject &json, c
message.id = json["id"].toString(); message.id = json["id"].toString();
message.isRedacted = json["isRedacted"].toBool(false); message.isRedacted = json["isRedacted"].toBool(false);
message.signature = json["signature"].toString(); message.signature = json["signature"].toString();
if (json.contains("attachments")) { if (json.contains("attachments")) {
QJsonArray attachmentsArray = json["attachments"].toArray(); QJsonArray attachmentsArray = json["attachments"].toArray();
for (const auto &attachmentValue : attachmentsArray) { for (const auto &attachmentValue : attachmentsArray) {
@ -148,7 +142,7 @@ ChatModel::Message ChatSerializer::deserializeMessage(const QJsonObject &json, c
message.attachments.append(attachment); message.attachments.append(attachment);
} }
} }
if (json.contains("images")) { if (json.contains("images")) {
QJsonArray imagesArray = json["images"].toArray(); QJsonArray imagesArray = json["images"].toArray();
for (const auto &imageValue : imagesArray) { for (const auto &imageValue : imagesArray) {
@ -160,7 +154,7 @@ ChatModel::Message ChatSerializer::deserializeMessage(const QJsonObject &json, c
message.images.append(image); message.images.append(image);
} }
} }
return message; return message;
} }
@ -178,7 +172,8 @@ QJsonObject ChatSerializer::serializeChat(const ChatModel *model, const QString
return root; return root;
} }
bool ChatSerializer::deserializeChat(ChatModel *model, const QJsonObject &json, const QString &chatFilePath) bool ChatSerializer::deserializeChat(
ChatModel *model, const QJsonObject &json, const QString &chatFilePath)
{ {
QJsonArray messagesArray = json["messages"].toArray(); QJsonArray messagesArray = json["messages"].toArray();
QVector<ChatModel::Message> messages; QVector<ChatModel::Message> messages;
@ -189,17 +184,24 @@ bool ChatSerializer::deserializeChat(ChatModel *model, const QJsonObject &json,
} }
model->clear(); model->clear();
model->setLoadingFromHistory(true); model->setLoadingFromHistory(true);
for (const auto &message : messages) { for (const auto &message : messages) {
model->addMessage(message.content, message.role, message.id, message.attachments, message.images, message.isRedacted, message.signature); model->addMessage(
message.content,
message.role,
message.id,
message.attachments,
message.images,
message.isRedacted,
message.signature);
LOG_MESSAGE(QString("Loaded message with %1 image(s), isRedacted=%2, signature length=%3") LOG_MESSAGE(QString("Loaded message with %1 image(s), isRedacted=%2, signature length=%3")
.arg(message.images.size()) .arg(message.images.size())
.arg(message.isRedacted) .arg(message.isRedacted)
.arg(message.signature.length())); .arg(message.signature.length()));
} }
model->setLoadingFromHistory(false); model->setLoadingFromHistory(false);
return true; return true;
@ -217,12 +219,14 @@ bool ChatSerializer::validateVersion(const QString &version)
if (version == VERSION) { if (version == VERSION) {
return true; return true;
} }
if (version == "0.1") { if (version == "0.1") {
LOG_MESSAGE("Loading chat from old format 0.1 - images folder structure has changed from _images to _content"); LOG_MESSAGE(
"Loading chat from old format 0.1 - images folder structure has changed from _images "
"to _content");
return true; return true;
} }
return false; return false;
} }
@ -234,10 +238,11 @@ QString ChatSerializer::getChatContentFolder(const QString &chatFilePath)
return QDir(dirPath).filePath(baseName + "_content"); return QDir(dirPath).filePath(baseName + "_content");
} }
bool ChatSerializer::saveContentToStorage(const QString &chatFilePath, bool ChatSerializer::saveContentToStorage(
const QString &fileName, const QString &chatFilePath,
const QString &base64Data, const QString &fileName,
QString &storedPath) const QString &base64Data,
QString &storedPath)
{ {
QString contentFolder = getChatContentFolder(chatFilePath); QString contentFolder = getChatContentFolder(chatFilePath);
QDir dir; QDir dir;
@ -247,34 +252,34 @@ bool ChatSerializer::saveContentToStorage(const QString &chatFilePath,
return false; return false;
} }
} }
QFileInfo originalFileInfo(fileName); QFileInfo originalFileInfo(fileName);
QString extension = originalFileInfo.suffix(); QString extension = originalFileInfo.suffix();
QString baseName = originalFileInfo.completeBaseName(); QString baseName = originalFileInfo.completeBaseName();
QString uniqueName = QString("%1_%2.%3") QString uniqueName = QString("%1_%2.%3")
.arg(baseName) .arg(baseName)
.arg(QUuid::createUuid().toString(QUuid::WithoutBraces).left(8)) .arg(QUuid::createUuid().toString(QUuid::WithoutBraces).left(8))
.arg(extension); .arg(extension);
QString fullPath = QDir(contentFolder).filePath(uniqueName); QString fullPath = QDir(contentFolder).filePath(uniqueName);
QByteArray contentData = QByteArray::fromBase64(base64Data.toUtf8()); QByteArray contentData = QByteArray::fromBase64(base64Data.toUtf8());
QFile file(fullPath); QFile file(fullPath);
if (!file.open(QIODevice::WriteOnly)) { if (!file.open(QIODevice::WriteOnly)) {
LOG_MESSAGE(QString("Failed to open file for writing: %1").arg(fullPath)); LOG_MESSAGE(QString("Failed to open file for writing: %1").arg(fullPath));
return false; return false;
} }
if (file.write(contentData) == -1) { if (file.write(contentData) == -1) {
LOG_MESSAGE(QString("Failed to write content data: %1").arg(file.errorString())); LOG_MESSAGE(QString("Failed to write content data: %1").arg(file.errorString()));
return false; return false;
} }
file.close(); file.close();
storedPath = uniqueName; storedPath = uniqueName;
LOG_MESSAGE(QString("Saved content: %1 to %2").arg(fileName, fullPath)); LOG_MESSAGE(QString("Saved content: %1 to %2").arg(fileName, fullPath));
return true; return true;
} }
@ -282,16 +287,16 @@ QString ChatSerializer::loadContentFromStorage(const QString &chatFilePath, cons
{ {
QString contentFolder = getChatContentFolder(chatFilePath); QString contentFolder = getChatContentFolder(chatFilePath);
QString fullPath = QDir(contentFolder).filePath(storedPath); QString fullPath = QDir(contentFolder).filePath(storedPath);
QFile file(fullPath); QFile file(fullPath);
if (!file.open(QIODevice::ReadOnly)) { if (!file.open(QIODevice::ReadOnly)) {
LOG_MESSAGE(QString("Failed to open content file: %1").arg(fullPath)); LOG_MESSAGE(QString("Failed to open content file: %1").arg(fullPath));
return QString(); return QString();
} }
QByteArray contentData = file.readAll(); QByteArray contentData = file.readAll();
file.close(); file.close();
return contentData.toBase64(); return contentData.toBase64();
} }