edouardlgp commited on
Commit
e21ebce
·
verified ·
1 Parent(s): 16bd478

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +172 -0
app.py CHANGED
@@ -617,6 +617,44 @@ def _extract_json(raw: str) -> str:
617
  json_text = json_text.strip()
618
  return json_text
619
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
620
  # ================= Process Analysis =================
621
  from concurrent.futures import ThreadPoolExecutor
622
 
@@ -700,6 +738,9 @@ def process_pdf(file):
700
  for skill in skills
701
  ]
702
 
 
 
 
703
  joined_skills_esco = []
704
  if has_esco and skill_esco_extract:
705
  assessment_esco_lookup = {item['skill_name']: item for item in skill_esco_map}
@@ -835,6 +876,8 @@ def generate_word_document(
835
  log_debug(f"Error building result dictionary: {str(e)}")
836
  result = default_values
837
 
 
 
838
  # ================= DOCUMENT CONTENT GENERATION =================
839
  try:
840
  # Document header
@@ -1131,6 +1174,105 @@ label {
1131
  .btn-primary:active {
1132
  transform: translateY(0) !important;
1133
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1134
  /* Output Markdown */
1135
  .gr-markdown {
1136
  background: #f9f9f9;
@@ -1181,6 +1323,36 @@ label {
1181
  <p>Use AI to standardise an initial draft position description and identify related Job Family, Occupation, Qualification, match Skills and suggest interview questions.</p>
1182
  </div>
1183
  """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1184
 
1185
  with gr.Row():
1186
  with gr.Column():
 
617
  json_text = json_text.strip()
618
  return json_text
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>
648
+ """
649
+ cards.append(card)
650
+
651
+ return f"<div class='skills-container'>{''.join(cards)}</div>"
652
+
653
+ def get_progress_value(level):
654
+ level_map = {"basic": 1, "intermediate": 2, "advanced": 3}
655
+ return str(level_map.get(level.lower(), 1))
656
+
657
+
658
  # ================= Process Analysis =================
659
  from concurrent.futures import ThreadPoolExecutor
660
 
 
738
  for skill in skills
739
  ]
740
 
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}
 
876
  log_debug(f"Error building result dictionary: {str(e)}")
877
  result = default_values
878
 
879
+
880
+
881
  # ================= DOCUMENT CONTENT GENERATION =================
882
  try:
883
  # Document header
 
1174
  .btn-primary:active {
1175
  transform: translateY(0) !important;
1176
  }
1177
+
1178
+ /* Intro */
1179
+ .intro-box {
1180
+ background: #f0f7ff;
1181
+ border-left: 4px solid #0033A0;
1182
+ border-radius: 4px;
1183
+ padding: 16px;
1184
+ margin-bottom: 20px;
1185
+ }
1186
+ .intro-title {
1187
+ color: #0033A0;
1188
+ font-weight: 600;
1189
+ margin-top: 0 !important;
1190
+ }
1191
+ .intro-icon {
1192
+ color: #0033A0;
1193
+ margin-right: 8px;
1194
+ }
1195
+ .benefits-grid {
1196
+ display: grid;
1197
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
1198
+ gap: 12px;
1199
+ margin: 16px 0;
1200
+ }
1201
+ .benefit-card {
1202
+ background: white;
1203
+ padding: 12px;
1204
+ border-radius: 8px;
1205
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
1206
+ }
1207
+
1208
+ /* Skills Card */
1209
+ .skills-container {
1210
+ display: grid;
1211
+ grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
1212
+ gap: 1rem;
1213
+ padding: 1rem;
1214
+ }
1215
+
1216
+ .skill-card {
1217
+ background: white;
1218
+ border-radius: 8px;
1219
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
1220
+ overflow: hidden;
1221
+ transition: transform 0.2s;
1222
+ }
1223
+
1224
+ .skill-card:hover {
1225
+ transform: translateY(-3px);
1226
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
1227
+ }
1228
+
1229
+ .skill-header {
1230
+ background: #0033A0;
1231
+ color: white;
1232
+ padding: 1rem;
1233
+ display: flex;
1234
+ flex-wrap: wrap;
1235
+ gap: 0.5rem;
1236
+ align-items: center;
1237
+ }
1238
+
1239
+ .skill-header h3 {
1240
+ margin: 0;
1241
+ flex-grow: 1;
1242
+ font-size: 1.1rem;
1243
+ }
1244
+
1245
+ .skill-pill {
1246
+ padding: 0.25rem 0.5rem;
1247
+ border-radius: 999px;
1248
+ font-size: 0.8rem;
1249
+ font-weight: bold;
1250
+ }
1251
+
1252
+ .skill-pill.skill { background: #4CAF50; }
1253
+ .skill-pill.knowledge { background: #2196F3; }
1254
+ .skill-pill.essential { background: #F44336; }
1255
+ .skill-pill.optional { background: #FF9800; }
1256
+
1257
+ .skill-body {
1258
+ padding: 1rem;
1259
+ }
1260
+
1261
+ .skill-meta {
1262
+ margin-top: 1rem;
1263
+ padding-top: 1rem;
1264
+ border-top: 1px solid #eee;
1265
+ display: flex;
1266
+ flex-direction: column;
1267
+ gap: 0.5rem;
1268
+ }
1269
+
1270
+ progress {
1271
+ width: 100%;
1272
+ height: 6px;
1273
+ margin-top: 0.25rem;
1274
+ }
1275
+
1276
  /* Output Markdown */
1277
  .gr-markdown {
1278
  background: #f9f9f9;
 
1323
  <p>Use AI to standardise an initial draft position description and identify related Job Family, Occupation, Qualification, match Skills and suggest interview questions.</p>
1324
  </div>
1325
  """)
1326
+ # Introduction Section
1327
+ with gr.Column(elem_classes="intro-box"):
1328
+ gr.Markdown("""
1329
+ <h2 class='intro-title'><span class='intro-icon'>📊</span>Standardizing Talent Management with AI</h2>
1330
+ <p>This tool transforms position descriptions into standardized job profiles using international classification frameworks.</p>
1331
+
1332
+ <div class='benefits-grid'>
1333
+ <div class='benefit-card'>
1334
+ <strong>🔍 Consistent Roles</strong>
1335
+ <p>Aligns with ESCO/CCOG standards automatically</p>
1336
+ </div>
1337
+ <div class='benefit-card'>
1338
+ <strong>⏱️ Time Saver</strong>
1339
+ <p>Reduces hours of manual research to minutes</p>
1340
+ </div>
1341
+ <div class='benefit-card'>
1342
+ <strong>⚖️ Reduced Bias</strong>
1343
+ <p>Data-driven skills recommendations</p>
1344
+ </div>
1345
+ <div class='benefit-card'>
1346
+ <strong>🎯 Better Hiring</strong>
1347
+ <p>Generates tailored interview questions</p>
1348
+ </div>
1349
+ </div>
1350
+
1351
+ <div style="background: #e6f2ff; padding: 12px; border-radius: 4px;">
1352
+ <strong>💡 How it works:</strong> Upload a PD PDF to get automated classification,
1353
+ skills mapping, and interview questions.
1354
+ </div>
1355
+ """)
1356
 
1357
  with gr.Row():
1358
  with gr.Column():