feat: 支持多图像上传和预览
This commit is contained in:
12
index.html
12
index.html
@@ -88,23 +88,25 @@
|
|||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<h5><i class="fas fa-upload me-2"></i>上传参考图像</h5>
|
<h5><i class="fas fa-upload me-2"></i>上传参考图像</h5>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-4">
|
||||||
<div class="border-2 border-dashed rounded p-4 text-center h-100 d-flex flex-column justify-content-center" id="dropZone">
|
<div class="border-2 border-dashed rounded p-4 text-center h-100 d-flex flex-column justify-content-center" id="dropZone">
|
||||||
<i class="fas fa-cloud-upload-alt fa-3x text-muted mb-3"></i>
|
<i class="fas fa-cloud-upload-alt fa-3x text-muted mb-3"></i>
|
||||||
<p class="text-muted">拖拽图像到此处或点击选择文件</p>
|
<p class="text-muted">拖拽图像到此处或点击选择文件 (最多10张)</p>
|
||||||
<input type="file" class="d-none" id="imageInput" accept="image/*">
|
<input type="file" class="d-none" id="imageInput" accept="image/*" multiple>
|
||||||
<button class="btn btn-outline-primary" onclick="document.getElementById('imageInput').click()">
|
<button class="btn btn-outline-primary" onclick="document.getElementById('imageInput').click()">
|
||||||
选择图像
|
选择图像
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-8">
|
||||||
<div id="imagePreview" class="h-100 d-flex align-items-center justify-content-center">
|
<div class="row" id="imagePreview" style="max-height: 250px; overflow-y: auto; border: 1px solid #dee2e6; border-radius: .25rem; padding-top: 1rem;">
|
||||||
|
<div class="col-12 d-flex h-100 align-items-center justify-content-center">
|
||||||
<p class="text-muted">未选择图像</p>
|
<p class="text-muted">未选择图像</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 图像生成模块 -->
|
<!-- 图像生成模块 -->
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
|
|||||||
42
script.js
42
script.js
@@ -17,7 +17,7 @@ let currentModalInstance = null; // 当前模态框实例
|
|||||||
// 配置常量
|
// 配置常量
|
||||||
const CONFIG = {
|
const CONFIG = {
|
||||||
MAX_FILE_SIZE: 10485760, // 10MB
|
MAX_FILE_SIZE: 10485760, // 10MB
|
||||||
MAX_FILES_PER_UPLOAD: 1, // 限制为只上传一张图片
|
MAX_FILES_PER_UPLOAD: 10, // 限制为最多上传10张图片
|
||||||
SUPPORTED_IMAGE_FORMATS: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
|
SUPPORTED_IMAGE_FORMATS: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
|
||||||
MAX_CHAT_HISTORY: 50, // 减少聊天历史记录数量以节省存储空间
|
MAX_CHAT_HISTORY: 50, // 减少聊天历史记录数量以节省存储空间
|
||||||
MAX_GENERATED_IMAGES: 20, // 减少存储的图像数量以防止存储空间溢出
|
MAX_GENERATED_IMAGES: 20, // 减少存储的图像数量以防止存储空间溢出
|
||||||
@@ -718,7 +718,8 @@ const apiService = {
|
|||||||
const payload = {
|
const payload = {
|
||||||
model: settings.model,
|
model: settings.model,
|
||||||
messages: messages,
|
messages: messages,
|
||||||
stream: false
|
stream: false,
|
||||||
|
"modalities": ["image","text"]
|
||||||
};
|
};
|
||||||
|
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
@@ -1485,6 +1486,10 @@ const uiController = {
|
|||||||
// 显示图像预览
|
// 显示图像预览
|
||||||
displayImagePreview: function(imageData) {
|
displayImagePreview: function(imageData) {
|
||||||
const preview = document.getElementById('imagePreview');
|
const preview = document.getElementById('imagePreview');
|
||||||
|
const placeholderContainer = preview.querySelector('.col-12.d-flex');
|
||||||
|
if (placeholderContainer) {
|
||||||
|
placeholderContainer.remove();
|
||||||
|
}
|
||||||
|
|
||||||
// 确保图像数据是Blob URL用于显示,但保持原始数据用于其他操作
|
// 确保图像数据是Blob URL用于显示,但保持原始数据用于其他操作
|
||||||
let displayUrl;
|
let displayUrl;
|
||||||
@@ -1498,19 +1503,25 @@ const uiController = {
|
|||||||
displayUrl = imageData.data;
|
displayUrl = imageData.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
preview.innerHTML = `
|
const wrapper = document.createElement('div');
|
||||||
<div class="card h-100">
|
wrapper.className = 'col-md-4 mb-3';
|
||||||
<img src="${displayUrl}" class="card-img-top image-preview h-75" alt="${imageData.name}" loading="lazy" style="object-fit: contain;">
|
wrapper.dataset.imageId = imageData.id; // Store imageId here
|
||||||
|
|
||||||
|
wrapper.innerHTML = `
|
||||||
|
<div class="card h-100 uploaded-image-card">
|
||||||
|
<img src="${displayUrl}" class="card-img-top image-preview" alt="${imageData.name}" loading="lazy" style="object-fit: contain; height: 100px;">
|
||||||
<div class="card-body p-2">
|
<div class="card-body p-2">
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
<small class="text-muted">${utils.formatFileSize(imageData.size)}</small>
|
<small class="text-muted text-truncate" title="${imageData.name}">${imageData.name}</small>
|
||||||
<button class="btn btn-sm btn-outline-danger" onclick="app.removeImage(${imageData.id})" title="删除">
|
<button class="btn btn-sm btn-outline-danger" onclick="app.removeImage(${imageData.id})" title="删除">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<small class="text-muted">${utils.formatFileSize(imageData.size)}</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
preview.appendChild(wrapper);
|
||||||
},
|
},
|
||||||
|
|
||||||
// 保存聊天历史 - 新增消息时调用
|
// 保存聊天历史 - 新增消息时调用
|
||||||
@@ -1783,11 +1794,12 @@ const fileHandler = {
|
|||||||
|
|
||||||
// 处理文件
|
// 处理文件
|
||||||
handleFiles: function(files) {
|
handleFiles: function(files) {
|
||||||
const preview = document.getElementById('imagePreview');
|
if (uploadedImages.length + files.length > CONFIG.MAX_FILES_PER_UPLOAD) {
|
||||||
preview.innerHTML = '';
|
utils.showNotification(`最多只能上传 ${CONFIG.MAX_FILES_PER_UPLOAD} 张图片。`, 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 限制文件数量
|
const filesToProcess = Array.from(files);
|
||||||
const filesToProcess = Array.from(files).slice(0, CONFIG.MAX_FILES_PER_UPLOAD);
|
|
||||||
|
|
||||||
filesToProcess.forEach(file => {
|
filesToProcess.forEach(file => {
|
||||||
try {
|
try {
|
||||||
@@ -2123,11 +2135,13 @@ const app = {
|
|||||||
removeImage: function(imageId) {
|
removeImage: function(imageId) {
|
||||||
uploadedImages = uploadedImages.filter(img => img.id !== imageId);
|
uploadedImages = uploadedImages.filter(img => img.id !== imageId);
|
||||||
const preview = document.getElementById('imagePreview');
|
const preview = document.getElementById('imagePreview');
|
||||||
|
const imageElement = preview.querySelector(`[data-image-id="${imageId}"]`);
|
||||||
|
if (imageElement) {
|
||||||
|
imageElement.remove();
|
||||||
|
}
|
||||||
|
|
||||||
if (uploadedImages.length === 0) {
|
if (uploadedImages.length === 0) {
|
||||||
preview.innerHTML = '<p class="text-muted">未选择图像</p>';
|
preview.innerHTML = '<div class="col-12 d-flex h-100 align-items-center justify-content-center"><p class="text-muted">未选择图像</p></div>';
|
||||||
} else {
|
|
||||||
preview.innerHTML = '';
|
|
||||||
uploadedImages.forEach(img => uiController.displayImagePreview(img));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user