priyadip Claude Sonnet 4.6 commited on
Commit
fe7a57c
Β·
1 Parent(s): 1e370cb

Add privacy notice to UI and README

Browse files

Added 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>

Files changed (3) hide show
  1. README.md +9 -0
  2. app.py +32 -8
  3. 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 sys
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": "warning",
42
  "title": "metadata.widgets exists but 'state' is empty",
43
- "desc": "The widget state dict is present but empty β€” harmless but adds noise.",
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
- # Compress oversized base64 images by keeping a placeholder
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 strip_large_outputs and img_bytes > MAX_IMAGE_SIZE:
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 an 'id' field (nbformat 4.5+)
242
- cell.setdefault("id", f"cell-{id(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
+