PD03 commited on
Commit
f0248fd
Β·
verified Β·
1 Parent(s): 368d8cd

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +352 -94
src/streamlit_app.py CHANGED
@@ -2,165 +2,423 @@ import streamlit as st
2
  import pandas as pd
3
  import plotly.express as px
4
  import plotly.graph_objects as go
 
5
 
6
- # Page config
7
  st.set_page_config(
8
- page_title="Auto Digital Public Infrastructure",
9
  page_icon="πŸ”—",
10
  layout="wide",
11
  initial_sidebar_state="expanded"
12
  )
13
 
14
- # Custom CSS for styling
15
  st.markdown("""
16
  <style>
17
- .main-header {
18
- background-color: #4a5568;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  color: white;
20
- padding: 1rem;
21
- border-radius: 0.5rem;
22
- margin-bottom: 1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
 
 
24
  .metric-card {
25
- background-color: #f7fafc;
26
- padding: 1rem;
27
- border-radius: 0.5rem;
28
- border-left: 4px solid #3182ce;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  }
30
  </style>
31
  """, unsafe_allow_html=True)
32
 
33
- # Sample data functions (since we can't import separate files easily)
34
  @st.cache_data
35
  def get_material_data():
36
  return pd.DataFrame({
37
- 'Material group': ['Engine', 'Hydraulic Cylinder', 'Seating and Interiors',
38
- 'Batteries', 'Control Arms', 'Ball Joints', 'Semiconductors',
39
- 'Sensors', 'Brake system', 'Shock Absorbers'],
40
- 'Fulfillment rate': [70, 65, 62, 70, 72, 70, 76, 75, 78, 80],
41
- 'Projected Fulfillment rate': [62, 65, 67, 68, 70, 71, 75, 76, 78, 80],
42
- 'MoM trend': [6.8, 4.1, 3.9, 1.1, 1.2, 6.8, 4.1, 3.9, 1.1, 1.2]
 
 
43
  })
44
 
45
  @st.cache_data
46
- def get_overall_metrics():
47
  return {
48
  'fulfillment': 86,
49
- 'mom_change': 1.5,
50
- 'material_groups': 3,
51
- 'skus': 1705,
52
- 'material_groups_at_risk': 20,
53
- 'risk_mom_change': 2.2,
54
- 'skus_at_risk': 25,
55
- 'sku_risk_mom_change': 4.1
 
 
56
  }
57
 
58
- # Header
59
  st.markdown("""
60
- <div class="main-header">
61
- <h1>πŸ”— Auto Digital Public Infrastructure</h1>
62
- <h2 style="color: #ffd700;">SUPPLY CHAIN RESILIENCE- CT- Overall metrics</h2>
63
  </div>
64
  """, unsafe_allow_html=True)
65
 
66
- # Sidebar navigation
67
  with st.sidebar:
68
- st.markdown("### Navigation")
69
- st.markdown("**Master Screen**")
 
 
 
 
70
 
71
  nav_options = [
72
- "HOME",
73
- "Supply Chain Resilience",
74
- "SC Control Tower",
75
- "Material Group View",
76
- "Supplier View",
77
- "Demand & Capacity Mgmt.",
78
- "Insights & Trends",
79
- "Use-Case 2",
80
- "Use-Case 3",
81
- "...other use-cases"
82
  ]
83
 
84
- selected_nav = st.selectbox("Select Page", nav_options, index=1)
 
 
 
 
 
 
 
85
 
86
- # Filters section
87
- st.markdown("### Filters/Splices")
 
 
 
 
88
 
89
- col1, col2, col3, col4, col5, col6, col7 = st.columns(7)
 
90
 
91
  with col1:
92
- plant_location = st.selectbox("Plant location", ["Chennai", "Mumbai", "Delhi"], index=0)
93
 
94
  with col2:
95
- material_group = st.selectbox("Material group", ["All", "Engine", "Electronics"], index=0)
96
 
97
  with col3:
98
- part_sku = st.selectbox("Part/SKU", ["All", "SKU001", "SKU002"], index=0)
99
 
100
  with col4:
101
- time_period = st.selectbox("Time Period", ["FY2026", "FY2025", "FY2027"], index=0)
102
 
103
  with col5:
104
- month = st.selectbox("Month", ["May", "June", "July"], index=0)
105
 
106
  with col6:
107
- supplier_type = st.selectbox("Supplier type", ["All", "Tier 1", "Tier 2"], index=0)
108
 
109
  with col7:
110
- supplier_name = st.selectbox("Supplier Name", ["All", "Supplier A", "Supplier B"], index=0)
 
 
 
111
 
112
- # Get data
113
  material_df = get_material_data()
114
- metrics = get_overall_metrics()
115
 
116
- # Main content area
117
- col1, col2 = st.columns([1, 2])
 
 
 
 
 
 
 
118
 
119
  with col1:
120
- # Overall metrics section
121
- st.markdown("### πŸ“Š Overall metrics")
122
-
123
- # Fulfillment metric
124
  st.markdown(f"""
125
  <div class="metric-card">
126
- <h2>Fulfillment: {metrics['fulfillment']}%</h2>
127
- <p style="color: green;">↑ {metrics['mom_change']}% MoM</p>
 
128
  </div>
129
  """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
- # Other metrics in a 2x2 grid
132
- met_col1, met_col2 = st.columns(2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
- with met_col1:
135
- st.metric("Material groups", metrics['material_groups'])
136
- st.metric("% Material groups at risk", f"{metrics['material_groups_at_risk']}%",
137
- delta=f"-{metrics['risk_mom_change']}% MoM")
 
 
 
 
 
 
138
 
139
- with met_col2:
140
- st.metric("SKUs", f"{metrics['skus']:,}")
141
- st.metric("% SKUs at risk", f"{metrics['skus_at_risk']}%",
142
- delta=f"↓{metrics['sku_risk_mom_change']}% MoM")
143
 
144
  with col2:
145
- # Material group fulfillment table
146
- st.markdown("### πŸ“‹ Material group wise fulfillment rates")
147
 
148
- # Display the dataframe
149
- st.dataframe(material_df, use_container_width=True)
150
-
151
- # Add a chart below
152
- st.markdown("### πŸ“ˆ Fulfillment Rate Trends")
153
-
154
- fig = px.bar(material_df,
155
- x='Material group',
156
- y=['Fulfillment rate', 'Projected Fulfillment rate'],
157
- title="Current vs Projected Fulfillment Rates",
158
- barmode='group')
 
 
 
 
 
 
159
 
160
- fig.update_layout(
161
- xaxis_tickangle=-45,
162
- height=400,
163
- showlegend=True
164
- )
165
 
166
- st.plotly_chart(fig, use_container_width=True)
 
 
 
 
 
 
2
  import pandas as pd
3
  import plotly.express as px
4
  import plotly.graph_objects as go
5
+ from datetime import datetime, timedelta
6
 
7
+ # Page config with modern styling
8
  st.set_page_config(
9
+ page_title="Supply Chain Intelligence",
10
  page_icon="πŸ”—",
11
  layout="wide",
12
  initial_sidebar_state="expanded"
13
  )
14
 
15
+ # Modern CSS styling
16
  st.markdown("""
17
  <style>
18
+ /* Import modern font */
19
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
20
+
21
+ /* Global styling */
22
+ .stApp {
23
+ font-family: 'Inter', sans-serif;
24
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
25
+ }
26
+
27
+ /* Main container */
28
+ .main-container {
29
+ background: rgba(255, 255, 255, 0.95);
30
+ backdrop-filter: blur(10px);
31
+ border-radius: 20px;
32
+ padding: 2rem;
33
+ margin: 1rem;
34
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
35
+ }
36
+
37
+ /* Modern header */
38
+ .modern-header {
39
+ background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
40
  color: white;
41
+ padding: 2rem;
42
+ border-radius: 15px;
43
+ margin-bottom: 2rem;
44
+ box-shadow: 0 10px 30px rgba(30, 60, 114, 0.3);
45
+ position: relative;
46
+ overflow: hidden;
47
+ }
48
+
49
+ .modern-header::before {
50
+ content: '';
51
+ position: absolute;
52
+ top: -50%;
53
+ right: -50%;
54
+ width: 100%;
55
+ height: 200%;
56
+ background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
57
+ transform: rotate(45deg);
58
+ }
59
+
60
+ .header-title {
61
+ font-size: 2.5rem;
62
+ font-weight: 700;
63
+ margin-bottom: 0.5rem;
64
+ position: relative;
65
+ z-index: 1;
66
+ }
67
+
68
+ .header-subtitle {
69
+ font-size: 1.2rem;
70
+ font-weight: 400;
71
+ color: #ffd700;
72
+ position: relative;
73
+ z-index: 1;
74
  }
75
+
76
+ /* Modern metric cards */
77
  .metric-card {
78
+ background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
79
+ padding: 1.5rem;
80
+ border-radius: 15px;
81
+ border: 1px solid rgba(226, 232, 240, 0.8);
82
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
83
+ transition: all 0.3s ease;
84
+ margin-bottom: 1rem;
85
+ }
86
+
87
+ .metric-card:hover {
88
+ transform: translateY(-5px);
89
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
90
+ }
91
+
92
+ .metric-number {
93
+ font-size: 2.5rem;
94
+ font-weight: 700;
95
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
96
+ -webkit-background-clip: text;
97
+ -webkit-text-fill-color: transparent;
98
+ background-clip: text;
99
+ margin-bottom: 0.5rem;
100
+ }
101
+
102
+ .metric-label {
103
+ color: #64748b;
104
+ font-size: 0.9rem;
105
+ font-weight: 500;
106
+ text-transform: uppercase;
107
+ letter-spacing: 0.05em;
108
+ }
109
+
110
+ .metric-change {
111
+ font-size: 0.85rem;
112
+ font-weight: 600;
113
+ padding: 0.3rem 0.8rem;
114
+ border-radius: 20px;
115
+ margin-top: 0.5rem;
116
+ display: inline-block;
117
+ }
118
+
119
+ .metric-positive {
120
+ background: rgba(34, 197, 94, 0.1);
121
+ color: #22c55e;
122
+ }
123
+
124
+ .metric-negative {
125
+ background: rgba(239, 68, 68, 0.1);
126
+ color: #ef4444;
127
+ }
128
+
129
+ /* Modern sidebar */
130
+ .sidebar-content {
131
+ background: linear-gradient(180deg, #1e293b 0%, #334155 100%);
132
+ color: white;
133
+ border-radius: 15px;
134
+ padding: 1.5rem;
135
+ margin-bottom: 1rem;
136
+ }
137
+
138
+ /* Filter pills */
139
+ .filter-container {
140
+ background: rgba(255, 255, 255, 0.7);
141
+ padding: 1.5rem;
142
+ border-radius: 15px;
143
+ margin-bottom: 2rem;
144
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
145
+ }
146
+
147
+ /* Data table styling */
148
+ .dataframe {
149
+ border-radius: 15px;
150
+ overflow: hidden;
151
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
152
+ }
153
+
154
+ /* Section headers */
155
+ .section-header {
156
+ font-size: 1.5rem;
157
+ font-weight: 600;
158
+ color: #1e293b;
159
+ margin-bottom: 1.5rem;
160
+ padding-bottom: 0.5rem;
161
+ border-bottom: 3px solid;
162
+ border-image: linear-gradient(135deg, #667eea 0%, #764ba2 100%) 1;
163
+ }
164
+
165
+ /* Status indicators */
166
+ .status-indicator {
167
+ display: inline-block;
168
+ width: 12px;
169
+ height: 12px;
170
+ border-radius: 50%;
171
+ margin-right: 8px;
172
+ }
173
+
174
+ .status-good { background-color: #22c55e; }
175
+ .status-warning { background-color: #f59e0b; }
176
+ .status-critical { background-color: #ef4444; }
177
+
178
+ /* Animation for loading */
179
+ @keyframes fadeInUp {
180
+ from {
181
+ opacity: 0;
182
+ transform: translateY(30px);
183
+ }
184
+ to {
185
+ opacity: 1;
186
+ transform: translateY(0);
187
+ }
188
+ }
189
+
190
+ .fade-in {
191
+ animation: fadeInUp 0.6s ease-out;
192
  }
193
  </style>
194
  """, unsafe_allow_html=True)
195
 
196
+ # Sample data functions with enhanced data
197
  @st.cache_data
198
  def get_material_data():
199
  return pd.DataFrame({
200
+ 'Material Group': ['Engine Components', 'Hydraulic Systems', 'Interior & Seating',
201
+ 'Battery Systems', 'Suspension Parts', 'Safety Components', 'Semiconductors',
202
+ 'Smart Sensors', 'Brake Systems', 'Shock Absorbers'],
203
+ 'Current Rate': [72, 68, 65, 73, 75, 72, 78, 77, 80, 82],
204
+ 'Target Rate': [75, 70, 70, 75, 78, 75, 80, 80, 82, 85],
205
+ 'Trend': ['+2.1%', '+1.8%', '+0.9%', '+2.4%', '+1.2%', '+1.8%', '+2.1%', '+1.9%', '+1.1%', '+1.2%'],
206
+ 'Risk Level': ['Medium', 'High', 'High', 'Low', 'Low', 'Medium', 'Low', 'Low', 'Low', 'Low'],
207
+ 'Last Updated': ['2 hrs ago', '1 hr ago', '3 hrs ago', '1 hr ago', '2 hrs ago', '1 hr ago', '30 min ago', '45 min ago', '1 hr ago', '2 hrs ago']
208
  })
209
 
210
  @st.cache_data
211
+ def get_enhanced_metrics():
212
  return {
213
  'fulfillment': 86,
214
+ 'mom_change': 2.3,
215
+ 'material_groups': 147,
216
+ 'skus': 12847,
217
+ 'material_groups_at_risk': 18,
218
+ 'risk_mom_change': -1.8,
219
+ 'skus_at_risk': 23,
220
+ 'sku_risk_mom_change': -2.1,
221
+ 'active_suppliers': 342,
222
+ 'on_time_delivery': 94.2
223
  }
224
 
225
+ # Header with modern design
226
  st.markdown("""
227
+ <div class="modern-header fade-in">
228
+ <div class="header-title">πŸ”— Supply Chain Intelligence Hub</div>
229
+ <div class="header-subtitle">Real-time Supply Chain Resilience Dashboard β€’ Control Tower Analytics</div>
230
  </div>
231
  """, unsafe_allow_html=True)
232
 
233
+ # Modern sidebar
234
  with st.sidebar:
235
+ st.markdown("""
236
+ <div class="sidebar-content">
237
+ <h3 style="margin-top: 0;">πŸŽ›οΈ Navigation Center</h3>
238
+ <p style="opacity: 0.8; font-size: 0.9rem;">Select your workspace</p>
239
+ </div>
240
+ """, unsafe_allow_html=True)
241
 
242
  nav_options = [
243
+ "🏠 Dashboard Home",
244
+ "πŸ“Š Supply Chain Resilience",
245
+ "🎯 Control Tower",
246
+ "πŸ“¦ Material Groups",
247
+ "🏭 Supplier Analytics",
248
+ "πŸ“ˆ Demand Planning",
249
+ "πŸ” Insights & Trends",
250
+ "⚑ Real-time Alerts",
251
+ "πŸ“‹ Reports Center"
 
252
  ]
253
 
254
+ selected_nav = st.selectbox("", nav_options, index=1)
255
+
256
+ # Add quick stats in sidebar
257
+ st.markdown("---")
258
+ st.markdown("**🚨 Quick Alerts**")
259
+ st.error("⚠️ 3 critical suppliers need attention")
260
+ st.warning("πŸ“‹ 12 SKUs below safety stock")
261
+ st.success("βœ… 94% on-time delivery this month")
262
 
263
+ # Modern filters section
264
+ st.markdown("""
265
+ <div class="filter-container fade-in">
266
+ <div class="section-header">πŸ”§ Smart Filters & Controls</div>
267
+ </div>
268
+ """, unsafe_allow_html=True)
269
 
270
+ col1, col2, col3, col4 = st.columns(4)
271
+ col5, col6, col7, col8 = st.columns(4)
272
 
273
  with col1:
274
+ plant_location = st.selectbox("🏭 Plant Location", ["Chennai Hub", "Mumbai Center", "Delhi North", "Bangalore Tech"], index=0)
275
 
276
  with col2:
277
+ material_group = st.selectbox("οΏ½οΏ½οΏ½ Material Category", ["All Categories", "Critical Components", "Standard Parts"], index=0)
278
 
279
  with col3:
280
+ time_period = st.selectbox("πŸ“… Time Horizon", ["Current Quarter", "FY2025", "Last 6 Months"], index=0)
281
 
282
  with col4:
283
+ supplier_tier = st.selectbox("🏒 Supplier Tier", ["All Tiers", "Tier 1 Strategic", "Tier 2 Operational"], index=0)
284
 
285
  with col5:
286
+ risk_level = st.selectbox("⚠️ Risk Filter", ["All Levels", "High Risk Only", "Medium Risk", "Low Risk"], index=0)
287
 
288
  with col6:
289
+ performance = st.selectbox("πŸ“Š Performance", ["All Performance", "Above Target", "Below Target"], index=0)
290
 
291
  with col7:
292
+ geography = st.selectbox("🌍 Geography", ["Global View", "Asia Pacific", "Americas", "Europe"], index=0)
293
+
294
+ with col8:
295
+ update_freq = st.selectbox("πŸ”„ Update Frequency", ["Real-time", "Hourly", "Daily"], index=0)
296
 
297
+ # Get enhanced data
298
  material_df = get_material_data()
299
+ metrics = get_enhanced_metrics()
300
 
301
+ # Main dashboard content
302
+ st.markdown("""
303
+ <div class="main-container fade-in">
304
+ """, unsafe_allow_html=True)
305
+
306
+ # Key metrics section with modern cards
307
+ st.markdown('<div class="section-header">πŸ“Š Executive Dashboard</div>', unsafe_allow_html=True)
308
+
309
+ col1, col2, col3, col4 = st.columns(4)
310
 
311
  with col1:
 
 
 
 
312
  st.markdown(f"""
313
  <div class="metric-card">
314
+ <div class="metric-number">{metrics['fulfillment']}%</div>
315
+ <div class="metric-label">Overall Fulfillment</div>
316
+ <div class="metric-change metric-positive">β†— +{metrics['mom_change']}% MoM</div>
317
  </div>
318
  """, unsafe_allow_html=True)
319
+
320
+ with col2:
321
+ st.markdown(f"""
322
+ <div class="metric-card">
323
+ <div class="metric-number">{metrics['on_time_delivery']}%</div>
324
+ <div class="metric-label">On-Time Delivery</div>
325
+ <div class="metric-change metric-positive">β†— +1.2% WoW</div>
326
+ </div>
327
+ """, unsafe_allow_html=True)
328
+
329
+ with col3:
330
+ st.markdown(f"""
331
+ <div class="metric-card">
332
+ <div class="metric-number">{metrics['material_groups_at_risk']}%</div>
333
+ <div class="metric-label">At-Risk Categories</div>
334
+ <div class="metric-change metric-positive">β†˜ {metrics['risk_mom_change']}% MoM</div>
335
+ </div>
336
+ """, unsafe_allow_html=True)
337
+
338
+ with col4:
339
+ st.markdown(f"""
340
+ <div class="metric-card">
341
+ <div class="metric-number">{metrics['active_suppliers']:,}</div>
342
+ <div class="metric-label">Active Suppliers</div>
343
+ <div class="metric-change metric-positive">β†— +15 new this month</div>
344
+ </div>
345
+ """, unsafe_allow_html=True)
346
+
347
+ # Enhanced data table
348
+ st.markdown('<div class="section-header">πŸ“‹ Material Group Performance Matrix</div>', unsafe_allow_html=True)
349
+
350
+ # Add status indicators to the dataframe
351
+ def add_status_indicators(df):
352
+ def get_status_html(risk_level):
353
+ if risk_level == 'Low':
354
+ return '<span class="status-indicator status-good"></span>Low Risk'
355
+ elif risk_level == 'Medium':
356
+ return '<span class="status-indicator status-warning"></span>Medium Risk'
357
+ else:
358
+ return '<span class="status-indicator status-critical"></span>High Risk'
359
 
360
+ df['Risk Status'] = df['Risk Level'].apply(get_status_html)
361
+ return df
362
+
363
+ # Display enhanced table
364
+ enhanced_df = add_status_indicators(material_df.copy())
365
+ st.markdown(enhanced_df.to_html(escape=False, index=False), unsafe_allow_html=True)
366
+
367
+ # Modern charts section
368
+ st.markdown('<div class="section-header">πŸ“ˆ Performance Analytics</div>', unsafe_allow_html=True)
369
+
370
+ col1, col2 = st.columns(2)
371
+
372
+ with col1:
373
+ # Modern fulfillment rate chart
374
+ fig1 = px.bar(
375
+ material_df,
376
+ x='Material Group',
377
+ y=['Current Rate', 'Target Rate'],
378
+ title="Current vs Target Fulfillment Rates",
379
+ color_discrete_sequence=['#667eea', '#764ba2']
380
+ )
381
 
382
+ fig1.update_layout(
383
+ plot_bgcolor='rgba(0,0,0,0)',
384
+ paper_bgcolor='rgba(0,0,0,0)',
385
+ font_family="Inter",
386
+ title_font_size=16,
387
+ title_font_color="#1e293b",
388
+ xaxis_tickangle=-45,
389
+ height=400,
390
+ margin=dict(t=50, l=50, r=50, b=100)
391
+ )
392
 
393
+ st.plotly_chart(fig1, use_container_width=True)
 
 
 
394
 
395
  with col2:
396
+ # Risk distribution pie chart
397
+ risk_counts = material_df['Risk Level'].value_counts()
398
 
399
+ fig2 = px.pie(
400
+ values=risk_counts.values,
401
+ names=risk_counts.index,
402
+ title="Risk Distribution Across Material Groups",
403
+ color_discrete_sequence=['#22c55e', '#f59e0b', '#ef4444']
404
+ )
405
+
406
+ fig2.update_layout(
407
+ plot_bgcolor='rgba(0,0,0,0)',
408
+ paper_bgcolor='rgba(0,0,0,0)',
409
+ font_family="Inter",
410
+ title_font_size=16,
411
+ title_font_color="#1e293b",
412
+ height=400
413
+ )
414
+
415
+ st.plotly_chart(fig2, use_container_width=True)
416
 
417
+ st.markdown("</div>", unsafe_allow_html=True)
 
 
 
 
418
 
419
+ # Footer with last update info
420
+ st.markdown("""
421
+ <div style="text-align: center; padding: 2rem; color: #64748b; border-top: 1px solid #e2e8f0; margin-top: 2rem;">
422
+ <p>πŸ“Š Dashboard last updated: {timestamp} | πŸ”„ Auto-refresh: Every 15 minutes | 🎯 Data accuracy: 99.7%</p>
423
+ </div>
424
+ """.format(timestamp=datetime.now().strftime("%B %d, %Y at %I:%M %p")), unsafe_allow_html=True)