Spaces:
Running
Running
Add privacy notice to UI and README
Browse filesAdded a collapsible π Privacy & Data accordion in the Gradio UI and
a matching section in README.md explaining that uploaded files are never
stored, logged, or shared β processed in memory only.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- README.md +9 -0
- app.py +32 -8
- requirements.txt +1 -0
README.md
CHANGED
|
@@ -35,6 +35,15 @@ Other causes include oversized cell outputs (>500 KB), giant base64 images, and
|
|
| 35 |
4. Download the fixed notebook
|
| 36 |
5. Push to GitHub β it will render!
|
| 37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
## Run locally
|
| 39 |
|
| 40 |
```bash
|
|
|
|
| 35 |
4. Download the fixed notebook
|
| 36 |
5. Push to GitHub β it will render!
|
| 37 |
|
| 38 |
+
## π Privacy & Data
|
| 39 |
+
|
| 40 |
+
**Your files are never stored.**
|
| 41 |
+
|
| 42 |
+
- Your `.ipynb` file is read **in memory** only β it never touches a database or persistent storage.
|
| 43 |
+
- A short-lived OS temp file is created so you can download the fixed notebook, then it is automatically deleted.
|
| 44 |
+
- No personal information, file content, or usage data is logged or shared with third parties.
|
| 45 |
+
- Once your session ends, every trace of your file is gone.
|
| 46 |
+
|
| 47 |
## Run locally
|
| 48 |
|
| 49 |
```bash
|
app.py
CHANGED
|
@@ -14,8 +14,7 @@ import gradio as gr
|
|
| 14 |
import json
|
| 15 |
import copy
|
| 16 |
import base64
|
| 17 |
-
import
|
| 18 |
-
import os
|
| 19 |
import tempfile
|
| 20 |
from pathlib import Path
|
| 21 |
|
|
@@ -38,9 +37,9 @@ GITHUB_ISSUES = {
|
|
| 38 |
),
|
| 39 |
},
|
| 40 |
"widgets_empty_state": {
|
| 41 |
-
"severity": "
|
| 42 |
"title": "metadata.widgets exists but 'state' is empty",
|
| 43 |
-
"desc": "The widget state dict is present but empty β
|
| 44 |
},
|
| 45 |
"no_kernelspec": {
|
| 46 |
"severity": "warning",
|
|
@@ -223,7 +222,7 @@ def fix_notebook(nb: dict, strip_widgets: bool = False, strip_large_outputs: boo
|
|
| 223 |
})
|
| 224 |
continue
|
| 225 |
|
| 226 |
-
#
|
| 227 |
data = out.get("data", {})
|
| 228 |
for mime in list(data.keys()):
|
| 229 |
if mime.startswith("image/") and isinstance(data[mime], str):
|
|
@@ -231,15 +230,17 @@ def fix_notebook(nb: dict, strip_widgets: bool = False, strip_large_outputs: boo
|
|
| 231 |
img_bytes = len(base64.b64decode(data[mime], validate=False))
|
| 232 |
except Exception:
|
| 233 |
img_bytes = len(data[mime])
|
| 234 |
-
if
|
| 235 |
data[mime] = "" # clear the giant image
|
| 236 |
data.setdefault("text/plain", ["[Large image removed for GitHub compatibility]"])
|
| 237 |
|
| 238 |
new_outputs.append(out)
|
| 239 |
cell["outputs"] = new_outputs
|
| 240 |
|
| 241 |
-
# Ensure every cell has
|
| 242 |
-
cell.
|
|
|
|
|
|
|
| 243 |
|
| 244 |
return nb
|
| 245 |
|
|
@@ -376,5 +377,28 @@ with gr.Blocks(
|
|
| 376 |
"Works for Colab, Jupyter, and any nbformat-4 notebook.*"
|
| 377 |
)
|
| 378 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 379 |
if __name__ == "__main__":
|
| 380 |
demo.launch()
|
|
|
|
| 14 |
import json
|
| 15 |
import copy
|
| 16 |
import base64
|
| 17 |
+
import uuid
|
|
|
|
| 18 |
import tempfile
|
| 19 |
from pathlib import Path
|
| 20 |
|
|
|
|
| 37 |
),
|
| 38 |
},
|
| 39 |
"widgets_empty_state": {
|
| 40 |
+
"severity": "info",
|
| 41 |
"title": "metadata.widgets exists but 'state' is empty",
|
| 42 |
+
"desc": "The widget state dict is present but empty β GitHub renders this fine.",
|
| 43 |
},
|
| 44 |
"no_kernelspec": {
|
| 45 |
"severity": "warning",
|
|
|
|
| 222 |
})
|
| 223 |
continue
|
| 224 |
|
| 225 |
+
# Always strip oversized base64 images regardless of the checkbox
|
| 226 |
data = out.get("data", {})
|
| 227 |
for mime in list(data.keys()):
|
| 228 |
if mime.startswith("image/") and isinstance(data[mime], str):
|
|
|
|
| 230 |
img_bytes = len(base64.b64decode(data[mime], validate=False))
|
| 231 |
except Exception:
|
| 232 |
img_bytes = len(data[mime])
|
| 233 |
+
if img_bytes > MAX_IMAGE_SIZE:
|
| 234 |
data[mime] = "" # clear the giant image
|
| 235 |
data.setdefault("text/plain", ["[Large image removed for GitHub compatibility]"])
|
| 236 |
|
| 237 |
new_outputs.append(out)
|
| 238 |
cell["outputs"] = new_outputs
|
| 239 |
|
| 240 |
+
# Ensure every cell has a valid nbformat 4.5+ id (8-char hex)
|
| 241 |
+
existing_id = cell.get("id", "")
|
| 242 |
+
if not existing_id or len(existing_id) < 8:
|
| 243 |
+
cell["id"] = uuid.uuid4().hex[:8]
|
| 244 |
|
| 245 |
return nb
|
| 246 |
|
|
|
|
| 377 |
"Works for Colab, Jupyter, and any nbformat-4 notebook.*"
|
| 378 |
)
|
| 379 |
|
| 380 |
+
with gr.Accordion("π Privacy & Data β your files are never stored", open=False):
|
| 381 |
+
gr.Markdown("""
|
| 382 |
+
### How this tool works
|
| 383 |
+
|
| 384 |
+
1. You upload a `.ipynb` file β it is read **entirely in memory** on the server.
|
| 385 |
+
2. The tool analyses the JSON structure, fixes any issues, and writes a temporary output file.
|
| 386 |
+
3. You download the fixed file.
|
| 387 |
+
4. The temporary file is managed by the OS and is **automatically deleted** β it is never persisted beyond your session.
|
| 388 |
+
|
| 389 |
+
### What we do NOT do
|
| 390 |
+
|
| 391 |
+
- β We do **not** save, log, or store your notebook file anywhere.
|
| 392 |
+
- β We do **not** collect any personal information or usage metadata linked to your file.
|
| 393 |
+
- β There is **no database** β nothing is written to permanent storage.
|
| 394 |
+
- β Your notebook content is **never shared** with third parties.
|
| 395 |
+
|
| 396 |
+
### What happens to your data
|
| 397 |
+
|
| 398 |
+
Your file lives only in the server's RAM and a short-lived OS temp file for the duration of your request.
|
| 399 |
+
Once you close the session or the Space restarts, every trace of it is gone.
|
| 400 |
+
**You are the only person who ever sees your notebook.**
|
| 401 |
+
""")
|
| 402 |
+
|
| 403 |
if __name__ == "__main__":
|
| 404 |
demo.launch()
|
requirements.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|