Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>Mission Console</title> | |
| <style> | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| font-family: "Inter", Arial, sans-serif; | |
| background-color: #121212; | |
| color: #e0e0e0; | |
| } | |
| h1 { | |
| text-align: center; | |
| padding: 20px; | |
| font-size: 26px; | |
| color: #f5f5f5; | |
| margin-bottom: 10px; | |
| } | |
| .container { | |
| width: 80%; | |
| max-width: 900px; | |
| margin: auto; | |
| background: #1e1e1e; | |
| padding: 25px; | |
| border-radius: 12px; | |
| box-shadow: 0 15px 40px rgba(0, 0, 0, 0.25); | |
| } | |
| .label { | |
| font-size: 15px; | |
| font-weight: 600; | |
| margin-top: 18px; | |
| display: block; | |
| color: #bdbdbd; | |
| } | |
| input[type="text"] { | |
| width: 100%; | |
| padding: 12px; | |
| margin-top: 5px; | |
| border: 1px solid #2c2c2c; | |
| background-color: #161616; | |
| color: #fff; | |
| font-size: 15px; | |
| border-radius: 8px; | |
| } | |
| input[type="file"], | |
| select { | |
| margin-top: 10px; | |
| padding: 10px; | |
| background-color: #161616; | |
| border: 1px solid #2c2c2c; | |
| border-radius: 8px; | |
| color: #f5f5f5; | |
| width: 100%; | |
| } | |
| button { | |
| margin-top: 25px; | |
| width: 100%; | |
| padding: 14px; | |
| background-color: #333333; | |
| border: none; | |
| color: #f5f5f5; | |
| font-size: 16px; | |
| font-weight: 600; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| transition: 0.2s; | |
| } | |
| button:hover { | |
| background-color: #4f4f4f; | |
| } | |
| .output-section { | |
| margin-top: 35px; | |
| padding: 20px; | |
| border-radius: 12px; | |
| background-color: #171717; | |
| border: 1px solid #2a2a2a; | |
| } | |
| #summary { | |
| margin-top: 10px; | |
| padding: 14px; | |
| border: 1px solid #2a2a2a; | |
| background-color: #111; | |
| color: #d1d1d1; | |
| font-size: 15px; | |
| min-height: 70px; | |
| white-space: pre-wrap; | |
| border-radius: 8px; | |
| } | |
| #processedVideo { | |
| margin-top: 20px; | |
| width: 100%; | |
| border: 1px solid #2a2a2a; | |
| border-radius: 8px; | |
| background-color: #000; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>Mission Console</h1> | |
| <div class="container"> | |
| <label class="label">MISSION PROMPT</label> | |
| <input id="missionPrompt" type="text" placeholder="e.g., Track hostile drone movement..."> | |
| <label class="label">UPLOAD VIDEO (.mp4)</label> | |
| <input id="videoInput" type="file" accept="video/mp4"> | |
| <label class="label">OBJECT DETECTOR</label> | |
| <select id="detectorSelect"> | |
| <option value="owlv2" selected>OWL-V2 (text-conditioned)</option> | |
| <option value="hf_yolov8">YOLOv8 (COCO classes)</option> | |
| </select> | |
| <button onclick="executeMission()">EXECUTE MISSION</button> | |
| <div class="output-section"> | |
| <h2 style="color:#00ffea; margin-bottom:10px;">MISSION SUMMARY</h2> | |
| <div id="summary">(Awaiting mission results...)</div> | |
| <h2 style="color:#00ffea; margin-top:25px;">PROCESSED VIDEO FEED</h2> | |
| <video id="processedVideo" controls></video> | |
| <div id="status" style="margin-top:15px;color:#ffa95c;font-size:13px;"></div> | |
| </div> | |
| </div> | |
| <script> | |
| const API_BASE_URL = "https://biaslab2025-demo-2025.hf.space"; | |
| const PROCESS_VIDEO_URL = `${API_BASE_URL}/process_video`; | |
| const SUMMARY_URL = `${API_BASE_URL}/mission_summary`; | |
| async function executeMission() { | |
| const videoFile = document.getElementById("videoInput").files[0]; | |
| const mission = document.getElementById("missionPrompt").value; | |
| const detector = document.getElementById("detectorSelect").value; | |
| const summaryEl = document.getElementById("summary"); | |
| const statusEl = document.getElementById("status"); | |
| if (!videoFile || !mission) { | |
| alert("Mission invalid: Upload video and enter mission parameters."); | |
| return; | |
| } | |
| statusEl.textContent = "Processing video..."; | |
| summaryEl.textContent = "(Awaiting summary...)"; | |
| try { | |
| const videoForm = new FormData(); | |
| videoForm.append("video", videoFile); | |
| videoForm.append("prompt", mission); | |
| videoForm.append("detector", detector); | |
| const response = await fetch(PROCESS_VIDEO_URL, { | |
| method: "POST", | |
| body: videoForm | |
| }); | |
| if (!response.ok) { | |
| let errorDetail = `Request failed (${response.status})`; | |
| try { | |
| const errJson = await response.json(); | |
| errorDetail = errJson.error || errorDetail; | |
| } catch (_) { | |
| // ignore | |
| } | |
| throw new Error(errorDetail); | |
| } | |
| const videoBlob = await response.blob(); | |
| const videoUrl = URL.createObjectURL(videoBlob); | |
| const videoEl = document.getElementById("processedVideo"); | |
| videoEl.src = videoUrl; | |
| videoEl.load(); | |
| statusEl.textContent = "Generating summary..."; | |
| const summaryForm = new FormData(); | |
| summaryForm.append("video", videoFile); | |
| summaryForm.append("prompt", mission); | |
| summaryForm.append("detector", detector); | |
| const summaryResponse = await fetch(SUMMARY_URL, { | |
| method: "POST", | |
| body: summaryForm | |
| }); | |
| if (!summaryResponse.ok) { | |
| let errorDetail = `Summary failed (${summaryResponse.status})`; | |
| try { | |
| const errJson = await summaryResponse.json(); | |
| errorDetail = errJson.error || errorDetail; | |
| } catch (_) {} | |
| throw new Error(errorDetail); | |
| } | |
| const summaryJson = await summaryResponse.json(); | |
| const summaryText = summaryJson.mission_summary || "No summary returned."; | |
| summaryEl.textContent = summaryText; | |
| statusEl.textContent = "Mission complete."; | |
| } catch (err) { | |
| console.error(err); | |
| summaryEl.textContent = "Mission failed."; | |
| statusEl.textContent = `Error: ${err.message}`; | |
| } | |
| } | |
| </script> | |
| </body> | |
| </html> | |