imaginecolorng / index.html
gaur3009's picture
Update index.html
a90cc76 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RookusAI - Dress Recoloring with CosXL</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>
.gradient-bg {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}
.upload-area {
border: 2px dashed #cbd5e0;
transition: all 0.3s ease;
}
.upload-area:hover {
border-color: #667eea;
}
.upload-area.active {
border-color: #667eea;
background-color: #ebf4ff;
}
.color-option {
width: 40px;
height: 40px;
border-radius: 50%;
cursor: pointer;
transition: transform 0.2s;
}
.color-option:hover {
transform: scale(1.1);
}
.color-option.selected {
border: 3px solid #4f46e5;
transform: scale(1.1);
}
.result-container {
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
.loading-spinner {
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.history-item {
transition: all 0.2s ease;
}
.history-item:hover {
transform: translateY(-2px);
}
</style>
</head>
<body class="gradient-bg min-h-screen">
<!-- Navigation -->
<nav class="bg-white shadow-sm">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex items-center">
<div class="flex-shrink-0 flex items-center">
<i class="fas fa-tshirt text-indigo-600 text-2xl mr-2"></i>
<span class="text-xl font-bold text-gray-900">RookusAI</span>
</div>
</div>
<div class="hidden sm:ml-6 sm:flex sm:items-center">
<a href="#" class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-indigo-600">Home</a>
<a href="#" class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-indigo-600">Features</a>
<a href="#" class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-indigo-600">Pricing</a>
<a href="#" class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-indigo-600">About</a>
</div>
<div class="hidden sm:ml-6 sm:flex sm:items-center">
<button class="px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Sign In
</button>
</div>
<div class="-mr-2 flex items-center sm:hidden">
<button type="button" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500" aria-controls="mobile-menu" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<i class="fas fa-bars"></i>
</button>
</div>
</div>
</div>
</nav>
<!-- Main Content -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div class="text-center mb-12">
<h1 class="text-4xl font-extrabold text-gray-900 sm:text-5xl sm:tracking-tight lg:text-6xl">
AI-Powered Dress Recoloring
</h1>
<p class="mt-5 max-w-xl mx-auto text-xl text-gray-500">
Transform your outfit with CosXL's advanced AI technology. Simply upload a photo and choose your desired color.
</p>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<!-- Upload and Controls Section -->
<div class="bg-white rounded-xl shadow-md p-6">
<div class="mb-6">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Upload Your Dress Photo</h2>
<div id="upload-area" class="upload-area rounded-lg p-8 text-center cursor-pointer">
<input type="file" id="file-input" class="hidden" accept="image/*">
<div id="upload-content">
<i class="fas fa-cloud-upload-alt text-4xl text-gray-400 mb-3"></i>
<p class="text-gray-500">Drag & drop your photo here or click to browse</p>
<p class="text-sm text-gray-400 mt-2">Supports JPG, PNG (Max 5MB)</p>
</div>
<img id="preview-image" class="hidden max-w-full h-auto rounded-lg mx-auto" alt="Preview">
</div>
</div>
<div class="mb-6">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Color Instructions</h2>
<div class="mb-4">
<label for="color-prompt" class="block text-sm font-medium text-gray-700 mb-1">Describe the color change</label>
<input type="text" id="color-prompt" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500" placeholder="e.g. Change the dress to emerald green">
</div>
<div class="grid grid-cols-5 gap-4 mb-4">
<div class="color-option bg-red-500 selected" data-prompt="change the dress to bright red" title="Red"></div>
<div class="color-option bg-blue-500" data-prompt="change the dress to deep blue" title="Blue"></div>
<div class="color-option bg-green-500" data-prompt="change the dress to emerald green" title="Green"></div>
<div class="color-option bg-yellow-400" data-prompt="change the dress to golden yellow" title="Yellow"></div>
<div class="color-option bg-purple-500" data-prompt="change the dress to royal purple" title="Purple"></div>
<div class="color-option bg-pink-500" data-prompt="change the dress to hot pink" title="Pink"></div>
<div class="color-option bg-indigo-500" data-prompt="change the dress to indigo" title="Indigo"></div>
<div class="color-option bg-teal-500" data-prompt="change the dress to teal" title="Teal"></div>
<div class="color-option bg-gray-500" data-prompt="change the dress to charcoal gray" title="Gray"></div>
<div class="color-option bg-black" data-prompt="change the dress to black" title="Black"></div>
</div>
</div>
<div class="mb-6">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Advanced Options</h2>
<div class="space-y-4">
<div>
<label for="negative-prompt" class="block text-sm font-medium text-gray-700 mb-1">Negative Prompt</label>
<input type="text" id="negative-prompt" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500" placeholder="Things you don't want in the result">
</div>
<div>
<label for="guidance-scale" class="block text-sm font-medium text-gray-700 mb-1">Guidance Scale</label>
<input type="range" id="guidance-scale" min="1" max="20" value="7" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
<div class="flex justify-between text-xs text-gray-500 mt-1">
<span>1</span>
<span>7</span>
<span>20</span>
</div>
</div>
<div>
<label for="steps" class="block text-sm font-medium text-gray-700 mb-1">Steps</label>
<input type="range" id="steps" min="10" max="50" value="20" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
<div class="flex justify-between text-xs text-gray-500 mt-1">
<span>10</span>
<span>20</span>
<span>50</span>
</div>
</div>
</div>
</div>
<button id="generate-btn" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-4 rounded-lg transition duration-200 flex items-center justify-center">
<span>Recolor Dress</span>
<i id="generate-icon" class="fas fa-magic ml-2"></i>
<i id="loading-icon" class="fas fa-circle-notch loading-spinner ml-2 hidden"></i>
</button>
</div>
<!-- Results Section -->
<div class="bg-white rounded-xl shadow-md p-6">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Your Results</h2>
<div id="result-container" class="result-container bg-gray-50 rounded-lg p-4 hidden">
<div class="flex justify-between mb-4">
<h3 class="text-lg font-medium text-gray-700">Original</h3>
<h3 class="text-lg font-medium text-gray-700">Recolored</h3>
</div>
<div class="grid grid-cols-2 gap-4">
<img id="original-image" class="w-full h-auto rounded-lg" alt="Original">
<img id="result-image" class="w-full h-auto rounded-lg" alt="Result">
</div>
<div class="mt-4 flex justify-between">
<button id="download-btn" class="bg-indigo-100 hover:bg-indigo-200 text-indigo-700 font-medium py-2 px-4 rounded-lg transition duration-200">
<i class="fas fa-download mr-2"></i> Download
</button>
<button id="save-btn" class="bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium py-2 px-4 rounded-lg transition duration-200">
<i class="fas fa-save mr-2"></i> Save to Profile
</button>
<button id="share-btn" class="bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium py-2 px-4 rounded-lg transition duration-200">
<i class="fas fa-share-alt mr-2"></i> Share
</button>
</div>
</div>
<div id="empty-state" class="text-center py-12">
<i class="fas fa-tshirt text-4xl text-gray-300 mb-4"></i>
<h3 class="text-lg font-medium text-gray-500">No results yet</h3>
<p class="text-gray-400 mt-1">Upload a photo and click "Recolor Dress" to see the magic!</p>
</div>
<div id="history-section" class="mt-8 hidden">
<h3 class="text-lg font-medium text-gray-700 mb-3">Recent Recolors</h3>
<div class="grid grid-cols-3 gap-3" id="history-grid">
<!-- History items will be added here dynamically -->
</div>
</div>
</div>
</div>
<!-- Features Section -->
<div class="mt-16">
<h2 class="text-3xl font-bold text-center text-gray-900 mb-12">Why Choose RookusAI with CosXL?</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<div class="bg-white p-6 rounded-xl shadow-sm hover:shadow-md transition duration-200">
<div class="text-indigo-600 mb-4">
<i class="fas fa-bolt text-3xl"></i>
</div>
<h3 class="text-xl font-semibold mb-2">Advanced AI Technology</h3>
<p class="text-gray-500">Powered by CosXL's state-of-the-art image editing capabilities for realistic color transformations.</p>
</div>
<div class="bg-white p-6 rounded-xl shadow-sm hover:shadow-md transition duration-200">
<div class="text-indigo-600 mb-4">
<i class="fas fa-palette text-3xl"></i>
</div>
<h3 class="text-xl font-semibold mb-2">Precise Color Control</h3>
<p class="text-gray-500">Get exactly the color you want with natural-looking results that maintain fabric textures.</p>
</div>
<div class="bg-white p-6 rounded-xl shadow-sm hover:shadow-md transition duration-200">
<div class="text-indigo-600 mb-4">
<i class="fas fa-lock text-3xl"></i>
</div>
<h3 class="text-xl font-semibold mb-2">Secure Processing</h3>
<p class="text-gray-500">Your images are processed securely through CosXL's API with no permanent storage.</p>
</div>
</div>
</div>
</div>
<!-- Footer -->
<footer class="bg-white mt-16">
<div class="max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-2 md:grid-cols-4 gap-8">
<div>
<h3 class="text-sm font-semibold text-gray-400 tracking-wider uppercase">Product</h3>
<ul class="mt-4 space-y-2">
<li><a href="#" class="text-base text-gray-500 hover:text-indigo-600">Features</a></li>
<li><a href="#" class="text-base text-gray-500 hover:text-indigo-600">Pricing</a></li>
<li><a href="#" class="text-base text-gray-500 hover:text-indigo-600">API</a></li>
</ul>
</div>
<div>
<h3 class="text-sm font-semibold text-gray-400 tracking-wider uppercase">Resources</h3>
<ul class="mt-4 space-y-2">
<li><a href="#" class="text-base text-gray-500 hover:text-indigo-600">Documentation</a></li>
<li><a href="#" class="text-base text-gray-500 hover:text-indigo-600">Tutorials</a></li>
<li><a href="#" class="text-base text-gray-500 hover:text-indigo-600">Blog</a></li>
</ul>
</div>
<div>
<h3 class="text-sm font-semibold text-gray-400 tracking-wider uppercase">Company</h3>
<ul class="mt-4 space-y-2">
<li><a href="#" class="text-base text-gray-500 hover:text-indigo-600">About</a></li>
<li><a href="#" class="text-base text-gray-500 hover:text-indigo-600">Careers</a></li>
<li><a href="#" class="text-base text-gray-500 hover:text-indigo-600">Contact</a></li>
</ul>
</div>
<div>
<h3 class="text-sm font-semibold text-gray-400 tracking-wider uppercase">Legal</h3>
<ul class="mt-4 space-y-2">
<li><a href="#" class="text-base text-gray-500 hover:text-indigo-600">Privacy</a></li>
<li><a href="#" class="text-base text-gray-500 hover:text-indigo-600">Terms</a></li>
<li><a href="#" class="text-base text-gray-500 hover:text-indigo-600">License</a></li>
</ul>
</div>
</div>
<div class="mt-8 border-t border-gray-200 pt-8 flex flex-col md:flex-row justify-between items-center">
<p class="text-gray-500 text-sm">© 2023 RookusAI. All rights reserved.</p>
<div class="flex space-x-6 mt-4 md:mt-0">
<a href="#" class="text-gray-400 hover:text-indigo-600">
<i class="fab fa-twitter"></i>
</a>
<a href="#" class="text-gray-400 hover:text-indigo-600">
<i class="fab fa-instagram"></i>
</a>
<a href="#" class="text-gray-400 hover:text-indigo-600">
<i class="fab fa-facebook"></i>
</a>
<a href="#" class="text-gray-400 hover:text-indigo-600">
<i class="fab fa-github"></i>
</a>
</div>
</div>
</div>
</footer>
<script>
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const uploadArea = document.getElementById('upload-area');
const fileInput = document.getElementById('file-input');
const uploadContent = document.getElementById('upload-content');
const previewImage = document.getElementById('preview-image');
const generateBtn = document.getElementById('generate-btn');
const generateIcon = document.getElementById('generate-icon');
const loadingIcon = document.getElementById('loading-icon');
const resultContainer = document.getElementById('result-container');
const emptyState = document.getElementById('empty-state');
const originalImage = document.getElementById('original-image');
const resultImage = document.getElementById('result-image');
const colorOptions = document.querySelectorAll('.color-option');
const colorPrompt = document.getElementById('color-prompt');
const negativePrompt = document.getElementById('negative-prompt');
const guidanceScale = document.getElementById('guidance-scale');
const steps = document.getElementById('steps');
const downloadBtn = document.getElementById('download-btn');
const historySection = document.getElementById('history-section');
const historyGrid = document.getElementById('history-grid');
// API Endpoint
const API_URL = 'https://cors-anywhere.herokuapp.com/https://multimodalart-cosxl.hf.space/run/predict';
// Current state
let uploadedImage = null;
let uploadedFile = null;
// Event Listeners
uploadArea.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
if (file.size > 5 * 1024 * 1024) {
alert('File size exceeds 5MB limit');
return;
}
uploadedFile = file;
const reader = new FileReader();
reader.onload = (event) => {
uploadedImage = event.target.result;
previewImage.src = uploadedImage;
previewImage.classList.remove('hidden');
uploadContent.classList.add('hidden');
uploadArea.classList.add('active');
};
reader.readAsDataURL(file);
}
});
uploadArea.addEventListener('dragover', (e) => {
e.preventDefault();
uploadArea.classList.add('active');
});
uploadArea.addEventListener('dragleave', () => {
uploadArea.classList.remove('active');
});
uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
uploadArea.classList.remove('active');
const file = e.dataTransfer.files[0];
if (file && file.type.match('image.*')) {
if (file.size > 5 * 1024 * 1024) {
alert('File size exceeds 5MB limit');
return;
}
uploadedFile = file;
const reader = new FileReader();
reader.onload = (event) => {
uploadedImage = event.target.result;
previewImage.src = uploadedImage;
previewImage.classList.remove('hidden');
uploadContent.classList.add('hidden');
};
reader.readAsDataURL(file);
}
});
colorOptions.forEach(option => {
option.addEventListener('click', () => {
document.querySelector('.color-option.selected').classList.remove('selected');
option.classList.add('selected');
colorPrompt.value = option.dataset.prompt;
});
});
generateBtn.addEventListener('click', async () => {
if (!uploadedImage) {
alert('Please upload an image first');
return;
}
if (!colorPrompt.value.trim()) {
alert('Please describe the color change you want');
return;
}
// Show loading state
generateIcon.classList.add('hidden');
loadingIcon.classList.remove('hidden');
generateBtn.disabled = true;
try {
// Prepare form data according to Gradio's API requirements
const formData = new FormData();
formData.append('data', JSON.stringify({
'data': [
await fileToBase64(uploadedFile), // Image
colorPrompt.value, // Prompt
negativePrompt.value, // Negative prompt
Number(guidanceScale.value), // Guidance scale
Number(steps.value) // Steps
],
'fn_index': 0 // Important for Gradio interface
}));
// API request with proper headers
const response = await fetch(API_URL, {
method: 'POST',
body: formData
});
// Handle response errors
if (!response.ok) {
const errorText = await response.text();
throw new Error(`API Error: ${response.status} - ${errorText}`);
}
const result = await response.json();
// Handle Gradio response format
if (!result.data || !result.data[0]) {
throw new Error('Invalid API response format');
}
// Display results
originalImage.src = URL.createObjectURL(uploadedFile);
resultImage.src = `data:image/png;base64,${result.data[0]}`;
emptyState.classList.add('hidden');
resultContainer.classList.remove('hidden');
// Add to history
addToHistory(URL.createObjectURL(uploadedFile), `data:image/png;base64,${result.data[0]}`);
historySection.classList.remove('hidden');
} catch (error) {
console.error('API Error:', error);
alert(`Error processing image: ${error.message}`);
} finally {
generateIcon.classList.remove('hidden');
loadingIcon.classList.add('hidden');
generateBtn.disabled = false;
}
});
// Helper function to convert file to base64
async function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result.split(',')[1]);
reader.onerror = error => reject(error);
});
}
downloadBtn.addEventListener('click', () => {
if (resultImage.src) {
const link = document.createElement('a');
link.href = resultImage.src;
link.download = 'rookusai-recolored-dress.png';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
});
function addToHistory(originalUrl, resultUrl) {
const historyItem = document.createElement('div');
historyItem.className = 'history-item bg-white p-2 rounded-lg shadow-sm cursor-pointer';
historyItem.innerHTML = `
<img src="${resultUrl}" class="w-full h-auto rounded" alt="History item">
`;
historyItem.addEventListener('click', () => {
originalImage.src = originalUrl;
resultImage.src = resultUrl;
emptyState.classList.add('hidden');
resultContainer.classList.remove('hidden');
});
historyGrid.insertBefore(historyItem, historyGrid.firstChild);
if (historyGrid.children.length > 6) {
historyGrid.removeChild(historyGrid.lastChild);
}
}
});
</script>
</body>
</html>