shaanilmo Claude Opus 4.8 commited on
Commit
8d010cd
·
1 Parent(s): e3f0b7c

Dashboard: Team column + Intern/Recovery badges from report fields

Browse files

Backward-compatible: reports without a team show 'Unassigned'; unknown team
strings are clamped server-side. Adds team to the sortable columns.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +26 -0
app.py CHANGED
@@ -86,12 +86,19 @@ class Counts(BaseModel):
86
 
87
  class Report(BaseModel):
88
  annotator: str
 
 
 
89
  folder: str = ""
90
  total: int = 0
91
  counts: Counts
92
  updatedAt: int = 0
93
 
94
 
 
 
 
 
95
  # ----------------------------------------------------------------------------
96
  # Helpers
97
  # ----------------------------------------------------------------------------
@@ -159,6 +166,7 @@ def submit_report(report: Report, x_report_token: str = Header(default="")):
159
  slug = slugify(report.annotator)
160
  payload = report.model_dump()
161
  payload["annotator"] = report.annotator.strip() or "Anonymous"
 
162
  payload["slug"] = slug
163
  payload["receivedAt"] = int(time.time() * 1000)
164
 
@@ -285,6 +293,13 @@ DASHBOARD_HTML = """<!DOCTYPE html>
285
  .medal.gold { background: linear-gradient(145deg, #ffe487, #f5b301); }
286
  .medal.silver { background: linear-gradient(145deg, #eef2f5, #b4bdc7); }
287
  .medal.bronze { background: linear-gradient(145deg, #f0b27a, #c2772f); }
 
 
 
 
 
 
 
288
  /* in-row stacked status bar (table Progress column) */
289
  .bar-track { flex: 1; display: flex; height: 14px; border-radius: 4px; overflow: hidden;
290
  background: var(--panel-2); }
@@ -313,6 +328,7 @@ DASHBOARD_HTML = """<!DOCTYPE html>
313
  <script>
314
  const STATUS = ["delete", "correct", "to_correct", "edited", "pending"];
315
  const LABEL = { delete: "Delete", correct: "Correct", to_correct: "To Fix", edited: "Edited", pending: "Pending" };
 
316
  // Chart segment order (done group first, backlog, then pending) + color var.
317
  const CHART_ORDER = [
318
  ["correct", "--correct"], ["edited", "--edited"], ["delete", "--delete"],
@@ -365,6 +381,7 @@ function sortValue(r, key) {
365
  const c = r.counts || {};
366
  switch (key) {
367
  case "name": return (r.annotator || "").toLowerCase();
 
368
  case "total": return r.total || 0;
369
  case "delete": return c.delete || 0;
370
  case "correct": return c.correct || 0;
@@ -505,9 +522,16 @@ async function refresh() {
505
  const rankCell = (podium && rank <= 3)
506
  ? `<td class="rank"><span class="medal ${MEDALS[rank - 1]}">${rank}</span></td>`
507
  : `<td class="rank">${rank}</td>`;
 
 
 
 
 
 
508
  return `<tr>
509
  ${rankCell}
510
  <td class="name">${escapeHtml(r.annotator || "—")}<div class="muted" style="font-weight:400;font-size:12px">${escapeHtml(r.folder || "")}</div></td>
 
511
  <td class="num">${r.total || 0}</td>
512
  <td><span class="pill delete">${c.delete || 0}</span></td>
513
  <td><span class="pill correct">${c.correct || 0}</span></td>
@@ -524,6 +548,7 @@ async function refresh() {
524
  const foot = `<tr>
525
  <td class="rank"></td>
526
  <td>Team total</td>
 
527
  <td class="num">${agg.total}</td>
528
  <td><span class="pill delete">${ac.delete || 0}</span></td>
529
  <td><span class="pill correct">${ac.correct || 0}</span></td>
@@ -539,6 +564,7 @@ async function refresh() {
539
  <thead><tr>
540
  <th class="rank-h" title="Rank in the current sort">#</th>
541
  <th data-sort="name" class="sortable">Annotator${arrow("name")}</th>
 
542
  <th data-sort="total" class="sortable num">Total${arrow("total")}</th>
543
  <th data-sort="delete" class="sortable">Delete${arrow("delete")}</th>
544
  <th data-sort="correct" class="sortable">Correct${arrow("correct")}</th>
 
86
 
87
  class Report(BaseModel):
88
  annotator: str
89
+ team: str = ""
90
+ intern: bool = False
91
+ recoveryUsed: bool = False
92
  folder: str = ""
93
  total: int = 0
94
  counts: Counts
95
  updatedAt: int = 0
96
 
97
 
98
+ # Known teams; anything else is treated as Unassigned.
99
+ TEAMS = {"Research", "Investments", "Growth", "ConvAI", "HyperPersonalization"}
100
+
101
+
102
  # ----------------------------------------------------------------------------
103
  # Helpers
104
  # ----------------------------------------------------------------------------
 
166
  slug = slugify(report.annotator)
167
  payload = report.model_dump()
168
  payload["annotator"] = report.annotator.strip() or "Anonymous"
169
+ payload["team"] = report.team if report.team in TEAMS else ""
170
  payload["slug"] = slug
171
  payload["receivedAt"] = int(time.time() * 1000)
172
 
 
293
  .medal.gold { background: linear-gradient(145deg, #ffe487, #f5b301); }
294
  .medal.silver { background: linear-gradient(145deg, #eef2f5, #b4bdc7); }
295
  .medal.bronze { background: linear-gradient(145deg, #f0b27a, #c2772f); }
296
+ /* team cell + intern/recovery tags */
297
+ td.team .team-name { font-weight: 600; color: var(--text); }
298
+ .tag-row { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
299
+ .tag { display: inline-block; padding: 1px 7px; border-radius: 99px; font-size: 11px;
300
+ font-weight: 600; line-height: 1.5; border: 1px solid transparent; }
301
+ .tag.intern { background: rgba(79,70,229,.16); color: #818cf8; border-color: rgba(79,70,229,.35); }
302
+ .tag.recovery { background: rgba(245,158,11,.16); color: #f59e0b; border-color: rgba(245,158,11,.35); }
303
  /* in-row stacked status bar (table Progress column) */
304
  .bar-track { flex: 1; display: flex; height: 14px; border-radius: 4px; overflow: hidden;
305
  background: var(--panel-2); }
 
328
  <script>
329
  const STATUS = ["delete", "correct", "to_correct", "edited", "pending"];
330
  const LABEL = { delete: "Delete", correct: "Correct", to_correct: "To Fix", edited: "Edited", pending: "Pending" };
331
+ const TEAMS = new Set(["Research", "Investments", "Growth", "ConvAI", "HyperPersonalization"]);
332
  // Chart segment order (done group first, backlog, then pending) + color var.
333
  const CHART_ORDER = [
334
  ["correct", "--correct"], ["edited", "--edited"], ["delete", "--delete"],
 
381
  const c = r.counts || {};
382
  switch (key) {
383
  case "name": return (r.annotator || "").toLowerCase();
384
+ case "team": return (r.team || "").toLowerCase();
385
  case "total": return r.total || 0;
386
  case "delete": return c.delete || 0;
387
  case "correct": return c.correct || 0;
 
522
  const rankCell = (podium && rank <= 3)
523
  ? `<td class="rank"><span class="medal ${MEDALS[rank - 1]}">${rank}</span></td>`
524
  : `<td class="rank">${rank}</td>`;
525
+ const team = TEAMS.has(r.team) ? r.team : "";
526
+ const tags = (r.intern ? `<span class="tag intern">Intern</span>` : "")
527
+ + (r.recoveryUsed ? `<span class="tag recovery" title="Used skip-ahead recovery; numbers are partly self-declared">Recovery</span>` : "");
528
+ const teamCell = `<td class="team">`
529
+ + (team ? `<span class="team-name">${escapeHtml(team)}</span>` : `<span class="muted">Unassigned</span>`)
530
+ + (tags ? `<div class="tag-row">${tags}</div>` : "") + `</td>`;
531
  return `<tr>
532
  ${rankCell}
533
  <td class="name">${escapeHtml(r.annotator || "—")}<div class="muted" style="font-weight:400;font-size:12px">${escapeHtml(r.folder || "")}</div></td>
534
+ ${teamCell}
535
  <td class="num">${r.total || 0}</td>
536
  <td><span class="pill delete">${c.delete || 0}</span></td>
537
  <td><span class="pill correct">${c.correct || 0}</span></td>
 
548
  const foot = `<tr>
549
  <td class="rank"></td>
550
  <td>Team total</td>
551
+ <td></td>
552
  <td class="num">${agg.total}</td>
553
  <td><span class="pill delete">${ac.delete || 0}</span></td>
554
  <td><span class="pill correct">${ac.correct || 0}</span></td>
 
564
  <thead><tr>
565
  <th class="rank-h" title="Rank in the current sort">#</th>
566
  <th data-sort="name" class="sortable">Annotator${arrow("name")}</th>
567
+ <th data-sort="team" class="sortable">Team${arrow("team")}</th>
568
  <th data-sort="total" class="sortable num">Total${arrow("total")}</th>
569
  <th data-sort="delete" class="sortable">Delete${arrow("delete")}</th>
570
  <th data-sort="correct" class="sortable">Correct${arrow("correct")}</th>