VibecoderMcSwaggins commited on
Commit
0edafbf
·
1 Parent(s): 0b424f6

docs: add spec for Issue #19 (base64 → file URL optimization)

Browse files

Create actionable spec doc for async agent to implement performance
optimization replacing ~65MB base64 data URLs with Gradio file serving.

Relates to: #19

docs/specs/19-perf-base64-to-file-urls.md ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Issue #19: Replace Base64 Data URLs with File URLs for NiiVue Viewer
2
+
3
+ ## Status: OPEN
4
+
5
+ **Date:** 2025-12-09
6
+ **Priority:** P3 (Performance optimization)
7
+ **GitHub Issue:** https://github.com/The-Obstacle-Is-The-Way/stroke-deepisles-demo/issues/19
8
+ **Related:** Bug #10, Bug #11 (both FIXED)
9
+
10
+ ---
11
+
12
+ ## TL;DR
13
+
14
+ Replace base64-encoded data URLs (~65MB payloads) with Gradio's file serving for
15
+ NiiVue volumes. The viewer works correctly now, but large payloads may cause
16
+ slow loading or memory issues.
17
+
18
+ ---
19
+
20
+ ## Problem
21
+
22
+ The NiiVue 3D viewer currently uses base64-encoded data URLs to pass NIfTI
23
+ volumes to the browser:
24
+
25
+ ```python
26
+ # Current implementation in viewer.py
27
+ def nifti_to_data_url(nifti_path: Path) -> str:
28
+ """Convert NIfTI file to base64 data URL."""
29
+ data = nifti_path.read_bytes()
30
+ b64 = base64.b64encode(data).decode("ascii")
31
+ return f"data:application/octet-stream;base64,{b64}"
32
+ ```
33
+
34
+ ### Payload Size Analysis
35
+
36
+ | File | Raw Size | Base64 Size |
37
+ |------|----------|-------------|
38
+ | DWI | 30.1 MB | ~40 MB |
39
+ | ADC | 17.7 MB | ~24 MB |
40
+ | **Total** | ~48 MB | **~65 MB** |
41
+
42
+ ### Potential Issues
43
+
44
+ 1. **Browser memory pressure** - Large base64 strings in DOM
45
+ 2. **Slow loading times** - 65MB transferred per segmentation
46
+ 3. **Gradio payload limits** - May hit internal limits on large responses
47
+ 4. **Mobile/low-bandwidth issues** - Poor UX on slower connections
48
+
49
+ ---
50
+
51
+ ## Proposed Solution
52
+
53
+ Use Gradio's built-in file serving instead of base64 data URLs.
54
+
55
+ ### Option A: Use `gr.File` component (Recommended)
56
+
57
+ Gradio automatically serves files and provides URLs:
58
+
59
+ ```python
60
+ from gradio import FileData
61
+
62
+ def nifti_to_file_url(nifti_path: Path) -> str:
63
+ """Get Gradio file URL for NIfTI file."""
64
+ file_data = FileData(path=str(nifti_path))
65
+ return file_data.url # Returns /file=... URL served by Gradio
66
+ ```
67
+
68
+ ### Option B: Use Gradio's file caching
69
+
70
+ ```python
71
+ import gradio as gr
72
+
73
+ # Gradio caches files and provides URLs
74
+ cached_path = gr.utils.get_upload_folder() / nifti_path.name
75
+ shutil.copy(nifti_path, cached_path)
76
+ file_url = f"/file={cached_path}"
77
+ ```
78
+
79
+ ---
80
+
81
+ ## Files to Modify
82
+
83
+ | File | Changes |
84
+ |------|---------|
85
+ | `src/stroke_deepisles_demo/ui/viewer.py` | Replace `nifti_to_data_url()` with file URL function |
86
+ | `src/stroke_deepisles_demo/ui/app.py` | Update `run_segmentation()` to use file URLs |
87
+
88
+ ---
89
+
90
+ ## Implementation Steps
91
+
92
+ ### Step 1: Research Gradio File Serving
93
+
94
+ Verify how Gradio serves files and what URL format NiiVue expects:
95
+
96
+ ```python
97
+ # Test script
98
+ import gradio as gr
99
+ from gradio import FileData
100
+
101
+ file_data = FileData(path="/path/to/test.nii.gz")
102
+ print(f"URL: {file_data.url}")
103
+ print(f"Type: {type(file_data.url)}")
104
+ ```
105
+
106
+ ### Step 2: Update `nifti_to_data_url()` → `nifti_to_file_url()`
107
+
108
+ ```python
109
+ # viewer.py
110
+ def nifti_to_file_url(nifti_path: Path) -> str:
111
+ """Get Gradio-served file URL for NIfTI file.
112
+
113
+ Args:
114
+ nifti_path: Path to NIfTI file
115
+
116
+ Returns:
117
+ URL string that Gradio will serve (e.g., /file=...)
118
+ """
119
+ from gradio import FileData
120
+ file_data = FileData(path=str(nifti_path))
121
+ return file_data.url
122
+ ```
123
+
124
+ ### Step 3: Update `app.py` to Use File URLs
125
+
126
+ ```python
127
+ # app.py - run_segmentation()
128
+ # Replace:
129
+ dwi_url = nifti_to_data_url(dwi_path)
130
+ mask_url = nifti_to_data_url(result.prediction_mask)
131
+
132
+ # With:
133
+ dwi_url = nifti_to_file_url(dwi_path)
134
+ mask_url = nifti_to_file_url(result.prediction_mask)
135
+ ```
136
+
137
+ ### Step 4: Test NiiVue with File URLs
138
+
139
+ Verify NiiVue can load from Gradio's file URLs:
140
+ - Check CORS headers
141
+ - Verify Content-Type header
142
+ - Test with different browsers
143
+
144
+ ### Step 5: Cleanup
145
+
146
+ Remove or deprecate `nifti_to_data_url()` if no longer needed.
147
+
148
+ ---
149
+
150
+ ## Testing Checklist
151
+
152
+ - [ ] NiiVue loads DWI volume from file URL
153
+ - [ ] NiiVue loads prediction mask overlay from file URL
154
+ - [ ] No CORS errors in browser console
155
+ - [ ] Loading time improved (measure before/after)
156
+ - [ ] Memory usage reduced (check browser DevTools)
157
+ - [ ] Works on HF Spaces deployment
158
+ - [ ] All existing tests pass
159
+
160
+ ---
161
+
162
+ ## Risks and Mitigations
163
+
164
+ | Risk | Mitigation |
165
+ |------|------------|
166
+ | CORS issues | Gradio should handle CORS for its own file serving |
167
+ | NiiVue URL format | Test that NiiVue accepts relative URLs |
168
+ | File cleanup | Gradio handles temp file cleanup automatically |
169
+ | Security | Gradio's file serving is sandboxed to allowed paths |
170
+
171
+ ---
172
+
173
+ ## Acceptance Criteria
174
+
175
+ 1. NiiVue viewer loads volumes from file URLs (not base64)
176
+ 2. No regression in viewer functionality
177
+ 3. Measurable improvement in loading time or memory usage
178
+ 4. All 130+ tests pass
179
+ 5. Works on HF Spaces
180
+
181
+ ---
182
+
183
+ ## References
184
+
185
+ - [Gradio FileData API](https://www.gradio.app/docs/gradio/filedata)
186
+ - [Gradio File Serving](https://www.gradio.app/guides/file-access)
187
+ - [NiiVue Loading Volumes](https://niivue.github.io/niivue/features/loading.volumes.html)
188
+ - [Bug #10 - Secondary Issue 1](./10-bug-niivue-viewer-black-screen.md)