editing_platform / index.html
gaur3009's picture
Update index.html
a81f61e verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Professional Image Editor</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a1a2e, #16213e);
color: #fff;
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
text-align: center;
margin-bottom: 30px;
padding: 20px;
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(4px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
background: linear-gradient(45deg, #ff7e5f, #feb47b);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.subtitle {
font-size: 1.2rem;
color: #a0a0c0;
max-width: 700px;
margin: 0 auto;
line-height: 1.6;
}
.app-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
margin-bottom: 40px;
}
@media (max-width: 768px) {
.app-container {
grid-template-columns: 1fr;
}
}
.panel {
background: rgba(30, 30, 50, 0.7);
border-radius: 15px;
padding: 25px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.panel-title {
font-size: 1.5rem;
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
color: #feb47b;
}
.panel-title i {
font-size: 1.8rem;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #d0d0e0;
}
input, textarea {
width: 100%;
padding: 12px 15px;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.2);
background: rgba(20, 20, 40, 0.8);
color: #fff;
font-size: 1rem;
}
textarea {
min-height: 100px;
resize: vertical;
}
input::placeholder, textarea::placeholder {
color: #8888a8;
}
.upload-area {
border: 2px dashed rgba(255, 255, 255, 0.2);
border-radius: 10px;
padding: 30px;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
background: rgba(20, 20, 40, 0.5);
}
.upload-area:hover {
border-color: #ff7e5f;
background: rgba(20, 20, 40, 0.7);
}
.upload-area i {
font-size: 3rem;
color: #ff7e5f;
margin-bottom: 15px;
}
.upload-text {
color: #a0a0c0;
margin-bottom: 15px;
}
.file-input {
display: none;
}
.btn {
background: linear-gradient(45deg, #ff7e5f, #feb47b);
color: white;
border: none;
padding: 14px 25px;
font-size: 1.1rem;
font-weight: 600;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
}
.btn:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(255, 126, 95, 0.4);
}
.btn:disabled {
background: #555575;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.image-container {
position: relative;
overflow: hidden;
border-radius: 10px;
height: 400px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(20, 20, 40, 0.5);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.image-placeholder {
color: #8888a8;
text-align: center;
padding: 20px;
}
.image-placeholder i {
font-size: 4rem;
margin-bottom: 20px;
color: #555575;
}
img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
display: none;
}
.loading {
display: none;
text-align: center;
padding: 20px;
}
.spinner {
border: 4px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top: 4px solid #ff7e5f;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.tips {
background: rgba(30, 30, 50, 0.7);
border-radius: 15px;
padding: 25px;
margin-top: 30px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.tips h2 {
margin-bottom: 20px;
color: #feb47b;
}
.tip {
display: flex;
gap: 15px;
margin-bottom: 15px;
align-items: flex-start;
}
.tip i {
color: #ff7e5f;
font-size: 1.2rem;
margin-top: 3px;
}
.footer {
text-align: center;
margin-top: 40px;
padding: 20px;
color: #8888a8;
font-size: 0.9rem;
}
.api-info {
display: flex;
gap: 10px;
align-items: center;
justify-content: center;
margin-top: 10px;
}
.api-badge {
background: rgba(255, 126, 95, 0.2);
padding: 5px 10px;
border-radius: 20px;
font-size: 0.8rem;
}
.error-box {
display: none;
background: rgba(200, 0, 0, 0.2);
border: 1px solid rgba(255, 0, 0, 0.3);
border-radius: 8px;
padding: 15px;
margin-top: 20px;
font-family: monospace;
font-size: 0.9rem;
max-height: 200px;
overflow-y: auto;
}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body>
<div class="container">
<header>
<h1>Professional Image Editor</h1>
<p class="subtitle">Transform your images with AI-powered editing. Powered by Hugging Face's multimodalart/cosxl model running on CPU.</p>
</header>
<div class="app-container">
<div class="panel">
<h2 class="panel-title"><i class="fas fa-edit"></i> Edit Parameters</h2>
<div class="form-group">
<label for="imageUpload">Upload Image</label>
<div class="upload-area" id="dropArea">
<i class="fas fa-cloud-upload-alt"></i>
<p class="upload-text">Drag & drop your image here or click to browse</p>
<button class="btn" id="browseBtn"><i class="fas fa-folder-open"></i> Select Image</button>
<input type="file" id="imageUpload" accept="image/*" class="file-input">
</div>
</div>
<div class="form-group">
<label for="prompt">Edit Prompt</label>
<textarea id="prompt" placeholder="Describe what to edit (e.g. 'Change the dress color to blue', 'Add a hat', 'Make background blurry')"></textarea>
</div>
<div class="form-group">
<label for="negativePrompt">Negative Prompt</label>
<input type="text" id="negativePrompt" value="blurry, distorted, low quality, artifacts" placeholder="Things to avoid in the result">
</div>
<div class="form-group">
<label for="guidanceScale">Guidance Scale: <span id="scaleValue">7</span></label>
<input type="range" id="guidanceScale" min="1" max="15" step="0.5" value="7">
</div>
<div class="form-group">
<label for="steps">Processing Steps: <span id="stepsValue">20</span></label>
<input type="range" id="steps" min="5" max="50" value="20">
</div>
<div class="form-group">
<label for="quality">Image Quality: <span id="qualityValue">85%</span></label>
<input type="range" id="quality" min="50" max="95" step="5" value="85">
</div>
<button class="btn" id="runEdit">
<i class="fas fa-magic"></i> Apply Edits
</button>
<div class="error-box" id="errorBox">
<pre id="errorDetails"></pre>
</div>
</div>
<div class="panel">
<h2 class="panel-title"><i class="fas fa-image"></i> Results</h2>
<div class="image-container" id="resultContainer">
<div class="image-placeholder" id="originalPlaceholder">
<i class="fas fa-image"></i>
<p>Original image will appear here</p>
</div>
<img id="originalImage">
</div>
<div class="loading" id="loadingIndicator">
<div class="spinner"></div>
<p>Processing your image... This may take 15-30 seconds</p>
<p><small>Using CPU-based model - slower than GPU but more accessible</small></p>
</div>
<div class="image-container" id="resultContainer">
<div class="image-placeholder" id="resultPlaceholder">
<i class="fas fa-star"></i>
<p>Edited result will appear here</p>
</div>
<img id="resultImage">
</div>
</div>
</div>
<div class="tips">
<h2><i class="fas fa-lightbulb"></i> Tips for Best Results</h2>
<div class="tip">
<i class="fas fa-check-circle"></i>
<p>Be specific in your prompts: "Change the dress color to navy blue" works better than "Change color"</p>
</div>
<div class="tip">
<i class="fas fa-check-circle"></i>
<p>Use negative prompts to avoid unwanted artifacts: "blurry, distorted, low quality"</p>
</div>
<div class="tip">
<i class="fas fa-check-circle"></i>
<p>For clothing edits, mention the garment: "Recolor the dress to emerald green"</p>
</div>
<div class="tip">
<i class="fas fa-check-circle"></i>
<p>Higher guidance scale (7-10) gives better adherence to prompts</p>
</div>
<div class="tip">
<i class="fas fa-check-circle"></i>
<p>More steps (20-30) generally improve quality but take longer to process</p>
</div>
<div class="tip">
<i class="fas fa-check-circle"></i>
<p>Reduce image quality to 80% for faster processing with minimal quality loss</p>
</div>
</div>
<div class="footer">
<p>Professional Image Editor | Powered by Hugging Face's multimodalart/cosxl model</p>
<div class="api-info">
<span class="api-badge">API: multimodalart/cosxl</span>
<span class="api-badge">Mode: CPU</span>
<span class="api-badge">Image Editing</span>
</div>
<p>Note: Processing may take 15-30 seconds as it uses CPU-based models</p>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// DOM elements
const imageUpload = document.getElementById('imageUpload');
const dropArea = document.getElementById('dropArea');
const browseBtn = document.getElementById('browseBtn');
const originalImage = document.getElementById('originalImage');
const originalPlaceholder = document.getElementById('originalPlaceholder');
const resultImage = document.getElementById('resultImage');
const resultPlaceholder = document.getElementById('resultPlaceholder');
const runEditBtn = document.getElementById('runEdit');
const loadingIndicator = document.getElementById('loadingIndicator');
const promptInput = document.getElementById('prompt');
const negativePromptInput = document.getElementById('negativePrompt');
const guidanceScaleInput = document.getElementById('guidanceScale');
const scaleValue = document.getElementById('scaleValue');
const stepsInput = document.getElementById('steps');
const stepsValue = document.getElementById('stepsValue');
const qualityInput = document.getElementById('quality');
const qualityValue = document.getElementById('qualityValue');
const errorBox = document.getElementById('errorBox');
const errorDetails = document.getElementById('errorDetails');
// Set initial slider values
scaleValue.textContent = guidanceScaleInput.value;
stepsValue.textContent = stepsInput.value;
qualityValue.textContent = qualityInput.value + '%';
// Event listeners for sliders
guidanceScaleInput.addEventListener('input', () => {
scaleValue.textContent = guidanceScaleInput.value;
});
stepsInput.addEventListener('input', () => {
stepsValue.textContent = stepsInput.value;
});
qualityInput.addEventListener('input', () => {
qualityValue.textContent = qualityInput.value + '%';
});
// File selection
browseBtn.addEventListener('click', () => {
imageUpload.click();
});
imageUpload.addEventListener('change', function(e) {
if (this.files && this.files[0]) {
handleImageUpload(this.files[0]);
}
});
// Drag and drop
dropArea.addEventListener('dragover', (e) => {
e.preventDefault();
dropArea.style.borderColor = '#ff7e5f';
dropArea.style.backgroundColor = 'rgba(20, 20, 40, 0.9)';
});
dropArea.addEventListener('dragleave', () => {
dropArea.style.borderColor = 'rgba(255, 255, 255, 0.2)';
dropArea.style.backgroundColor = 'rgba(20, 20, 40, 0.5)';
});
dropArea.addEventListener('drop', (e) => {
e.preventDefault();
dropArea.style.borderColor = 'rgba(255, 255, 255, 0.2)';
dropArea.style.backgroundColor = 'rgba(20, 20, 40, 0.5)';
if (e.dataTransfer.files && e.dataTransfer.files[0]) {
handleImageUpload(e.dataTransfer.files[0]);
}
});
// Handle image upload and preview
function handleImageUpload(file) {
if (!file.type.match('image.*')) {
alert('Please select an image file');
return;
}
const reader = new FileReader();
reader.onload = function(e) {
originalImage.src = e.target.result;
originalImage.style.display = 'block';
originalPlaceholder.style.display = 'none';
// Clear previous result
resultImage.style.display = 'none';
resultPlaceholder.style.display = 'block';
// Hide any previous errors
errorBox.style.display = 'none';
};
reader.readAsDataURL(file);
}
// Function to compress image
async function compressImage(imageSrc, quality) {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'Anonymous';
img.src = imageSrc;
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Calculate new dimensions to max 1024px
let width = img.width;
let height = img.height;
const maxDimension = 1024;
if (width > maxDimension || height > maxDimension) {
const ratio = Math.min(maxDimension / width, maxDimension / height);
width = Math.floor(width * ratio);
height = Math.floor(height * ratio);
}
canvas.width = width;
canvas.height = height;
// Draw image on canvas
ctx.drawImage(img, 0, 0, width, height);
// Convert to blob with specified quality
canvas.toBlob(blob => {
if (!blob) {
reject(new Error('Image compression failed'));
return;
}
resolve(blob);
}, 'image/jpeg', quality / 100);
};
img.onerror = () => {
reject(new Error('Failed to load image for compression'));
};
});
}
// Show error details
function showError(message, details) {
errorDetails.textContent = details || message;
errorBox.style.display = 'block';
console.error(message, details);
}
// Run the edit process
runEditBtn.addEventListener('click', async () => {
// Validate inputs
if (!originalImage.src || originalImage.src === window.location.href) {
alert('Please upload an image first');
return;
}
if (!promptInput.value.trim()) {
alert('Please enter an edit prompt');
return;
}
// Show loading indicator
runEditBtn.disabled = true;
loadingIndicator.style.display = 'block';
errorBox.style.display = 'none';
try {
// Compress image
const quality = parseInt(qualityInput.value) / 100;
const compressedBlob = await compressImage(originalImage.src, quality);
// Create FormData
const formData = new FormData();
formData.append('image', compressedBlob, 'image.jpg');
formData.append('prompt', promptInput.value);
formData.append('negative_prompt', negativePromptInput.value);
formData.append('guidance_scale', guidanceScaleInput.value);
formData.append('steps', stepsInput.value);
// Make request to Hugging Face API
const response = await fetch('https://multimodalart-cosxl.hf.space/run/predict', {
method: 'POST',
body: formData
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`API request failed: ${response.status} ${response.statusText}\n${errorText}`);
}
// Get the result image
const resultBlob = await response.blob();
if (!resultBlob.type.startsWith('image/')) {
const errorData = await resultBlob.text();
throw new Error(`API returned non-image response: ${errorData}`);
}
const resultUrl = URL.createObjectURL(resultBlob);
// Display result
resultImage.src = resultUrl;
resultImage.style.display = 'block';
resultPlaceholder.style.display = 'none';
} catch (error) {
showError('Error processing image:', error.message);
} finally {
// Hide loading indicator
runEditBtn.disabled = false;
loadingIndicator.style.display = 'none';
}
});
// Example prompts
const examplePrompts = [
"Change the dress color to royal blue",
"Make the background blurry with bokeh effect",
"Recolor the jacket to bright red",
"Add a sun hat to the person",
"Change the hair color to purple",
"Make the dress look like silk material"
];
// Set a random example prompt
promptInput.placeholder = examplePrompts[Math.floor(Math.random() * examplePrompts.length)];
});
</script>
</body>
</html>