Parth-07 commited on
Commit
4e039b0
Β·
verified Β·
1 Parent(s): ccccb96

Upload 2 files

Browse files
src/app.py ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ import time
5
+ import os
6
+
7
+ st.set_page_config(
8
+ page_title="BurnoutIQ β€” Developer Burnout Intelligence",
9
+ page_icon="πŸ”₯",
10
+ layout="wide",
11
+ initial_sidebar_state="collapsed"
12
+ )
13
+
14
+ # ── Custom CSS ──────────────────────────────────────────────────────────────
15
+ st.markdown("""
16
+ <style>
17
+ @import url('https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=DM+Mono:wght@400;500&family=Epilogue:wght@300;400;500;600&display=swap');
18
+
19
+ html, body, [data-testid="stAppViewContainer"], [data-testid="stMain"] {
20
+ background: #0d0f12 !important;
21
+ color: #e8eaf0 !important;
22
+ font-family: 'Epilogue', sans-serif !important;
23
+ }
24
+ [data-testid="stHeader"] { background: #151820 !important; border-bottom: 1px solid rgba(255,255,255,0.07); }
25
+ #MainMenu, footer { visibility: hidden; }
26
+ [data-testid="stMainBlockContainer"] { padding-top: 0 !important; max-width: 1100px; }
27
+
28
+ [data-testid="stSlider"] label {
29
+ font-family: 'DM Mono', monospace !important;
30
+ font-size: 11px !important;
31
+ color: #7a7f8e !important;
32
+ text-transform: uppercase;
33
+ letter-spacing: .4px;
34
+ }
35
+ [data-testid="stButton"] button {
36
+ background: #5b8dee !important;
37
+ color: #fff !important;
38
+ border: none !important;
39
+ border-radius: 10px !important;
40
+ font-family: 'Epilogue', sans-serif !important;
41
+ font-size: 14px !important;
42
+ font-weight: 500 !important;
43
+ padding: 0.65rem 2rem !important;
44
+ }
45
+ [data-testid="stButton"] button:hover { opacity: 0.88 !important; }
46
+
47
+ [data-testid="stTabs"] [role="tab"] {
48
+ font-family: 'DM Mono', monospace !important;
49
+ font-size: 12px !important;
50
+ color: #7a7f8e !important;
51
+ text-transform: uppercase;
52
+ letter-spacing: .5px;
53
+ }
54
+ [data-testid="stTabs"] [role="tab"][aria-selected="true"] {
55
+ color: #e8eaf0 !important;
56
+ border-bottom: 2px solid #5b8dee !important;
57
+ }
58
+ </style>
59
+ """, unsafe_allow_html=True)
60
+
61
+
62
+ # ── Data ─────────────────────────────────────────────────────────────────────
63
+ DATASET = "developer_burnout_dataset_7000.csv"
64
+
65
+ @st.cache_data
66
+ def load_data():
67
+ if os.path.exists(DATASET):
68
+ return pd.read_csv(DATASET)
69
+ np.random.seed(42)
70
+ n = 7000
71
+ df = pd.DataFrame({
72
+ "age": np.random.randint(22, 55, n).astype(float),
73
+ "experience_years": np.random.randint(0, 25, n).astype(float),
74
+ "daily_work_hours": np.round(np.random.uniform(4, 14, n), 2),
75
+ "sleep_hours": np.round(np.random.uniform(3, 10, n), 2),
76
+ "caffeine_intake": np.random.randint(0, 8, n).astype(float),
77
+ "bugs_per_day": np.random.randint(0, 25, n).astype(float),
78
+ "commits_per_day": np.random.randint(0, 30, n).astype(float),
79
+ "meetings_per_day": np.random.randint(0, 10, n).astype(float),
80
+ "screen_time": np.round(np.random.uniform(6, 18, n), 2),
81
+ "exercise_hours": np.round(np.random.uniform(0, 5, n), 2),
82
+ "stress_level": np.round(np.random.uniform(5, 98, n), 2),
83
+ })
84
+ df["burnout_level"] = pd.cut(df["stress_level"], bins=[0,35,65,100], labels=["Low","Medium","High"])
85
+ return df
86
+
87
+ df = load_data()
88
+ df_clean = df.dropna(subset=["burnout_level"])
89
+ low_df = df_clean[df_clean["burnout_level"] == "Low"]
90
+ med_df = df_clean[df_clean["burnout_level"] == "Medium"]
91
+ high_df = df_clean[df_clean["burnout_level"] == "High"]
92
+ total = len(df_clean)
93
+
94
+ def pct(n): return round(n / total * 100, 1)
95
+
96
+
97
+ # ── Hero ──────────────────────────────────────────────────────────────────────
98
+ st.markdown("""
99
+ <div style="max-width:700px;margin:0 auto;padding:3.5rem 1rem 2rem;text-align:center">
100
+ <div style="display:inline-block;background:rgba(91,141,238,.12);border:1px solid rgba(91,141,238,.25);
101
+ color:#5b8dee;font-family:'DM Mono',monospace;font-size:11px;padding:4px 14px;
102
+ border-radius:100px;margin-bottom:1.2rem;letter-spacing:.5px">
103
+ 7,000 developer records Β· live analysis
104
+ </div>
105
+ <h1 style="font-family:'DM Serif Display',serif;font-size:clamp(1.9rem,4vw,2.8rem);
106
+ line-height:1.15;letter-spacing:-.4px;margin-bottom:1rem;color:#f0f2f8">
107
+ Developer Burnout <em style="font-style:italic;color:#3ecfb2">Intelligence</em>
108
+ </h1>
109
+ <p style="color:#7a7f8e;font-size:15px;max-width:500px;margin:0 auto;line-height:1.7">
110
+ Explore burnout patterns, analyze risk factors, and predict burnout levels
111
+ across 7,000 software engineers.
112
+ </p>
113
+ </div>
114
+ """, unsafe_allow_html=True)
115
+
116
+
117
+ # ── Tabs ────────────���─────────────────────────────────────────────────────────
118
+ tab1, tab2, tab3 = st.tabs(["Dashboard", "Risk Predictor", "Dataset"])
119
+
120
+
121
+ # ════════════════════════════════════════
122
+ # TAB 1 β€” DASHBOARD
123
+ # ════════════════════════════════════════
124
+ with tab1:
125
+ st.markdown(f"""
126
+ <div style="display:flex;align-items:baseline;gap:.8rem;margin:1.5rem 0 1.2rem;
127
+ padding-bottom:.6rem;border-bottom:1px solid rgba(255,255,255,0.07)">
128
+ <span style="font-family:'DM Serif Display',serif;font-size:1.3rem;color:#f0f2f8;font-weight:400">Dataset Overview</span>
129
+ <span style="font-family:'DM Mono',monospace;font-size:11px;color:#7a7f8e">{total:,} clean records</span>
130
+ </div>
131
+ """, unsafe_allow_html=True)
132
+
133
+ # Stat cards
134
+ for col, label, value, sub, color in zip(
135
+ st.columns(4),
136
+ ["total developers", "low burnout", "medium burnout", "high burnout"],
137
+ [f"{total:,}", f"{pct(len(low_df))}%", f"{pct(len(med_df))}%", f"{pct(len(high_df))}%"],
138
+ ["records analyzed", f"{len(low_df):,} developers", f"{len(med_df):,} developers", f"{len(high_df):,} developers"],
139
+ ["#5b8dee", "#3ecfb2", "#e5c07b", "#e06c75"]
140
+ ):
141
+ with col:
142
+ st.markdown(f"""
143
+ <div style="background:#1c2029;border:1px solid rgba(255,255,255,0.07);border-radius:12px;padding:1.2rem 1.4rem;margin-bottom:.5rem">
144
+ <div style="font-family:'DM Mono',monospace;font-size:11px;color:#7a7f8e;text-transform:uppercase;letter-spacing:.4px;margin-bottom:.4rem">{label}</div>
145
+ <div style="font-size:2rem;font-weight:600;color:{color};line-height:1">{value}</div>
146
+ <div style="font-size:11px;color:#7a7f8e;margin-top:.3rem">{sub}</div>
147
+ </div>""", unsafe_allow_html=True)
148
+
149
+ # Distribution bar
150
+ lp, mp, hp = pct(len(low_df)), pct(len(med_df)), pct(len(high_df))
151
+ st.markdown(f"""
152
+ <div style="height:7px;display:flex;border-radius:100px;overflow:hidden;gap:2px;margin:.5rem 0">
153
+ <div style="width:{lp}%;background:#3ecfb2;border-radius:100px"></div>
154
+ <div style="width:{mp}%;background:#e5c07b;border-radius:100px"></div>
155
+ <div style="width:{hp}%;background:#e06c75;border-radius:100px"></div>
156
+ </div>
157
+ <div style="display:flex;gap:1.3rem;font-family:'DM Mono',monospace;font-size:11px;color:#7a7f8e;margin-bottom:1.8rem">
158
+ <span><span style="display:inline-block;width:7px;height:7px;border-radius:50%;background:#3ecfb2;margin-right:5px;vertical-align:middle"></span>Low {lp}%</span>
159
+ <span><span style="display:inline-block;width:7px;height:7px;border-radius:50%;background:#e5c07b;margin-right:5px;vertical-align:middle"></span>Medium {mp}%</span>
160
+ <span><span style="display:inline-block;width:7px;height:7px;border-radius:50%;background:#e06c75;margin-right:5px;vertical-align:middle"></span>High {hp}%</span>
161
+ </div>
162
+ """, unsafe_allow_html=True)
163
+
164
+ # Charts
165
+ import altair as alt
166
+
167
+ chart_data = pd.DataFrame({
168
+ "Burnout Level": ["Low", "Medium", "High"],
169
+ "Avg Stress": [round(low_df["stress_level"].mean(),1), round(med_df["stress_level"].mean(),1), round(high_df["stress_level"].mean(),1)],
170
+ "Avg Sleep": [round(low_df["sleep_hours"].mean(),1), round(med_df["sleep_hours"].mean(),1), round(high_df["sleep_hours"].mean(),1)],
171
+ "Avg Work Hrs": [round(low_df["daily_work_hours"].mean(),1), round(med_df["daily_work_hours"].mean(),1), round(high_df["daily_work_hours"].mean(),1)],
172
+ })
173
+
174
+ COLOR_SCALE = alt.Scale(domain=["Low","Medium","High"], range=["#3ecfb2","#e5c07b","#e06c75"])
175
+ CHART_BG = dict(background="#1c2029", view=alt.ViewConfig(stroke="transparent"))
176
+
177
+ def make_bar(field, title):
178
+ return alt.Chart(chart_data).mark_bar(
179
+ cornerRadiusTopLeft=6, cornerRadiusTopRight=6, opacity=0.85
180
+ ).encode(
181
+ x=alt.X("Burnout Level:N", axis=alt.Axis(labelColor="#7a7f8e", tickColor="transparent", domainColor="transparent", labelFont="DM Mono", title=None)),
182
+ y=alt.Y(f"{field}:Q", axis=alt.Axis(labelColor="#7a7f8e", gridColor="rgba(255,255,255,0.05)", domainOpacity=0, tickOpacity=0, labelFont="DM Mono", title=None)),
183
+ color=alt.Color("Burnout Level:N", scale=COLOR_SCALE, legend=None),
184
+ tooltip=["Burnout Level", field]
185
+ ).properties(
186
+ title=alt.TitleParams(title, color="#7a7f8e", font="DM Mono", fontSize=11), height=200
187
+ ).configure(**CHART_BG)
188
+
189
+ col1, col2 = st.columns(2)
190
+ with col1:
191
+ st.markdown('<div style="background:#1c2029;border:1px solid rgba(255,255,255,0.07);border-radius:14px;padding:1.2rem">', unsafe_allow_html=True)
192
+ st.altair_chart(make_bar("Avg Stress", "AVG STRESS LEVEL BY BURNOUT"), use_container_width=True)
193
+ st.markdown('</div>', unsafe_allow_html=True)
194
+ with col2:
195
+ st.markdown('<div style="background:#1c2029;border:1px solid rgba(255,255,255,0.07);border-radius:14px;padding:1.2rem">', unsafe_allow_html=True)
196
+ st.altair_chart(make_bar("Avg Sleep", "AVG SLEEP HOURS BY BURNOUT"), use_container_width=True)
197
+ st.markdown('</div>', unsafe_allow_html=True)
198
+
199
+ col3, col4 = st.columns(2)
200
+ with col3:
201
+ st.markdown('<div style="background:#1c2029;border:1px solid rgba(255,255,255,0.07);border-radius:14px;padding:1.2rem">', unsafe_allow_html=True)
202
+ st.altair_chart(make_bar("Avg Work Hrs", "AVG DAILY WORK HOURS BY BURNOUT"), use_container_width=True)
203
+ st.markdown('</div>', unsafe_allow_html=True)
204
+ with col4:
205
+ st.markdown('<div style="background:#1c2029;border:1px solid rgba(255,255,255,0.07);border-radius:14px;padding:1.2rem">', unsafe_allow_html=True)
206
+ dist_data = pd.DataFrame({
207
+ "Level": ["Low","Medium","High"],
208
+ "Count": [len(low_df), len(med_df), len(high_df)]
209
+ })
210
+ pie = alt.Chart(dist_data).mark_arc(
211
+ innerRadius=55, outerRadius=90, padAngle=0.02
212
+ ).encode(
213
+ theta=alt.Theta("Count:Q"),
214
+ color=alt.Color("Level:N", scale=COLOR_SCALE,
215
+ legend=alt.Legend(labelColor="#7a7f8e", labelFont="DM Mono", title=None, orient="bottom", symbolSize=60)),
216
+ tooltip=["Level","Count"]
217
+ ).properties(
218
+ title=alt.TitleParams("BURNOUT DISTRIBUTION", color="#7a7f8e", font="DM Mono", fontSize=11), height=200
219
+ ).configure(**CHART_BG)
220
+ st.altair_chart(pie, use_container_width=True)
221
+ st.markdown('</div>', unsafe_allow_html=True)
222
+
223
+
224
+ # ════════════════════════════════════════
225
+ # TAB 2 β€” PREDICTOR
226
+ # ════════════════════════════════════════
227
+ with tab2:
228
+ st.markdown("""
229
+ <div style="display:flex;align-items:baseline;gap:.8rem;margin:1.5rem 0 1.5rem;
230
+ padding-bottom:.6rem;border-bottom:1px solid rgba(255,255,255,0.07)">
231
+ <span style="font-family:'DM Serif Display',serif;font-size:1.3rem;color:#f0f2f8;font-weight:400">Burnout Risk Predictor</span>
232
+ <span style="font-family:'DM Mono',monospace;font-size:11px;color:#7a7f8e">heuristic model</span>
233
+ </div>
234
+ """, unsafe_allow_html=True)
235
+
236
+ st.markdown('<div style="background:#1c2029;border:1px solid rgba(255,255,255,0.07);border-radius:14px;padding:2rem 2.2rem">', unsafe_allow_html=True)
237
+
238
+ ca, cb, cc = st.columns(3)
239
+ with ca:
240
+ work_hours = st.slider("Daily Work Hours", 2.0, 16.0, 8.0, 0.5)
241
+ sleep_hours = st.slider("Sleep Hours / Night", 2.0, 12.0, 7.0, 0.5)
242
+ with cb:
243
+ stress = st.slider("Stress Level (0–100)", 0, 100, 45, 1)
244
+ meetings = st.slider("Meetings / Day", 0, 12, 3, 1)
245
+ with cc:
246
+ exercise = st.slider("Exercise Hrs / Week", 0.0, 14.0, 2.0, 0.5)
247
+ screen_time = st.slider("Screen Time hrs/day", 4.0, 20.0, 10.0, 0.5)
248
+
249
+ st.markdown("<div style='height:.5rem'></div>", unsafe_allow_html=True)
250
+
251
+ if st.button("Analyze Risk β†’"):
252
+ with st.spinner("Analyzing..."):
253
+ time.sleep(0.6)
254
+
255
+ score = ((work_hours - 6) * 4.5 + (7 - sleep_hours) * 5 + stress * 0.6
256
+ + (meetings - 2) * 2.5 - exercise * 3 + (screen_time - 8) * 1.5)
257
+ score = max(0.0, min(100.0, score))
258
+
259
+ if score < 33:
260
+ level, desc = "Low Burnout Risk", "Your current habits indicate a healthy work-life balance. Sleep is adequate and exercise offsets screen time effectively."
261
+ color, bg, bc = "#3ecfb2", "rgba(62,207,178,.06)", "rgba(62,207,178,.3)"
262
+ elif score < 66:
263
+ level, desc = "Medium Burnout Risk", "Some risk factors are elevated. Consider reducing meetings, improving sleep, or adding more physical activity weekly."
264
+ color, bg, bc = "#e5c07b", "rgba(229,192,123,.06)", "rgba(229,192,123,.3)"
265
+ else:
266
+ level, desc = "High Burnout Risk", "Multiple risk factors are significantly elevated. Reducing work hours, improving sleep, and managing stress are strongly advised."
267
+ color, bg, bc = "#e06c75", "rgba(224,108,117,.06)", "rgba(224,108,117,.3)"
268
+
269
+ st.markdown(f"""
270
+ <div style="background:{bg};border:1px solid {bc};border-radius:12px;padding:1.4rem;margin-top:1.2rem">
271
+ <div style="font-family:'DM Serif Display',serif;font-size:1.8rem;color:{color};margin-bottom:.3rem">{level}</div>
272
+ <div style="color:#7a7f8e;font-size:13px;line-height:1.65;margin-bottom:1rem">{desc}</div>
273
+ <div style="height:5px;background:rgba(255,255,255,.08);border-radius:3px;overflow:hidden;margin-bottom:5px">
274
+ <div style="width:{round(score)}%;height:100%;background:{color};border-radius:3px"></div>
275
+ </div>
276
+ <div style="display:flex;justify-content:space-between;font-family:'DM Mono',monospace;font-size:10px;color:#7a7f8e">
277
+ <span>Low risk</span><span>Score: {round(score)}/100</span><span>High risk</span>
278
+ </div>
279
+ </div>
280
+ """, unsafe_allow_html=True)
281
+
282
+ st.session_state["result"] = level
283
+ st.session_state["inputs"] = [work_hours, sleep_hours, stress, meetings, exercise, screen_time]
284
+
285
+ st.markdown('</div>', unsafe_allow_html=True)
286
+
287
+
288
+ # ════════════════════════════════════════
289
+ # TAB 3 β€” DATASET
290
+ # ════════════════════════════════════════
291
+ with tab3:
292
+ st.markdown("""
293
+ <div style="display:flex;align-items:baseline;gap:.8rem;margin:1.5rem 0 1.2rem;
294
+ padding-bottom:.6rem;border-bottom:1px solid rgba(255,255,255,0.07)">
295
+ <span style="font-family:'DM Serif Display',serif;font-size:1.3rem;color:#f0f2f8;font-weight:400">Dataset Sample</span>
296
+ <span style="font-family:'DM Mono',monospace;font-size:11px;color:#7a7f8e">first 20 records</span>
297
+ </div>
298
+ """, unsafe_allow_html=True)
299
+
300
+ cols = ["age","experience_years","daily_work_hours","sleep_hours",
301
+ "caffeine_intake","bugs_per_day","commits_per_day",
302
+ "meetings_per_day","stress_level","exercise_hours","burnout_level"]
303
+ display_df = df_clean[cols].head(20).reset_index(drop=True)
304
+
305
+ def color_burnout(val):
306
+ m = {"Low": "color: #3ecfb2", "Medium": "color: #e5c07b", "High": "color: #e06c75"}
307
+ return m.get(str(val), "")
308
+
309
+ st.dataframe(
310
+ display_df.style.map(color_burnout, subset=["burnout_level"]),
311
+ use_container_width=True,
312
+ height=420
313
+ )
314
+
315
+
316
+ # ── Footer ────────────────────────────────────────────────────────────────────
317
+ st.markdown("""
318
+ <div style="border-top:1px solid rgba(255,255,255,0.07);margin-top:2rem;padding:1.5rem;
319
+ text-align:center;color:#7a7f8e;font-family:'DM Mono',monospace;font-size:12px">
320
+ BurnoutIQ &nbsp;Β·&nbsp; Streamlit &nbsp;Β·&nbsp; 7,000 developer records
321
+ </div>
322
+ """, unsafe_allow_html=True)
src/developer_burnout_dataset_7000.csv ADDED
The diff for this file is too large to render. See raw diff