"""Files tab โ€” BLAKE3 content-addressed blob store (M07).""" from __future__ import annotations def build_files_tab(bus=None): import gradio as gr with gr.Column(): gr.HTML("""

๐Ÿ—‚๏ธ Files & Shared Blobs

BLAKE3 content-addressed storage ยท CID deduplication ยท mesh file sharing

""") gr.Markdown("""### ๐Ÿ—‚๏ธ Files & Shared Blobs All files are stored with a **BLAKE3 content hash** as their identifier (CID). The same file uploaded on two different nodes gets the same CID โ€” deduplication is automatic. **How to use:** - Upload any file โ€” it is stored locally and advertised to the mesh - Other nodes can fetch the file by CID via `bus.call("file.get", {"cid": ...})` - On a multi-node mesh, files are available from any node that has them **What works on HF Space:** Local upload/list only (no peer nodes to share with) **What works locally:** Full mesh file sharing โ€” any node can request any file from any peer """) refresh_btn = gr.Button("๐Ÿ”„ Refresh List", size="sm") blobs_out = gr.JSON(label="Stored Files") gr.Markdown("#### Upload File") file_upload = gr.File(label="Choose file to upload to mesh", type="filepath") upload_btn = gr.Button("โฌ† Upload", variant="primary") upload_result = gr.JSON(label="Upload Result", visible=False) gr.Markdown("#### Download File by CID") with gr.Row(): cid_input = gr.Textbox( label="CID (paste from list above)", placeholder="blake3:...", scale=4 ) download_btn = gr.Button("โฌ‡ Download", scale=1) download_file = gr.File(label="Download", visible=False) download_err = gr.Markdown(visible=False) async def do_refresh(): if bus is None: return [{"info": "bus not connected โ€” pass bus= to build_files_tab()"}] try: r = await bus.call("file.list", (1, 0), {"input": {}}) files = r.get("output", {}).get("files", []) if not files: return [{"info": "No files stored yet. Upload a file above."}] return files except Exception as e: return [{"error": str(e)}] async def do_upload(filepath): if not filepath: return ( gr.update(visible=True, value={"error": "No file selected"}), gr.update(), # blobs_out unchanged ) if bus is None: return ( gr.update(visible=True, value={"error": "Bus not connected"}), gr.update(), ) try: import base64 import os with open(filepath, "rb") as fh: data = fh.read() data_b64 = base64.b64encode(data).decode() filename = os.path.basename(filepath) r = await bus.call( "file.put", (1, 0), {"input": {"data_b64": data_b64, "filename": filename}}, ) # Auto-refresh the list list_r = await bus.call("file.list", (1, 0), {"input": {}}) files = list_r.get("output", {}).get("files", []) return ( gr.update(visible=True, value=r.get("output", r)), files or [{"info": "No files yet"}], ) except Exception as e: return ( gr.update(visible=True, value={"error": str(e)}), gr.update(), ) async def do_download(cid: str): cid = (cid or "").strip() if not cid: return ( gr.update(visible=False), gr.update(visible=True, value="โš  Enter a CID first."), ) if bus is None: return ( gr.update(visible=False), gr.update(visible=True, value="โš  Bus not connected."), ) try: import base64 import tempfile r = await bus.call("file.get", (1, 0), {"input": {"cid": cid}}) if "error" in r: return ( gr.update(visible=False), gr.update(visible=True, value=f"โš  {r['error']}"), ) out = r.get("output", {}) data = base64.b64decode(out["data_b64"]) filename = out.get("filename", cid[:16]) # Write to a temp file so Gradio can serve it tmp = tempfile.NamedTemporaryFile( delete=False, suffix="_" + filename, dir=tempfile.gettempdir() ) tmp.write(data) tmp.close() return ( gr.update(visible=True, value=tmp.name), gr.update(visible=False), ) except Exception as e: return ( gr.update(visible=False), gr.update(visible=True, value=f"โš  Error: {e}"), ) refresh_btn.click(do_refresh, outputs=blobs_out) upload_btn.click(do_upload, inputs=file_upload, outputs=[upload_result, blobs_out]) download_btn.click(do_download, inputs=cid_input, outputs=[download_file, download_err])