fix: Remove image dublicate (#271)

This commit is contained in:
Petr Mironychev
2025-11-20 23:25:00 +01:00
committed by GitHub
parent 24565dc81f
commit a3527e1442
8 changed files with 70 additions and 51 deletions

View File

@ -20,8 +20,11 @@
#include "ChatModel.hpp"
#include <utils/aspects.h>
#include <QDateTime>
#include <QDir>
#include <QFileInfo>
#include <QJsonDocument>
#include <QJsonObject>
#include <QUrl>
#include <QtQml>
#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

View File

@ -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<Message> m_messages;
bool m_loadingFromHistory = false;
QString m_chatFilePath;
};
} // namespace QodeAssist::Chat

View File

@ -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);

View File

@ -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);

View File

@ -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<LLMCore::ImageAttachment> ClientInterface::loadImagesFromStorage(const Q
void ClientInterface::setChatFilePath(const QString &filePath)
{
m_chatFilePath = filePath;
m_chatModel->setChatFilePath(filePath);
}
QString ClientInterface::chatFilePath() const

View File

@ -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)
}
}
}

View File

@ -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};
}
}

View File

@ -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)
}
}
}