Spaces:
Running
Running
| <!-- Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. --> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>HNSWTuner Starting</title> | |
| <style> | |
| :root { | |
| color-scheme: light; | |
| font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif; | |
| } | |
| body { | |
| margin: 0; | |
| min-height: 100vh; | |
| display: grid; | |
| place-items: center; | |
| background: | |
| radial-gradient(circle at top, rgba(76, 132, 255, 0.16), transparent 40%), | |
| linear-gradient(180deg, #f4f1ec 0%, #efe8de 100%); | |
| color: #1f2933; | |
| padding: 24px; | |
| } | |
| main { | |
| width: min(100%, 680px); | |
| background: rgba(255, 255, 255, 0.96); | |
| border: 1px solid #d8dee4; | |
| border-radius: 20px; | |
| box-shadow: 0 24px 60px rgba(15, 23, 42, 0.12); | |
| padding: 36px 32px; | |
| } | |
| h1 { | |
| margin: 0 0 12px; | |
| font-size: clamp(2rem, 4vw, 3rem); | |
| line-height: 1.1; | |
| } | |
| p { | |
| margin: 0 0 18px; | |
| line-height: 1.6; | |
| color: #52606d; | |
| } | |
| .status { | |
| display: flex; | |
| align-items: center; | |
| gap: 14px; | |
| margin-top: 24px; | |
| font-weight: 600; | |
| } | |
| .status-text { | |
| color: #243b53; | |
| } | |
| .pulse { | |
| width: 14px; | |
| height: 14px; | |
| border-radius: 50%; | |
| background: #2f6fed; | |
| box-shadow: 0 0 0 0 rgba(47, 111, 237, 0.35); | |
| animation: pulse 1.8s infinite; | |
| } | |
| .pulse.failed { | |
| background: #c23b22; | |
| box-shadow: none; | |
| animation: none; | |
| } | |
| .details { | |
| margin-top: 16px; | |
| padding: 14px 16px; | |
| background: #f8fafc; | |
| border-radius: 12px; | |
| color: #334e68; | |
| white-space: pre-wrap; | |
| word-break: break-word; | |
| } | |
| @keyframes pulse { | |
| 0% { | |
| box-shadow: 0 0 0 0 rgba(47, 111, 237, 0.35); | |
| } | |
| 70% { | |
| box-shadow: 0 0 0 14px rgba(47, 111, 237, 0); | |
| } | |
| 100% { | |
| box-shadow: 0 0 0 0 rgba(47, 111, 237, 0); | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <main> | |
| <h1>HNSWTuner is starting</h1> | |
| <p> | |
| Vespa and the demo dataset are bootstrapping in the background. This page will switch to the | |
| full UI as soon as startup finishes. | |
| </p> | |
| <div class="status"> | |
| <div id="status-dot" class="pulse" aria-hidden="true"></div> | |
| <div id="status-text" class="status-text">Checking startup status...</div> | |
| </div> | |
| <div id="status-message" class="details">Waiting for bootstrap...</div> | |
| </main> | |
| <script> | |
| const statusText = document.getElementById("status-text"); | |
| const statusMessage = document.getElementById("status-message"); | |
| const statusDot = document.getElementById("status-dot"); | |
| let pollTimer = null; | |
| function stopPolling() { | |
| if (pollTimer !== null) { | |
| clearInterval(pollTimer); | |
| pollTimer = null; | |
| } | |
| } | |
| async function pollStatus() { | |
| try { | |
| const response = await fetch("/status", { cache: "no-store" }); | |
| const status = await response.json(); | |
| statusMessage.textContent = status.message || "Waiting for bootstrap..."; | |
| if (status.state === "ready") { | |
| stopPolling(); | |
| window.location.replace("/"); | |
| return; | |
| } | |
| if (status.state === "failed") { | |
| stopPolling(); | |
| statusText.textContent = "Startup failed"; | |
| statusDot.classList.add("failed"); | |
| return; | |
| } | |
| statusText.textContent = "Startup in progress"; | |
| statusDot.classList.remove("failed"); | |
| } catch (error) { | |
| statusText.textContent = "Waiting for status endpoint"; | |
| statusMessage.textContent = String(error); | |
| } | |
| } | |
| pollStatus(); | |
| pollTimer = setInterval(pollStatus, 2000); | |
| </script> | |
| </body> | |
| </html> | |