Update app.py
Browse files
app.py
CHANGED
|
@@ -710,7 +710,7 @@ def _same_tab_download_button(label: str, data_bytes: bytes, file_name: str, mim
|
|
| 710 |
# =========================
|
| 711 |
# Per-file processing
|
| 712 |
# =========================
|
| 713 |
-
def process_nifti_case(nifti_path: str, model, rows_acc: List[Dict], per_frame_rows_acc: List[pd.DataFrame]):
|
| 714 |
pid = Path(nifti_path).stem
|
| 715 |
log(f"Using NIfTI input: {nifti_path}")
|
| 716 |
|
|
@@ -785,11 +785,13 @@ def process_nifti_case(nifti_path: str, model, rows_acc: List[Dict], per_frame_r
|
|
| 785 |
# GIF: ED vs ES (slices animate)
|
| 786 |
gif_path = gif_animation_for_patient_pred_only(imgs_4d, preds_4d, pid, ed_idx, es_idx, GIFS_DIR)
|
| 787 |
try:
|
| 788 |
-
st.image(gif_path, caption="Generated GIF", use_column_width=True)
|
| 789 |
except TypeError:
|
| 790 |
-
st.image(gif_path, caption="Generated GIF")
|
| 791 |
log(f"GIF saved: {gif_path}")
|
| 792 |
-
|
|
|
|
|
|
|
| 793 |
|
| 794 |
# =========================
|
| 795 |
# UI
|
|
@@ -917,15 +919,22 @@ def main():
|
|
| 917 |
|
| 918 |
st.markdown('</div></div>', unsafe_allow_html=True)
|
| 919 |
|
| 920 |
-
|
|
|
|
|
|
|
| 921 |
if uploaded_zip is not None:
|
| 922 |
if st.session_state.get("_last_zip_name") != uploaded_zip.name:
|
| 923 |
st.session_state.pop("csv_bytes", None)
|
| 924 |
st.session_state.pop("csv_name", None)
|
| 925 |
st.session_state.pop("rows_count", None)
|
| 926 |
st.session_state.pop("_dl_token", None) # reset download-button identity
|
|
|
|
|
|
|
|
|
|
|
|
|
| 927 |
st.session_state["_last_zip_name"] = uploaded_zip.name
|
| 928 |
|
|
|
|
| 929 |
# ---- Extract helper ----
|
| 930 |
def extract_zip(zip_path, extract_to):
|
| 931 |
os.makedirs(extract_to, exist_ok=True)
|
|
@@ -974,13 +983,21 @@ def main():
|
|
| 974 |
|
| 975 |
rows: List[Dict] = []
|
| 976 |
per_frame_rows: List[pd.DataFrame] = []
|
|
|
|
|
|
|
|
|
|
|
|
|
| 977 |
|
| 978 |
for fp in sorted(nii_files):
|
| 979 |
try:
|
| 980 |
-
process_nifti_case(fp, model, rows, per_frame_rows)
|
|
|
|
|
|
|
| 981 |
except Exception as e:
|
| 982 |
st.warning(f"Failed: {Path(fp).name} — {e}")
|
| 983 |
|
|
|
|
|
|
|
| 984 |
# ---- BELOW the GIF(s): write CSV & persist bytes/name ----
|
| 985 |
csv_path = write_all_in_one_csv(rows, per_frame_rows, CSV_DIR)
|
| 986 |
csv_download_name = f"{Path(zip_label).stem}_Results.csv"
|
|
@@ -990,12 +1007,25 @@ def main():
|
|
| 990 |
st.session_state["csv_bytes"] = csv_bytes
|
| 991 |
st.session_state["csv_name"] = csv_download_name
|
| 992 |
st.session_state["rows_count"] = len(rows)
|
|
|
|
|
|
|
|
|
|
| 993 |
|
| 994 |
-
# ---- Re-render
|
| 995 |
if "csv_bytes" in st.session_state and "csv_name" in st.session_state:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 996 |
st.success(f"Processed {st.session_state.get('rows_count', 0)} NIfTI file(s).")
|
| 997 |
-
|
| 998 |
-
# Use our same-tab data:URI button that looks like Streamlit's and turns red on hover
|
| 999 |
_same_tab_download_button(
|
| 1000 |
label="Download CSV",
|
| 1001 |
data_bytes=st.session_state["csv_bytes"],
|
|
@@ -1005,7 +1035,6 @@ def main():
|
|
| 1005 |
)
|
| 1006 |
|
| 1007 |
|
| 1008 |
-
|
| 1009 |
# ===== Tab 2: Dataset =====
|
| 1010 |
with tab2:
|
| 1011 |
st.markdown(
|
|
|
|
| 710 |
# =========================
|
| 711 |
# Per-file processing
|
| 712 |
# =========================
|
| 713 |
+
def process_nifti_case(nifti_path: str, model, rows_acc: List[Dict], per_frame_rows_acc: List[pd.DataFrame]) -> Optional[str]:
|
| 714 |
pid = Path(nifti_path).stem
|
| 715 |
log(f"Using NIfTI input: {nifti_path}")
|
| 716 |
|
|
|
|
| 785 |
# GIF: ED vs ES (slices animate)
|
| 786 |
gif_path = gif_animation_for_patient_pred_only(imgs_4d, preds_4d, pid, ed_idx, es_idx, GIFS_DIR)
|
| 787 |
try:
|
| 788 |
+
st.image(gif_path, caption=f"Generated GIF — {pid}", use_column_width=True)
|
| 789 |
except TypeError:
|
| 790 |
+
st.image(gif_path, caption=f"Generated GIF — {pid}")
|
| 791 |
log(f"GIF saved: {gif_path}")
|
| 792 |
+
|
| 793 |
+
return gif_path
|
| 794 |
+
|
| 795 |
|
| 796 |
# =========================
|
| 797 |
# UI
|
|
|
|
| 919 |
|
| 920 |
st.markdown('</div></div>', unsafe_allow_html=True)
|
| 921 |
|
| 922 |
+
|
| 923 |
+
|
| 924 |
+
# ---- Clear stale results when a new ZIP is picked ----
|
| 925 |
if uploaded_zip is not None:
|
| 926 |
if st.session_state.get("_last_zip_name") != uploaded_zip.name:
|
| 927 |
st.session_state.pop("csv_bytes", None)
|
| 928 |
st.session_state.pop("csv_name", None)
|
| 929 |
st.session_state.pop("rows_count", None)
|
| 930 |
st.session_state.pop("_dl_token", None) # reset download-button identity
|
| 931 |
+
|
| 932 |
+
# NEW: clear any previously displayed GIFs
|
| 933 |
+
st.session_state.pop("gif_paths", None)
|
| 934 |
+
|
| 935 |
st.session_state["_last_zip_name"] = uploaded_zip.name
|
| 936 |
|
| 937 |
+
|
| 938 |
# ---- Extract helper ----
|
| 939 |
def extract_zip(zip_path, extract_to):
|
| 940 |
os.makedirs(extract_to, exist_ok=True)
|
|
|
|
| 983 |
|
| 984 |
rows: List[Dict] = []
|
| 985 |
per_frame_rows: List[pd.DataFrame] = []
|
| 986 |
+
|
| 987 |
+
# NEW: collect GIFs generated during this run
|
| 988 |
+
gif_paths: List[str] = []
|
| 989 |
+
|
| 990 |
|
| 991 |
for fp in sorted(nii_files):
|
| 992 |
try:
|
| 993 |
+
gif_path = process_nifti_case(fp, model, rows, per_frame_rows)
|
| 994 |
+
if gif_path:
|
| 995 |
+
gif_paths.append(gif_path)
|
| 996 |
except Exception as e:
|
| 997 |
st.warning(f"Failed: {Path(fp).name} — {e}")
|
| 998 |
|
| 999 |
+
|
| 1000 |
+
|
| 1001 |
# ---- BELOW the GIF(s): write CSV & persist bytes/name ----
|
| 1002 |
csv_path = write_all_in_one_csv(rows, per_frame_rows, CSV_DIR)
|
| 1003 |
csv_download_name = f"{Path(zip_label).stem}_Results.csv"
|
|
|
|
| 1007 |
st.session_state["csv_bytes"] = csv_bytes
|
| 1008 |
st.session_state["csv_name"] = csv_download_name
|
| 1009 |
st.session_state["rows_count"] = len(rows)
|
| 1010 |
+
# NEW: persist GIFs so they can be shown after reruns
|
| 1011 |
+
st.session_state["gif_paths"] = gif_paths
|
| 1012 |
+
|
| 1013 |
|
| 1014 |
+
# ---- Re-render GIFs + success + download on EVERY run ----
|
| 1015 |
if "csv_bytes" in st.session_state and "csv_name" in st.session_state:
|
| 1016 |
+
# NEW: show GIFs again (persisted from the run that created the CSV)
|
| 1017 |
+
if "gif_paths" in st.session_state and st.session_state["gif_paths"]:
|
| 1018 |
+
st.markdown("### Generated GIFs")
|
| 1019 |
+
for gp in st.session_state["gif_paths"]:
|
| 1020 |
+
# Optional: show filename/patient id
|
| 1021 |
+
cap = f"{Path(gp).stem}"
|
| 1022 |
+
try:
|
| 1023 |
+
st.image(gp, caption=cap, use_column_width=True)
|
| 1024 |
+
except TypeError:
|
| 1025 |
+
st.image(gp, caption=cap)
|
| 1026 |
+
|
| 1027 |
st.success(f"Processed {st.session_state.get('rows_count', 0)} NIfTI file(s).")
|
| 1028 |
+
|
|
|
|
| 1029 |
_same_tab_download_button(
|
| 1030 |
label="Download CSV",
|
| 1031 |
data_bytes=st.session_state["csv_bytes"],
|
|
|
|
| 1035 |
)
|
| 1036 |
|
| 1037 |
|
|
|
|
| 1038 |
# ===== Tab 2: Dataset =====
|
| 1039 |
with tab2:
|
| 1040 |
st.markdown(
|