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)