Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Image to Prompt Generator</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
.dropzone { | |
border: 2px dashed #9CA3AF; | |
transition: all 0.3s ease; | |
} | |
.dropzone.active { | |
border-color: #3B82F6; | |
background-color: rgba(59, 130, 246, 0.05); | |
} | |
.prompt-card { | |
transition: all 0.3s ease; | |
} | |
.prompt-card:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1); | |
} | |
.loading-spinner { | |
animation: spin 1s linear infinite; | |
} | |
@keyframes spin { | |
0% { transform: rotate(0deg); } | |
100% { transform: rotate(360deg); } | |
} | |
</style> | |
</head> | |
<body class="bg-gray-50 min-h-screen"> | |
<div class="container mx-auto px-4 py-12"> | |
<!-- Header --> | |
<header class="text-center mb-12"> | |
<h1 class="text-4xl font-bold text-gray-800 mb-2">Image to Prompt Generator</h1> | |
<p class="text-gray-600 max-w-2xl mx-auto"> | |
Upload any image and get creative AI prompts generated automatically. Perfect for artists, writers, and content creators! | |
</p> | |
</header> | |
<!-- Main Content --> | |
<div class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden"> | |
<!-- Upload Section --> | |
<div class="p-8"> | |
<div id="dropzone" class="dropzone rounded-lg p-12 text-center cursor-pointer"> | |
<div class="flex flex-col items-center justify-center"> | |
<div class="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4"> | |
<i class="fas fa-cloud-upload-alt text-blue-500 text-2xl"></i> | |
</div> | |
<h3 class="text-lg font-medium text-gray-700 mb-2">Drag & drop your image here</h3> | |
<p class="text-gray-500 mb-4">or click to browse files</p> | |
<input type="file" id="fileInput" class="hidden" accept="image/*"> | |
<button id="uploadBtn" class="bg-blue-500 hover:bg-blue-600 text-white px-6 py-2 rounded-lg transition"> | |
Select Image | |
</button> | |
</div> | |
</div> | |
<div id="imagePreviewContainer" class="mt-6 hidden"> | |
<h3 class="text-lg font-medium text-gray-700 mb-3">Image Preview</h3> | |
<div class="flex flex-col md:flex-row gap-6"> | |
<div class="w-full md:w-1/2"> | |
<img id="imagePreview" src="#" alt="Preview" class="w-full h-auto rounded-lg border border-gray-200"> | |
</div> | |
<div class="w-full md:w-1/2"> | |
<div class="flex items-center mb-3"> | |
<h4 class="text-md font-medium text-gray-700">Prompt Style</h4> | |
<div class="ml-auto relative"> | |
<select id="styleSelect" class="appearance-none bg-gray-100 border border-gray-200 rounded-md px-4 py-2 pr-8 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
<option value="creative">Creative</option> | |
<option value="detailed">Detailed</option> | |
<option value="minimal">Minimal</option> | |
<option value="artistic">Artistic</option> | |
<option value="technical">Technical</option> | |
</select> | |
<div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"> | |
<i class="fas fa-chevron-down text-sm"></i> | |
</div> | |
</div> | |
</div> | |
<button id="generateBtn" class="w-full bg-blue-500 hover:bg-blue-600 text-white px-6 py-3 rounded-lg transition flex items-center justify-center"> | |
<span>Generate Prompts</span> | |
<i id="generateIcon" class="fas fa-magic ml-2"></i> | |
</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Loading State --> | |
<div id="loadingState" class="p-8 hidden"> | |
<div class="flex flex-col items-center justify-center py-12"> | |
<div class="w-16 h-16 border-4 border-blue-500 border-t-transparent rounded-full loading-spinner mb-4"></div> | |
<h3 class="text-lg font-medium text-gray-700 mb-2">Analyzing your image</h3> | |
<p class="text-gray-500">This may take a few moments...</p> | |
</div> | |
</div> | |
<!-- Results Section --> | |
<div id="resultsSection" class="p-8 hidden"> | |
<div class="flex items-center justify-between mb-6"> | |
<h2 class="text-xl font-bold text-gray-800">Generated Prompts</h2> | |
<button id="copyAllBtn" class="text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 px-4 py-2 rounded-md transition flex items-center"> | |
<i class="fas fa-copy mr-2"></i> | |
Copy All | |
</button> | |
</div> | |
<div id="promptsContainer" class="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
<!-- Prompts will be inserted here by JavaScript --> | |
</div> | |
<div class="mt-8 pt-6 border-t border-gray-200"> | |
<h3 class="text-lg font-medium text-gray-700 mb-4">Try another image</h3> | |
<button id="newImageBtn" class="bg-gray-100 hover:bg-gray-200 text-gray-700 px-6 py-2 rounded-lg transition"> | |
<i class="fas fa-redo mr-2"></i> | |
Start Over | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- Features Section --> | |
<div class="max-w-4xl mx-auto mt-16"> | |
<h2 class="text-2xl font-bold text-gray-800 mb-8 text-center">How It Works</h2> | |
<div class="grid grid-cols-1 md:grid-cols-3 gap-8"> | |
<div class="bg-white p-6 rounded-xl shadow-sm"> | |
<div class="w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center mb-4"> | |
<i class="fas fa-upload text-blue-500"></i> | |
</div> | |
<h3 class="text-lg font-medium text-gray-800 mb-2">Upload Image</h3> | |
<p class="text-gray-600">Drag & drop or select any image from your device. We support JPG, PNG, and WEBP formats.</p> | |
</div> | |
<div class="bg-white p-6 rounded-xl shadow-sm"> | |
<div class="w-12 h-12 bg-purple-100 rounded-full flex items-center justify-center mb-4"> | |
<i class="fas fa-brain text-purple-500"></i> | |
</div> | |
<h3 class="text-lg font-medium text-gray-800 mb-2">AI Analysis</h3> | |
<p class="text-gray-600">Our advanced AI analyzes the visual elements, composition, and style of your image.</p> | |
</div> | |
<div class="bg-white p-6 rounded-xl shadow-sm"> | |
<div class="w-12 h-12 bg-green-100 rounded-full flex items-center justify-center mb-4"> | |
<i class="fas fa-lightbulb text-green-500"></i> | |
</div> | |
<h3 class="text-lg font-medium text-gray-800 mb-2">Get Prompts</h3> | |
<p class="text-gray-600">Receive multiple creative prompts tailored to your image's content and your selected style.</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
// DOM Elements | |
const dropzone = document.getElementById('dropzone'); | |
const fileInput = document.getElementById('fileInput'); | |
const uploadBtn = document.getElementById('uploadBtn'); | |
const imagePreviewContainer = document.getElementById('imagePreviewContainer'); | |
const imagePreview = document.getElementById('imagePreview'); | |
const generateBtn = document.getElementById('generateBtn'); | |
const loadingState = document.getElementById('loadingState'); | |
const resultsSection = document.getElementById('resultsSection'); | |
const promptsContainer = document.getElementById('promptsContainer'); | |
const copyAllBtn = document.getElementById('copyAllBtn'); | |
const newImageBtn = document.getElementById('newImageBtn'); | |
const styleSelect = document.getElementById('styleSelect'); | |
const generateIcon = document.getElementById('generateIcon'); | |
// Event Listeners | |
uploadBtn.addEventListener('click', () => fileInput.click()); | |
fileInput.addEventListener('change', handleFileSelect); | |
dropzone.addEventListener('dragover', handleDragOver); | |
dropzone.addEventListener('dragleave', handleDragLeave); | |
dropzone.addEventListener('drop', handleDrop); | |
generateBtn.addEventListener('click', generatePrompts); | |
copyAllBtn.addEventListener('click', copyAllPrompts); | |
newImageBtn.addEventListener('click', resetForm); | |
// Functions | |
function handleFileSelect(e) { | |
const file = e.target.files[0]; | |
if (file && file.type.match('image.*')) { | |
displayImagePreview(file); | |
} | |
} | |
function handleDragOver(e) { | |
e.preventDefault(); | |
dropzone.classList.add('active'); | |
} | |
function handleDragLeave() { | |
dropzone.classList.remove('active'); | |
} | |
function handleDrop(e) { | |
e.preventDefault(); | |
dropzone.classList.remove('active'); | |
const file = e.dataTransfer.files[0]; | |
if (file && file.type.match('image.*')) { | |
displayImagePreview(file); | |
} | |
} | |
function displayImagePreview(file) { | |
const reader = new FileReader(); | |
reader.onload = function(e) { | |
imagePreview.src = e.target.result; | |
imagePreviewContainer.classList.remove('hidden'); | |
dropzone.classList.add('hidden'); | |
}; | |
reader.readAsDataURL(file); | |
} | |
function generatePrompts() { | |
// Show loading state | |
imagePreviewContainer.classList.add('hidden'); | |
loadingState.classList.remove('hidden'); | |
generateIcon.classList.replace('fa-magic', 'fa-spinner'); | |
generateIcon.classList.add('loading-spinner'); | |
// Simulate API call with timeout | |
setTimeout(() => { | |
loadingState.classList.add('hidden'); | |
resultsSection.classList.remove('hidden'); | |
displayGeneratedPrompts(); | |
}, 2500); | |
} | |
function displayGeneratedPrompts() { | |
// Clear previous prompts | |
promptsContainer.innerHTML = ''; | |
// Get selected style | |
const style = styleSelect.value; | |
// Generate sample prompts based on style (in a real app, these would come from an API) | |
const samplePrompts = { | |
creative: [ | |
"A surreal dreamscape where the elements of this image come alive in unexpected ways", | |
"Imagine this scene as part of a fantasy world with magical enhancements", | |
"Reinterpret this composition in the style of a famous artist's painting" | |
], | |
detailed: [ | |
"A highly detailed description of all visual elements including colors, textures, lighting, and spatial relationships", | |
"Break down the composition into its fundamental elements with precise terminology", | |
"Technical analysis of the image's color palette, contrast, and focal points" | |
], | |
minimal: [ | |
"Simple, clean interpretation focusing only on essential elements", | |
"Reduced to basic shapes and colors while maintaining recognizability", | |
"Minimalist version emphasizing negative space and simplicity" | |
], | |
artistic: [ | |
"Artistic interpretation with emphasis on brush strokes and painterly qualities", | |
"Describe how to recreate this image using traditional art techniques", | |
"Analysis of the artistic style and potential influences" | |
], | |
technical: [ | |
"Technical specifications for recreating this image in digital art software", | |
"Detailed breakdown of camera settings if this were a photograph", | |
"Color theory analysis with hex codes for major color areas" | |
] | |
}; | |
// Create prompt cards | |
samplePrompts[style].forEach((prompt, index) => { | |
const promptCard = document.createElement('div'); | |
promptCard.className = 'prompt-card bg-white border border-gray-200 rounded-lg p-4 hover:shadow-md cursor-pointer'; | |
promptCard.innerHTML = ` | |
<div class="flex items-start mb-3"> | |
<div class="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center flex-shrink-0 mr-3"> | |
<span class="text-blue-500 font-medium">${index + 1}</span> | |
</div> | |
<p class="text-gray-700 flex-grow">${prompt}</p> | |
</div> | |
<div class="flex justify-end"> | |
<button class="copy-prompt-btn text-sm text-gray-500 hover:text-blue-500 transition"> | |
<i class="fas fa-copy mr-1"></i> | |
Copy | |
</button> | |
</div> | |
`; | |
promptsContainer.appendChild(promptCard); | |
// Add click event to copy button | |
const copyBtn = promptCard.querySelector('.copy-prompt-btn'); | |
copyBtn.addEventListener('click', (e) => { | |
e.stopPropagation(); | |
navigator.clipboard.writeText(prompt); | |
// Show feedback | |
const originalText = copyBtn.innerHTML; | |
copyBtn.innerHTML = '<i class="fas fa-check mr-1"></i> Copied!'; | |
setTimeout(() => { | |
copyBtn.innerHTML = originalText; | |
}, 2000); | |
}); | |
// Add click event to select prompt | |
promptCard.addEventListener('click', () => { | |
navigator.clipboard.writeText(prompt); | |
promptCard.classList.add('border-blue-500', 'bg-blue-50'); | |
setTimeout(() => { | |
promptCard.classList.remove('border-blue-500', 'bg-blue-50'); | |
}, 1000); | |
}); | |
}); | |
} | |
function copyAllPrompts() { | |
const prompts = Array.from(document.querySelectorAll('.prompt-card p')).map(p => p.textContent); | |
navigator.clipboard.writeText(prompts.join('\n\n')); | |
// Show feedback | |
const originalText = copyAllBtn.innerHTML; | |
copyAllBtn.innerHTML = '<i class="fas fa-check mr-2"></i> All Copied!'; | |
setTimeout(() => { | |
copyAllBtn.innerHTML = originalText; | |
}, 2000); | |
} | |
function resetForm() { | |
fileInput.value = ''; | |
imagePreview.src = '#'; | |
resultsSection.classList.add('hidden'); | |
imagePreviewContainer.classList.add('hidden'); | |
dropzone.classList.remove('hidden'); | |
generateIcon.classList.replace('fa-spinner', 'fa-magic'); | |
generateIcon.classList.remove('loading-spinner'); | |
} | |
}); | |
</script> |