edouardlgp commited on
Commit
468f84a
·
verified ·
1 Parent(s): 9c6f22a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +185 -46
app.py CHANGED
@@ -619,29 +619,66 @@ def _extract_json(raw: str) -> str:
619
 
620
  # ================= Format Skills Visualisation =================
621
  def format_skill_cards(skills_data):
622
- if not skills_data:
623
- return "No skills data available"
624
 
625
  cards = []
626
  for skill in skills_data:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
627
  card = f"""
628
  <div class='skill-card'>
629
  <div class='skill-header'>
630
- <h3>{skill.get('skill_name', 'Unnamed Skill')}</h3>
631
- <div class='skill-pill {skill.get("type", "").lower()}'>{skill.get("type", "").capitalize()}</div>
632
- <div class='skill-pill {skill.get("importance", "").lower()}'>{skill.get("importance", "").capitalize()}</div>
 
 
 
 
 
633
  </div>
 
634
  <div class='skill-body'>
635
- <p><strong>Description:</strong> {skill.get('skill_description', '')}</p>
636
- <div class='skill-meta'>
637
- <span class='proficiency'>
638
- <strong>Level:</strong>
639
- <progress value={get_progress_value(skill.get("proficiency_level"))} max="3"></progress>
640
- {skill.get("proficiency_level", "").capitalize()}
641
- </span>
642
- <span class='assessment'>
643
- <strong>Assessment:</strong> {skill.get("assessment_method", "")}
644
- </span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
645
  </div>
646
  </div>
647
  </div>
@@ -741,6 +778,7 @@ def process_pdf(file):
741
  # Format skills before returning
742
  formatted_skills = format_skill_cards(joined_skills)
743
 
 
744
  joined_skills_esco = []
745
  if has_esco and skill_esco_extract:
746
  assessment_esco_lookup = {item['skill_name']: item for item in skill_esco_map}
@@ -753,7 +791,7 @@ def process_pdf(file):
753
  }
754
  for skill in skill_esco_extract
755
  ]
756
-
757
  interview = build_interview(responsibilities, skills)
758
 
759
  # Prepare the results for each output component
@@ -773,6 +811,8 @@ def process_pdf(file):
773
  for i in range(1, 6) for field in ["code", "name", "desc"]}
774
  esco_skills = None
775
 
 
 
776
  debug_message = "Processing completed successfully."
777
  return (
778
  os.path.basename(file.name),
@@ -784,7 +824,8 @@ def process_pdf(file):
784
  #joined_skills,
785
  formatted_skills,
786
  esco_levels,
787
- esco_skills,
 
788
  debug_message if DEBUG else None
789
  )
790
 
@@ -1209,69 +1250,147 @@ label {
1209
  /* Skills Card */
1210
  .skills-container {
1211
  display: grid;
1212
- grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
1213
- gap: 1rem;
1214
  padding: 1rem;
1215
  }
1216
 
 
1217
  .skill-card {
1218
  background: white;
1219
  border-radius: 8px;
1220
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
1221
  overflow: hidden;
1222
- transition: transform 0.2s;
 
1223
  }
1224
 
1225
  .skill-card:hover {
1226
- transform: translateY(-3px);
1227
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
1228
  }
1229
 
 
1230
  .skill-header {
1231
  background: #0033A0;
1232
  color: white;
1233
- padding: 1rem;
1234
  display: flex;
1235
- flex-wrap: wrap;
1236
- gap: 0.5rem;
 
 
 
 
 
1237
  align-items: center;
1238
  }
1239
 
1240
- .skill-header h3 {
1241
  margin: 0;
1242
- flex-grow: 1;
1243
- font-size: 1.1rem;
1244
  }
1245
 
1246
- .skill-pill {
 
 
 
1247
  padding: 0.25rem 0.5rem;
 
 
 
 
 
 
 
 
 
 
 
1248
  border-radius: 999px;
1249
  font-size: 0.8rem;
1250
- font-weight: bold;
1251
  }
1252
 
1253
- .skill-pill.skill { background: #4CAF50; }
1254
- .skill-pill.knowledge { background: #2196F3; }
1255
- .skill-pill.essential { background: #F44336; }
1256
- .skill-pill.optional { background: #FF9800; }
 
1257
 
 
1258
  .skill-body {
1259
- padding: 1rem;
 
 
 
 
 
 
1260
  }
1261
 
1262
- .skill-meta {
1263
- margin-top: 1rem;
1264
- padding-top: 1rem;
1265
- border-top: 1px solid #eee;
 
 
 
 
1266
  display: flex;
1267
  flex-direction: column;
1268
- gap: 0.5rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1269
  }
1270
 
1271
  progress {
1272
- width: 100%;
1273
- height: 6px;
1274
- margin-top: 0.25rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1275
  }
1276
 
1277
  /* Output Markdown */
@@ -1299,6 +1418,20 @@ progress {
1299
  margin-right: 0 !important;
1300
  margin-bottom: 1rem !important;
1301
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1302
  }
1303
  """,
1304
  head='''
@@ -1364,7 +1497,10 @@ progress {
1364
  with gr.Row():
1365
  with gr.Column():
1366
  gr.Markdown("### Mapped Skills")
1367
- skills_output = gr.HTML(label="Related identified Skills")
 
 
 
1368
 
1369
  with gr.Row():
1370
  with gr.Column():
@@ -1391,7 +1527,10 @@ progress {
1391
 
1392
  with gr.Row():
1393
  with gr.Column():
1394
- esco_skills_output = gr.Textbox(label="Mapped ESCO Skills linked to this Occupation Group")
 
 
 
1395
 
1396
 
1397
 
 
619
 
620
  # ================= Format Skills Visualisation =================
621
  def format_skill_cards(skills_data):
622
+ if not skills_data or not isinstance(skills_data, list):
623
+ return "<div class='skills-container'><p>No skills data available</p></div>"
624
 
625
  cards = []
626
  for skill in skills_data:
627
+ if not isinstance(skill, dict):
628
+ continue
629
+
630
+ # Safely get all fields with fallbacks
631
+ skill_name = skill.get('skill_name', 'Unnamed Skill')
632
+ skill_code = skill.get('skill_code', 'N/A')
633
+ description = skill.get('skill_description', 'No description available')
634
+ skill_type = skill.get('type', '').capitalize()
635
+ importance = skill.get('importance', '').capitalize()
636
+ proficiency = skill.get('proficiency_level', '').capitalize()
637
+ distinctive = skill.get('distinctive_elements', 'Not specified')
638
+ resume_signals = skill.get('resume_signals', 'Not specified')
639
+ assessment = skill.get('assessment_method', 'Not specified')
640
+
641
  card = f"""
642
  <div class='skill-card'>
643
  <div class='skill-header'>
644
+ <div class='skill-title'>
645
+ <h3>{skill_name}</h3>
646
+ <span class='skill-code'>Code: {skill_code}</span>
647
+ </div>
648
+ <div class='skill-pills'>
649
+ <span class='skill-pill type-{skill.get("type", "").lower()}'>{skill_type}</span>
650
+ <span class='skill-pill importance-{skill.get("importance", "").lower()}'>{importance}</span>
651
+ </div>
652
  </div>
653
+
654
  <div class='skill-body'>
655
+ <div class='skill-description'>
656
+ <p>{description}</p>
657
+ </div>
658
+
659
+ <div class='skill-details'>
660
+ <div class='detail-group'>
661
+ <label>Proficiency Level:</label>
662
+ <div class='proficiency-bar'>
663
+ <progress value={get_progress_value(skill.get("proficiency_level"))} max="3"></progress>
664
+ <span>{proficiency}</span>
665
+ </div>
666
+ </div>
667
+
668
+ <div class='detail-group'>
669
+ <label>Distinctive Elements:</label>
670
+ <p class='detail-content'>{distinctive}</p>
671
+ </div>
672
+
673
+ <div class='detail-group'>
674
+ <label>Resume Signals:</label>
675
+ <p class='detail-content'>{resume_signals}</p>
676
+ </div>
677
+
678
+ <div class='detail-group'>
679
+ <label>Assessment Method:</label>
680
+ <p class='detail-content'>{assessment}</p>
681
+ </div>
682
  </div>
683
  </div>
684
  </div>
 
778
  # Format skills before returning
779
  formatted_skills = format_skill_cards(joined_skills)
780
 
781
+
782
  joined_skills_esco = []
783
  if has_esco and skill_esco_extract:
784
  assessment_esco_lookup = {item['skill_name']: item for item in skill_esco_map}
 
791
  }
792
  for skill in skill_esco_extract
793
  ]
794
+
795
  interview = build_interview(responsibilities, skills)
796
 
797
  # Prepare the results for each output component
 
811
  for i in range(1, 6) for field in ["code", "name", "desc"]}
812
  esco_skills = None
813
 
814
+ formatted_esco_skills = format_skill_cards(esco_skills)
815
+
816
  debug_message = "Processing completed successfully."
817
  return (
818
  os.path.basename(file.name),
 
824
  #joined_skills,
825
  formatted_skills,
826
  esco_levels,
827
+ #esco_skills,
828
+ formatted_esco_skills
829
  debug_message if DEBUG else None
830
  )
831
 
 
1250
  /* Skills Card */
1251
  .skills-container {
1252
  display: grid;
1253
+ grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
1254
+ gap: 1.5rem;
1255
  padding: 1rem;
1256
  }
1257
 
1258
+ /* Card styling */
1259
  .skill-card {
1260
  background: white;
1261
  border-radius: 8px;
1262
+ box-shadow: 0 2px 12px rgba(0,0,0,0.08);
1263
  overflow: hidden;
1264
+ transition: all 0.3s ease;
1265
+ border: 1px solid #e0e0e0;
1266
  }
1267
 
1268
  .skill-card:hover {
1269
+ transform: translateY(-5px);
1270
+ box-shadow: 0 6px 16px rgba(0,0,0,0.12);
1271
  }
1272
 
1273
+ /* Header section */
1274
  .skill-header {
1275
  background: #0033A0;
1276
  color: white;
1277
+ padding: 1.2rem;
1278
  display: flex;
1279
+ flex-direction: column;
1280
+ gap: 0.8rem;
1281
+ }
1282
+
1283
+ .skill-title {
1284
+ display: flex;
1285
+ justify-content: space-between;
1286
  align-items: center;
1287
  }
1288
 
1289
+ .skill-title h3 {
1290
  margin: 0;
1291
+ font-size: 1.2rem;
1292
+ font-weight: 600;
1293
  }
1294
 
1295
+ .skill-code {
1296
+ font-size: 0.85rem;
1297
+ opacity: 0.8;
1298
+ background: rgba(255,255,255,0.15);
1299
  padding: 0.25rem 0.5rem;
1300
+ border-radius: 4px;
1301
+ }
1302
+
1303
+ .skill-pills {
1304
+ display: flex;
1305
+ gap: 0.5rem;
1306
+ flex-wrap: wrap;
1307
+ }
1308
+
1309
+ .skill-pill {
1310
+ padding: 0.35rem 0.7rem;
1311
  border-radius: 999px;
1312
  font-size: 0.8rem;
1313
+ font-weight: 500;
1314
  }
1315
 
1316
+ /* Type and Importance pills */
1317
+ .skill-pill.type-skill { background: #4CAF50; color: white; }
1318
+ .skill-pill.type-knowledge { background: #2196F3; color: white; }
1319
+ .skill-pill.importance-essential { background: #F44336; color: white; }
1320
+ .skill-pill.importance-optional { background: #FF9800; color: white; }
1321
 
1322
+ /* Body section */
1323
  .skill-body {
1324
+ padding: 1.2rem;
1325
+ }
1326
+
1327
+ .skill-description {
1328
+ margin-bottom: 1.2rem;
1329
+ padding-bottom: 1rem;
1330
+ border-bottom: 1px dashed #eee;
1331
  }
1332
 
1333
+ .skill-description p {
1334
+ margin: 0;
1335
+ color: #555;
1336
+ line-height: 1.5;
1337
+ }
1338
+
1339
+ /* Details sections */
1340
+ .skill-details {
1341
  display: flex;
1342
  flex-direction: column;
1343
+ gap: 1rem;
1344
+ }
1345
+
1346
+ .detail-group {
1347
+ display: flex;
1348
+ flex-direction: column;
1349
+ gap: 0.3rem;
1350
+ }
1351
+
1352
+ .detail-group label {
1353
+ font-weight: 600;
1354
+ font-size: 0.9rem;
1355
+ color: #0033A0;
1356
+ }
1357
+
1358
+ .detail-content {
1359
+ margin: 0;
1360
+ font-size: 0.95rem;
1361
+ color: #444;
1362
+ line-height: 1.5;
1363
+ }
1364
+
1365
+ /* Proficiency bar */
1366
+ .proficiency-bar {
1367
+ display: flex;
1368
+ align-items: center;
1369
+ gap: 0.8rem;
1370
+ margin-top: 0.3rem;
1371
  }
1372
 
1373
  progress {
1374
+ flex-grow: 1;
1375
+ height: 8px;
1376
+ border-radius: 4px;
1377
+ }
1378
+
1379
+ progress::-webkit-progress-bar {
1380
+ background-color: #f0f0f0;
1381
+ border-radius: 4px;
1382
+ }
1383
+
1384
+ progress::-webkit-progress-value {
1385
+ background-color: #0033A0;
1386
+ border-radius: 4px;
1387
+ }
1388
+
1389
+ .proficiency-bar span {
1390
+ font-size: 0.9rem;
1391
+ font-weight: 500;
1392
+ min-width: 80px;
1393
+ text-align: right;
1394
  }
1395
 
1396
  /* Output Markdown */
 
1418
  margin-right: 0 !important;
1419
  margin-bottom: 1rem !important;
1420
  }
1421
+
1422
+ .skills-container {
1423
+ grid-template-columns: 1fr;
1424
+ }
1425
+
1426
+ .skill-header {
1427
+ flex-direction: column;
1428
+ }
1429
+
1430
+ .skill-title {
1431
+ flex-direction: column;
1432
+ align-items: flex-start;
1433
+ gap: 0.5rem;
1434
+ }
1435
  }
1436
  """,
1437
  head='''
 
1497
  with gr.Row():
1498
  with gr.Column():
1499
  gr.Markdown("### Mapped Skills")
1500
+ skills_output = gr.HTML(
1501
+ elem_classes="skills-container",
1502
+ label=""
1503
+ )
1504
 
1505
  with gr.Row():
1506
  with gr.Column():
 
1527
 
1528
  with gr.Row():
1529
  with gr.Column():
1530
+ esco_skills_output = (
1531
+ elem_classes="skills-container",
1532
+ label=""
1533
+ )
1534
 
1535
 
1536