banao-tech commited on
Commit
013651a
Β·
verified Β·
1 Parent(s): 844ddbb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -51
app.py CHANGED
@@ -82,35 +82,28 @@ def fetch_todays_messages(slack: WebClient, log: list) -> list:
82
 
83
 
84
  # ─── STEP 2B: CHECK LEAVE STATUS VIA SLACK PROFILE ──────────────────────────
85
- def is_on_leave_today(name: str, status_text: str, status_emoji: str, claude_client) -> bool:
86
- """Use Claude to intelligently determine if an intern is on leave today."""
87
- if not status_text and not status_emoji:
88
  return False
89
 
90
  today = datetime.datetime.now(IST).strftime("%d-%m-%Y")
91
 
92
- prompt = f"""Today's date is {today}.
93
 
94
- Intern name: {name}
95
- Slack status text: "{status_text}"
96
- Slack status emoji: "{status_emoji}"
97
 
98
- Is this intern on leave TODAY? Consider:
99
- - Date ranges like "on leave 27-04-2026 to 09-05-2026"
100
- - Simple messages like "on leave", "off today", "absent"
101
- - Red circle emoji or similar leave indicators
102
- - Any combination of emoji + text suggesting absence
103
-
104
- Reply with ONLY "yes" or "no"."""
105
 
106
  try:
107
  resp = claude_client.messages.create(
108
  model="claude-sonnet-4-20250514",
109
- max_tokens=10,
110
  messages=[{"role": "user", "content": prompt}]
111
  )
112
- answer = resp.content[0].text.strip().lower()
113
- return answer.startswith("yes")
114
  except Exception:
115
  return False
116
 
@@ -123,22 +116,22 @@ def get_interns_on_leave(slack: WebClient, claude_client, interns: list, log: li
123
 
124
  for intern in interns:
125
  try:
126
- resp = slack.users_profile_get(user=intern["userId"])
127
- profile = resp.get("profile", {})
 
128
  status_text = profile.get("status_text", "")
129
  status_emoji = profile.get("status_emoji", "")
 
130
 
131
- if not status_text and not status_emoji:
132
  continue
133
 
134
- on_leave_today = is_on_leave_today(
135
- intern["name"], status_text, status_emoji, claude_client
136
- )
137
  if on_leave_today:
138
  on_leave.add(intern["userId"])
139
- log.append(f" {intern['name']} is on leave β€” status: '{status_emoji} {status_text}'")
140
  except Exception as e:
141
- log.append(f" Could not check status for {intern['name']}: {e}")
142
 
143
  return on_leave
144
 
@@ -277,49 +270,59 @@ def get_alert_channel_id(slack: WebClient, log: list) -> str:
277
 
278
  # ─── STEP 5: BUILD SLACK MESSAGE ──────────────────────────────────────────────
279
  def build_slack_message(results: dict, evals: dict, run_time: str) -> str:
280
- submitted = [r for r in results.values() if r["submitted"]]
281
- missed = [r for r in results.values() if not r["submitted"]]
282
- good = [r for uid, r in results.items() if r["submitted"] and evals.get(uid, {}).get("quality") == "good"]
283
- weak = [r for uid, r in results.items() if r["submitted"] and evals.get(uid, {}).get("quality") == "weak"]
284
- invalid = [r for uid, r in results.items() if r["submitted"] and evals.get(uid, {}).get("quality") == "invalid"]
 
 
285
 
286
  total = len(results)
 
287
  date_str = datetime.datetime.now(IST).strftime("%d %b %Y")
 
288
  lines = []
289
- lines.append(f"<!channel> *EOD Report Summary β€” {date_str}*")
290
- lines.append(f"_{total} interns | Deadline: 11:00 PM IST_")
 
 
291
  lines.append("")
292
 
293
- on_leave_list = [r for r in results.values() if r.get("on_leave")]
294
- if on_leave_list:
295
- lines.append(f"*On Leave ({len(on_leave_list)}/{total})*")
296
- for r in on_leave_list:
297
- lines.append(f" :red_circle: *{r['name']}* β€” on approved leave")
298
- lines.append("")
299
-
300
  if submitted:
301
- lines.append(f"*Submitted ({len(submitted)}/{total})*")
302
- for uid, r in results.items():
303
- if not r["submitted"] or r.get("on_leave"):
304
  continue
305
- ev = evals.get(uid, {})
306
- q = ev.get("quality", "?")
307
- sc = ev.get("score", "?")
308
- label = {"good": ":large_green_circle:", "weak": ":large_yellow_circle:", "invalid": ":red_circle:"}.get(q, ":white_circle:")
309
  flags = ev.get("flags", [])
310
- line = f" {label} *{r['name']}* β€” {sc}/10 β€” {ev.get('reason', '')}"
311
  if flags:
312
- line += f" | flags: {', '.join(flags)}"
313
  lines.append(line)
314
  lines.append("")
315
 
 
316
  if missed:
317
- lines.append(f"*Did Not Submit ({len(missed)}/{total})*")
318
  for r in missed:
319
- lines.append(f" :x: *{r['name']}* β€” no report received")
 
 
 
 
 
 
 
320
  lines.append("")
321
 
322
- lines.append(f"Good: {len(good)} | Weak: {len(weak)} | Invalid: {len(invalid)} | Missed: {len(missed)}")
 
 
323
 
324
  return "\n".join(lines)
325
 
 
82
 
83
 
84
  # ─── STEP 2B: CHECK LEAVE STATUS VIA SLACK PROFILE ──────────────────────────
85
+ def is_on_leave_today(name: str, full_status: str, claude_client) -> bool:
86
+ """Use Claude to determine if intern is on leave today from their full Slack status string."""
87
+ if not full_status or full_status.strip() == "":
88
  return False
89
 
90
  today = datetime.datetime.now(IST).strftime("%d-%m-%Y")
91
 
92
+ prompt = f"""Today is {today}.
93
 
94
+ Intern Slack status: "{full_status}"
 
 
95
 
96
+ Is this intern on leave TODAY?
97
+ Consider: date ranges, "on leave", "off", "absent", :red_circle: emoji, away messages.
98
+ Reply ONLY with "yes" or "no"."""
 
 
 
 
99
 
100
  try:
101
  resp = claude_client.messages.create(
102
  model="claude-sonnet-4-20250514",
103
+ max_tokens=5,
104
  messages=[{"role": "user", "content": prompt}]
105
  )
106
+ return resp.content[0].text.strip().lower().startswith("yes")
 
107
  except Exception:
108
  return False
109
 
 
116
 
117
  for intern in interns:
118
  try:
119
+ # Use users.info for reliable status reading
120
+ resp = slack.users_info(user=intern["userId"])
121
+ profile = resp.get("user", {}).get("profile", {})
122
  status_text = profile.get("status_text", "")
123
  status_emoji = profile.get("status_emoji", "")
124
+ full_status = f"{status_emoji} {status_text}".strip()
125
 
126
+ if not full_status:
127
  continue
128
 
129
+ on_leave_today = is_on_leave_today(intern["name"], full_status, claude_client)
 
 
130
  if on_leave_today:
131
  on_leave.add(intern["userId"])
132
+ log.append(f" {intern['name']} β€” on leave ({full_status})")
133
  except Exception as e:
134
+ log.append(f" Could not check {intern['name']}: {e}")
135
 
136
  return on_leave
137
 
 
270
 
271
  # ─── STEP 5: BUILD SLACK MESSAGE ──────────────────────────────────────────────
272
  def build_slack_message(results: dict, evals: dict, run_time: str) -> str:
273
+ active = {uid: r for uid, r in results.items() if not r.get("on_leave")}
274
+ submitted = [r for r in active.values() if r["submitted"]]
275
+ missed = [r for r in active.values() if not r["submitted"]]
276
+ on_leave_list = [r for r in results.values() if r.get("on_leave")]
277
+ good = [r for uid, r in active.items() if r["submitted"] and evals.get(uid, {}).get("quality") == "good"]
278
+ weak = [r for uid, r in active.items() if r["submitted"] and evals.get(uid, {}).get("quality") == "weak"]
279
+ invalid = [r for uid, r in active.items() if r["submitted"] and evals.get(uid, {}).get("quality") == "invalid"]
280
 
281
  total = len(results)
282
+ active_count = len(active)
283
  date_str = datetime.datetime.now(IST).strftime("%d %b %Y")
284
+
285
  lines = []
286
+ lines.append(f"<!channel>")
287
+ lines.append(f"*Daily Report Check β€” {date_str}*")
288
+ lines.append(f"{'─' * 32}")
289
+ lines.append(f":busts_in_silhouette: *{active_count} active* Β· :spiral_calendar_pad: Deadline 11:00 PM IST")
290
  lines.append("")
291
 
292
+ # Submitted
 
 
 
 
 
 
293
  if submitted:
294
+ lines.append(f":notepad_spiral: *Reports Received β€” {len(submitted)}/{active_count}*")
295
+ for uid, r in active.items():
296
+ if not r["submitted"]:
297
  continue
298
+ ev = evals.get(uid, {})
299
+ q = ev.get("quality", "?")
300
+ sc = ev.get("score", "?")
301
+ icon = {"good": ":large_green_circle:", "weak": ":large_yellow_circle:", "invalid": ":red_circle:"}.get(q, ":white_circle:")
302
  flags = ev.get("flags", [])
303
+ line = f" {icon} *{r['name']}* Β· {sc}/10 Β· {ev.get('reason', '')}"
304
  if flags:
305
+ line += "\n _flags: " + ", ".join(flags) + "_"
306
  lines.append(line)
307
  lines.append("")
308
 
309
+ # Missed
310
  if missed:
311
+ lines.append(f":x: *No Report β€” {len(missed)}/{active_count}*")
312
  for r in missed:
313
+ lines.append(f" :red_circle: *{r['name']}*")
314
+ lines.append("")
315
+
316
+ # On Leave
317
+ if on_leave_list:
318
+ lines.append(f":palm_tree: *On Leave β€” {len(on_leave_list)}/{total}*")
319
+ for r in on_leave_list:
320
+ lines.append(f" :white_circle: *{r['name']}*")
321
  lines.append("")
322
 
323
+ # Footer
324
+ lines.append(f"{'─' * 32}")
325
+ lines.append(f":large_green_circle: {len(good)} :large_yellow_circle: {len(weak)} :red_circle: {len(invalid)} :x: {len(missed)} :palm_tree: {len(on_leave_list)}")
326
 
327
  return "\n".join(lines)
328