refactor: Reworking attaching files (#280)

chore: Upgrade chat format version
This commit is contained in:
Petr Mironychev
2025-11-28 16:17:25 +01:00
committed by GitHub
parent 22377c8f6a
commit 2d5667d8ca
8 changed files with 264 additions and 70 deletions

View File

@ -30,7 +30,7 @@
namespace QodeAssist::Chat {
const QString ChatSerializer::VERSION = "0.1";
const QString ChatSerializer::VERSION = "0.2";
SerializationResult ChatSerializer::saveToFile(const ChatModel *model, const QString &filePath)
{
@ -38,11 +38,11 @@ SerializationResult ChatSerializer::saveToFile(const ChatModel *model, const QSt
return {false, "Failed to create directory structure"};
}
QString imagesFolder = getChatImagesFolder(filePath);
QString contentFolder = getChatContentFolder(filePath);
QDir dir;
if (!dir.exists(imagesFolder)) {
if (!dir.mkpath(imagesFolder)) {
LOG_MESSAGE(QString("Warning: Failed to create images folder: %1").arg(imagesFolder));
if (!dir.exists(contentFolder)) {
if (!dir.mkpath(contentFolder)) {
LOG_MESSAGE(QString("Warning: Failed to create content folder: %1").arg(contentFolder));
}
}
@ -103,6 +103,17 @@ QJsonObject ChatSerializer::serializeMessage(const ChatModel::Message &message,
messageObj["signature"] = message.signature;
}
if (!message.attachments.isEmpty()) {
QJsonArray attachmentsArray;
for (const auto &attachment : message.attachments) {
QJsonObject attachmentObj;
attachmentObj["fileName"] = attachment.filename;
attachmentObj["storedPath"] = attachment.content;
attachmentsArray.append(attachmentObj);
}
messageObj["attachments"] = attachmentsArray;
}
if (!message.images.isEmpty()) {
QJsonArray imagesArray;
for (const auto &image : message.images) {
@ -127,6 +138,17 @@ ChatModel::Message ChatSerializer::deserializeMessage(const QJsonObject &json, c
message.isRedacted = json["isRedacted"].toBool(false);
message.signature = json["signature"].toString();
if (json.contains("attachments")) {
QJsonArray attachmentsArray = json["attachments"].toArray();
for (const auto &attachmentValue : attachmentsArray) {
QJsonObject attachmentObj = attachmentValue.toObject();
Context::ContentFile attachment;
attachment.filename = attachmentObj["fileName"].toString();
attachment.content = attachmentObj["storedPath"].toString();
message.attachments.append(attachment);
}
}
if (json.contains("images")) {
QJsonArray imagesArray = json["images"].toArray();
for (const auto &imageValue : imagesArray) {
@ -192,27 +214,36 @@ bool ChatSerializer::ensureDirectoryExists(const QString &filePath)
bool ChatSerializer::validateVersion(const QString &version)
{
return version == VERSION;
if (version == VERSION) {
return true;
}
if (version == "0.1") {
LOG_MESSAGE("Loading chat from old format 0.1 - images folder structure has changed from _images to _content");
return true;
}
return false;
}
QString ChatSerializer::getChatImagesFolder(const QString &chatFilePath)
QString ChatSerializer::getChatContentFolder(const QString &chatFilePath)
{
QFileInfo fileInfo(chatFilePath);
QString baseName = fileInfo.completeBaseName();
QString dirPath = fileInfo.absolutePath();
return QDir(dirPath).filePath(baseName + "_images");
return QDir(dirPath).filePath(baseName + "_content");
}
bool ChatSerializer::saveImageToStorage(const QString &chatFilePath,
const QString &fileName,
const QString &base64Data,
QString &storedPath)
bool ChatSerializer::saveContentToStorage(const QString &chatFilePath,
const QString &fileName,
const QString &base64Data,
QString &storedPath)
{
QString imagesFolder = getChatImagesFolder(chatFilePath);
QString contentFolder = getChatContentFolder(chatFilePath);
QDir dir;
if (!dir.exists(imagesFolder)) {
if (!dir.mkpath(imagesFolder)) {
LOG_MESSAGE(QString("Failed to create images folder: %1").arg(imagesFolder));
if (!dir.exists(contentFolder)) {
if (!dir.mkpath(contentFolder)) {
LOG_MESSAGE(QString("Failed to create content folder: %1").arg(contentFolder));
return false;
}
}
@ -225,43 +256,43 @@ bool ChatSerializer::saveImageToStorage(const QString &chatFilePath,
.arg(QUuid::createUuid().toString(QUuid::WithoutBraces).left(8))
.arg(extension);
QString fullPath = QDir(imagesFolder).filePath(uniqueName);
QString fullPath = QDir(contentFolder).filePath(uniqueName);
QByteArray imageData = QByteArray::fromBase64(base64Data.toUtf8());
QByteArray contentData = QByteArray::fromBase64(base64Data.toUtf8());
QFile file(fullPath);
if (!file.open(QIODevice::WriteOnly)) {
LOG_MESSAGE(QString("Failed to open file for writing: %1").arg(fullPath));
return false;
}
if (file.write(imageData) == -1) {
LOG_MESSAGE(QString("Failed to write image data: %1").arg(file.errorString()));
if (file.write(contentData) == -1) {
LOG_MESSAGE(QString("Failed to write content data: %1").arg(file.errorString()));
return false;
}
file.close();
storedPath = uniqueName;
LOG_MESSAGE(QString("Saved image: %1 to %2").arg(fileName, fullPath));
LOG_MESSAGE(QString("Saved content: %1 to %2").arg(fileName, fullPath));
return true;
}
QString ChatSerializer::loadImageFromStorage(const QString &chatFilePath, const QString &storedPath)
QString ChatSerializer::loadContentFromStorage(const QString &chatFilePath, const QString &storedPath)
{
QString imagesFolder = getChatImagesFolder(chatFilePath);
QString fullPath = QDir(imagesFolder).filePath(storedPath);
QString contentFolder = getChatContentFolder(chatFilePath);
QString fullPath = QDir(contentFolder).filePath(storedPath);
QFile file(fullPath);
if (!file.open(QIODevice::ReadOnly)) {
LOG_MESSAGE(QString("Failed to open image file: %1").arg(fullPath));
LOG_MESSAGE(QString("Failed to open content file: %1").arg(fullPath));
return QString();
}
QByteArray imageData = file.readAll();
QByteArray contentData = file.readAll();
file.close();
return imageData.toBase64();
return contentData.toBase64();
}
} // namespace QodeAssist::Chat