# Bug #10: NiiVue 3D Viewer Renders Black Screen on HF Spaces ## Status: PARTIALLY FIXED → See Bug #11 **Date:** 2025-12-09 **Branch:** `fix/niivue-js-on-load` (merged), now `fix/niivue-js-rerun` **Discovered:** After fixing Bug #9 (DeepISLES subprocess bridge) ### Fix Applied (2025-12-09) - PARTIAL Implemented `js_on_load` approach (Solution 1 from this spec): 1. **`viewer.py`**: Removed ` """ # components.py:42 - Basic HTML component without js_on_load niivue_viewer = gr.HTML(label="Interactive 3D Viewer") # No js_on_load! ``` ### Why It Fails 1. `gr.HTML` receives our HTML string as `value` 2. Gradio renders the `
` and `` elements (static HTML) 3. Gradio **strips or ignores** the ` ''' demo.launch( head=NIIVUE_HEAD, server_name="0.0.0.0", server_port=7860 ) ``` **Pros:** Loads library once, available globally **Cons:** GitHub Issue #10250 reports unreliable execution ### Solution 3: Server-Side File Serving Instead of base64 data URLs, serve NIfTI files via Gradio's file system: ```python # Use Gradio's file URL instead of data URLs from gradio import FileData file_data = FileData(path=str(dwi_path)) # Pass file_data.url to NiiVue instead of base64 ``` **Pros:** Avoids 65MB payload, better memory efficiency **Cons:** Requires refactoring data flow, CORS considerations ### Solution 4: Custom Gradio Component Build a proper `gradio_niivue` package: ```bash gradio cc create NiiVue --template HTML # Implement Svelte frontend with NiiVue # Publish to PyPI ``` **Pros:** Most robust, reusable, proper architecture **Cons:** Significant development effort ### Solution 5: Enhanced 2D Fallback (Simplest) Remove NiiVue entirely, enhance matplotlib visualization: ```python def create_results_display(): with gr.Group(): # Remove: niivue_viewer = gr.HTML(...) # Enhanced 2D visualization slice_plot = gr.Plot(label="Multi-View Comparison") slice_slider = gr.Slider(label="Slice", minimum=0, maximum=100) # Add orthogonal views with gr.Row(): axial_plot = gr.Plot(label="Axial") coronal_plot = gr.Plot(label="Coronal") sagittal_plot = gr.Plot(label="Sagittal") ``` **Pros:** Eliminates WebGL complexity, works reliably **Cons:** Loses 3D interactivity, less impressive demo --- ## Investigation Steps ### Step 0: Test Async/Await in js_on_load (CRITICAL) Before implementing Solution 1, verify async works: ```python import gradio as gr with gr.Blocks() as demo: html = gr.HTML( value="
Testing async...
", js_on_load=""" (async () => { element.innerText = 'Async started...'; await new Promise(r => setTimeout(r, 1000)); element.innerText = 'Async works!'; element.style.background = 'green'; })(); """ ) demo.launch() ``` If this shows "Async works!" with green background after 1 second, async is supported. ### Step 1: Verify js_on_load Works (Basic) Create minimal test: ```python import gradio as gr with gr.Blocks() as demo: html = gr.HTML( value="
Loading...
", js_on_load="element.style.background='green'; element.innerText='JS Works!';" ) demo.launch() ``` ### Step 2: Test Dynamic Import in js_on_load ```python js_on_load=""" (async () => { const mod = await import('https://unpkg.com/@niivue/niivue@0.65.0/dist/index.js'); console.log('NiiVue loaded:', mod); element.innerText = 'Import succeeded!'; })(); """ ``` ### Step 3: Check Browser Console 1. Open HF Spaces demo 2. Open DevTools (F12) → Console 3. Look for errors related to: - Module loading failures - WebGL context issues - CORS errors - Memory errors ### Step 4: Test with Smaller Files Create downsampled test NIfTI (~1MB) to isolate size vs JS issues. --- ## Related Issues - **Bug #9**: DeepISLES modules not found (FIXED - subprocess bridge) - **Bug #8**: HF Spaces streaming hang (FIXED) - **Technical Debt**: NiiVue memory overhead (P2) - **[Gradio #4511](https://github.com/gradio-app/gradio/issues/4511)**: 3D medical image support request (closed, not planned) - **[Gradio #10250](https://github.com/gradio-app/gradio/issues/10250)**: JS in head param issues (open) --- ## Priority Assessment **Severity:** P2 (Medium) - Core inference pipeline works correctly - 2D visualization provides adequate fallback - No data loss or security impact - Demo is functional for evaluation purposes **Impact:** - Less impressive without 3D viewer - Users can still evaluate predictions via 2D slices - Download functionality unaffected **Recommendation:** 1. First, validate inference accuracy across multiple cases 2. Then attempt Solution 1 (js_on_load) as quick fix 3. If that fails, implement Solution 5 (enhanced 2D) for reliability 4. Consider Solution 4 (custom component) for future enhancement --- ## References - [Gradio HTML Docs](https://www.gradio.app/docs/gradio/html) - [Gradio Custom HTML Components Guide](https://www.gradio.app/guides/custom_HTML_components) - [Gradio 6 Migration Guide](https://www.gradio.app/main/guides/gradio-6-migration-guide) - [HuggingFace Forum: JS doesn't work in gr.HTML](https://discuss.huggingface.co/t/gradio-html-component-with-javascript-code-dont-work/37316) - [GitHub Issue #10250: JS in head param](https://github.com/gradio-app/gradio/issues/10250) - [GitHub Issue #4511: 3D Medical Images](https://github.com/gradio-app/gradio/issues/4511) - [NiiVue GitHub](https://github.com/niivue/niivue) - [ipyniivue (Jupyter Widget)](https://github.com/niivue/ipyniivue) - [Gradio 6 Announcement](https://alternativeto.net/news/2025/11/gradio-6-released-with-faster-performance-for-creating-machine-learning-apps-in-python/) --- ## Appendix: HF Spaces Logs ```text INFO: Running segmentation for sub-stroke0002 INFO: Case sub-stroke0002 ready: DWI=20.9MB, ADC=12.6MB INFO: DeepISLES subprocess completed in 30.88s ``` Note: No JavaScript errors visible in server logs (client-side only).