File size: 4,855 Bytes
338ddc8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# pages/99_File_Explorer.py
# -------------------------------------------------------------------
# Universal File Explorer for the /data directory (and subfolders).
# Allows browsing, viewing JSON/Markdown/text, and downloading files.
# -------------------------------------------------------------------
from __future__ import annotations
import os
import json
import mimetypes
from pathlib import Path
import streamlit as st
# --- Page setup ---
st.set_page_config(page_title="File Explorer", page_icon="π", layout="wide")
st.title("π File Explorer")
st.caption("Browse and download files under the /data directory (e.g., cases, exports, FAISS indexes, etc.)")
# --- Root directory (default /data) ---
ROOT_DIR = Path("/data")
if not ROOT_DIR.exists():
st.error("β οΈ /data directory not found in this environment.")
st.stop()
# --- Utility functions ---
def list_dir(path: Path):
"""Return a sorted list of (name, is_dir) tuples."""
items = []
for entry in sorted(os.listdir(path)):
p = path / entry
if entry.startswith("."): # hide hidden files
continue
items.append((entry, p.is_dir()))
return items
def render_file(path: Path):
"""Render or offer download for the selected file."""
mime, _ = mimetypes.guess_type(str(path))
st.markdown(f"**Path:** `{path}` \n**Size:** {path.stat().st_size:,} bytes")
if path.suffix.lower() in [".json", ".md", ".txt", ".log"]:
try:
text = path.read_text(encoding="utf-8")
if path.suffix.lower() == ".json":
st.json(json.loads(text))
elif path.suffix.lower() == ".md":
st.markdown(text)
else:
st.code(text)
except Exception as e:
st.error(f"Error reading file: {e}")
else:
with open(path, "rb") as f:
st.download_button(
label="β¬οΈ Download File",
data=f,
file_name=path.name,
mime=mime or "application/octet-stream",
use_container_width=True,
)
def export_metadata_tree(root: Path) -> dict:
"""Recursively export metadata (name, size, type, children)."""
tree = {"name": root.name, "path": str(root), "type": "directory" if root.is_dir() else "file"}
if root.is_dir():
children = []
for entry in sorted(os.listdir(root)):
p = root / entry
if entry.startswith("."):
continue
children.append(export_metadata_tree(p))
tree["children"] = children
else:
try:
tree["size"] = root.stat().st_size
except Exception:
tree["size"] = None
return tree
# --- Sidebar navigation ---
st.sidebar.header("π Directory Browser")
def browse(path: Path):
st.sidebar.markdown(f"**Current:** `{path}`")
items = list_dir(path)
for name, is_dir in items:
sub_path = path / name
if is_dir:
if st.sidebar.button(f"π {name}", key=str(sub_path)):
st.session_state["explorer_path"] = str(sub_path)
else:
if st.sidebar.button(f"π {name}", key=str(sub_path)):
st.session_state["selected_file"] = str(sub_path)
# --- Manage navigation state ---
if "explorer_path" not in st.session_state:
st.session_state["explorer_path"] = str(ROOT_DIR)
if "selected_file" not in st.session_state:
st.session_state["selected_file"] = ""
current_path = Path(st.session_state["explorer_path"])
browse(current_path)
# --- Main view ---
st.divider()
st.markdown(f"### π {current_path}")
if st.button("β¬οΈ Up one level", use_container_width=False):
if current_path != ROOT_DIR:
st.session_state["explorer_path"] = str(current_path.parent)
st.session_state["selected_file"] = ""
st.rerun()
# --- Show directory contents ---
entries = list_dir(current_path)
for name, is_dir in entries:
p = current_path / name
icon = "π" if is_dir else "π"
st.write(f"{icon} `{name}`")
st.divider()
# --- Show selected file (if any) ---
selected_path = Path(st.session_state["selected_file"]) if st.session_state["selected_file"] else None
if selected_path and selected_path.exists():
st.subheader(f"π File: {selected_path.name}")
render_file(selected_path)
else:
st.info("Select a file in the sidebar to preview its contents.")
# --- Export metadata tree ---
st.divider()
if st.button("π¦ Export Metadata Tree", use_container_width=True):
tree = export_metadata_tree(ROOT_DIR)
st.download_button(
"β¬οΈ Download Metadata (JSON)",
data=json.dumps(tree, indent=2),
file_name="data_directory_tree.json",
mime="application/json",
use_container_width=True,
)
st.json(tree)
|