Ryonaly commited on
Commit
de6a2d9
·
verified ·
1 Parent(s): f6bc3da

Upload 4 files

Browse files
Files changed (4) hide show
  1. LICENSE +3 -0
  2. README.md +2 -19
  3. requirements.txt +2 -3
  4. streamlit_app.py +113 -0
LICENSE ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ MIT License
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy...
README.md CHANGED
@@ -1,20 +1,3 @@
1
- ---
2
- title: Nicu Handover
3
- emoji: 🚀
4
- colorFrom: red
5
- colorTo: red
6
- sdk: docker
7
- app_port: 8501
8
- tags:
9
- - streamlit
10
- pinned: false
11
- short_description: Streamlit template space
12
- license: mit
13
- ---
14
 
15
- # Welcome to Streamlit!
16
-
17
- Edit `/src/streamlit_app.py` to customize this app to your heart's desire. :heart:
18
-
19
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
20
- forums](https://discuss.streamlit.io).
 
1
+ # NICU Handover
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
+ Streamlit app to manage NICU patient handovers. Built without a database, using local JSON file for storage.
 
 
 
 
 
requirements.txt CHANGED
@@ -1,3 +1,2 @@
1
- altair
2
- pandas
3
- streamlit
 
1
+ streamlit>=1.29
2
+ pandas>=1.5
 
streamlit_app.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from datetime import date
4
+ from typing import List, Dict
5
+ import pandas as pd
6
+ import streamlit as st
7
+
8
+ DATA_FILE = os.path.join(os.path.dirname(__file__), "patients.json")
9
+
10
+ def load_data() -> List[Dict]:
11
+ if os.path.exists(DATA_FILE):
12
+ try:
13
+ with open(DATA_FILE, "r", encoding="utf-8") as f:
14
+ data = json.load(f)
15
+ if isinstance(data, list):
16
+ return data
17
+ except Exception:
18
+ pass
19
+ return []
20
+
21
+ def save_data(data: List[Dict]) -> None:
22
+ tmp_path = DATA_FILE + ".tmp"
23
+ with open(tmp_path, "w", encoding="utf-8") as f:
24
+ json.dump(data, f, indent=4, default=str)
25
+ os.replace(tmp_path, DATA_FILE)
26
+
27
+ def add_patient(data: List[Dict]) -> None:
28
+ st.subheader("Add new patient")
29
+ with st.form("add_patient_form", clear_on_submit=True):
30
+ patient_id = st.text_input("Patient ID*")
31
+ name = st.text_input("Patient name*")
32
+ dob = st.date_input("Date of birth", value=None)
33
+ gestational_age = st.number_input("Gestational age (weeks)", min_value=0, max_value=50, step=1)
34
+ weight = st.number_input("Weight (kg)", min_value=0.0, step=0.01, format="%.2f")
35
+ location = st.text_input("Location (unit/room/bed)")
36
+ diagnosis = st.text_area("Diagnosis and condition")
37
+ st.markdown("**Latest vital signs**")
38
+ vital_hr = st.number_input("Heart rate (bpm)", min_value=0, step=1)
39
+ vital_rr = st.number_input("Respiratory rate (breaths/min)", min_value=0, step=1)
40
+ vital_sat = st.number_input("Oxygen saturation (%)", min_value=0, max_value=100, step=1)
41
+ medications = st.text_area("Important medications")
42
+ labs = st.text_area("Important lab results")
43
+ to_do = st.text_area("To-do items / contingencies")
44
+ submitted = st.form_submit_button("Add patient")
45
+ if submitted:
46
+ if not patient_id.strip() or not name.strip():
47
+ st.error("Patient ID and name are required.")
48
+ else:
49
+ new_patient = {
50
+ "patient_id": patient_id.strip(),
51
+ "name": name.strip(),
52
+ "dob": str(dob) if dob else "",
53
+ "gestational_age": int(gestational_age),
54
+ "weight": float(weight),
55
+ "location": location.strip(),
56
+ "diagnosis": diagnosis.strip(),
57
+ "vital_hr": int(vital_hr),
58
+ "vital_rr": int(vital_rr),
59
+ "vital_sat": int(vital_sat),
60
+ "medications": medications.strip(),
61
+ "labs": labs.strip(),
62
+ "to_do": to_do.strip(),
63
+ "created": str(date.today()),
64
+ "last_updated": str(date.today()),
65
+ }
66
+ data.append(new_patient)
67
+ save_data(data)
68
+ st.success(f"Patient {name} added successfully.")
69
+
70
+ def handover_summary(data: List[Dict]) -> None:
71
+ st.subheader("Handover summary")
72
+ if not data:
73
+ st.info("No patients in the system.")
74
+ return
75
+ for p in data:
76
+ with st.expander(f"{p['name']} (ID: {p['patient_id']})"):
77
+ st.write(f"**Location:** {p.get('location', '')}")
78
+ st.write(f"**Diagnosis:** {p.get('diagnosis', '')}")
79
+ col1, col2, col3 = st.columns(3)
80
+ col1.metric("HR", f"{p.get('vital_hr', '—')} bpm")
81
+ col2.metric("RR", f"{p.get('vital_rr', '—')} bpm")
82
+ col3.metric("Sat", f"{p.get('vital_sat', '—')} %")
83
+ if p.get("medications"):
84
+ st.write("**Medications:**\n" + p["medications"])
85
+ if p.get("labs"):
86
+ st.write("**Labs:**\n" + p["labs"])
87
+ if p.get("to_do"):
88
+ st.write("**To-do:**\n" + p["to_do"])
89
+ st.write(f"**Last updated:** {p.get('last_updated', '')}")
90
+
91
+ def export_data(data: List[Dict]) -> None:
92
+ st.subheader("Export data")
93
+ if not data:
94
+ st.info("No patients to export.")
95
+ return
96
+ df = pd.DataFrame(data)
97
+ csv = df.to_csv(index=False).encode("utf-8")
98
+ st.download_button("Download CSV", data=csv, file_name="nicu_patients.csv", mime="text/csv")
99
+
100
+ def main():
101
+ st.set_page_config(page_title="NICU Handover", page_icon="👶", layout="wide")
102
+ st.title("NICU Handover Tool")
103
+ data = load_data()
104
+ page = st.sidebar.radio("Menu", ["Add patient", "Handover summary", "Export data"])
105
+ if page == "Add patient":
106
+ add_patient(data)
107
+ elif page == "Handover summary":
108
+ handover_summary(data)
109
+ elif page == "Export data":
110
+ export_data(data)
111
+
112
+ if __name__ == "__main__":
113
+ main()