bytez-spark / templates /index.html
diwash-barla's picture
Update templates/index.html
8524b20 verified
<!doctype html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8">
<title>Bytez Spark AI</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- PWA and Theme Settings -->
<meta name="theme-color" content="#1a1a1a">
<link rel="manifest" href="/manifest.json">
<!-- Icons -->
<link rel="icon" href="/static/favicon.ico" type="image/x-icon">
<link rel="apple-touch-icon" href="/static/icon-512x512.png">
<!-- Stylesheets -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
:root {
--bs-body-bg: #111;
--bs-body-color: #eee;
}
.card {
background: #1a1a1a;
border: 1px solid #333;
border-radius: 1rem;
}
.btn-primary {
background-color: #0d6efd;
border-color: #0d6efd;
}
.form-control, .form-select {
background-color: #222;
border-color: #444;
color: #eee;
}
.form-control:focus, .form-select:focus {
background-color: #222;
border-color: #0d6efd;
box-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25);
color: #eee;
}
video {
border-radius: 0.75rem;
background-color: #000;
}
.container {
max-width: 720px;
}
.page {
display: none;
}
.page.active {
display: block;
}
.form-label h5 {
margin-bottom: 0.5rem;
}
#liveLog {
background-color: #000;
border: 1px solid #333;
border-radius: 0.5rem;
height: 150px;
overflow-y: auto;
font-family: monospace;
font-size: 0.9em;
padding: 10px;
white-space: pre-wrap;
margin-top: 1rem;
text-align: left;
}
#liveLog p {
margin: 0;
padding: 2px 0;
}
</style>
</head>
<body>
<!-- आपके Body का हिस्सा यहाँ से शुरू होता है, इसमें कोई बदलाव नहीं है -->
<div class="container py-4">
<div id="inputPage" class="page active">
<h2 class="text-center mb-4">🎬 AI Video Generator</h2>
<div class="card p-4">
<div class="mb-3">
<label for="prompt" class="form-label"><h5>1. Describe your video (or use an image)</h5></label>
<textarea id="prompt" class="form-control" rows="3" placeholder="e.g., A robot walking through a neon-lit city in the rain"></textarea>
</div>
<div class="mb-3">
<label for="imageUpload" class="form-label"><h5>2. Upload Image (Optional)</h5></label>
<input type="file" id="imageUpload" class="form-control" accept="image/png, image/jpeg">
</div>
<div class="row g-3">
<div class="col-md-6 mb-3">
<label for="num_clips" class="form-label"><h5>3. Number of clips</h5></label>
<input id="num_clips" type="number" class="form-control" min="1" max="20" value="3">
</div>
<div class="col-md-6 mb-3">
<label for="style" class="form-label"><h5>4. Style</h5></label>
<select id="style" class="form-select">
<option value="none" selected>Default</option>
<option value="cinematic">Cinematic</option>
<option value="cartoon">Cartoon</option>
<option value="realistic">Realistic</option>
<option value="minimalist">Minimalist</option>
</select>
</div>
</div>
<div class="mb-3">
<label for="bytezModelCustom" class="form-label"><h5>5. Custom AI Model (Optional)</h5></label>
<input type="text" id="bytezModelCustom" class="form-control" placeholder="Default: ali-vilab/text-to-video-ms-1.7b">
</div>
<div class="d-grid mt-2">
<button id="startBtn" class="btn btn-primary btn-lg">🚀 Generate Video</button>
</div>
</div>
<div id="inputError" class="text-danger mt-3 text-center d-none"></div>
</div>
<div id="progressPage" class="page">
<div class="card p-4 text-center">
<div id="progressBox">
<h3 class="mb-3">Generating your video...</h3>
<div class="d-flex justify-content-center align-items-center mb-3">
<div class="spinner-border me-3" role="status"></div>
<div class="mono" id="statusText" style="font-size: 1.1rem;">Initializing...</div>
</div>
<div class="progress" role="progressbar" style="height: 10px">
<div id="bar" class="progress-bar progress-bar-striped progress-bar-animated" style="width: 2%"></div>
</div>
<div id="liveLogContainer">
<h6 class="text-secondary mt-3">Mission Control Log:</h6>
<div id="liveLog"></div>
</div>
</div>
<div id="errorBox" class="d-none">
<h3 class="text-danger">An Error Occurred</h3>
<p id="errorMessage" class="mono bg-dark p-3 rounded"></p>
<button class="btn btn-secondary" onclick="goHomeAndReset()">Try Again</button>
</div>
<div id="resultBox" class="d-none">
<h3 class="mb-3">✅ Your video is ready!</h3>
<video id="player" width="100%" controls playsinline></video>
<div class="d-grid gap-2 mt-3">
<a id="dl" class="btn btn-success btn-lg" download>⬇️ Download Video</a>
<button class="btn btn-outline-secondary" onclick="goHomeAndReset()">Create Another Video</button>
</div>
</div>
</div>
</div>
</div>
<script>
const bytezModelCustomEl=document.getElementById("bytezModelCustom"),startBtn=document.getElementById("startBtn"),promptEl=document.getElementById("prompt"),clipsEl=document.getElementById("num_clips"),styleEl=document.getElementById("style"),imageUploadEl=document.getElementById("imageUpload"),liveLogEl=document.getElementById("liveLog"),inputPage=document.getElementById("inputPage"),progressPage=document.getElementById("progressPage"),progressBox=document.getElementById("progressBox"),statusText=document.getElementById("statusText"),bar=document.getElementById("bar"),errorBox=document.getElementById("errorBox"),errorMessage=document.getElementById("errorMessage"),inputError=document.getElementById("inputError"),resultBox=document.getElementById("resultBox"),player=document.getElementById("player"),dl=document.getElementById("dl");let pollTimer=null;function showPage(e){document.querySelectorAll(".page").forEach(e=>e.classList.remove("active")),document.getElementById(e).classList.add("active")}function resetUI(){inputError.classList.add("d-none"),errorBox.classList.add("d-none"),resultBox.classList.add("d-none"),progressBox.style.display="block",bar.style.width="2%",startBtn.disabled=!1,imageUploadEl.value=null,promptEl.value="",liveLogEl.innerHTML="",bytezModelCustomEl.value=""}function goHomeAndReset(){resetUI(),showPage("inputPage")}async function startJob(){inputError.classList.add("d-none"),liveLogEl.innerHTML="";const e=promptEl.value.trim(),t=imageUploadEl.files[0];if(!e&&!t)return inputError.textContent="Please provide a text prompt or upload an image.",void inputError.classList.remove("d-none");startBtn.disabled=!0,showPage("progressPage");try{const a=new FormData;a.append("prompt",e),a.append("num_clips",parseInt(clipsEl.value,10)),a.append("style",styleEl.value),t&&a.append("image",t);const o=bytezModelCustomEl.value.trim();a.append("bytez_model",o);const n=await fetch("/start",{method:"POST",body:a}),s=await n.json();if(!n.ok)throw new Error(s.error||"Failed to start job.");pollTimer=setInterval(pollProgress,1500)}catch(l){errorMessage.textContent=l.message,progressBox.style.display="none",errorBox.classList.remove("d-none"),startBtn.disabled=!1}}async function pollProgress(){try{const e=await fetch("/progress"),t=await e.json(),a=Math.max(1,t.total),o=Math.min(100,Math.floor(t.step/a*100));if(bar.style.width=o+"%",statusText.textContent=t.message,t.live_log&&(liveLogEl.innerHTML=t.live_log.map(e=>`<p>${e}</p>`).join(""),liveLogEl.scrollTop=liveLogEl.scrollHeight),t.status==="done"&&t.video_relpath){clearInterval(pollTimer);const n=`/${t.video_relpath.replace(/\\\\/g,"/")}`;player.src=n,dl.href=n,dl.download=`ai_video_${Date.now()}.mp4`,progressBox.style.display="none",resultBox.classList.remove("d-none")}else if(t.status==="error"){clearInterval(pollTimer),errorMessage.textContent=t.error||"An unknown error occurred.",progressBox.style.display="none",errorBox.classList.remove("d-none")}}catch(r){clearInterval(pollTimer),errorMessage.textContent="Connection to server lost. Please try again.",progressBox.style.display="none",errorBox.classList.remove("d-none")}}startBtn.addEventListener("click",startJob);if("serviceWorker" in navigator){window.addEventListener("load",()=>{navigator.serviceWorker.register("/service-worker.js").then(reg=>console.log("Service worker registered.")).catch(err=>console.log("Service worker registration failed: ",err));});}
</script>
</body>
</html>