nicovlr commited on
Commit
a04d9e4
·
verified ·
1 Parent(s): a2c454a

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +103 -81
app.py CHANGED
@@ -420,93 +420,115 @@ def analyze_job(job_title):
420
  empty, "", ""
421
  )
422
 
423
- row = df_jobs[df_jobs["title"] == job_title]
424
- if row.empty:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
425
  empty = go.Figure()
426
  apply_layout(empty, height=100)
427
  return (
428
- "<p style='color:#999;'>Job not found</p>",
429
  empty, "", ""
430
  )
431
 
432
- row = row.iloc[0]
433
- score = row["observed_exposure"]
434
- rank = row["rank"]
435
- occ_code = row["occ_code"]
436
-
437
- # Percentile
438
- percentile = ((total_jobs - rank) / total_jobs * 100)
439
-
440
- # Find similar jobs (same 2-digit SOC code)
441
- soc_prefix = occ_code[:2]
442
- similar = df_jobs[
443
- (df_jobs["occ_code"].str.startswith(soc_prefix))
444
- & (df_jobs["title"] != job_title)
445
- ].head(5)
446
-
447
- # Build cards HTML
448
- cards_html = f"""
449
- <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;margin:16px 0;">
450
- {styled_card("AI Exposure Score", f"{score*100:.1f}%", f"Rank #{rank} of {total_jobs}",
451
- COLORS['danger'] if score >= 0.5 else COLORS['warning'] if score >= 0.3
452
- else COLORS['info'] if score >= 0.15 else COLORS['success'])}
453
- {styled_card("Percentile", f"{percentile:.0f}th",
454
- "Higher = more exposed than other jobs",
455
- COLORS['primary'])}
456
- {styled_card("Risk Level", risk_badge(score), "", COLORS['text'])}
457
- </div>
458
- <div style="background:white;border-radius:16px;padding:24px;margin-top:16px;
459
- box-shadow:0 2px 12px rgba(0,0,0,0.06);border:1px solid #f0ece8;">
460
- <h3 style="margin:0 0 4px 0;color:{COLORS['secondary']};">{job_title}</h3>
461
- <p style="margin:0;color:{COLORS['muted']};">O*NET Code: {occ_code}</p>
462
- </div>
463
- """
464
-
465
- # Gauge chart
466
- gauge = make_gauge(score)
467
-
468
- # Similar jobs comparison
469
- if not similar.empty:
470
- compare_data = pd.concat([row.to_frame().T, similar])
471
- similar_html = "<div style='margin-top:16px;'><h4>Related Occupations</h4><table style='width:100%;border-collapse:collapse;'>"
472
- similar_html += "<tr style='border-bottom:2px solid #f0ece8;'><th style='text-align:left;padding:8px;'>Occupation</th><th style='text-align:right;padding:8px;'>Exposure</th></tr>"
473
- for _, s in similar.iterrows():
474
- bar_width = s["observed_exposure"] * 100
475
- similar_html += f"""
476
- <tr style='border-bottom:1px solid #f5f0eb;'>
477
- <td style='padding:10px 8px;'>{s['title']}</td>
478
- <td style='padding:10px 8px;text-align:right;'>
479
- <div style='display:flex;align-items:center;justify-content:flex-end;gap:8px;'>
480
- <div style='width:80px;height:8px;background:#f0ece8;border-radius:4px;overflow:hidden;'>
481
- <div style='width:{bar_width}%;height:100%;background:{COLORS["primary"]};border-radius:4px;'></div>
482
- </div>
483
- <span style='font-weight:600;min-width:45px;'>{s['observed_exposure']*100:.1f}%</span>
484
- </div>
485
- </td>
486
- </tr>"""
487
- similar_html += "</table></div>"
488
- else:
489
- similar_html = ""
490
-
491
- # Interpretation
492
- if score >= 0.5:
493
- interp = "This occupation has **very high** AI exposure. A significant portion of its tasks are already being performed with AI assistance. Workers in this field should actively develop AI collaboration skills."
494
- elif score >= 0.3:
495
- interp = "This occupation has **high** AI exposure. Many of its tasks intersect with AI capabilities. Embracing AI tools can significantly boost productivity."
496
- elif score >= 0.15:
497
- interp = "This occupation has **moderate** AI exposure. Some tasks are being augmented by AI, but core functions still require substantial human expertise."
498
- else:
499
- interp = "This occupation has **low** AI exposure. Most of its tasks are not significantly impacted by current AI capabilities, though this may change over time."
500
-
501
- interp_html = f"""
502
- <div style="background:#fef9f5;border-left:4px solid {COLORS['primary']};padding:16px 20px;
503
- border-radius:0 12px 12px 0;margin-top:16px;">
504
- <strong>Interpretation:</strong> {interp}
505
- </div>
506
- """
507
-
508
- return cards_html, gauge, similar_html, interp_html
509
-
510
 
511
  # ============================================================================
512
  # KEY METRICS
 
420
  empty, "", ""
421
  )
422
 
423
+ try:
424
+ row = df_jobs[df_jobs["title"] == job_title]
425
+ if row.empty:
426
+ empty = go.Figure()
427
+ apply_layout(empty, height=100)
428
+ return (
429
+ "<p style='color:#999;'>Job not found</p>",
430
+ empty, "", ""
431
+ )
432
+
433
+ row = row.iloc[0]
434
+ score = float(row["observed_exposure"])
435
+ rank = int(row["rank"])
436
+ occ_code = str(row["occ_code"])
437
+
438
+ # Percentile
439
+ percentile = (total_jobs - rank) / total_jobs * 100
440
+
441
+ # Find similar jobs (same 2-digit SOC code)
442
+ soc_prefix = occ_code[:2]
443
+ similar = df_jobs[
444
+ (df_jobs["occ_code"].str.startswith(soc_prefix))
445
+ & (df_jobs["title"] != job_title)
446
+ ].head(5)
447
+
448
+ # Risk color
449
+ if score >= 0.5:
450
+ score_color = COLORS["danger"]
451
+ elif score >= 0.3:
452
+ score_color = COLORS["warning"]
453
+ elif score >= 0.15:
454
+ score_color = COLORS["info"]
455
+ else:
456
+ score_color = COLORS["success"]
457
+
458
+ # Build cards HTML
459
+ badge = risk_badge(score)
460
+ card1 = styled_card("AI Exposure Score", f"{score*100:.1f}%", f"Rank #{rank} of {total_jobs}", score_color)
461
+ card2 = styled_card("Percentile", f"{percentile:.0f}th", "Higher = more exposed than other jobs", COLORS["primary"])
462
+ card3 = styled_card("Risk Level", badge, "", COLORS["text"])
463
+
464
+ cards_html = f"""
465
+ <div style="display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin:16px 0;">
466
+ {card1}
467
+ {card2}
468
+ {card3}
469
+ </div>
470
+ <div style="background:white;border-radius:16px;padding:24px;margin-top:16px;
471
+ box-shadow:0 2px 12px rgba(0,0,0,0.06);border:1px solid #f0ece8;">
472
+ <h3 style="margin:0 0 4px 0;color:{COLORS['secondary']};">{job_title}</h3>
473
+ <p style="margin:0;color:{COLORS['muted']};">O*NET Code: {occ_code}</p>
474
+ </div>
475
+ """
476
+
477
+ # Gauge chart
478
+ gauge = make_gauge(score)
479
+
480
+ # Similar jobs comparison
481
+ if not similar.empty:
482
+ similar_html = "<div style='margin-top:16px;'><h4>Related Occupations</h4><table style='width:100%;border-collapse:collapse;'>"
483
+ similar_html += "<tr style='border-bottom:2px solid #f0ece8;'><th style='text-align:left;padding:8px;'>Occupation</th><th style='text-align:right;padding:8px;'>Exposure</th></tr>"
484
+ for _, s in similar.iterrows():
485
+ bar_width = float(s["observed_exposure"]) * 100
486
+ similar_html += f"""
487
+ <tr style='border-bottom:1px solid #f5f0eb;'>
488
+ <td style='padding:10px 8px;'>{s['title']}</td>
489
+ <td style='padding:10px 8px;text-align:right;'>
490
+ <div style='display:flex;align-items:center;justify-content:flex-end;gap:8px;'>
491
+ <div style='width:80px;height:8px;background:#f0ece8;border-radius:4px;overflow:hidden;'>
492
+ <div style='width:{bar_width:.1f}%;height:100%;background:{COLORS["primary"]};border-radius:4px;'></div>
493
+ </div>
494
+ <span style='font-weight:600;min-width:45px;'>{bar_width:.1f}%</span>
495
+ </div>
496
+ </td>
497
+ </tr>"""
498
+ similar_html += "</table></div>"
499
+ else:
500
+ similar_html = ""
501
+
502
+ # Interpretation
503
+ if score >= 0.5:
504
+ interp = "This occupation has <b>very high</b> AI exposure. A significant portion of its tasks are already being performed with AI assistance. Workers in this field should actively develop AI collaboration skills."
505
+ elif score >= 0.3:
506
+ interp = "This occupation has <b>high</b> AI exposure. Many of its tasks intersect with AI capabilities. Embracing AI tools can significantly boost productivity."
507
+ elif score >= 0.15:
508
+ interp = "This occupation has <b>moderate</b> AI exposure. Some tasks are being augmented by AI, but core functions still require substantial human expertise."
509
+ else:
510
+ interp = "This occupation has <b>low</b> AI exposure. Most of its tasks are not significantly impacted by current AI capabilities, though this may change over time."
511
+
512
+ interp_html = f"""
513
+ <div style="background:#fef9f5;border-left:4px solid {COLORS['primary']};padding:16px 20px;
514
+ border-radius:0 12px 12px 0;margin-top:16px;">
515
+ <strong>Interpretation:</strong> {interp}
516
+ </div>
517
+ """
518
+
519
+ return cards_html, gauge, similar_html, interp_html
520
+
521
+ except Exception as e:
522
+ import traceback
523
+ err = traceback.format_exc()
524
+ print(f"Error in analyze_job: {err}")
525
  empty = go.Figure()
526
  apply_layout(empty, height=100)
527
  return (
528
+ f"<p style='color:red;'>Error analyzing job: {str(e)}</p>",
529
  empty, "", ""
530
  )
531
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
532
 
533
  # ============================================================================
534
  # KEY METRICS