From a3527e14421c04fec529d89a24b91cb2ad96c1f3 Mon Sep 17 00:00:00 2001 From: Petr Mironychev <9195189+Palm1r@users.noreply.github.com> Date: Thu, 20 Nov 2025 23:25:00 +0100 Subject: [PATCH] fix: Remove image dublicate (#271) --- ChatView/ChatModel.cpp | 26 +++++++++++++++++++++++++ ChatView/ChatModel.hpp | 4 ++++ ChatView/ChatRootView.cpp | 15 ++++++++++++++ ChatView/ChatRootView.hpp | 1 + ChatView/ClientInterface.cpp | 18 ++--------------- ChatView/qml/RootItem.qml | 14 +++++++++---- ChatView/qml/chatparts/ChatItem.qml | 17 +--------------- ChatView/qml/controls/SplitDropZone.qml | 26 +++++++++++-------------- 8 files changed, 70 insertions(+), 51 deletions(-) diff --git a/ChatView/ChatModel.cpp b/ChatView/ChatModel.cpp index ddc9e13..12c8827 100644 --- a/ChatView/ChatModel.cpp +++ b/ChatView/ChatModel.cpp @@ -20,8 +20,11 @@ #include "ChatModel.hpp" #include #include +#include +#include #include #include +#include #include #include "ChatAssistantSettings.hpp" @@ -91,6 +94,19 @@ QVariant ChatModel::data(const QModelIndex &index, int role) const imageMap["fileName"] = image.fileName; imageMap["storedPath"] = image.storedPath; imageMap["mediaType"] = image.mediaType; + + // Generate proper file URL for cross-platform compatibility + if (!m_chatFilePath.isEmpty()) { + QFileInfo fileInfo(m_chatFilePath); + QString baseName = fileInfo.completeBaseName(); + QString dirPath = fileInfo.absolutePath(); + QString imagesFolder = QDir(dirPath).filePath(baseName + "_images"); + QString fullPath = QDir(imagesFolder).filePath(image.storedPath); + imageMap["imageUrl"] = QUrl::fromLocalFile(fullPath).toString(); + } else { + imageMap["imageUrl"] = QString(); + } + imagesList.append(imageMap); } return imagesList; @@ -549,4 +565,14 @@ void ChatModel::updateFileEditStatus(const QString &editId, const QString &statu } } +void ChatModel::setChatFilePath(const QString &filePath) +{ + m_chatFilePath = filePath; +} + +QString ChatModel::chatFilePath() const +{ + return m_chatFilePath; +} + } // namespace QodeAssist::Chat diff --git a/ChatView/ChatModel.hpp b/ChatView/ChatModel.hpp index 735cf50..1ad4331 100644 --- a/ChatView/ChatModel.hpp +++ b/ChatView/ChatModel.hpp @@ -101,6 +101,9 @@ public: void setLoadingFromHistory(bool loading); bool isLoadingFromHistory() const; + + void setChatFilePath(const QString &filePath); + QString chatFilePath() const; signals: void tokensThresholdChanged(); @@ -116,6 +119,7 @@ private: QVector m_messages; bool m_loadingFromHistory = false; + QString m_chatFilePath; }; } // namespace QodeAssist::Chat diff --git a/ChatView/ChatRootView.cpp b/ChatView/ChatRootView.cpp index 147a213..ef92b31 100644 --- a/ChatView/ChatRootView.cpp +++ b/ChatView/ChatRootView.cpp @@ -601,6 +601,21 @@ void ChatRootView::showAddImageDialog() } } +QStringList ChatRootView::convertUrlsToLocalPaths(const QVariantList &urls) const +{ + QStringList localPaths; + for (const QVariant &urlVariant : urls) { + QUrl url(urlVariant.toString()); + if (url.isLocalFile()) { + QString localPath = url.toLocalFile(); + if (!localPath.isEmpty()) { + localPaths.append(localPath); + } + } + } + return localPaths; +} + void ChatRootView::calculateMessageTokensCount(const QString &message) { m_messageTokensCount = Context::TokenUtils::estimateTokens(message); diff --git a/ChatView/ChatRootView.hpp b/ChatView/ChatRootView.hpp index 00a775f..55480d5 100644 --- a/ChatView/ChatRootView.hpp +++ b/ChatView/ChatRootView.hpp @@ -88,6 +88,7 @@ public: Q_INVOKABLE void showLinkFilesDialog(); Q_INVOKABLE void addFilesToLinkList(const QStringList &filePaths); Q_INVOKABLE void removeFileFromLinkList(int index); + Q_INVOKABLE QStringList convertUrlsToLocalPaths(const QVariantList &urls) const; Q_INVOKABLE void showAddImageDialog(); Q_INVOKABLE bool isImageFile(const QString &filePath) const; Q_INVOKABLE void calculateMessageTokensCount(const QString &message); diff --git a/ChatView/ClientInterface.cpp b/ChatView/ClientInterface.cpp index 14a5243..142f9eb 100644 --- a/ChatView/ClientInterface.cpp +++ b/ChatView/ClientInterface.cpp @@ -183,22 +183,7 @@ void ClientInterface::sendMessage( messages.append(apiMessage); } - if (!imageAttachments.isEmpty() && provider->supportImage() && !messages.isEmpty()) { - for (int i = messages.size() - 1; i >= 0; --i) { - if (messages[i].role == "user") { - auto newImages = loadImagesFromStorage(imageAttachments); - if (!newImages.isEmpty()) { - if (messages[i].images.has_value()) { - messages[i].images.value().append(newImages); - } else { - messages[i].images = newImages; - } - LOG_MESSAGE(QString("Added %1 new image(s) to message").arg(newImages.size())); - } - break; - } - } - } else if (!imageFiles.isEmpty() && !provider->supportImage()) { + if (!imageFiles.isEmpty() && !provider->supportImage()) { LOG_MESSAGE(QString("Provider %1 doesn't support images, %2 ignored") .arg(provider->name(), QString::number(imageFiles.size()))); } @@ -522,6 +507,7 @@ QVector ClientInterface::loadImagesFromStorage(const Q void ClientInterface::setChatFilePath(const QString &filePath) { m_chatFilePath = filePath; + m_chatModel->setChatFilePath(filePath); } QString ClientInterface::chatFilePath() const diff --git a/ChatView/qml/RootItem.qml b/ChatView/qml/RootItem.qml index b28d947..c61cdc3 100644 --- a/ChatView/qml/RootItem.qml +++ b/ChatView/qml/RootItem.qml @@ -61,12 +61,18 @@ ChatRootView { SplitDropZone { anchors.fill: parent - onFilesDroppedToAttach: (filePaths) => { - root.addFilesToAttachList(filePaths) + onFilesDroppedToAttach: (urlStrings) => { + var localPaths = root.convertUrlsToLocalPaths(urlStrings) + if (localPaths.length > 0) { + root.addFilesToAttachList(localPaths) + } } - onFilesDroppedToLink: (filePaths) => { - root.addFilesToLinkList(filePaths) + onFilesDroppedToLink: (urlStrings) => { + var localPaths = root.convertUrlsToLocalPaths(urlStrings) + if (localPaths.length > 0) { + root.addFilesToLinkList(localPaths) + } } } diff --git a/ChatView/qml/chatparts/ChatItem.qml b/ChatView/qml/chatparts/ChatItem.qml index 988e690..404f879 100644 --- a/ChatView/qml/chatparts/ChatItem.qml +++ b/ChatView/qml/chatparts/ChatItem.qml @@ -263,12 +263,7 @@ Rectangle { Layout.maximumWidth: parent.parent.maxImageWidth Layout.maximumHeight: parent.parent.maxImageHeight - source: { - if (!itemData.storedPath || !root.chatFilePath) return ""; - var fileInfo = chatFileInfo(root.chatFilePath); - var imagesFolder = fileInfo.dir + "/" + fileInfo.baseName + "_images"; - return "file://" + imagesFolder + "/" + itemData.storedPath; - } + source: itemData.imageUrl ? itemData.imageUrl : "" sourceSize.width: parent.parent.maxImageWidth sourceSize.height: parent.parent.maxImageHeight @@ -303,14 +298,4 @@ Rectangle { } } } - - function chatFileInfo(filePath) { - if (!filePath) return {dir: "", baseName: ""}; - var lastSlash = filePath.lastIndexOf("/"); - var dir = lastSlash >= 0 ? filePath.substring(0, lastSlash) : ""; - var fileName = lastSlash >= 0 ? filePath.substring(lastSlash + 1) : filePath; - var lastDot = fileName.lastIndexOf("."); - var baseName = lastDot >= 0 ? fileName.substring(0, lastDot) : fileName; - return {dir: dir, baseName: baseName}; - } } diff --git a/ChatView/qml/controls/SplitDropZone.qml b/ChatView/qml/controls/SplitDropZone.qml index 24b22d6..8b9260a 100644 --- a/ChatView/qml/controls/SplitDropZone.qml +++ b/ChatView/qml/controls/SplitDropZone.qml @@ -23,8 +23,8 @@ import QtQuick.Controls Item { id: root - signal filesDroppedToAttach(var filePaths) - signal filesDroppedToLink(var filePaths) + signal filesDroppedToAttach(var urlStrings) // Array of URL strings (file://...) + signal filesDroppedToLink(var urlStrings) // Array of URL strings (file://...) property string activeZone: "" @@ -216,21 +216,17 @@ Item { splitDropOverlay.visible = false root.activeZone = "" - if (drop.hasUrls) { - var filePaths = [] + if (drop.hasUrls && drop.urls.length > 0) { + // Convert URLs to array of strings for C++ processing + var urlStrings = [] for (var i = 0; i < drop.urls.length; i++) { - var url = drop.urls[i].toString() - if (url.startsWith("file://")) { - filePaths.push(decodeURIComponent(url.replace(/^file:\/\//, ''))) - } + urlStrings.push(drop.urls[i].toString()) } - - if (filePaths.length > 0) { - if (targetZone === "right") { - root.filesDroppedToLink(filePaths) - } else { - root.filesDroppedToAttach(filePaths) - } + + if (targetZone === "right") { + root.filesDroppedToLink(urlStrings) + } else { + root.filesDroppedToAttach(urlStrings) } } }