Gttg / templates /index.html
Athspi's picture
Update templates/index.html
452d71e verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AI Object Remover</title>
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap"
rel="stylesheet"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
/>
<style>
:root {
--primary-color: #6366f1;
--secondary-color: #4f46e5;
--accent-color: #8b5cf6;
--background: #f8fafc;
--card-bg: #ffffff;
--text-primary: #1e293b;
--text-secondary: #64748b;
--success: #10b981;
--error: #ef4444;
}
body {
font-family: 'Poppins', sans-serif;
background-color: var(--background);
color: var(--text-primary);
margin: 0;
padding: 0;
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
header {
text-align: center;
margin-bottom: 2rem;
}
.logo {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
margin-bottom: 1rem;
}
.logo i {
font-size: 2.5rem;
color: var(--primary-color);
}
h1 {
font-size: 2.5rem;
margin: 0;
background: linear-gradient(to right, var(--primary-color), var(--accent-color));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.subtitle {
color: var(--text-secondary);
margin-top: 0.5rem;
font-weight: 400;
}
.app-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
@media (max-width: 768px) {
.app-container {
grid-template-columns: 1fr;
}
}
.card {
background-color: var(--card-bg);
border-radius: 1rem;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05);
padding: 1.5rem;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
}
.upload-area {
border: 2px dashed #d1d5db;
border-radius: 0.75rem;
padding: 2rem;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
margin-bottom: 1rem;
position: relative;
min-height: 200px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.upload-area:hover {
border-color: var(--primary-color);
background-color: rgba(99, 102, 241, 0.05);
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
}
.preview-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
align-items: center;
justify-content: center;
background-color: var(--card-bg);
}
.preview-container img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.form-group {
margin-bottom: 1.5rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
}
input[type="text"] {
width: 100%;
padding: 0.75rem 1rem;
border-radius: 0.5rem;
border: 1px solid #d1d5db;
font-family: inherit;
font-size: 1rem;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
input[type="text"]:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
}
.button {
background-color: var(--primary-color);
color: white;
border: none;
border-radius: 0.5rem;
padding: 0.75rem 1.5rem;
font-family: inherit;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
width: 100%;
}
.button:hover {
background-color: var(--secondary-color);
transform: translateY(-2px);
}
.button:disabled {
background-color: #d1d5db;
cursor: not-allowed;
}
.result-area {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
min-height: 200px;
position: relative;
}
.result-image {
max-width: 100%;
max-height: 300px;
border-radius: 0.5rem;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
display: none;
}
.spinner {
display: none;
width: 40px;
height: 40px;
border: 4px solid rgba(99, 102, 241, 0.1);
border-left-color: var(--primary-color);
border-radius: 50%;
animation: spin 1s linear infinite;
}
.download-btn {
margin-top: 1rem;
background-color: var(--success);
display: none;
}
.error-message {
color: var(--error);
margin-top: 1rem;
display: none;
text-align: center;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<div class="container">
<header>
<div class="logo">
<i class="fas fa-magic"></i>
<h1>AI Object Remover</h1>
</div>
<p class="subtitle">Remove unwanted objects from your images with AI</p>
</header>
<div class="app-container">
<div class="card">
<div class="upload-area" id="uploadArea">
<div class="upload-placeholder">
<i class="fas fa-cloud-upload-alt"></i>
<p>Click or drag & drop your image here</p>
<span style="font-size: 0.85rem; color: var(--text-secondary);">Supported formats: JPG, PNG</span>
</div>
<div class="preview-container" id="previewContainer">
<img id="imagePreview" src="#" alt="Preview" />
</div>
</div>
<div class="form-group">
<label for="objectType">What do you want to remove?</label>
<input type="text" id="objectType" placeholder="e.g., person, text, car..." value="text" />
</div>
<button id="processBtn" class="button" disabled>
<i class="fas fa-wand-magic-sparkles"></i>
<span>Remove Object</span>
</button>
<p class="error-message" id="errorMessage"></p>
</div>
<div class="card">
<div class="result-area">
<div id="resultPlaceholder">
<i class="fas fa-image"></i>
<p>Your edited image will appear here</p>
</div>
<div class="spinner" id="spinner"></div>
<img id="resultImage" class="result-image" src="#" alt="Result" />
</div>
<a id="downloadBtn" class="button download-btn" download="edited-image.png">
<i class="fas fa-download"></i>
<span>Download Image</span>
</a>
</div>
</div>
</div>
<script>
const uploadArea = document.getElementById('uploadArea');
const previewContainer = document.getElementById('previewContainer');
const imagePreview = document.getElementById('imagePreview');
const objectTypeInput = document.getElementById('objectType');
const processBtn = document.getElementById('processBtn');
const resultPlaceholder = document.getElementById('resultPlaceholder');
const resultImage = document.getElementById('resultImage');
const spinner = document.getElementById('spinner');
const downloadBtn = document.getElementById('downloadBtn');
const errorMessage = document.getElementById('errorMessage');
let selectedFile = null;
// Handle file selection
uploadArea.addEventListener('click', () => {
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = 'image/jpeg, image/png';
fileInput.onchange = handleFileSelect;
fileInput.click();
});
// Handle drag and drop
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');
if (e.dataTransfer.files.length > 0) {
handleFile(e.dataTransfer.files[0]);
}
});
function handleFileSelect(e) {
if (e.target.files.length > 0) {
handleFile(e.target.files[0]);
}
}
function handleFile(file) {
if (!file.type.match('image.*')) {
showError('Please select a valid image file (JPG or PNG)');
return;
}
selectedFile = file;
const reader = new FileReader();
reader.onload = (e) => {
imagePreview.src = e.target.result;
previewContainer.style.display = 'flex';
document.querySelector('.upload-placeholder').style.opacity = '0';
processBtn.disabled = false;
hideError();
};
reader.readAsDataURL(file);
}
// Process image
processBtn.addEventListener('click', () => {
if (!selectedFile) {
showError('Please select an image first');
return;
}
const objectType = objectTypeInput.value.trim();
if (!objectType) {
showError('Please specify what you want to remove');
return;
}
showLoading();
const reader = new FileReader();
reader.onload = (e) => {
const imageData = e.target.result;
processImage(imageData, objectType);
};
reader.readAsDataURL(selectedFile);
});
function processImage(imageData, objectType) {
// Replace the URL below with your server endpoint for processing the image.
fetch('/process', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify({
image: imageData,
objectType: objectType
})
})
.then(response => response.json())
.then(data => {
hideLoading();
if (data.success) {
resultImage.src = data.resultPath + '?t=' + new Date().getTime();
resultImage.style.display = 'block';
resultPlaceholder.style.display = 'none';
downloadBtn.style.display = 'flex';
downloadBtn.href = data.resultPath;
} else {
showError(data.message || 'Failed to process image');
}
})
.catch(error => {
hideLoading();
showError('Error processing image. Please try again.');
console.error('Error:', error);
});
}
function showLoading() {
spinner.style.display = 'block';
resultPlaceholder.style.display = 'none';
resultImage.style.display = 'none';
downloadBtn.style.display = 'none';
processBtn.disabled = true;
}
function hideLoading() {
spinner.style.display = 'none';
processBtn.disabled = false;
}
function showError(message) {
errorMessage.textContent = message;
errorMessage.style.display = 'block';
}
function hideError() {
errorMessage.style.display = 'none';
}
</script>
</body>
</html>