// Global variables
let uploadedImages = [];
let keywords = [];
let generatedNames = [];
// DOM elements
const dropArea = document.getElementById('drop-area');
const fileInput = document.getElementById('file-input');
const browseBtn = document.getElementById('browse-btn');
const keywordsSection = document.getElementById('keywords-section');
const keywordInput = document.getElementById('keyword-input');
const enhanceBtn = document.getElementById('enhance-btn');
const keywordsDisplay = document.getElementById('keywords-display');
const imagesPreview = document.getElementById('images-preview');
const imagesContainer = document.getElementById('images-container');
const downloadBtn = document.getElementById('download-btn');
// AI Configuration (in a real app, this would be loaded from .env)
const AI_CONFIG = {
API_KEY: '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',
MODEL_NAME: 'deepseek/deepseek-chat-v3-0324:free',
API_URL: 'https://openrouter.ai/api/v1/chat/completions'
};
// Event listeners
document.addEventListener('DOMContentLoaded', () => {
// Upload area event listeners
dropArea.addEventListener('click', () => fileInput.click());
browseBtn.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', handleFileSelect);
// Drag and drop events
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, preventDefaults, false);
});
['dragenter', 'dragover'].forEach(eventName => {
dropArea.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, unhighlight, false);
});
dropArea.addEventListener('drop', handleDrop, false);
// Keyword events
keywordInput.addEventListener('input', toggleEnhanceButton);
enhanceBtn.addEventListener('click', enhanceKeywords);
// Download button
downloadBtn.addEventListener('click', downloadImages);
});
// Prevent default drag behaviors
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
// Highlight drop area when item is dragged over it
function highlight() {
dropArea.classList.add('dragover');
}
// Remove highlight when item is dragged out of drop area
function unhighlight() {
dropArea.classList.remove('dragover');
}
// Handle dropped files
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
handleFiles(files);
}
// Handle file selection
function handleFileSelect(e) {
const files = e.target.files;
handleFiles(files);
}
// Process uploaded files
function handleFiles(files) {
if (files.length === 0) return;
// Convert FileList to Array
const filesArray = Array.from(files);
// Filter only image files
const imageFiles = filesArray.filter(file => file.type.startsWith('image/'));
if (imageFiles.length === 0) {
alert('Please select image files only.');
return;
}
// Clear previous images
uploadedImages = [];
// Process each image file
let processedCount = 0;
imageFiles.forEach(file => {
const reader = new FileReader();
reader.onload = (e) => {
uploadedImages.push({
file: file,
name: file.name,
size: file.size,
type: file.type,
src: e.target.result,
newName: generateFileName(file.name)
});
processedCount++;
// Show keywords section after all files are processed
if (processedCount === imageFiles.length) {
keywordsSection.style.display = 'block';
imagesPreview.style.display = 'block';
updateImagesPreview();
}
};
reader.readAsDataURL(file);
});
}
// Generate a simple filename based on original name
function generateFileName(originalName) {
// Remove extension
const nameWithoutExt = originalName.substring(0, originalName.lastIndexOf('.'));
// Replace non-alphanumeric characters with spaces
const cleanName = nameWithoutExt.replace(/[^a-zA-Z0-9]/g, ' ');
// Capitalize first letter and make it SEO friendly
return cleanName.charAt(0).toUpperCase() + cleanName.slice(1);
}
// Toggle enhance button based on keyword input
function toggleEnhanceButton() {
enhanceBtn.disabled = keywordInput.value.trim() === '';
}
// Enhance keywords with AI
async function enhanceKeywords() {
const keywordText = keywordInput.value.trim();
if (keywordText === '') return;
// Show loading state
enhanceBtn.innerHTML = ' Enhancing...';
enhanceBtn.disabled = true;
try {
// Call AI API to enhance keywords
const enhancedKeywords = await callAIKeywordEnhancement(keywordText);
// Split keywords by comma or space
const newKeywords = enhancedKeywords.split(/[, ]+/).filter(k => k !== '');
// Add new keywords to the list
newKeywords.forEach(keyword => {
if (!keywords.includes(keyword)) {
keywords.push(keyword);
}
});
// Update keywords display
updateKeywordsDisplay();
// Clear input
keywordInput.value = '';
// Generate new filenames for images
await generateNewFileNamesWithAI();
} catch (error) {
console.error('Error enhancing keywords:', error);
alert('An error occurred while enhancing keywords. Please try again.');
} finally {
// Reset button
enhanceBtn.innerHTML = ' Enhance with AI';
enhanceBtn.disabled = keywordInput.value.trim() === '';
}
}
// Call AI API to enhance keywords
async function callAIKeywordEnhancement(keywords) {
const prompt = `Enhance these keywords for SEO image optimization. Provide 10 additional related keywords that would help images rank better in search engines. Return only the keywords separated by commas, nothing else. Keywords: ${keywords}`;
const response = await fetch(AI_CONFIG.API_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${AI_CONFIG.API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: AI_CONFIG.MODEL_NAME,
messages: [
{
role: "user",
content: prompt
}
]
})
});
if (!response.ok) {
throw new Error(`API request failed with status ${response.status}`);
}
const data = await response.json();
return data.choices[0].message.content.trim();
}
// Generate new filenames for images based on keywords using AI
async function generateNewFileNamesWithAI() {
if (keywords.length === 0) return;
// Show loading state for each image
document.querySelectorAll('.new-name-input').forEach(input => {
input.disabled = true;
input.placeholder = 'Generating AI filename...';
});
try {
// Generate new filename for each image
for (let i = 0; i < uploadedImages.length; i++) {
const image = uploadedImages[i];
const keywordString = keywords.slice(0, 5).join(', ');
// Call AI to generate a descriptive filename
const aiGeneratedName = await callAIFilenameGeneration(image.name, keywordString);
// Update the image with the new name
const nameWithoutExt = image.name.substring(0, image.name.lastIndexOf('.'));
const extension = image.name.substring(image.name.lastIndexOf('.'));
const newName = `${aiGeneratedName.substring(0, 50)}${extension}`;
image.newName = newName;
}
// Update images preview
updateImagesPreview();
// Enable download button
downloadBtn.disabled = false;
} catch (error) {
console.error('Error generating filenames:', error);
alert('An error occurred while generating filenames. Please try again.');
// Revert to simple filename generation
generateNewFileNames();
} finally {
// Re-enable inputs
document.querySelectorAll('.new-name-input').forEach(input => {
input.disabled = false;
input.placeholder = '';
});
}
}
// Call AI API to generate filename
async function callAIFilenameGeneration(originalName, keywords) {
const prompt = `Generate an SEO-optimized filename for an image. The original filename is "${originalName}" and the keywords are: ${keywords}. Create a descriptive, SEO-friendly filename that is 3-6 words long. Use only letters, numbers, and hyphens. Do not include the file extension. Return only the filename, nothing else.`;
const response = await fetch(AI_CONFIG.API_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${AI_CONFIG.API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: AI_CONFIG.MODEL_NAME,
messages: [
{
role: "user",
content: prompt
}
]
})
});
if (!response.ok) {
throw new Error(`API request failed with status ${response.status}`);
}
const data = await response.json();
return data.choices[0].message.content.trim().replace(/[^a-zA-Z0-9\- ]/g, '').replace(/\s+/g, '-');
}
// Fallback function to generate new filenames without AI
function generateNewFileNames() {
if (keywords.length === 0) return;
uploadedImages.forEach((image, index) => {
// Combine keywords with the original filename
const keywordString = keywords.slice(0, 3).join(' ');
const nameWithoutExt = image.name.substring(0, image.name.lastIndexOf('.'));
const extension = image.name.substring(image.name.lastIndexOf('.'));
// Create new name
const newName = `${keywordString} ${nameWithoutExt}`.substring(0, 50) + extension;
image.newName = newName;
});
// Update images preview
updateImagesPreview();
// Enable download button
downloadBtn.disabled = false;
}
// Update keywords display
function updateKeywordsDisplay() {
keywordsDisplay.innerHTML = '';
keywords.forEach((keyword, index) => {
const keywordChip = document.createElement('div');
keywordChip.className = 'keyword-chip';
keywordChip.innerHTML = `
${keyword}
`;
keywordsDisplay.appendChild(keywordChip);
});
// Add event listeners to remove buttons
document.querySelectorAll('.remove-keyword').forEach(button => {
button.addEventListener('click', (e) => {
const index = parseInt(e.target.getAttribute('data-index'));
keywords.splice(index, 1);
updateKeywordsDisplay();
generateNewFileNames();
});
});
}
// Update images preview
function updateImagesPreview() {
imagesContainer.innerHTML = '';
uploadedImages.forEach((image, index) => {
const imageCard = document.createElement('div');
imageCard.className = 'image-card';
imageCard.innerHTML = `