vid3 / templates /index.html
IZERE HIRWA Roger
g
4e1bce5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Talking Avatar Generator</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@200;300;400;600;700;800;900&display=swap" rel="stylesheet">
<!-- Custom CSS -->
<style>
/* Custom Bootstrap overrides */
:root {
--primary-color: #4e73df;
--secondary-color: #858796;
--success-color: #1cc88a;
}
body {
background-color: #f8f9fc;
font-family: 'Nunito', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
.card {
border: none;
border-radius: 0.35rem;
box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
}
.card-header {
background-color: var(--primary-color);
border-bottom: none;
}
.btn-primary {
background-color: var(--primary-color);
border-color: var(--primary-color);
}
.btn-primary:hover {
background-color: #2e59d9;
border-color: #2653d4;
}
/* Upload area styling */
.upload-area {
border: 2px dashed #d1d3e2;
border-radius: 0.35rem;
padding: 2rem;
text-align: center;
margin-bottom: 1.5rem;
cursor: pointer;
transition: all 0.3s;
}
.upload-area:hover {
border-color: var(--primary-color);
background-color: rgba(78, 115, 223, 0.05);
}
.upload-area i {
font-size: 3rem;
color: var(--secondary-color);
margin-bottom: 1rem;
}
/* Video result styling */
#result {
transition: all 0.3s;
}
#outputVideo {
border-radius: 0.35rem;
background-color: #000;
}
/* Loading spinner */
.spinner-border {
width: 1.2rem;
height: 1.2rem;
border-width: 0.15em;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.card-body {
padding: 1.25rem;
}
.upload-area {
padding: 1.5rem;
}
}
/* Animation for processing state */
@keyframes pulse {
0% { opacity: 0.6; }
50% { opacity: 1; }
100% { opacity: 0.6; }
}
.processing {
animation: pulse 1.5s infinite;
}
</style>
</head>
<body>
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card">
<div class="card-header text-white">
<h4 class="mb-0"><i class="fas fa-video me-2"></i>AI Talking Avatar Generator</h4>
</div>
<div class="card-body">
<form id="avatarForm" enctype="multipart/form-data">
<!-- Image Upload -->
<div class="mb-4">
<label class="form-label">Upload Photo</label>
<div class="upload-area" onclick="document.getElementById('imageInput').click()">
<i class="fas fa-cloud-upload-alt"></i>
<p class="mb-0">Click to upload an image</p>
<small class="text-muted">Supports JPG, PNG formats</small>
</div>
<input type="file" id="imageInput" class="d-none" accept="image/*" required>
</div>
<!-- Text Input -->
<div class="mb-4">
<label for="textInput" class="form-label">Enter Text</label>
<textarea id="textInput" class="form-control" rows="4"
placeholder="Enter the text you want the avatar to speak..." required></textarea>
</div>
<!-- Submit Button -->
<button type="submit" class="btn btn-primary btn-lg w-100">
<i class="fas fa-magic me-2"></i>Generate Video
</button>
</form>
</div>
</div>
<!-- Result Section -->
<div id="result" class="card mt-4 d-none">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-play-circle me-2"></i>Generated Video</h5>
</div>
<div class="card-body text-center">
<video id="outputVideo" controls class="w-100 mb-3" style="max-height: 400px;"></video>
<button id="downloadBtn" class="btn btn-success">
<i class="fas fa-download me-2"></i>Download Video
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Debug: Check if script is loaded
console.log('Scripts.js loaded successfully');
document.addEventListener('DOMContentLoaded', function() {
console.log('DOM loaded, initializing form handler');
const form = document.getElementById('avatarForm');
if (!form) {
console.error('Avatar form not found!');
return;
}
form.addEventListener('submit', async (e) => {
e.preventDefault();
console.log('Form submitted');
const imageInput = document.getElementById('imageInput');
const textInput = document.getElementById('textInput');
if (!imageInput.files[0]) {
alert('Please select an image');
return;
}
if (!textInput.value.trim()) {
alert('Please enter some text');
return;
}
const formData = new FormData();
formData.append('image', imageInput.files[0]);
formData.append('text', textInput.value);
// Show loading state
const btn = document.querySelector('button[type="submit"]');
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2" role="status"></span> Processing...';
try {
console.log('Sending request to /generate');
const response = await fetch('/generate', {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('Response received:', data);
if (data.error) {
throw new Error(data.error);
}
// Display result
const video = document.getElementById('outputVideo');
video.src = data.video;
document.getElementById('result').classList.remove('d-none');
// Set up download
document.getElementById('downloadBtn').onclick = () => {
const a = document.createElement('a');
a.href = data.video;
a.download = 'talking_avatar.mp4';
a.click();
};
} catch (error) {
console.error('Error:', error);
alert('Error: ' + error.message);
} finally {
btn.disabled = false;
btn.innerHTML = '<i class="fas fa-magic me-2"></i>Generate Video';
}
});
});
</script>
</body>
</html>