minor / app.py
NitinBot001's picture
Update app.py
b93b52b verified
Raw
History Blame Contribute Delete
12.1 kB
from flask import Flask, request, jsonify, render_template_string
import sqlite3
import datetime
app = Flask(__name__)
DB_NAME = "hospital.db"
def init_db():
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS patients
(bed_id INTEGER PRIMARY KEY, name TEXT, age INTEGER, gender TEXT, disease TEXT)''')
c.execute('''CREATE TABLE IF NOT EXISTS vitals
(id INTEGER PRIMARY KEY AUTOINCREMENT, bed_id INTEGER, bpm REAL, spo2 REAL, temp REAL, ecg TEXT, timestamp TEXT)''')
conn.commit()
conn.close()
init_db()
# --- MAIN DASHBOARD TEMPLATE ---
HTML_TEMPLATE = '''
<!DOCTYPE html>
<html>
<head>
<title>Hospital Ward Control Dashboard</title>
<style>
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; padding: 20px; }
.container { max-width: 1000px; margin: 0 auto; background: white; padding: 25px; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
table { width: 100%; border-collapse: collapse; margin-top: 15px; margin-bottom: 30px; }
th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }
th { background-color: #3498db; color: white; }
input, select { padding: 10px; border: 1px solid #ccc; border-radius: 4px; width: 140px; }
button { background-color: #2ecc71; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; }
.btn-view { background-color: #f39c12; color: white; padding: 6px 12px; text-decoration: none; border-radius: 4px; font-weight: bold; font-size: 14px; }
.btn-remove { color: red; font-weight: bold; text-decoration: none; margin-left: 15px; font-size: 14px; }
</style>
</head>
<body>
<div class="container">
<h2>🏥 Autonomous Medical Assistant - Ward Dashboard</h2>
<h3>Assign Patient to Bed</h3>
<form action="/add_patient" method="POST" style="margin-bottom: 30px;">
Bed No: <input type="number" name="bed_id" min="1" style="width:60px;" required>
Name: <input type="text" name="name" required>
Age: <input type="number" name="age" style="width:60px;" required>
Gen: <select name="gender" style="width:60px;"><option>M</option><option>F</option></select>
Disease: <input type="text" name="disease" required>
<button type="submit">Assign Patient</button>
</form>
<h3>Active Patients in Ward</h3>
<table>
<tr><th>Bed No</th><th>Patient Name</th><th>Age</th><th>Gender</th><th>Diagnosed Disease</th><th>Actions</th></tr>
{% for p in patients %}
<tr>
<td><b>Bed {{ p[0] }}</b></td><td>{{ p[1] }}</td><td>{{ p[2] }}</td><td>{{ p[3] }}</td><td>{{ p[4] }}</td>
<td>
<a class="btn-view" href="/report/{{ p[0] }}">View Report</a>
<a class="btn-remove" href="/remove/{{ p[0] }}">Discharge</a>
</td>
</tr>
{% endfor %}
{% if not patients %}
<tr><td colspan="6" style="text-align: center; color: #7f8c8d;">No active patients in the ward.</td></tr>
{% endif %}
</table>
</div>
</body>
</html>
'''
# --- PATIENT REPORT TEMPLATE (NOW WITH CHART.JS FOR ECG) ---
REPORT_TEMPLATE = '''
<!DOCTYPE html>
<html>
<head>
<title>Patient Report - Bed {{ bed_id }}</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; padding: 20px; }
.container { max-width: 900px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
.header-card { background: #34495e; color: white; padding: 20px; border-radius: 8px; margin-bottom: 25px; }
.header-card h2 { margin: 0 0 10px 0; color: #ecf0f1; }
.header-card p { margin: 5px 0; font-size: 16px; color: #bdc3c7; }
.header-card span { color: #fff; font-weight: bold; }
table { width: 100%; border-collapse: collapse; margin-top: 15px; }
th, td { border: 1px solid #ddd; padding: 12px; text-align: center; }
th { background-color: #2c3e50; color: white; }
tr:nth-child(even) { background-color: #f9f9f9; }
.btn-back { display: inline-block; background-color: #3498db; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px; margin-bottom: 20px; font-weight: bold; }
.btn-graph { background-color: #e74c3c; color: white; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-weight: bold; }
.btn-graph:hover { background-color: #c0392b; }
.graph-row { display: none; background-color: #fff !important; }
.canvas-container { width: 100%; height: 250px; }
</style>
</head>
<body>
<div class="container">
<a href="/" class="btn-back">⬅ Back to Dashboard</a>
<div class="header-card">
<h2>Patient Portfolio - Bed {{ bed_id }}</h2>
<p>Name: <span>{{ patient[1] }}</span> &nbsp;|&nbsp; Age: <span>{{ patient[2] }}</span> &nbsp;|&nbsp; Gender: <span>{{ patient[3] }}</span></p>
<p>Diagnosis: <span>{{ patient[4] }}</span></p>
</div>
<h3>Vitals History</h3>
<table>
<tr><th>Timestamp</th><th>Heart Rate</th><th>SpO2 Level</th><th>Temperature</th><th>ECG Trace</th></tr>
{% for v in vitals %}
<tr>
<td>{{ v[6] }}</td>
<td><b>{% if v[2] > 0 %}{{ v[2] }} BPM{% else %}None{% endif %}</b></td>
<td><b>{% if v[3] > 0 %}{{ v[3] }} %{% else %}None{% endif %}</b></td>
<td><b>{% if v[4] > 0 %}{{ v[4] }} °C{% else %}None{% endif %}</b></td>
<td>
{% if v[5] == '[0]' or v[5] == '0' %}
<span style="color:#7f8c8d;">Not Recorded</span>
{% else %}
<button class="btn-graph" onclick="toggleGraph('ecgRow{{ v[0] }}', 'ecgCanvas{{ v[0] }}', {{ v[5] }})">View Graph</button>
{% endif %}
</td>
</tr>
{% if v[5] != '[0]' and v[5] != '0' %}
<tr id="ecgRow{{ v[0] }}" class="graph-row">
<td colspan="5">
<div class="canvas-container">
<canvas id="ecgCanvas{{ v[0] }}"></canvas>
</div>
</td>
</tr>
{% endif %}
{% endfor %}
{% if not vitals %}
<tr><td colspan="5" style="text-align: center; color: #7f8c8d;">No vitals recorded yet.</td></tr>
{% endif %}
</table>
</div>
<script>
// Object to store chart instances so we don't recreate them on every click
const charts = {};
function toggleGraph(rowId, canvasId, ecgData) {
const row = document.getElementById(rowId);
const canvas = document.getElementById(canvasId);
if (row.style.display === "none" || row.style.display === "") {
row.style.display = "table-row";
// Draw chart only if it hasn't been drawn yet
if (!charts[canvasId]) {
const ctx = canvas.getContext('2d');
// Generate X-axis labels (just numbers from 1 to 500)
const labels = Array.from({length: ecgData.length}, (_, i) => i + 1);
charts[canvasId] = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'ECG Signal (20s Trace)',
data: ecgData,
borderColor: '#2ecc71',
borderWidth: 1.5,
pointRadius: 0, // Hides the dots to make it look like a smooth medical wave
fill: false,
tension: 0.1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: true }
},
scales: {
x: { display: false }, // Hide numbers on X axis
y: {
suggestedMin: 0,
suggestedMax: 4095,
title: { display: true, text: 'ADC Value (0-4095)' }
}
}
}
});
}
} else {
row.style.display = "none";
}
}
</script>
</body>
</html>
'''
@app.route('/')
def index():
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute("SELECT * FROM patients ORDER BY bed_id ASC")
patients = c.fetchall()
conn.close()
return render_template_string(HTML_TEMPLATE, patients=patients)
@app.route('/report/<int:bed_id>')
def view_report(bed_id):
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute("SELECT * FROM patients WHERE bed_id=?", (bed_id,))
patient = c.fetchone()
if not patient:
conn.close()
return "Patient not found. They might have been discharged.", 404
c.execute("SELECT * FROM vitals WHERE bed_id=? ORDER BY timestamp DESC", (bed_id,))
vitals = c.fetchall()
conn.close()
return render_template_string(REPORT_TEMPLATE, patient=patient, vitals=vitals, bed_id=bed_id)
@app.route('/add_patient', methods=['POST'])
def add_patient():
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute("REPLACE INTO patients (bed_id, name, age, gender, disease) VALUES (?, ?, ?, ?, ?)",
(request.form['bed_id'], request.form['name'][:15], request.form['age'], request.form['gender'], request.form['disease'][:15]))
conn.commit()
conn.close()
return index()
@app.route('/remove/<int:bed_id>')
def remove_patient(bed_id):
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute("DELETE FROM patients WHERE bed_id=?", (bed_id,))
c.execute("DELETE FROM vitals WHERE bed_id=?", (bed_id,))
conn.commit()
conn.close()
return index()
@app.route('/api/system_status', methods=['GET'])
def get_status():
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute("SELECT COUNT(*) FROM patients")
count = c.fetchone()[0]
conn.close()
return jsonify({"total_patients": count})
@app.route('/api/patient/<int:bed_id>', methods=['GET'])
def get_patient(bed_id):
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute("SELECT name, age, gender, disease FROM patients WHERE bed_id=?", (bed_id,))
row = c.fetchone()
conn.close()
if row: return jsonify({"found": True, "name": row[0], "age": row[1], "gender": row[2], "disease": row[3]})
return jsonify({"found": False})
@app.route('/api/vitals', methods=['POST'])
def save_vitals():
data = request.json
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
conn = sqlite3.connect(DB_NAME)
c = conn.cursor()
c.execute("INSERT INTO vitals (bed_id, bpm, spo2, temp, ecg, timestamp) VALUES (?, ?, ?, ?, ?, ?)",
(data['bed_id'], data['bpm'], data['spo2'], data['temp'], str(data['ecg']), timestamp))
conn.commit()
conn.close()
return jsonify({"status": "success"})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=7860)