owner120 commited on
Commit
0d4f97b
·
verified ·
1 Parent(s): 6b86bf3

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. app.py +118 -0
  2. dashboard.html +140 -0
  3. train.py +68 -0
app.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, jsonify, render_template
2
+ import joblib, pandas as pd, numpy as np
3
+ from datetime import datetime
4
+ import psycopg2
5
+ from psycopg2 import pool
6
+
7
+ app = Flask(_name_)
8
+
9
+ # ---------- Load model bundle ----------
10
+ bundle = joblib.load('gas_danger_model.pkl')
11
+ model = bundle['model']
12
+ FEATURES = bundle['features'] # ['Hour', 'Weekday', 'Month', 'Afternoon']
13
+
14
+ # ---------- PostgreSQL connection pool ----------
15
+ PG_POOL = pool.SimpleConnectionPool(
16
+ 1, 5,
17
+ user="postgres.czytuqnowdogaowfnfhe",
18
+ password="235711",
19
+ host="aws-0-eu-central-1.pooler.supabase.com",
20
+ port="5432",
21
+ dbname="postgres"
22
+ )
23
+
24
+ # ---------- Per‑gas safety limits ----------
25
+ SAFETY_THRESHOLDS = {
26
+ 'alcohol': 1000, 'NH3': 25, 'CO': 35, 'CO2': 5000,
27
+ 'Toluene': 100, 'acetone': 750, 'lpg': 1000, 'smoke': 1.0
28
+ }
29
+
30
+ # ---------- Helper to fetch latest row ----------
31
+ def fetch_latest_reading():
32
+ """
33
+ Returns a dict with keys exactly matching the ones used elsewhere:
34
+ CO2, NH3, alcohol, Toluene, acetone, lpg, CO, smoke, timestamp
35
+ """
36
+ sql = """
37
+ SELECT co2,
38
+ nh3,
39
+ alcohol,
40
+ toluene,
41
+ acetone,
42
+ lpg,
43
+ co,
44
+ smoke,
45
+ "timestamp"
46
+ FROM gas_data
47
+ ORDER BY "timestamp" DESC
48
+ LIMIT 1;
49
+ """
50
+ conn = PG_POOL.getconn()
51
+ try:
52
+ with conn.cursor() as cur:
53
+ cur.execute(sql)
54
+ row = cur.fetchone()
55
+ if row is None:
56
+ return None
57
+ raw_keys = ['co2','nh3','alcohol','toluene','acetone',
58
+ 'lpg','co','smoke','timestamp']
59
+ raw = dict(zip(raw_keys, row))
60
+ # Map to mixed‑case keys expected elsewhere
61
+ return {
62
+ 'CO2': raw['co2'],
63
+ 'NH3': raw['nh3'],
64
+ 'alcohol': raw['alcohol'],
65
+ 'Toluene': raw['toluene'],
66
+ 'acetone': raw['acetone'],
67
+ 'lpg': raw['lpg'],
68
+ 'CO': raw['co'],
69
+ 'smoke': raw['smoke'],
70
+ 'timestamp':raw['timestamp']
71
+ }
72
+ finally:
73
+ PG_POOL.putconn(conn)
74
+
75
+ # ---------- Routes ----------
76
+ @app.route('/api/predict', methods=['GET'])
77
+ def predict():
78
+ current = fetch_latest_reading()
79
+ if current is None:
80
+ return jsonify({'error': 'No rows in gas_data table'}), 404
81
+
82
+ ts = current['timestamp']
83
+ now = ts if ts else datetime.now()
84
+
85
+ # Add time‑based features
86
+ current.update({
87
+ 'Hour': now.hour,
88
+ 'Weekday': now.weekday(),
89
+ 'Month': now.month,
90
+ 'Afternoon': int(12 <= now.hour <= 15)
91
+ })
92
+
93
+ # Build feature vector in training order
94
+ X = pd.DataFrame([[current.get(f, np.nan) for f in FEATURES]], columns=FEATURES)
95
+ prob = float(model.predict_proba(X)[0, 1])
96
+
97
+ # Per‑gas alert block
98
+ alerts = {
99
+ g: {
100
+ 'value': current[g],
101
+ 'threshold': thr,
102
+ 'status': 'danger' if current[g] > thr else 'safe'
103
+ } for g, thr in SAFETY_THRESHOLDS.items()
104
+ }
105
+
106
+ return jsonify({
107
+ 'prediction': prob,
108
+ 'alerts': alerts,
109
+ 'overall_status': 'danger' if prob > 0.4 else 'safe',
110
+ 'timestamp': now.isoformat()
111
+ })
112
+
113
+ @app.route('/')
114
+ def dashboard():
115
+ return render_template('dashboard.html') # supply your own template
116
+
117
+ if _name_ == '_main_':
118
+ app.run(debug=True, port=5000)
dashboard.html ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Gas Danger Monitoring</title>
5
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
6
+ <style>
7
+ body { font-family: Arial, sans-serif; margin: 20px; }
8
+ .dashboard { display: grid; grid-template-columns: 2fr 1fr; gap: 20px; }
9
+ .card { background: #f5f5f5; padding: 15px; border-radius: 8px; margin-bottom: 15px; }
10
+ .danger { background: #ffcccc; border-left: 5px solid red; }
11
+ .safe { background: #ccffcc; border-left: 5px solid green; }
12
+ .gauge { height: 20px; background: #ddd; border-radius: 10px; margin: 5px 0; }
13
+ .gauge-fill { height: 100%; border-radius: 10px; }
14
+ </style>
15
+ </head>
16
+ <body>
17
+ <h1>Factory Gas Monitoring</h1>
18
+ <div class="dashboard">
19
+ <div>
20
+ <div class="card" id="status-card">
21
+ <h2>System Status: <span id="overall-status">Loading...</span></h2>
22
+ <p>Danger Probability: <span id="danger-prob">-</span></p>
23
+ <div class="gauge">
24
+ <div class="gauge-fill" id="danger-gauge"></div>
25
+ </div>
26
+ </div>
27
+
28
+ <div class="card">
29
+ <h2>Gas Levels vs Safety Thresholds</h2>
30
+ <canvas id="gasChart" height="300"></canvas>
31
+ </div>
32
+ </div>
33
+
34
+ <div>
35
+ <div class="card">
36
+ <h2>Alerts</h2>
37
+ <div id="alerts-container"></div>
38
+ </div>
39
+
40
+ <div class="card">
41
+ <h2>Key Metrics</h2>
42
+ <div id="metrics">
43
+ <p>Last Updated: <span id="timestamp">-</span></p>
44
+ <p>Top Risk Factor: <span id="top-risk">CO_rolling_12h</span></p>
45
+ </div>
46
+ </div>
47
+ </div>
48
+ </div>
49
+
50
+ <script>
51
+ let gasChart;
52
+
53
+ // Fetch data every 5 seconds
54
+ function updateData() {
55
+ fetch('/api/predict')
56
+ .then(response => response.json())
57
+ .then(data => {
58
+ // Update overall status
59
+ document.getElementById('overall-status').textContent =
60
+ data.overall_status.toUpperCase();
61
+ document.getElementById('overall-status').className = data.overall_status;
62
+
63
+ // Update danger probability
64
+ const dangerPercent = (data.prediction * 100).toFixed(1);
65
+ document.getElementById('danger-prob').textContent = ${dangerPercent}%;
66
+ document.getElementById('danger-gauge').style.width = ${dangerPercent}%;
67
+ document.getElementById('danger-gauge').style.backgroundColor =
68
+ data.prediction > 0.4 ? 'red' : 'green';
69
+
70
+ // Update timestamp
71
+ document.getElementById('timestamp').textContent =
72
+ new Date(data.timestamp).toLocaleString();
73
+
74
+ // Update alerts
75
+ const alertsContainer = document.getElementById('alerts-container');
76
+ alertsContainer.innerHTML = '';
77
+ for (const [gas, info] of Object.entries(data.alerts)) {
78
+ const alertDiv = document.createElement('div');
79
+ alertDiv.className = card ${info.status};
80
+ alertDiv.innerHTML = `
81
+ <h3>${gas}</h3>
82
+ <p>${info.value.toFixed(2)} ppm (Threshold: ${info.threshold} ppm)</p>
83
+ <p>Status: <strong>${info.status.toUpperCase()}</strong></p>
84
+ `;
85
+ alertsContainer.appendChild(alertDiv);
86
+ }
87
+
88
+ // Update chart
89
+ updateChart(data.alerts);
90
+ });
91
+ }
92
+
93
+ function updateChart(alerts) {
94
+ const gases = Object.keys(alerts);
95
+ const values = gases.map(gas => alerts[gas].value);
96
+ const thresholds = gases.map(gas => alerts[gas].threshold);
97
+
98
+ if (gasChart) {
99
+ gasChart.data.datasets[0].data = values;
100
+ gasChart.data.datasets[1].data = thresholds;
101
+ gasChart.update();
102
+ } else {
103
+ const ctx = document.getElementById('gasChart').getContext('2d');
104
+ gasChart = new Chart(ctx, {
105
+ type: 'bar',
106
+ data: {
107
+ labels: gases,
108
+ datasets: [
109
+ {
110
+ label: 'Current Level (ppm)',
111
+ data: values,
112
+ backgroundColor: values.map((v, i) =>
113
+ v > thresholds[i] ? 'rgba(255, 99, 132, 0.7)' : 'rgba(54, 162, 235, 0.7)'
114
+ )
115
+ },
116
+ {
117
+ label: 'Safety Threshold',
118
+ data: thresholds,
119
+ type: 'line',
120
+ borderColor: 'rgba(255, 159, 64, 1)',
121
+ borderWidth: 2,
122
+ fill: false
123
+ }
124
+ ]
125
+ },
126
+ options: {
127
+ scales: {
128
+ y: { beginAtZero: true, title: { display: true, text: 'Concentration (ppm)' } }
129
+ }
130
+ }
131
+ });
132
+ }
133
+ }
134
+
135
+ // Initial load
136
+ updateData();
137
+ setInterval(updateData, 5000); // Refresh every 5 seconds
138
+ </script>
139
+ </body>
140
+ </html>
train.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ import joblib
4
+ from sklearn.pipeline import make_pipeline
5
+ from sklearn.preprocessing import StandardScaler
6
+ from xgboost import XGBClassifier
7
+ from sklearn.metrics import classification_report
8
+
9
+ # ---------------- Load & preprocess ----------------
10
+ df = pd.read_csv('../city_day_clean_dated.csv', parse_dates=['Date']).sort_values('Date')
11
+
12
+ # Fill missing hours
13
+ full = pd.DataFrame(pd.date_range(df['Date'].min(), df['Date'].max(), freq='h'), # 'H' → 'h'
14
+ columns=['DateTime'])
15
+ df = full.merge(df, left_on=full['DateTime'].dt.date,
16
+ right_on=df['Date'].dt.date, how='left').ffill()
17
+ df['Date'] = df['DateTime']
18
+
19
+ # Filter numeric gas columns only (avoid 'DateTime', etc.)
20
+ gas_cols = ['alcohol', 'NH3', 'CO', 'CO2', 'Toluene', 'acetone', 'lpg', 'smoke']
21
+
22
+ # Create danger flags
23
+ danger_thresholds = {col: np.percentile(df[col].dropna(), 95) for col in gas_cols}
24
+ for col in gas_cols:
25
+ df[f'{col}_danger'] = (df[col] > danger_thresholds[col]).astype(int)
26
+
27
+ df['Danger'] = df[[f'{col}_danger' for col in gas_cols]].max(axis=1)
28
+
29
+ # Time features
30
+ df['Hour'] = df['DateTime'].dt.hour
31
+ df['Weekday'] = df['DateTime'].dt.weekday
32
+ df['Month'] = df['DateTime'].dt.month
33
+ df['Afternoon'] = ((df['Hour'] >= 12) & (df['Hour'] <= 15)).astype(int)
34
+
35
+ # Simple demo features
36
+ features = ['Hour', 'Weekday', 'Month', 'Afternoon']
37
+ target = 'Danger'
38
+
39
+ train = df[df['DateTime'] < '2020-01-01']
40
+ test = df[df['DateTime'] >= '2020-01-01']
41
+
42
+ X_train, y_train = train[features], train[target]
43
+ X_test, y_test = test[features], test[target]
44
+
45
+ # ---------------- Build model ----------------
46
+ model = make_pipeline(
47
+ StandardScaler(),
48
+ XGBClassifier(
49
+ n_estimators=200,
50
+ max_depth=5,
51
+ learning_rate=0.1,
52
+ subsample=0.8,
53
+ colsample_bytree=0.8,
54
+ scale_pos_weight=10,
55
+ random_state=42,
56
+ eval_metric='logloss'
57
+ )
58
+ )
59
+ model.fit(X_train, y_train)
60
+
61
+ print('Training report:')
62
+ print(classification_report(y_train, model.predict(X_train)))
63
+ print('\nTest report:')
64
+ print(classification_report(y_test, model.predict(X_test)))
65
+
66
+ # ---------------- Save bundle ----------------
67
+ joblib.dump({'model': model, 'features': features}, 'gas_danger_model.pkl')
68
+ print('✔️ Model saved to gas_danger_model.pkl')