Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>FADA Mobile - Fetal Ultrasound AI</title> | |
| <style> | |
| *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } | |
| :root { | |
| --bg: #0f1117; --surface: #1a1b26; --border: #2a2b3d; | |
| --text: #e0e0e0; --text-muted: #888; --accent: #6366f1; | |
| --accent-hover: #818cf8; --success: #22c55e; --error: #ef4444; | |
| } | |
| html, body { height: 100%; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: var(--bg); color: var(--text); } | |
| .app { display: flex; flex-direction: column; height: 100vh; max-width: 900px; margin: 0 auto; padding: 12px; gap: 10px; } | |
| header { text-align: center; padding: 8px 0; } | |
| header h1 { font-size: 1.4rem; color: var(--accent); } | |
| header p { font-size: 0.85rem; color: var(--text-muted); } | |
| #status { font-size: 0.8rem; color: var(--text-muted); padding: 4px 0; } | |
| #gpu-info { font-size: 0.75rem; color: var(--success); padding: 2px 0; font-family: monospace; } | |
| #progress-container { display: none; background: var(--surface); border-radius: 6px; overflow: hidden; height: 22px; position: relative; } | |
| #progress-bar { height: 100%; background: var(--accent); transition: width 0.3s; width: 0%; } | |
| #progress-text { position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; font-size: 0.75rem; color: white; } | |
| .toolbar { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; } | |
| .toolbar button, .toolbar label, .toolbar select { | |
| padding: 8px 16px; border-radius: 6px; border: 1px solid var(--border); | |
| background: var(--surface); color: var(--text); cursor: pointer; font-size: 0.85rem; | |
| transition: background 0.2s, border-color 0.2s; | |
| } | |
| .toolbar button:hover, .toolbar label:hover { background: var(--border); border-color: var(--accent); } | |
| .toolbar button:disabled { opacity: 0.5; cursor: not-allowed; } | |
| .toolbar button.primary { background: var(--accent); border-color: var(--accent); color: white; } | |
| .toolbar button.primary:hover { background: var(--accent-hover); } | |
| .toolbar input[type="file"] { display: none; } | |
| .toolbar select { appearance: auto; } | |
| #image-preview { min-height: 40px; } | |
| #image-preview img { max-width: 100%; max-height: 200px; border-radius: 6px; border: 1px solid var(--border); } | |
| #chat-log { | |
| flex: 1; overflow-y: auto; background: var(--surface); border: 1px solid var(--border); | |
| border-radius: 8px; padding: 12px; display: flex; flex-direction: column; gap: 8px; | |
| } | |
| .message { padding: 10px 14px; border-radius: 8px; max-width: 90%; line-height: 1.5; font-size: 0.9rem; word-wrap: break-word; } | |
| .message.user { background: var(--accent); color: white; align-self: flex-end; } | |
| .message.assistant { background: #1e293b; align-self: flex-start; } | |
| .message.system { background: transparent; color: var(--text-muted); font-size: 0.8rem; align-self: center; text-align: center; } | |
| .message.thinking { opacity: 0.6; font-style: italic; } | |
| .message img.annotation-img { max-width: 100%; margin-top: 8px; border-radius: 4px; } | |
| .input-row { display: flex; gap: 8px; } | |
| #user-input { | |
| flex: 1; padding: 10px 14px; border-radius: 8px; border: 1px solid var(--border); | |
| background: var(--surface); color: var(--text); font-size: 0.9rem; outline: none; | |
| transition: border-color 0.2s; | |
| } | |
| #user-input:focus { border-color: var(--accent); } | |
| #send-btn { | |
| padding: 10px 20px; border-radius: 8px; border: none; | |
| background: var(--accent); color: white; cursor: pointer; font-size: 0.9rem; | |
| transition: background 0.2s; | |
| } | |
| #send-btn:hover { background: var(--accent-hover); } | |
| #send-btn:disabled { opacity: 0.5; cursor: not-allowed; } | |
| @media (max-width: 600px) { | |
| .app { padding: 8px; } | |
| .message { max-width: 95%; font-size: 0.85rem; } | |
| header h1 { font-size: 1.2rem; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="app"> | |
| <header> | |
| <h1>FADA Mobile</h1> | |
| <p>Fetal Ultrasound AI - runs entirely in your browser via WebGPU</p> | |
| </header> | |
| <div id="status">Click "Load Model" to start (~887 MB download + 2-5 min GPU compilation)</div> | |
| <div id="gpu-info" style="font-size: 0.75rem; color: #22c55e;"></div> | |
| <div id="progress-container"> | |
| <div id="progress-bar"></div> | |
| <div id="progress-text"></div> | |
| </div> | |
| <div class="toolbar"> | |
| <button id="load-btn" class="primary">Load Model</button> | |
| <select id="device-select" title="Inference device"> | |
| <option value="webgpu">GPU (WebGPU)</option> | |
| <option value="wasm">CPU (WASM)</option> | |
| </select> | |
| <label for="image-input">Upload Image | |
| <input type="file" id="image-input" accept="image/*"> | |
| </label> | |
| <button id="auto-btn" disabled>Auto Pipeline</button> | |
| <button id="test-text-btn" disabled onclick="window.runTextTest()">Test Text-Only</button> | |
| </div> | |
| <div id="image-preview"></div> | |
| <div id="chat-log"> | |
| <div class="message system"> | |
| Welcome! Load the model, then upload a fetal ultrasound image to begin analysis.<br> | |
| Supported tasks: interpret, classify, detect, segment. | |
| </div> | |
| </div> | |
| <div class="input-row"> | |
| <input type="text" id="user-input" placeholder="Ask about the image... (e.g., 'interpret', 'detect brain', 'segment cardiac')" disabled> | |
| <button id="send-btn" disabled>Send</button> | |
| </div> | |
| </div> | |
| <script type="module" src="js/app.js"></script> | |
| </body> | |
| </html> | |