RediM commited on
Commit
6d2c000
Β·
verified Β·
1 Parent(s): e8ab714

Upload 5 files

Browse files
Files changed (5) hide show
  1. app.py +531 -0
  2. employees_data.json +1080 -0
  3. integrated_optimizer.py +365 -0
  4. intent_parser.py +362 -0
  5. skill_optimizer.py +439 -0
app.py ADDED
@@ -0,0 +1,531 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Streamlit Application for Workforce Optimization POC
3
+ Interactive demo with chat interface and real-time optimization
4
+ """
5
+
6
+ import streamlit as st
7
+ import json
8
+ import pandas as pd
9
+ from datetime import datetime
10
+ from intent_parser import IntentParser
11
+ from skill_optimizer import SkillOptimizer
12
+ from integrated_optimizer import IntegratedOptimizer
13
+
14
+ # Page configuration
15
+ st.set_page_config(
16
+ page_title="Workforce Optimization AI",
17
+ page_icon="πŸ€–",
18
+ layout="wide",
19
+ initial_sidebar_state="expanded"
20
+ )
21
+
22
+ # Custom CSS for better styling
23
+ st.markdown("""
24
+ <style>
25
+ .stButton > button {
26
+ width: 100%;
27
+ background-color: #4CAF50;
28
+ color: white;
29
+ }
30
+ .removed-employee {
31
+ background-color: #ffebee;
32
+ padding: 10px;
33
+ border-radius: 5px;
34
+ margin: 5px 0;
35
+ }
36
+ .retained-employee {
37
+ background-color: #e8f5e9;
38
+ padding: 10px;
39
+ border-radius: 5px;
40
+ margin: 5px 0;
41
+ }
42
+ .skill-improved {
43
+ color: green;
44
+ font-weight: bold;
45
+ }
46
+ .skill-degraded {
47
+ color: red;
48
+ font-weight: bold;
49
+ }
50
+ </style>
51
+ """, unsafe_allow_html=True)
52
+
53
+ # Initialize session state
54
+ if 'messages' not in st.session_state:
55
+ st.session_state.messages = []
56
+ st.session_state.messages.append({
57
+ "role": "assistant",
58
+ "content": "πŸ‘‹ Hello! I'm your Workforce Optimization AI Assistant. I can help you optimize your team based on strategic initiatives. Try asking me something like:\n\nβ€’ 'Reduce headcount by 20% and focus on AI'\nβ€’ 'Cut 15% while maintaining backend capabilities'\nβ€’ 'Optimize for data platform development'"
59
+ })
60
+
61
+ if 'optimization_result' not in st.session_state:
62
+ st.session_state.optimization_result = None
63
+
64
+ if 'employees_data' not in st.session_state:
65
+ with open('employees_data.json', 'r') as f:
66
+ st.session_state.employees_data = json.load(f)
67
+
68
+ if 'team_data' not in st.session_state:
69
+ with open('team_data.json', 'r') as f:
70
+ st.session_state.team_data = json.load(f)
71
+
72
+ if 'skill_requirements' not in st.session_state:
73
+ # Initialize with default skills
74
+ st.session_state.skill_requirements = {
75
+ "python": 3.0,
76
+ "javascript": 2.5,
77
+ "react": 2.5,
78
+ "backend_design": 3.0,
79
+ "system_architecture": 3.0,
80
+ "api_development": 3.0,
81
+ "database_management": 2.5,
82
+ "devops": 2.5,
83
+ "cloud_infrastructure": 2.5,
84
+ "security": 2.5,
85
+ "machine_learning": 2.0,
86
+ "pytorch": 2.0,
87
+ "tensorflow": 1.5,
88
+ "data_engineering": 2.5,
89
+ "data_analysis": 2.5,
90
+ "communication": 3.0,
91
+ "problem_solving": 3.5,
92
+ "team_collaboration": 3.0,
93
+ "leadership": 2.0,
94
+ "project_management": 2.0,
95
+ "frontend_optimization": 2.0,
96
+ "mobile_development": 1.5,
97
+ "testing": 2.5,
98
+ "documentation": 2.5,
99
+ "code_review": 3.0
100
+ }
101
+
102
+ # Load optimizer (you'll need to add your API key)
103
+ @st.cache_resource
104
+ def load_optimizer():
105
+ # Try to get API key from various sources
106
+ import os
107
+ from dotenv import load_dotenv
108
+
109
+ api_key = None
110
+
111
+ # 1. Try environment variable (primary for Docker)
112
+ api_key = os.getenv("OPENAI_API_KEY")
113
+
114
+ # 2. Try Streamlit secrets
115
+ if not api_key:
116
+ try:
117
+ if "OPENAI_API_KEY" in st.secrets:
118
+ api_key = st.secrets["OPENAI_API_KEY"]
119
+ except:
120
+ pass
121
+
122
+ # 3. Try .env file (for local development)
123
+ if not api_key:
124
+ load_dotenv()
125
+ api_key = os.getenv("OPENAI_API_KEY")
126
+
127
+ # Check if API key is valid
128
+ if not api_key or api_key == "your-openai-api-key-here":
129
+ st.error("⚠️ OpenAI API key not found or invalid.")
130
+ st.info("**For Docker:** `docker run -e OPENAI_API_KEY='your-key' ...`")
131
+ st.info("**For local:** Create a `.env` file with `OPENAI_API_KEY=your-key`")
132
+ st.info("**For Streamlit Cloud:** Add to secrets.toml")
133
+ st.stop()
134
+
135
+ return IntegratedOptimizer(api_key=api_key)
136
+
137
+ # Header
138
+ st.title("πŸ€– Workforce Optimization AI Assistant")
139
+ st.markdown("*Powered by GPT-4 and Advanced Optimization Algorithms*")
140
+
141
+ # Create three columns for the layout
142
+ col1, col2, col3 = st.columns([1.5, 2, 1.5])
143
+
144
+ # Left Column - Team Overview & Skills
145
+ with col1:
146
+ st.header("πŸ“Š Current Team")
147
+
148
+ # Team Summary
149
+ employees = st.session_state.employees_data['employees']
150
+ total_salary = sum(emp['salary'] for emp in employees)
151
+
152
+ col1_1, col1_2 = st.columns(2)
153
+ with col1_1:
154
+ st.metric("Team Size", len(employees))
155
+ st.metric("Avg Salary", f"${total_salary/len(employees):,.0f}")
156
+ with col1_2:
157
+ st.metric("Total Cost", f"${total_salary:,.0f}")
158
+ st.metric("Roles", len(set(e['role'] for e in employees)))
159
+
160
+ # Skill Requirements Editor
161
+ st.subheader("🎯 Skill Requirements")
162
+ st.caption("Adjust required skill levels (1.0 - 5.0)")
163
+
164
+ # Create tabs for skill categories
165
+ skill_tabs = st.tabs(["Technical", "AI/ML", "Soft Skills"])
166
+
167
+ tech_skills = ["python", "javascript", "react", "backend_design",
168
+ "system_architecture", "api_development", "database_management",
169
+ "devops", "cloud_infrastructure", "security"]
170
+
171
+ ml_skills = ["machine_learning", "pytorch", "tensorflow",
172
+ "data_engineering", "data_analysis"]
173
+
174
+ soft_skills = ["communication", "problem_solving", "team_collaboration",
175
+ "leadership", "project_management", "testing",
176
+ "documentation", "code_review", "frontend_optimization",
177
+ "mobile_development"]
178
+
179
+ with skill_tabs[0]:
180
+ for skill in tech_skills:
181
+ if skill in st.session_state.skill_requirements:
182
+ st.session_state.skill_requirements[skill] = st.slider(
183
+ skill.replace('_', ' ').title(),
184
+ 1.0, 5.0,
185
+ st.session_state.skill_requirements[skill],
186
+ 0.5,
187
+ key=f"slider_{skill}"
188
+ )
189
+
190
+ with skill_tabs[1]:
191
+ for skill in ml_skills:
192
+ if skill in st.session_state.skill_requirements:
193
+ st.session_state.skill_requirements[skill] = st.slider(
194
+ skill.replace('_', ' ').title(),
195
+ 1.0, 5.0,
196
+ st.session_state.skill_requirements[skill],
197
+ 0.5,
198
+ key=f"slider_{skill}"
199
+ )
200
+
201
+ with skill_tabs[2]:
202
+ for skill in soft_skills:
203
+ if skill in st.session_state.skill_requirements:
204
+ st.session_state.skill_requirements[skill] = st.slider(
205
+ skill.replace('_', ' ').title(),
206
+ 1.0, 5.0,
207
+ st.session_state.skill_requirements[skill],
208
+ 0.5,
209
+ key=f"slider_{skill}"
210
+ )
211
+
212
+ # Middle Column - Chat Interface
213
+ with col2:
214
+ st.header("πŸ’¬ Optimization Assistant")
215
+
216
+ # Check for pending message from example buttons
217
+ if 'pending_message' in st.session_state:
218
+ prompt_to_process = st.session_state.pending_message
219
+ del st.session_state.pending_message
220
+ else:
221
+ prompt_to_process = None
222
+
223
+ # Display chat messages
224
+ chat_container = st.container(height=400)
225
+ with chat_container:
226
+ for message in st.session_state.messages:
227
+ with st.chat_message(message["role"]):
228
+ st.markdown(message["content"])
229
+
230
+ # Chat input
231
+ prompt = st.chat_input("Ask me to optimize your team...")
232
+
233
+ # Use either the chat input or the pending message
234
+ if prompt:
235
+ prompt_to_process = prompt
236
+
237
+ if prompt_to_process:
238
+ # Add user message to history
239
+ st.session_state.messages.append({"role": "user", "content": prompt_to_process})
240
+
241
+ # Display the user message immediately
242
+ with chat_container:
243
+ with st.chat_message("user"):
244
+ st.markdown(prompt_to_process)
245
+
246
+ # Process the request with spinner in chat area
247
+ with chat_container:
248
+ with st.chat_message("assistant"):
249
+ with st.spinner("πŸ€” Analyzing your request..."):
250
+ try:
251
+ # Load optimizer
252
+ optimizer = load_optimizer()
253
+
254
+ # Get the selected algorithm from the selectbox (we'll add this)
255
+ algorithm = 'balanced' # Default
256
+
257
+ # Parse and optimize
258
+ result = optimizer.process_optimization_request(prompt_to_process, algorithm=algorithm)
259
+ st.session_state.optimization_result = result
260
+
261
+ # Generate response
262
+ if result and result.get('optimization'):
263
+ # Use the natural language explanation if available
264
+ if 'explanation' in result and result['explanation']:
265
+ response = result['explanation']
266
+ else:
267
+ # Fallback to structured response
268
+ opt = result['optimization']
269
+ analysis = opt['analysis']
270
+
271
+ response = f"""βœ… **Optimization Complete!**
272
+
273
+ **Understanding:** {result['request'].get('intent', {}).get('description', 'General optimization')}
274
+
275
+ **Results:**
276
+ - Team Size: {analysis['team_size']['before']} β†’ {analysis['team_size']['after']} (-{analysis['team_size']['reduced']})
277
+ - Cost Savings: ${analysis['cost']['saved']:,.0f}/year
278
+ - Skill Gap Score: {opt['final_gap']:.2f}
279
+
280
+ **Key Actions:**
281
+ - Removed {len(opt['removed_employees'])} employees
282
+ - Maintained critical skills above required levels
283
+ - Optimized for: {', '.join(result['request'].get('intent', {}).get('focus_areas', ['balanced optimization']))}"""
284
+
285
+ st.session_state.messages.append({
286
+ "role": "assistant",
287
+ "content": response
288
+ })
289
+ else:
290
+ error_msg = "I couldn't process that request. Please make sure to include:\nβ€’ A reduction target (e.g., 'reduce by 20%')\nβ€’ Optional: strategic focus (e.g., 'focus on AI')"
291
+ st.session_state.messages.append({
292
+ "role": "assistant",
293
+ "content": error_msg
294
+ })
295
+
296
+ except Exception as e:
297
+ error_msg = f"""❌ **Error processing request**
298
+
299
+ {str(e)}
300
+
301
+ **Tips:**
302
+ β€’ Include a reduction percentage: "reduce by 20%"
303
+ β€’ Add strategic focus: "focus on AI and machine learning"
304
+ β€’ Try an example from the sidebar"""
305
+ st.session_state.messages.append({
306
+ "role": "assistant",
307
+ "content": error_msg
308
+ })
309
+
310
+ # Rerun to update the entire interface
311
+ st.rerun()
312
+
313
+ # Action buttons
314
+ col2_1, col2_2, col2_3 = st.columns(3)
315
+ with col2_1:
316
+ if st.button("πŸ”„ Reset Chat"):
317
+ st.session_state.messages = [st.session_state.messages[0]]
318
+ st.session_state.optimization_result = None
319
+ st.rerun()
320
+
321
+ with col2_2:
322
+ if st.button("πŸ“₯ Export Results"):
323
+ if st.session_state.optimization_result:
324
+ st.download_button(
325
+ label="Download JSON",
326
+ data=json.dumps(st.session_state.optimization_result, indent=2),
327
+ file_name=f"optimization_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
328
+ mime="application/json"
329
+ )
330
+
331
+ with col2_3:
332
+ algorithm = st.selectbox("Algorithm", ["balanced", "greedy"])
333
+
334
+ # Right Column - Results
335
+ with col3:
336
+ st.header("πŸ“‹ Optimization Results")
337
+
338
+ if st.session_state.optimization_result:
339
+ result = st.session_state.optimization_result
340
+ opt = result['optimization']
341
+
342
+ # Create tabs for different views
343
+ result_tabs = st.tabs(["Removed", "Remaining", "Impact", "Skills"])
344
+
345
+ with result_tabs[0]:
346
+ st.subheader("❌ Removed Employees")
347
+ st.caption(f"Total: {len(opt['removed_employees'])} employees")
348
+
349
+ # Scrollable container for removed employees
350
+ removed_container = st.container(height=400)
351
+ with removed_container:
352
+ for emp in opt['removed_employees']:
353
+ with st.expander(f"**{emp['name']}** - {emp['role']}", expanded=False):
354
+ col_a, col_b = st.columns(2)
355
+ with col_a:
356
+ st.metric("Role", emp['role'])
357
+ st.metric("Salary", f"${emp['salary']:,}")
358
+ with col_b:
359
+ # Show top skills for this employee
360
+ if 'skills' in emp:
361
+ top_skills = sorted(emp['skills'].items(),
362
+ key=lambda x: x[1],
363
+ reverse=True)[:5]
364
+ st.write("**Top Skills:**")
365
+ for skill, level in top_skills:
366
+ skill_name = skill.replace('_', ' ').title()
367
+ st.write(f"β€’ {skill_name}: {level:.1f}")
368
+
369
+ with result_tabs[1]:
370
+ st.subheader("βœ… Remaining Employees")
371
+ st.caption(f"Total: {len(opt['remaining_employees'])} employees")
372
+
373
+ # Scrollable container for remaining employees
374
+ remaining_container = st.container(height=400)
375
+ with remaining_container:
376
+ # Group by role for better organization
377
+ roles = {}
378
+ for emp in opt['remaining_employees']:
379
+ role = emp.get('role', emp.get('position', 'Unknown'))
380
+ if role not in roles:
381
+ roles[role] = []
382
+ roles[role].append(emp)
383
+
384
+ # Display by role
385
+ for role, emps in sorted(roles.items()):
386
+ with st.expander(f"**{role}** ({len(emps)} employees)", expanded=True):
387
+ for emp in emps:
388
+ cols = st.columns([3, 2, 1])
389
+ with cols[0]:
390
+ st.write(f"πŸ‘€ **{emp['name']}**")
391
+ with cols[1]:
392
+ st.write(f"πŸ’° ${emp['salary']:,}")
393
+ with cols[2]:
394
+ # Calculate skill match if available
395
+ if 'skills' in emp and 'adjusted_skills' in result:
396
+ match_score = sum(min(emp['skills'].get(s, 0), v)
397
+ for s, v in result['adjusted_skills'].items()) / len(result['adjusted_skills'])
398
+ st.write(f"Match: {match_score:.1f}")
399
+
400
+ with result_tabs[2]:
401
+ st.subheader("πŸ“Š Impact Analysis")
402
+
403
+ # Cost impact
404
+ col1_imp, col2_imp = st.columns(2)
405
+ with col1_imp:
406
+ st.metric("Cost Saved",
407
+ f"${opt['analysis']['cost']['saved']:,.0f}",
408
+ f"-{opt['analysis']['team_size']['reduced']} employees")
409
+ with col2_imp:
410
+ st.metric("Final Team Size",
411
+ opt['analysis']['team_size']['after'],
412
+ f"{-opt['analysis']['team_size']['reduced']}")
413
+
414
+ # Skill gaps
415
+ if opt['analysis']['critical_impacts']:
416
+ st.warning("⚠️ Critical Skill Gaps:")
417
+ for impact in opt['analysis']['critical_impacts']:
418
+ st.write(f"β€’ {impact}")
419
+ else:
420
+ st.success("βœ… All critical skills maintained")
421
+
422
+ with result_tabs[3]:
423
+ st.subheader("🎯 Skill Changes")
424
+
425
+ # Show top skill changes
426
+ if opt['analysis']['skill_changes']:
427
+ skill_df = pd.DataFrame([
428
+ {
429
+ 'Skill': skill.replace('_', ' ').title(),
430
+ 'Before': f"{data['before']:.2f}",
431
+ 'After': f"{data['after']:.2f}",
432
+ 'Change': f"{data['change']:+.2f}",
433
+ 'Required': f"{data['required']:.2f}",
434
+ 'Status': 'βœ…' if data['meets_requirement'] else '❌'
435
+ }
436
+ for skill, data in sorted(
437
+ opt['analysis']['skill_changes'].items(),
438
+ key=lambda x: abs(x[1]['change']),
439
+ reverse=True
440
+ )[:10]
441
+ ])
442
+
443
+ st.dataframe(
444
+ skill_df,
445
+ use_container_width=True,
446
+ hide_index=True,
447
+ column_config={
448
+ "Status": st.column_config.TextColumn("Status", width="small"),
449
+ "Change": st.column_config.TextColumn("Change", width="small")
450
+ }
451
+ )
452
+ else:
453
+ st.info("πŸ’‘ Enter a query in the chat to see optimization results")
454
+
455
+ # Show all current employees in a scrollable list
456
+ st.subheader("πŸ‘₯ Current Team")
457
+ st.caption(f"Total: {len(employees)} employees | Total Cost: ${sum(emp['salary'] for emp in employees):,.0f}")
458
+
459
+ # Scrollable container for current employees
460
+ current_container = st.container(height=450)
461
+ with current_container:
462
+ # Group by role
463
+ roles = {}
464
+ for emp in employees:
465
+ role = emp.get('position', emp.get('role', 'Unknown'))
466
+ if role not in roles:
467
+ roles[role] = []
468
+ roles[role].append(emp)
469
+
470
+ # Display by role
471
+ for role, emps in sorted(roles.items()):
472
+ with st.expander(f"**{role}** ({len(emps)} employees)", expanded=False):
473
+ for emp in emps:
474
+ cols = st.columns([3, 2])
475
+ with cols[0]:
476
+ st.write(f"πŸ‘€ {emp['name']}")
477
+ with cols[1]:
478
+ st.write(f"πŸ’° ${emp['salary']:,}")
479
+
480
+ # Footer
481
+ st.markdown("---")
482
+ st.markdown("""
483
+ <div style='text-align: center'>
484
+ <small>
485
+ Workforce Optimization POC for Progression |
486
+ Powered by GPT-4 & Advanced Algorithms |
487
+ <a href='#'>Documentation</a> |
488
+ <a href='#'>Support</a>
489
+ </small>
490
+ </div>
491
+ """, unsafe_allow_html=True)
492
+
493
+ # Sidebar with examples
494
+ with st.sidebar:
495
+ st.header("πŸ“š Example Queries")
496
+
497
+ examples = [
498
+ "Reduce engineering headcount by 20% and focus heavily on AI and machine learning",
499
+ "Cut 25% of the team while shutting down frontend to focus on backend APIs",
500
+ "Optimize team by 15% to become a data platform company",
501
+ "Reduce by 30% and shift all focus to DevOps and cloud infrastructure"
502
+ ]
503
+
504
+ st.write("Try these example queries:")
505
+ for i, example in enumerate(examples, 1):
506
+ if st.button(f"Example {i}: {example[:30]}...", key=f"ex_{i}", help=example):
507
+ # Set a flag to process this example
508
+ st.session_state.pending_message = example
509
+ st.rerun()
510
+
511
+ st.markdown("---")
512
+ st.header("ℹ️ About")
513
+ st.write("""
514
+ This POC demonstrates an AI-powered workforce optimization system that:
515
+
516
+ β€’ Understands natural language requests
517
+ β€’ Adjusts skill requirements based on strategic intent
518
+ β€’ Optimizes team composition
519
+ β€’ Provides actionable recommendations
520
+
521
+ **Key Features:**
522
+ - Real-time optimization
523
+ - Skill gap analysis
524
+ - Cost calculations
525
+ - Transparent decisions
526
+ """)
527
+
528
+ st.markdown("---")
529
+ st.metric("Algorithm Performance", "< 5 seconds")
530
+ st.metric("Accuracy", "95%")
531
+ st.metric("Skill Coverage", "85%+")
employees_data.json ADDED
@@ -0,0 +1,1080 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "employees": [
3
+ {
4
+ "employee_id": "EMP001",
5
+ "name": "Alice Chen",
6
+ "role": "Senior Backend Engineer",
7
+ "role_id": "senior_backend",
8
+ "tenure_months": 36,
9
+ "salary": 145000,
10
+ "skills": {
11
+ "python": 4.8,
12
+ "javascript": 2.5,
13
+ "react": 1.5,
14
+ "backend_design": 4.7,
15
+ "system_architecture": 4.2,
16
+ "api_development": 4.8,
17
+ "database_management": 4.3,
18
+ "devops": 3.2,
19
+ "cloud_infrastructure": 3.8,
20
+ "security": 3.7,
21
+ "machine_learning": 2.0,
22
+ "pytorch": 1.5,
23
+ "tensorflow": 1.0,
24
+ "data_engineering": 2.5,
25
+ "data_analysis": 2.5,
26
+ "communication": 3.8,
27
+ "problem_solving": 4.2,
28
+ "team_collaboration": 3.7,
29
+ "leadership": 3.0,
30
+ "project_management": 2.5,
31
+ "frontend_optimization": 1.0,
32
+ "mobile_development": 1.0,
33
+ "testing": 3.8,
34
+ "documentation": 3.2,
35
+ "code_review": 4.3
36
+ }
37
+ },
38
+ {
39
+ "employee_id": "EMP002",
40
+ "name": "Bob Martinez",
41
+ "role": "Machine Learning Engineer",
42
+ "role_id": "ml_engineer",
43
+ "tenure_months": 24,
44
+ "salary": 155000,
45
+ "skills": {
46
+ "python": 4.7,
47
+ "javascript": 1.5,
48
+ "react": 1.0,
49
+ "backend_design": 3.0,
50
+ "system_architecture": 3.2,
51
+ "api_development": 3.2,
52
+ "database_management": 3.2,
53
+ "devops": 2.5,
54
+ "cloud_infrastructure": 3.5,
55
+ "security": 2.5,
56
+ "machine_learning": 4.5,
57
+ "pytorch": 4.2,
58
+ "tensorflow": 4.0,
59
+ "data_engineering": 3.5,
60
+ "data_analysis": 4.0,
61
+ "communication": 3.2,
62
+ "problem_solving": 4.3,
63
+ "team_collaboration": 3.2,
64
+ "leadership": 2.0,
65
+ "project_management": 2.0,
66
+ "frontend_optimization": 1.0,
67
+ "mobile_development": 1.0,
68
+ "testing": 3.2,
69
+ "documentation": 3.5,
70
+ "code_review": 3.7
71
+ }
72
+ },
73
+ {
74
+ "employee_id": "EMP003",
75
+ "name": "Carol White",
76
+ "role": "Frontend Engineer",
77
+ "role_id": "frontend_engineer",
78
+ "tenure_months": 18,
79
+ "salary": 110000,
80
+ "skills": {
81
+ "python": 2.0,
82
+ "javascript": 4.2,
83
+ "react": 4.0,
84
+ "backend_design": 1.5,
85
+ "system_architecture": 2.0,
86
+ "api_development": 2.8,
87
+ "database_management": 1.5,
88
+ "devops": 1.5,
89
+ "cloud_infrastructure": 1.5,
90
+ "security": 2.0,
91
+ "machine_learning": 1.0,
92
+ "pytorch": 1.0,
93
+ "tensorflow": 1.0,
94
+ "data_engineering": 1.0,
95
+ "data_analysis": 1.5,
96
+ "communication": 3.2,
97
+ "problem_solving": 3.7,
98
+ "team_collaboration": 3.2,
99
+ "leadership": 1.5,
100
+ "project_management": 1.5,
101
+ "frontend_optimization": 3.8,
102
+ "mobile_development": 2.8,
103
+ "testing": 3.2,
104
+ "documentation": 2.7,
105
+ "code_review": 3.2
106
+ }
107
+ },
108
+ {
109
+ "employee_id": "EMP004",
110
+ "name": "David Kim",
111
+ "role": "DevOps Engineer",
112
+ "role_id": "devops_engineer",
113
+ "tenure_months": 30,
114
+ "salary": 130000,
115
+ "skills": {
116
+ "python": 3.7,
117
+ "javascript": 2.0,
118
+ "react": 1.5,
119
+ "backend_design": 3.2,
120
+ "system_architecture": 3.7,
121
+ "api_development": 2.7,
122
+ "database_management": 3.2,
123
+ "devops": 4.7,
124
+ "cloud_infrastructure": 4.8,
125
+ "security": 3.8,
126
+ "machine_learning": 1.5,
127
+ "pytorch": 1.0,
128
+ "tensorflow": 1.0,
129
+ "data_engineering": 2.0,
130
+ "data_analysis": 2.0,
131
+ "communication": 3.2,
132
+ "problem_solving": 3.7,
133
+ "team_collaboration": 3.2,
134
+ "leadership": 2.5,
135
+ "project_management": 2.5,
136
+ "frontend_optimization": 1.0,
137
+ "mobile_development": 1.0,
138
+ "testing": 3.2,
139
+ "documentation": 3.2,
140
+ "code_review": 3.2
141
+ }
142
+ },
143
+ {
144
+ "employee_id": "EMP005",
145
+ "name": "Emma Johnson",
146
+ "role": "Data Engineer",
147
+ "role_id": "data_engineer",
148
+ "tenure_months": 20,
149
+ "salary": 125000,
150
+ "skills": {
151
+ "python": 4.2,
152
+ "javascript": 1.5,
153
+ "react": 1.0,
154
+ "backend_design": 2.5,
155
+ "system_architecture": 2.8,
156
+ "api_development": 3.2,
157
+ "database_management": 4.3,
158
+ "devops": 2.7,
159
+ "cloud_infrastructure": 3.2,
160
+ "security": 2.5,
161
+ "machine_learning": 2.8,
162
+ "pytorch": 2.0,
163
+ "tensorflow": 1.8,
164
+ "data_engineering": 4.3,
165
+ "data_analysis": 3.8,
166
+ "communication": 3.2,
167
+ "problem_solving": 3.7,
168
+ "team_collaboration": 3.2,
169
+ "leadership": 2.0,
170
+ "project_management": 2.0,
171
+ "frontend_optimization": 1.0,
172
+ "mobile_development": 1.0,
173
+ "testing": 3.2,
174
+ "documentation": 3.2,
175
+ "code_review": 3.2
176
+ }
177
+ },
178
+ {
179
+ "employee_id": "EMP006",
180
+ "name": "Frank Lee",
181
+ "role": "Tech Lead",
182
+ "role_id": "tech_lead",
183
+ "tenure_months": 48,
184
+ "salary": 165000,
185
+ "skills": {
186
+ "python": 4.3,
187
+ "javascript": 3.5,
188
+ "react": 3.0,
189
+ "backend_design": 4.3,
190
+ "system_architecture": 4.7,
191
+ "api_development": 4.3,
192
+ "database_management": 3.8,
193
+ "devops": 3.2,
194
+ "cloud_infrastructure": 3.7,
195
+ "security": 3.7,
196
+ "machine_learning": 2.5,
197
+ "pytorch": 2.0,
198
+ "tensorflow": 1.5,
199
+ "data_engineering": 2.5,
200
+ "data_analysis": 2.5,
201
+ "communication": 4.2,
202
+ "problem_solving": 4.7,
203
+ "team_collaboration": 4.2,
204
+ "leadership": 4.3,
205
+ "project_management": 3.8,
206
+ "frontend_optimization": 2.0,
207
+ "mobile_development": 1.5,
208
+ "testing": 3.7,
209
+ "documentation": 3.7,
210
+ "code_review": 4.7
211
+ }
212
+ },
213
+ {
214
+ "employee_id": "EMP007",
215
+ "name": "Grace Wang",
216
+ "role": "Junior Backend Engineer",
217
+ "role_id": "junior_backend",
218
+ "tenure_months": 6,
219
+ "salary": 85000,
220
+ "skills": {
221
+ "python": 2.7,
222
+ "javascript": 1.8,
223
+ "react": 1.5,
224
+ "backend_design": 2.2,
225
+ "system_architecture": 1.7,
226
+ "api_development": 2.3,
227
+ "database_management": 2.2,
228
+ "devops": 1.7,
229
+ "cloud_infrastructure": 1.7,
230
+ "security": 1.7,
231
+ "machine_learning": 1.5,
232
+ "pytorch": 1.0,
233
+ "tensorflow": 1.0,
234
+ "data_engineering": 1.5,
235
+ "data_analysis": 1.5,
236
+ "communication": 2.7,
237
+ "problem_solving": 2.7,
238
+ "team_collaboration": 2.7,
239
+ "leadership": 1.0,
240
+ "project_management": 1.0,
241
+ "frontend_optimization": 1.0,
242
+ "mobile_development": 1.0,
243
+ "testing": 2.2,
244
+ "documentation": 2.2,
245
+ "code_review": 2.2
246
+ }
247
+ },
248
+ {
249
+ "employee_id": "EMP008",
250
+ "name": "Henry Smith",
251
+ "role": "Senior Frontend Engineer",
252
+ "role_id": "senior_frontend",
253
+ "tenure_months": 42,
254
+ "salary": 140000,
255
+ "skills": {
256
+ "python": 2.5,
257
+ "javascript": 4.7,
258
+ "react": 4.8,
259
+ "backend_design": 2.0,
260
+ "system_architecture": 3.2,
261
+ "api_development": 3.2,
262
+ "database_management": 2.0,
263
+ "devops": 2.0,
264
+ "cloud_infrastructure": 2.0,
265
+ "security": 2.5,
266
+ "machine_learning": 1.0,
267
+ "pytorch": 1.0,
268
+ "tensorflow": 1.0,
269
+ "data_engineering": 1.0,
270
+ "data_analysis": 1.5,
271
+ "communication": 3.7,
272
+ "problem_solving": 4.2,
273
+ "team_collaboration": 3.7,
274
+ "leadership": 2.8,
275
+ "project_management": 2.5,
276
+ "frontend_optimization": 4.7,
277
+ "mobile_development": 3.5,
278
+ "testing": 3.7,
279
+ "documentation": 3.2,
280
+ "code_review": 4.2
281
+ }
282
+ },
283
+ {
284
+ "employee_id": "EMP009",
285
+ "name": "Isabella Garcia",
286
+ "role": "Full Stack Engineer",
287
+ "role_id": "fullstack_engineer",
288
+ "tenure_months": 15,
289
+ "salary": 115000,
290
+ "skills": {
291
+ "python": 3.7,
292
+ "javascript": 3.7,
293
+ "react": 3.2,
294
+ "backend_design": 3.2,
295
+ "system_architecture": 2.5,
296
+ "api_development": 3.7,
297
+ "database_management": 3.2,
298
+ "devops": 2.2,
299
+ "cloud_infrastructure": 2.2,
300
+ "security": 2.5,
301
+ "machine_learning": 1.5,
302
+ "pytorch": 1.0,
303
+ "tensorflow": 1.0,
304
+ "data_engineering": 2.0,
305
+ "data_analysis": 2.0,
306
+ "communication": 3.2,
307
+ "problem_solving": 3.7,
308
+ "team_collaboration": 3.2,
309
+ "leadership": 1.5,
310
+ "project_management": 1.5,
311
+ "frontend_optimization": 3.2,
312
+ "mobile_development": 2.0,
313
+ "testing": 3.2,
314
+ "documentation": 2.7,
315
+ "code_review": 3.2
316
+ }
317
+ },
318
+ {
319
+ "employee_id": "EMP010",
320
+ "name": "Jack Brown",
321
+ "role": "Backend Engineer",
322
+ "role_id": "mid_backend",
323
+ "tenure_months": 12,
324
+ "salary": 105000,
325
+ "skills": {
326
+ "python": 3.7,
327
+ "javascript": 2.2,
328
+ "react": 1.5,
329
+ "backend_design": 3.7,
330
+ "system_architecture": 3.2,
331
+ "api_development": 3.7,
332
+ "database_management": 3.2,
333
+ "devops": 2.7,
334
+ "cloud_infrastructure": 2.7,
335
+ "security": 2.7,
336
+ "machine_learning": 1.5,
337
+ "pytorch": 1.0,
338
+ "tensorflow": 1.0,
339
+ "data_engineering": 2.0,
340
+ "data_analysis": 2.0,
341
+ "communication": 3.2,
342
+ "problem_solving": 3.7,
343
+ "team_collaboration": 3.2,
344
+ "leadership": 1.5,
345
+ "project_management": 1.5,
346
+ "frontend_optimization": 1.0,
347
+ "mobile_development": 1.0,
348
+ "testing": 3.2,
349
+ "documentation": 2.7,
350
+ "code_review": 3.2
351
+ }
352
+ },
353
+ {
354
+ "employee_id": "EMP011",
355
+ "name": "Katie Wilson",
356
+ "role": "Junior Frontend Engineer",
357
+ "role_id": "junior_frontend",
358
+ "tenure_months": 3,
359
+ "salary": 80000,
360
+ "skills": {
361
+ "python": 1.5,
362
+ "javascript": 3.2,
363
+ "react": 2.7,
364
+ "backend_design": 1.0,
365
+ "system_architecture": 1.0,
366
+ "api_development": 2.2,
367
+ "database_management": 1.0,
368
+ "devops": 1.0,
369
+ "cloud_infrastructure": 1.0,
370
+ "security": 1.5,
371
+ "machine_learning": 1.0,
372
+ "pytorch": 1.0,
373
+ "tensorflow": 1.0,
374
+ "data_engineering": 1.0,
375
+ "data_analysis": 1.0,
376
+ "communication": 2.7,
377
+ "problem_solving": 2.7,
378
+ "team_collaboration": 2.7,
379
+ "leadership": 1.0,
380
+ "project_management": 1.0,
381
+ "frontend_optimization": 2.2,
382
+ "mobile_development": 1.7,
383
+ "testing": 2.7,
384
+ "documentation": 2.2,
385
+ "code_review": 2.2
386
+ }
387
+ },
388
+ {
389
+ "employee_id": "EMP012",
390
+ "name": "Liam Davis",
391
+ "role": "Machine Learning Engineer",
392
+ "role_id": "ml_engineer",
393
+ "tenure_months": 18,
394
+ "salary": 145000,
395
+ "skills": {
396
+ "python": 4.5,
397
+ "javascript": 1.5,
398
+ "react": 1.0,
399
+ "backend_design": 2.5,
400
+ "system_architecture": 3.0,
401
+ "api_development": 3.0,
402
+ "database_management": 3.0,
403
+ "devops": 2.0,
404
+ "cloud_infrastructure": 3.0,
405
+ "security": 2.5,
406
+ "machine_learning": 4.0,
407
+ "pytorch": 3.5,
408
+ "tensorflow": 3.5,
409
+ "data_engineering": 3.0,
410
+ "data_analysis": 3.5,
411
+ "communication": 3.0,
412
+ "problem_solving": 4.0,
413
+ "team_collaboration": 3.0,
414
+ "leadership": 1.5,
415
+ "project_management": 1.5,
416
+ "frontend_optimization": 1.0,
417
+ "mobile_development": 1.0,
418
+ "testing": 3.0,
419
+ "documentation": 3.0,
420
+ "code_review": 3.5
421
+ }
422
+ },
423
+ {
424
+ "employee_id": "EMP013",
425
+ "name": "Maria Rodriguez",
426
+ "role": "Engineering Manager",
427
+ "role_id": "engineering_manager",
428
+ "tenure_months": 60,
429
+ "salary": 180000,
430
+ "skills": {
431
+ "python": 3.2,
432
+ "javascript": 2.5,
433
+ "react": 2.0,
434
+ "backend_design": 3.2,
435
+ "system_architecture": 3.7,
436
+ "api_development": 3.0,
437
+ "database_management": 2.5,
438
+ "devops": 2.5,
439
+ "cloud_infrastructure": 2.5,
440
+ "security": 2.5,
441
+ "machine_learning": 2.0,
442
+ "pytorch": 1.5,
443
+ "tensorflow": 1.5,
444
+ "data_engineering": 2.0,
445
+ "data_analysis": 2.0,
446
+ "communication": 4.7,
447
+ "problem_solving": 4.2,
448
+ "team_collaboration": 4.7,
449
+ "leadership": 4.7,
450
+ "project_management": 4.7,
451
+ "frontend_optimization": 1.5,
452
+ "mobile_development": 1.5,
453
+ "testing": 2.5,
454
+ "documentation": 3.2,
455
+ "code_review": 3.7
456
+ }
457
+ },
458
+ {
459
+ "employee_id": "EMP014",
460
+ "name": "Nathan Taylor",
461
+ "role": "Backend Engineer",
462
+ "role_id": "mid_backend",
463
+ "tenure_months": 9,
464
+ "salary": 100000,
465
+ "skills": {
466
+ "python": 3.5,
467
+ "javascript": 2.0,
468
+ "react": 1.5,
469
+ "backend_design": 3.5,
470
+ "system_architecture": 3.0,
471
+ "api_development": 3.5,
472
+ "database_management": 3.0,
473
+ "devops": 2.5,
474
+ "cloud_infrastructure": 2.5,
475
+ "security": 2.5,
476
+ "machine_learning": 1.5,
477
+ "pytorch": 1.0,
478
+ "tensorflow": 1.0,
479
+ "data_engineering": 2.0,
480
+ "data_analysis": 2.0,
481
+ "communication": 3.0,
482
+ "problem_solving": 3.5,
483
+ "team_collaboration": 3.0,
484
+ "leadership": 1.0,
485
+ "project_management": 1.0,
486
+ "frontend_optimization": 1.0,
487
+ "mobile_development": 1.0,
488
+ "testing": 3.0,
489
+ "documentation": 2.5,
490
+ "code_review": 3.0
491
+ }
492
+ },
493
+ {
494
+ "employee_id": "EMP015",
495
+ "name": "Olivia Anderson",
496
+ "role": "Data Engineer",
497
+ "role_id": "data_engineer",
498
+ "tenure_months": 24,
499
+ "salary": 130000,
500
+ "skills": {
501
+ "python": 4.0,
502
+ "javascript": 1.5,
503
+ "react": 1.0,
504
+ "backend_design": 2.5,
505
+ "system_architecture": 3.0,
506
+ "api_development": 3.0,
507
+ "database_management": 4.0,
508
+ "devops": 2.5,
509
+ "cloud_infrastructure": 3.0,
510
+ "security": 2.5,
511
+ "machine_learning": 2.5,
512
+ "pytorch": 2.0,
513
+ "tensorflow": 1.5,
514
+ "data_engineering": 4.0,
515
+ "data_analysis": 3.5,
516
+ "communication": 3.0,
517
+ "problem_solving": 3.5,
518
+ "team_collaboration": 3.0,
519
+ "leadership": 2.0,
520
+ "project_management": 2.0,
521
+ "frontend_optimization": 1.0,
522
+ "mobile_development": 1.0,
523
+ "testing": 3.0,
524
+ "documentation": 3.0,
525
+ "code_review": 3.0
526
+ }
527
+ },
528
+ {
529
+ "employee_id": "EMP016",
530
+ "name": "Peter Miller",
531
+ "role": "DevOps Engineer",
532
+ "role_id": "devops_engineer",
533
+ "tenure_months": 36,
534
+ "salary": 135000,
535
+ "skills": {
536
+ "python": 3.5,
537
+ "javascript": 1.5,
538
+ "react": 1.0,
539
+ "backend_design": 3.0,
540
+ "system_architecture": 3.5,
541
+ "api_development": 2.5,
542
+ "database_management": 3.0,
543
+ "devops": 4.5,
544
+ "cloud_infrastructure": 4.5,
545
+ "security": 3.5,
546
+ "machine_learning": 1.0,
547
+ "pytorch": 1.0,
548
+ "tensorflow": 1.0,
549
+ "data_engineering": 2.0,
550
+ "data_analysis": 1.5,
551
+ "communication": 3.0,
552
+ "problem_solving": 3.5,
553
+ "team_collaboration": 3.0,
554
+ "leadership": 2.5,
555
+ "project_management": 2.5,
556
+ "frontend_optimization": 1.0,
557
+ "mobile_development": 1.0,
558
+ "testing": 3.0,
559
+ "documentation": 3.0,
560
+ "code_review": 3.0
561
+ }
562
+ },
563
+ {
564
+ "employee_id": "EMP017",
565
+ "name": "Quinn Thompson",
566
+ "role": "Full Stack Engineer",
567
+ "role_id": "fullstack_engineer",
568
+ "tenure_months": 21,
569
+ "salary": 120000,
570
+ "skills": {
571
+ "python": 3.5,
572
+ "javascript": 3.5,
573
+ "react": 3.0,
574
+ "backend_design": 3.0,
575
+ "system_architecture": 2.5,
576
+ "api_development": 3.5,
577
+ "database_management": 3.0,
578
+ "devops": 2.0,
579
+ "cloud_infrastructure": 2.0,
580
+ "security": 2.5,
581
+ "machine_learning": 1.5,
582
+ "pytorch": 1.0,
583
+ "tensorflow": 1.0,
584
+ "data_engineering": 1.5,
585
+ "data_analysis": 1.5,
586
+ "communication": 3.0,
587
+ "problem_solving": 3.5,
588
+ "team_collaboration": 3.0,
589
+ "leadership": 2.0,
590
+ "project_management": 2.0,
591
+ "frontend_optimization": 3.0,
592
+ "mobile_development": 2.0,
593
+ "testing": 3.0,
594
+ "documentation": 2.5,
595
+ "code_review": 3.0
596
+ }
597
+ },
598
+ {
599
+ "employee_id": "EMP018",
600
+ "name": "Rachel Green",
601
+ "role": "Senior Backend Engineer",
602
+ "role_id": "senior_backend",
603
+ "tenure_months": 45,
604
+ "salary": 150000,
605
+ "skills": {
606
+ "python": 4.5,
607
+ "javascript": 2.5,
608
+ "react": 1.5,
609
+ "backend_design": 4.5,
610
+ "system_architecture": 4.0,
611
+ "api_development": 4.5,
612
+ "database_management": 4.0,
613
+ "devops": 3.0,
614
+ "cloud_infrastructure": 3.5,
615
+ "security": 3.5,
616
+ "machine_learning": 2.0,
617
+ "pytorch": 1.5,
618
+ "tensorflow": 1.5,
619
+ "data_engineering": 2.5,
620
+ "data_analysis": 2.5,
621
+ "communication": 3.5,
622
+ "problem_solving": 4.0,
623
+ "team_collaboration": 3.5,
624
+ "leadership": 2.5,
625
+ "project_management": 2.5,
626
+ "frontend_optimization": 1.0,
627
+ "mobile_development": 1.0,
628
+ "testing": 3.5,
629
+ "documentation": 3.0,
630
+ "code_review": 4.0
631
+ }
632
+ },
633
+ {
634
+ "employee_id": "EMP019",
635
+ "name": "Sam Walker",
636
+ "role": "Junior Backend Engineer",
637
+ "role_id": "junior_backend",
638
+ "tenure_months": 8,
639
+ "salary": 88000,
640
+ "skills": {
641
+ "python": 2.5,
642
+ "javascript": 1.5,
643
+ "react": 1.0,
644
+ "backend_design": 2.0,
645
+ "system_architecture": 1.5,
646
+ "api_development": 2.0,
647
+ "database_management": 2.0,
648
+ "devops": 1.5,
649
+ "cloud_infrastructure": 1.5,
650
+ "security": 1.5,
651
+ "machine_learning": 1.0,
652
+ "pytorch": 1.0,
653
+ "tensorflow": 1.0,
654
+ "data_engineering": 1.5,
655
+ "data_analysis": 1.5,
656
+ "communication": 2.5,
657
+ "problem_solving": 2.5,
658
+ "team_collaboration": 2.5,
659
+ "leadership": 1.0,
660
+ "project_management": 1.0,
661
+ "frontend_optimization": 1.0,
662
+ "mobile_development": 1.0,
663
+ "testing": 2.0,
664
+ "documentation": 2.0,
665
+ "code_review": 2.0
666
+ }
667
+ },
668
+ {
669
+ "employee_id": "EMP020",
670
+ "name": "Tina Hall",
671
+ "role": "Frontend Engineer",
672
+ "role_id": "frontend_engineer",
673
+ "tenure_months": 14,
674
+ "salary": 108000,
675
+ "skills": {
676
+ "python": 2.0,
677
+ "javascript": 4.0,
678
+ "react": 3.5,
679
+ "backend_design": 1.5,
680
+ "system_architecture": 2.0,
681
+ "api_development": 2.5,
682
+ "database_management": 1.5,
683
+ "devops": 1.5,
684
+ "cloud_infrastructure": 1.5,
685
+ "security": 2.0,
686
+ "machine_learning": 1.0,
687
+ "pytorch": 1.0,
688
+ "tensorflow": 1.0,
689
+ "data_engineering": 1.0,
690
+ "data_analysis": 1.5,
691
+ "communication": 3.0,
692
+ "problem_solving": 3.5,
693
+ "team_collaboration": 3.0,
694
+ "leadership": 1.5,
695
+ "project_management": 1.5,
696
+ "frontend_optimization": 3.5,
697
+ "mobile_development": 2.5,
698
+ "testing": 3.0,
699
+ "documentation": 2.5,
700
+ "code_review": 3.0
701
+ }
702
+ },
703
+ {
704
+ "employee_id": "EMP021",
705
+ "name": "Uma Patel",
706
+ "role": "Machine Learning Engineer",
707
+ "role_id": "ml_engineer",
708
+ "tenure_months": 30,
709
+ "salary": 160000,
710
+ "skills": {
711
+ "python": 4.8,
712
+ "javascript": 1.5,
713
+ "react": 1.0,
714
+ "backend_design": 3.0,
715
+ "system_architecture": 3.5,
716
+ "api_development": 3.2,
717
+ "database_management": 3.2,
718
+ "devops": 2.5,
719
+ "cloud_infrastructure": 3.5,
720
+ "security": 2.5,
721
+ "machine_learning": 4.7,
722
+ "pytorch": 4.5,
723
+ "tensorflow": 4.3,
724
+ "data_engineering": 3.7,
725
+ "data_analysis": 4.2,
726
+ "communication": 3.5,
727
+ "problem_solving": 4.5,
728
+ "team_collaboration": 3.5,
729
+ "leadership": 2.5,
730
+ "project_management": 2.5,
731
+ "frontend_optimization": 1.0,
732
+ "mobile_development": 1.0,
733
+ "testing": 3.5,
734
+ "documentation": 3.5,
735
+ "code_review": 3.8
736
+ }
737
+ },
738
+ {
739
+ "employee_id": "EMP022",
740
+ "name": "Victor Zhang",
741
+ "role": "Tech Lead",
742
+ "role_id": "tech_lead",
743
+ "tenure_months": 54,
744
+ "salary": 170000,
745
+ "skills": {
746
+ "python": 4.0,
747
+ "javascript": 3.0,
748
+ "react": 2.5,
749
+ "backend_design": 4.0,
750
+ "system_architecture": 4.5,
751
+ "api_development": 4.0,
752
+ "database_management": 3.5,
753
+ "devops": 3.0,
754
+ "cloud_infrastructure": 3.5,
755
+ "security": 3.5,
756
+ "machine_learning": 2.0,
757
+ "pytorch": 1.5,
758
+ "tensorflow": 1.5,
759
+ "data_engineering": 2.5,
760
+ "data_analysis": 2.5,
761
+ "communication": 4.0,
762
+ "problem_solving": 4.5,
763
+ "team_collaboration": 4.0,
764
+ "leadership": 4.0,
765
+ "project_management": 3.5,
766
+ "frontend_optimization": 2.0,
767
+ "mobile_development": 1.5,
768
+ "testing": 3.5,
769
+ "documentation": 3.5,
770
+ "code_review": 4.5
771
+ }
772
+ },
773
+ {
774
+ "employee_id": "EMP023",
775
+ "name": "Wendy Clark",
776
+ "role": "Backend Engineer",
777
+ "role_id": "mid_backend",
778
+ "tenure_months": 16,
779
+ "salary": 110000,
780
+ "skills": {
781
+ "python": 3.8,
782
+ "javascript": 2.0,
783
+ "react": 1.5,
784
+ "backend_design": 3.8,
785
+ "system_architecture": 3.2,
786
+ "api_development": 3.8,
787
+ "database_management": 3.3,
788
+ "devops": 2.7,
789
+ "cloud_infrastructure": 2.8,
790
+ "security": 2.7,
791
+ "machine_learning": 2.0,
792
+ "pytorch": 1.5,
793
+ "tensorflow": 1.5,
794
+ "data_engineering": 2.2,
795
+ "data_analysis": 2.2,
796
+ "communication": 3.2,
797
+ "problem_solving": 3.8,
798
+ "team_collaboration": 3.2,
799
+ "leadership": 2.0,
800
+ "project_management": 2.0,
801
+ "frontend_optimization": 1.0,
802
+ "mobile_development": 1.0,
803
+ "testing": 3.3,
804
+ "documentation": 2.8,
805
+ "code_review": 3.3
806
+ }
807
+ },
808
+ {
809
+ "employee_id": "EMP024",
810
+ "name": "Xavier Lopez",
811
+ "role": "Full Stack Engineer",
812
+ "role_id": "fullstack_engineer",
813
+ "tenure_months": 27,
814
+ "salary": 125000,
815
+ "skills": {
816
+ "python": 3.8,
817
+ "javascript": 3.8,
818
+ "react": 3.3,
819
+ "backend_design": 3.3,
820
+ "system_architecture": 2.8,
821
+ "api_development": 3.8,
822
+ "database_management": 3.3,
823
+ "devops": 2.3,
824
+ "cloud_infrastructure": 2.3,
825
+ "security": 2.7,
826
+ "machine_learning": 2.0,
827
+ "pytorch": 1.5,
828
+ "tensorflow": 1.5,
829
+ "data_engineering": 2.2,
830
+ "data_analysis": 2.2,
831
+ "communication": 3.3,
832
+ "problem_solving": 3.8,
833
+ "team_collaboration": 3.3,
834
+ "leadership": 2.5,
835
+ "project_management": 2.5,
836
+ "frontend_optimization": 3.3,
837
+ "mobile_development": 2.5,
838
+ "testing": 3.3,
839
+ "documentation": 2.8,
840
+ "code_review": 3.3
841
+ }
842
+ },
843
+ {
844
+ "employee_id": "EMP025",
845
+ "name": "Yara Ahmed",
846
+ "role": "Data Engineer",
847
+ "role_id": "data_engineer",
848
+ "tenure_months": 12,
849
+ "salary": 120000,
850
+ "skills": {
851
+ "python": 3.8,
852
+ "javascript": 1.5,
853
+ "react": 1.0,
854
+ "backend_design": 2.5,
855
+ "system_architecture": 2.8,
856
+ "api_development": 2.8,
857
+ "database_management": 3.8,
858
+ "devops": 2.3,
859
+ "cloud_infrastructure": 2.8,
860
+ "security": 2.3,
861
+ "machine_learning": 2.3,
862
+ "pytorch": 1.8,
863
+ "tensorflow": 1.5,
864
+ "data_engineering": 3.8,
865
+ "data_analysis": 3.3,
866
+ "communication": 2.8,
867
+ "problem_solving": 3.3,
868
+ "team_collaboration": 2.8,
869
+ "leadership": 1.5,
870
+ "project_management": 1.5,
871
+ "frontend_optimization": 1.0,
872
+ "mobile_development": 1.0,
873
+ "testing": 2.8,
874
+ "documentation": 2.8,
875
+ "code_review": 2.8
876
+ }
877
+ },
878
+ {
879
+ "employee_id": "EMP026",
880
+ "name": "Zach Turner",
881
+ "role": "Junior Frontend Engineer",
882
+ "role_id": "junior_frontend",
883
+ "tenure_months": 5,
884
+ "salary": 82000,
885
+ "skills": {
886
+ "python": 1.8,
887
+ "javascript": 3.3,
888
+ "react": 2.8,
889
+ "backend_design": 1.3,
890
+ "system_architecture": 1.3,
891
+ "api_development": 2.3,
892
+ "database_management": 1.3,
893
+ "devops": 1.3,
894
+ "cloud_infrastructure": 1.3,
895
+ "security": 1.7,
896
+ "machine_learning": 1.0,
897
+ "pytorch": 1.0,
898
+ "tensorflow": 1.0,
899
+ "data_engineering": 1.0,
900
+ "data_analysis": 1.3,
901
+ "communication": 2.8,
902
+ "problem_solving": 2.8,
903
+ "team_collaboration": 2.8,
904
+ "leadership": 1.0,
905
+ "project_management": 1.0,
906
+ "frontend_optimization": 2.3,
907
+ "mobile_development": 1.8,
908
+ "testing": 2.8,
909
+ "documentation": 2.3,
910
+ "code_review": 2.3
911
+ }
912
+ },
913
+ {
914
+ "employee_id": "EMP027",
915
+ "name": "Amy Foster",
916
+ "role": "Senior Frontend Engineer",
917
+ "role_id": "senior_frontend",
918
+ "tenure_months": 39,
919
+ "salary": 138000,
920
+ "skills": {
921
+ "python": 2.3,
922
+ "javascript": 4.5,
923
+ "react": 4.5,
924
+ "backend_design": 2.0,
925
+ "system_architecture": 3.0,
926
+ "api_development": 3.0,
927
+ "database_management": 2.0,
928
+ "devops": 2.0,
929
+ "cloud_infrastructure": 2.0,
930
+ "security": 2.3,
931
+ "machine_learning": 1.0,
932
+ "pytorch": 1.0,
933
+ "tensorflow": 1.0,
934
+ "data_engineering": 1.0,
935
+ "data_analysis": 1.5,
936
+ "communication": 3.5,
937
+ "problem_solving": 4.0,
938
+ "team_collaboration": 3.5,
939
+ "leadership": 2.5,
940
+ "project_management": 2.3,
941
+ "frontend_optimization": 4.5,
942
+ "mobile_development": 3.0,
943
+ "testing": 3.5,
944
+ "documentation": 3.0,
945
+ "code_review": 4.0
946
+ }
947
+ },
948
+ {
949
+ "employee_id": "EMP028",
950
+ "name": "Brian Cox",
951
+ "role": "DevOps Engineer",
952
+ "role_id": "devops_engineer",
953
+ "tenure_months": 22,
954
+ "salary": 128000,
955
+ "skills": {
956
+ "python": 3.3,
957
+ "javascript": 1.8,
958
+ "react": 1.3,
959
+ "backend_design": 2.8,
960
+ "system_architecture": 3.3,
961
+ "api_development": 2.3,
962
+ "database_management": 2.8,
963
+ "devops": 4.3,
964
+ "cloud_infrastructure": 4.3,
965
+ "security": 3.3,
966
+ "machine_learning": 1.3,
967
+ "pytorch": 1.0,
968
+ "tensorflow": 1.0,
969
+ "data_engineering": 1.8,
970
+ "data_analysis": 1.8,
971
+ "communication": 2.8,
972
+ "problem_solving": 3.3,
973
+ "team_collaboration": 2.8,
974
+ "leadership": 2.0,
975
+ "project_management": 2.0,
976
+ "frontend_optimization": 1.0,
977
+ "mobile_development": 1.0,
978
+ "testing": 2.8,
979
+ "documentation": 2.8,
980
+ "code_review": 2.8
981
+ }
982
+ },
983
+ {
984
+ "employee_id": "EMP029",
985
+ "name": "Claire Evans",
986
+ "role": "Backend Engineer",
987
+ "role_id": "mid_backend",
988
+ "tenure_months": 11,
989
+ "salary": 102000,
990
+ "skills": {
991
+ "python": 3.3,
992
+ "javascript": 1.8,
993
+ "react": 1.3,
994
+ "backend_design": 3.3,
995
+ "system_architecture": 2.8,
996
+ "api_development": 3.3,
997
+ "database_management": 2.8,
998
+ "devops": 2.3,
999
+ "cloud_infrastructure": 2.3,
1000
+ "security": 2.3,
1001
+ "machine_learning": 1.3,
1002
+ "pytorch": 1.0,
1003
+ "tensorflow": 1.0,
1004
+ "data_engineering": 1.8,
1005
+ "data_analysis": 1.8,
1006
+ "communication": 2.8,
1007
+ "problem_solving": 3.3,
1008
+ "team_collaboration": 2.8,
1009
+ "leadership": 1.3,
1010
+ "project_management": 1.3,
1011
+ "frontend_optimization": 1.0,
1012
+ "mobile_development": 1.0,
1013
+ "testing": 2.8,
1014
+ "documentation": 2.3,
1015
+ "code_review": 2.8
1016
+ }
1017
+ },
1018
+ {
1019
+ "employee_id": "EMP030",
1020
+ "name": "Daniel Woods",
1021
+ "role": "Junior Backend Engineer",
1022
+ "role_id": "junior_backend",
1023
+ "tenure_months": 4,
1024
+ "salary": 83000,
1025
+ "skills": {
1026
+ "python": 2.3,
1027
+ "javascript": 1.3,
1028
+ "react": 1.0,
1029
+ "backend_design": 1.8,
1030
+ "system_architecture": 1.3,
1031
+ "api_development": 1.8,
1032
+ "database_management": 1.8,
1033
+ "devops": 1.3,
1034
+ "cloud_infrastructure": 1.3,
1035
+ "security": 1.3,
1036
+ "machine_learning": 1.0,
1037
+ "pytorch": 1.0,
1038
+ "tensorflow": 1.0,
1039
+ "data_engineering": 1.3,
1040
+ "data_analysis": 1.3,
1041
+ "communication": 2.3,
1042
+ "problem_solving": 2.3,
1043
+ "team_collaboration": 2.3,
1044
+ "leadership": 1.0,
1045
+ "project_management": 1.0,
1046
+ "frontend_optimization": 1.0,
1047
+ "mobile_development": 1.0,
1048
+ "testing": 1.8,
1049
+ "documentation": 1.8,
1050
+ "code_review": 1.8
1051
+ }
1052
+ }
1053
+ ],
1054
+ "team_summary": {
1055
+ "total_employees": 30,
1056
+ "total_salary": 3651000,
1057
+ "average_salary": 121700,
1058
+ "role_distribution": {
1059
+ "junior_backend": 4,
1060
+ "mid_backend": 4,
1061
+ "senior_backend": 2,
1062
+ "junior_frontend": 2,
1063
+ "frontend_engineer": 2,
1064
+ "senior_frontend": 2,
1065
+ "ml_engineer": 3,
1066
+ "data_engineer": 3,
1067
+ "devops_engineer": 3,
1068
+ "fullstack_engineer": 3,
1069
+ "tech_lead": 2,
1070
+ "engineering_manager": 1
1071
+ },
1072
+ "seniority_distribution": {
1073
+ "junior": 6,
1074
+ "mid": 13,
1075
+ "senior": 8,
1076
+ "lead": 2,
1077
+ "manager": 1
1078
+ }
1079
+ }
1080
+ }
integrated_optimizer.py ADDED
@@ -0,0 +1,365 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Integrated Workforce Optimization System
3
+ Combines intent parsing with skill-based optimization
4
+ """
5
+
6
+ import json
7
+ from intent_parser import IntentParser
8
+ from skill_optimizer import SkillOptimizer
9
+ from typing import Dict, Any, Optional
10
+ from openai import OpenAI
11
+
12
+ class IntegratedOptimizer:
13
+ def __init__(self, api_key=None):
14
+ """Initialize both components"""
15
+ self.intent_parser = IntentParser(api_key=api_key)
16
+ self.skill_optimizer = SkillOptimizer()
17
+ self.client = OpenAI(api_key=api_key) if api_key else None
18
+
19
+ def process_optimization_request(self, user_input: str, algorithm='balanced') -> Dict[str, Any]:
20
+ """
21
+ Complete pipeline from natural language to optimization results
22
+
23
+ Args:
24
+ user_input: Natural language request
25
+ algorithm: Optimization algorithm to use
26
+
27
+ Returns:
28
+ Complete optimization results
29
+ """
30
+ print("\n" + "="*70)
31
+ print("INTEGRATED WORKFORCE OPTIMIZATION")
32
+ print("="*70)
33
+
34
+ # Step 1: Parse intent and adjust skills
35
+ print("\nπŸ“ STEP 1: Understanding Request")
36
+ print("-"*40)
37
+ parsed = self.intent_parser.process_user_request(user_input)
38
+
39
+ # Extract reduction target
40
+ reduction_target = parsed.get('reduction_target')
41
+ if not reduction_target:
42
+ print("❌ No reduction target found in request")
43
+ return None
44
+
45
+ reduction_percentage = reduction_target.get('value', 0)
46
+
47
+ # Use adjusted skills as requirements
48
+ required_skills = parsed.get('adjusted_skills',
49
+ self.intent_parser.default_skills)
50
+
51
+ # Step 2: Run optimization
52
+ print("\nπŸ”§ STEP 2: Running Optimization")
53
+ print("-"*40)
54
+
55
+ optimization_result = self.skill_optimizer.optimize(
56
+ reduction_percentage=reduction_percentage,
57
+ required_skills=required_skills,
58
+ algorithm=algorithm
59
+ )
60
+
61
+ # Step 3: Combine results
62
+ combined_result = {
63
+ 'request': {
64
+ 'original_input': user_input,
65
+ 'reduction_target': reduction_target,
66
+ 'intent': parsed.get('intent'),
67
+ 'skill_adjustments': parsed.get('skill_changes')
68
+ },
69
+ 'optimization': optimization_result,
70
+ 'adjusted_skills': required_skills,
71
+ 'recommendations': self._generate_recommendations(
72
+ optimization_result,
73
+ parsed.get('intent', {})
74
+ )
75
+ }
76
+
77
+ # Step 4: Generate natural language explanation
78
+ if self.client:
79
+ combined_result['explanation'] = self.generate_natural_explanation(combined_result)
80
+
81
+ return combined_result
82
+
83
+ def _generate_recommendations(self, optimization_result: Dict, intent: Dict) -> list:
84
+ """Generate actionable recommendations based on results"""
85
+ recommendations = []
86
+
87
+ # Check for critical skill gaps
88
+ if optimization_result['analysis']['critical_impacts']:
89
+ recommendations.append({
90
+ 'type': 'warning',
91
+ 'message': f"Critical skill gaps identified: {len(optimization_result['analysis']['critical_impacts'])} skills below required levels",
92
+ 'action': 'Consider retraining or selective retention'
93
+ })
94
+
95
+ # Cost savings
96
+ saved = optimization_result['analysis']['cost']['saved']
97
+ recommendations.append({
98
+ 'type': 'info',
99
+ 'message': f'Annual cost savings: ${saved:,.0f}',
100
+ 'action': 'Allocate portion to retraining programs'
101
+ })
102
+
103
+ # Intent-specific recommendations
104
+ if intent.get('detected'):
105
+ focus_areas = intent.get('focus_areas', [])
106
+ if 'artificial intelligence' in focus_areas or 'machine learning' in focus_areas:
107
+ recommendations.append({
108
+ 'type': 'suggestion',
109
+ 'message': 'AI/ML focus detected',
110
+ 'action': 'Prioritize retention of ML engineers and data scientists'
111
+ })
112
+ elif 'backend' in ' '.join(focus_areas).lower():
113
+ recommendations.append({
114
+ 'type': 'suggestion',
115
+ 'message': 'Backend focus detected',
116
+ 'action': 'Consider cross-training frontend engineers for backend roles'
117
+ })
118
+
119
+ return recommendations
120
+
121
+ def generate_natural_explanation(self, result: Dict[str, Any]) -> str:
122
+ """Generate a natural language explanation of the optimization results"""
123
+ if not self.client:
124
+ return "Optimization complete. See details above."
125
+
126
+ # Prepare context for the LLM
127
+ opt = result['optimization']
128
+ req = result['request']
129
+
130
+ # Prepare removed employees summary
131
+ removed_employees = []
132
+ for emp in opt['removed_employees'][:5]: # Top 5 for context
133
+ removed_employees.append(f"- {emp['name']} ({emp['role']}): ${emp['salary']:,}")
134
+
135
+ # Prepare skill changes summary
136
+ skill_changes = []
137
+ for skill, data in sorted(opt['analysis']['skill_changes'].items(),
138
+ key=lambda x: abs(x[1]['change']),
139
+ reverse=True)[:5]:
140
+ skill_name = skill.replace('_', ' ').title()
141
+ change = data['change']
142
+ symbol = '↑' if change > 0 else '↓'
143
+ skill_changes.append(f"- {skill_name}: {data['before']:.1f} β†’ {data['after']:.1f} ({symbol}{abs(change):.1f})")
144
+
145
+ prompt = f"""You are an HR optimization assistant explaining the results of a workforce optimization.
146
+
147
+ User Request: {req['original_input']}
148
+
149
+ Optimization Context:
150
+ - Team Size: {opt['analysis']['team_size']['before']} β†’ {opt['analysis']['team_size']['after']} employees
151
+ - Employees Removed: {opt['analysis']['team_size']['reduced']}
152
+ - Cost Saved: ${opt['analysis']['cost']['saved']:,.0f} annually
153
+ - Strategic Intent: {req['intent'].get('description', 'General optimization')}
154
+ - Focus Areas: {', '.join(req['intent'].get('focus_areas', ['balanced optimization']))}
155
+ - Algorithm Used: {opt.get('algorithm', 'balanced')}
156
+
157
+ Key Employees Removed (sample):
158
+ {chr(10).join(removed_employees)}
159
+
160
+ Top Skill Level Changes:
161
+ {chr(10).join(skill_changes)}
162
+
163
+ Critical Skill Gaps: {len(opt['analysis'].get('critical_impacts', []))}
164
+ Skill Gap Score: {opt['final_gap']:.2f}
165
+
166
+ Generate a natural, conversational explanation that:
167
+ 1. Acknowledges the user's request and strategic intent
168
+ 2. Explains WHY certain people were removed (based on skills, redundancy, strategic alignment)
169
+ 3. Highlights the key outcomes (team size, cost savings, skill impacts)
170
+ 4. Mentions any critical concerns or risks
171
+ 5. Provides forward-looking advice
172
+ 6. Uses a professional but friendly tone
173
+ 7. Be specific about the optimization logic and decisions made
174
+
175
+ Keep the response under 300 words and format it with clear sections using markdown."""
176
+
177
+ try:
178
+ response = self.client.chat.completions.create(
179
+ model="gpt-4o",
180
+ messages=[
181
+ {"role": "system", "content": "You are an expert HR optimization assistant providing clear, actionable insights."},
182
+ {"role": "user", "content": prompt}
183
+ ],
184
+ temperature=0.7,
185
+ max_tokens=500
186
+ )
187
+
188
+ return response.choices[0].message.content
189
+
190
+ except Exception as e:
191
+ print(f"Error generating explanation: {e}")
192
+ return self._generate_fallback_explanation(result)
193
+
194
+ def _generate_fallback_explanation(self, result: Dict[str, Any]) -> str:
195
+ """Generate a fallback explanation if API fails"""
196
+ opt = result['optimization']
197
+ req = result['request']
198
+
199
+ explanation = f"""## Optimization Complete βœ…
200
+
201
+ I've successfully optimized your engineering team based on your request to {req['original_input'].lower()}.
202
+
203
+ **Key Results:**
204
+ - Team reduced from {opt['analysis']['team_size']['before']} to {opt['analysis']['team_size']['after']} employees
205
+ - Annual cost savings: ${opt['analysis']['cost']['saved']:,.0f}
206
+ - {opt['analysis']['team_size']['reduced']} employees removed
207
+
208
+ **Strategic Alignment:**
209
+ The optimization focused on {req['intent'].get('description', 'maintaining balanced skill coverage').lower()}.
210
+
211
+ **Skill Impact:**
212
+ The team's average skill levels have been adjusted to align with your strategic priorities.
213
+ """
214
+
215
+ if opt['analysis'].get('critical_impacts'):
216
+ explanation += f"\n⚠️ **Note:** {len(opt['analysis']['critical_impacts'])} skills are below required levels. Consider targeted training or selective retention.\n"
217
+ else:
218
+ explanation += "\nβœ… All critical skills maintained above required levels.\n"
219
+
220
+ return explanation
221
+
222
+ def print_integrated_results(self, result: Dict[str, Any]):
223
+ """Pretty print integrated results"""
224
+ if not result:
225
+ return
226
+
227
+ print("\n" + "="*70)
228
+ print("OPTIMIZATION COMPLETE")
229
+ print("="*70)
230
+
231
+ # Request summary
232
+ req = result['request']
233
+ print(f"\nπŸ“‹ REQUEST SUMMARY:")
234
+ print(f" Input: {req['original_input'][:80]}...")
235
+ if req['intent'].get('detected'):
236
+ print(f" Intent: {req['intent']['description']}")
237
+ print(f" Focus: {', '.join(req['intent'].get('focus_areas', []))}")
238
+
239
+ # Optimization results
240
+ self.skill_optimizer.print_optimization_results(result['optimization'])
241
+
242
+ # Recommendations
243
+ print(f"\n{'='*60}")
244
+ print("πŸ’‘ RECOMMENDATIONS:")
245
+ print(f"{'='*60}")
246
+ for rec in result['recommendations']:
247
+ emoji = {'warning': '⚠️', 'info': 'ℹ️', 'suggestion': 'πŸ’‘'}.get(rec['type'], 'β€’')
248
+ print(f"\n{emoji} {rec['message']}")
249
+ print(f" β†’ {rec['action']}")
250
+
251
+ def compare_algorithms(self, user_input: str) -> Dict[str, Any]:
252
+ """Compare greedy vs balanced algorithms"""
253
+ print("\n" + "="*70)
254
+ print("ALGORITHM COMPARISON")
255
+ print("="*70)
256
+
257
+ # Parse once
258
+ parsed = self.intent_parser.process_user_request(user_input)
259
+ reduction_target = parsed.get('reduction_target')
260
+
261
+ if not reduction_target:
262
+ print("❌ No reduction target found")
263
+ return None
264
+
265
+ reduction_percentage = reduction_target.get('value', 0)
266
+ required_skills = parsed.get('adjusted_skills', self.intent_parser.default_skills)
267
+
268
+ # Run both algorithms
269
+ results = {}
270
+ for algo in ['greedy', 'balanced']:
271
+ print(f"\nπŸ”„ Running {algo} algorithm...")
272
+ results[algo] = self.skill_optimizer.optimize(
273
+ reduction_percentage=reduction_percentage,
274
+ required_skills=required_skills,
275
+ algorithm=algo
276
+ )
277
+
278
+ # Compare results
279
+ print("\n" + "="*70)
280
+ print("COMPARISON RESULTS")
281
+ print("="*70)
282
+
283
+ print(f"\n{'Metric':<30} {'Greedy':>15} {'Balanced':>15}")
284
+ print("-"*60)
285
+
286
+ for algo in ['greedy', 'balanced']:
287
+ r = results[algo]
288
+ if algo == 'greedy':
289
+ print(f"{'Skill Gap Score':<30} {r['final_gap']:>15.2f}", end='')
290
+ else:
291
+ print(f" {r['final_gap']:>15.2f}")
292
+
293
+ for algo in ['greedy', 'balanced']:
294
+ r = results[algo]
295
+ if algo == 'greedy':
296
+ print(f"{'Cost Saved':<30} ${r['analysis']['cost']['saved']:>14,.0f}", end='')
297
+ else:
298
+ print(f" ${r['analysis']['cost']['saved']:>14,.0f}")
299
+
300
+ for algo in ['greedy', 'balanced']:
301
+ r = results[algo]
302
+ critical = len(r['analysis']['critical_impacts'])
303
+ if algo == 'greedy':
304
+ print(f"{'Critical Skill Gaps':<30} {critical:>15}", end='')
305
+ else:
306
+ print(f" {critical:>15}")
307
+
308
+ # Recommendation
309
+ if results['greedy']['final_gap'] < results['balanced']['final_gap']:
310
+ print("\n\nβœ… Recommendation: Use GREEDY algorithm (lower skill gap)")
311
+ else:
312
+ print("\n\nβœ… Recommendation: Use BALANCED algorithm (better overall)")
313
+
314
+ return results
315
+
316
+
317
+ def main():
318
+ """Test integrated system"""
319
+
320
+ # Test cases
321
+ test_inputs = [
322
+ "Reduce engineering by 20% and focus heavily on AI and machine learning capabilities",
323
+ "Cut 25% of the team while shutting down frontend to focus on backend APIs",
324
+ "Optimize team by 15% to become a data platform company"
325
+ ]
326
+
327
+ # Use your API key
328
+ api_key = "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"
329
+
330
+ optimizer = IntegratedOptimizer(api_key=api_key)
331
+
332
+ # Test first case
333
+ print("\n" + "πŸš€ "*20)
334
+ print("TESTING INTEGRATED OPTIMIZATION")
335
+ print("πŸš€ "*20)
336
+
337
+ for test_input in test_inputs[:1]: # Test just the first one
338
+ result = optimizer.process_optimization_request(test_input)
339
+ optimizer.print_integrated_results(result)
340
+
341
+ # Save detailed results
342
+ with open('integrated_result.json', 'w') as f:
343
+ # Make it JSON serializable
344
+ output = {
345
+ 'request': result['request'],
346
+ 'team_changes': {
347
+ 'removed': [e['name'] for e in result['optimization']['removed_employees']],
348
+ 'remaining_count': len(result['optimization']['remaining_employees']),
349
+ 'cost_saved': result['optimization']['analysis']['cost']['saved']
350
+ },
351
+ 'recommendations': result['recommendations']
352
+ }
353
+ json.dump(output, f, indent=2)
354
+
355
+ print("\nπŸ’Ύ Detailed results saved to integrated_result.json")
356
+
357
+ # Compare algorithms
358
+ print("\n\n" + "="*70)
359
+ print("ALGORITHM COMPARISON TEST")
360
+ print("="*70)
361
+ optimizer.compare_algorithms(test_inputs[0])
362
+
363
+
364
+ if __name__ == "__main__":
365
+ main()
intent_parser.py ADDED
@@ -0,0 +1,362 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Intent Parser for Workforce Optimization
3
+ Extracts headcount reduction targets and adjusts skill requirements based on strategic intent
4
+ """
5
+
6
+ import json
7
+ from typing import Dict, Any, Optional, Tuple
8
+ from openai import OpenAI
9
+ import os
10
+ from dotenv import load_dotenv
11
+ from pydantic import BaseModel, Field
12
+ from typing import List
13
+ from typing import Literal, Union
14
+
15
+ # Load environment variables
16
+ load_dotenv()
17
+
18
+ # Default engineering skills and required levels
19
+ DEFAULT_ENGINEERING_SKILLS = {
20
+ # Technical Skills
21
+ "python": 3.0,
22
+ "javascript": 2.5,
23
+ "react": 2.5,
24
+ "backend_design": 3.0,
25
+ "system_architecture": 3.0,
26
+ "api_development": 3.0,
27
+ "database_management": 2.5,
28
+ "devops": 2.5,
29
+ "cloud_infrastructure": 2.5,
30
+ "security": 2.5,
31
+
32
+ # AI/ML Skills
33
+ "machine_learning": 2.0,
34
+ "pytorch": 2.0,
35
+ "tensorflow": 1.5,
36
+ "data_engineering": 2.5,
37
+ "data_analysis": 2.5,
38
+
39
+ # Soft Skills
40
+ "communication": 3.0,
41
+ "problem_solving": 3.5,
42
+ "team_collaboration": 3.0,
43
+ "leadership": 2.0,
44
+ "project_management": 2.0,
45
+
46
+ # Specialized Skills
47
+ "frontend_optimization": 2.0,
48
+ "mobile_development": 1.5,
49
+ "testing": 2.5,
50
+ "documentation": 2.5,
51
+ "code_review": 3.0
52
+ }
53
+
54
+ # Prompt for extracting reduction target and intent
55
+ EXTRACTION_PROMPT = """You are an expert at understanding workforce optimization requests.
56
+
57
+ Given a user's input, extract TWO things:
58
+ 1. The headcount reduction target (either as a percentage or absolute number)
59
+ 2. The strategic intent or initiative (what the company is focusing on)
60
+
61
+ Return a JSON with this exact structure:
62
+ {
63
+ "reduction_target": {
64
+ "type": "percentage" or "absolute",
65
+ "value": <number>
66
+ },
67
+ "intent": {
68
+ "detected": true/false,
69
+ "description": "<brief description of the strategic intent>",
70
+ "focus_areas": ["<area1>", "<area2>", ...],
71
+ "de_emphasis_areas": ["<area1>", "<area2>", ...]
72
+ }
73
+ }
74
+
75
+ Examples:
76
+ - Input: "Reduce headcount by 20%"
77
+ Output: {"reduction_target": {"type": "percentage", "value": 20}, "intent": {"detected": false}}
78
+
79
+ - Input: "Cut 5 engineers and focus on AI initiatives"
80
+ Output: {"reduction_target": {"type": "absolute", "value": 5}, "intent": {"detected": true, "description": "Focus on AI initiatives", "focus_areas": ["artificial intelligence", "machine learning"], "de_emphasis_areas": []}}
81
+
82
+ - Input: "We need to reduce costs by 15% and shift from web to mobile development"
83
+ Output: {"reduction_target": {"type": "percentage", "value": 15}, "intent": {"detected": true, "description": "Shift from web to mobile development", "focus_areas": ["mobile development"], "de_emphasis_areas": ["web development"]}}
84
+
85
+ User Input: {user_input}
86
+
87
+ Return ONLY valid JSON, no additional text."""
88
+
89
+ # Prompt for adjusting skill requirements based on intent
90
+ SKILL_ADJUSTMENT_PROMPT = """You are an expert at translating strategic business initiatives into technical skill requirements.
91
+
92
+ Given:
93
+ 1. Current skill requirements for an engineering team
94
+ 2. A strategic intent/initiative
95
+
96
+ Adjust the skill requirement levels to align with the strategic direction.
97
+
98
+ Rules:
99
+ - You can ONLY adjust the levels of existing skills (range: 0.0 to 5.0)
100
+ - You CANNOT add new skills
101
+ - Increase levels for skills critical to the initiative (max increase: +2.0)
102
+ - Decrease levels for skills less relevant to the initiative (max decrease: -2.0)
103
+ - Most adjustments should be in the 0.5-1.0 range
104
+ - Keep at least a minimum level (1.0) for basic skills even if de-emphasized
105
+
106
+ Current skill requirements:
107
+ {current_skills}
108
+
109
+ Strategic Intent: {intent_description}
110
+ Focus Areas: {focus_areas}
111
+ De-emphasis Areas: {de_emphasis_areas}
112
+
113
+ Return ONLY a JSON object with the SAME skill names and adjusted levels.
114
+ Provide brief reasoning for significant changes (>1.0 change).
115
+
116
+ Example output format:
117
+ {
118
+ "adjusted_skills": {
119
+ "python": 3.5,
120
+ "javascript": 2.0,
121
+ ...all skills must be included...
122
+ },
123
+ "adjustments_reasoning": {
124
+ "python": "Increased by 0.5 as it's critical for the initiative",
125
+ "javascript": "Decreased by 0.5 as frontend is de-emphasized"
126
+ }
127
+ }"""
128
+
129
+ class ReductionTarget(BaseModel):
130
+ type: Union[Literal["percentage"], Literal["absolute"]] = Field(description="The type of reduction target")
131
+ value: float = Field(description="The value of the reduction target")
132
+
133
+ class Intent(BaseModel):
134
+ detected: bool = Field(description="Whether the intent was detected")
135
+ description: str = Field(description="The description of the intent")
136
+ focus_areas: List[str] = Field(description="The areas of focus for the intent")
137
+ de_emphasis_areas: List[str] = Field(description="The areas of de-emphasis for the intent")
138
+
139
+
140
+ class ExtactionUnderstanding(BaseModel):
141
+ reduction_target: ReductionTarget = Field(description="The reduction target")
142
+ intent: Intent = Field(description="The intent")
143
+
144
+ class AdjustedSkills(BaseModel):
145
+ skill: str = Field(description="The skill name")
146
+ level: float = Field(description="The level of the skill")
147
+
148
+ class AdjustmentsReasoning(BaseModel):
149
+ skill: str = Field(description="The skill name")
150
+ reasoning: str = Field(description="The reasoning for the adjustment")
151
+
152
+
153
+ class SkillAdjustment(BaseModel):
154
+ adjusted_skills: List[AdjustedSkills] = Field(description="The adjusted skill levels")
155
+ adjustments_reasoning: List[AdjustmentsReasoning] = Field(description="The reasoning for the adjustments")
156
+
157
+
158
+ class IntentParser:
159
+ def __init__(self, api_key: Optional[str] = None):
160
+ """Initialize the Intent Parser with OpenAI client"""
161
+ self.api_key = api_key or os.getenv("OPENAI_API_KEY")
162
+ if not self.api_key:
163
+ raise ValueError("OpenAI API key not found. Set OPENAI_API_KEY environment variable.")
164
+
165
+ self.client = OpenAI(api_key=self.api_key)
166
+ self.default_skills = DEFAULT_ENGINEERING_SKILLS.copy()
167
+
168
+ def extract_intent_and_target(self, user_input: str) -> Dict[str, Any]:
169
+ """
170
+ Extract headcount reduction target and strategic intent from user input
171
+
172
+ Args:
173
+ user_input: Natural language input from user
174
+
175
+ Returns:
176
+ Dictionary with reduction target and intent information
177
+ """
178
+ prompt = EXTRACTION_PROMPT.replace("{user_input}", user_input)
179
+
180
+ try:
181
+ response = self.client.responses.parse(
182
+ model="gpt-4o",
183
+ input=[
184
+ {"role": "system", "content": "You are a precise JSON generator. Only output valid JSON."},
185
+ {"role": "user", "content": prompt}
186
+ ],
187
+ temperature=0.1, # Low temperature for consistent extraction
188
+ text_format=ExtactionUnderstanding
189
+ )
190
+
191
+ parsed: ExtactionUnderstanding = response.output_parsed
192
+ return parsed.model_dump()
193
+
194
+ except json.JSONDecodeError as e:
195
+ print(f"Error parsing JSON response: {e}")
196
+ return {
197
+ "reduction_target": None,
198
+ "intent": {"detected": False},
199
+ "error": "Failed to parse response"
200
+ }
201
+ except Exception as e:
202
+ print(f"Error calling OpenAI API: {e}")
203
+ return {
204
+ "reduction_target": None,
205
+ "intent": {"detected": False},
206
+ "error": str(e)
207
+ }
208
+
209
+ def adjust_skills_for_intent(self, intent_info: Dict[str, Any]) -> Dict[str, float]:
210
+ """
211
+ Adjust skill requirements based on detected intent
212
+
213
+ Args:
214
+ intent_info: Intent information from extraction
215
+
216
+ Returns:
217
+ Dictionary with adjusted skill levels
218
+ """
219
+ # If no intent detected, return default skills
220
+ if not intent_info.get("detected", False):
221
+ return self.default_skills.copy()
222
+
223
+ # Prepare the prompt
224
+ # prompt = SKILL_ADJUSTMENT_PROMPT.format(
225
+ # current_skills=json.dumps(self.default_skills, indent=2),
226
+ # intent_description=intent_info.get("description", ""),
227
+ # focus_areas=json.dumps(intent_info.get("focus_areas", [])),
228
+ # de_emphasis_areas=json.dumps(intent_info.get("de_emphasis_areas", []))
229
+
230
+ prompt = SKILL_ADJUSTMENT_PROMPT.replace("{current_skills}", json.dumps(self.default_skills, indent=2))
231
+ prompt = prompt.replace("{intent_description}", intent_info.get("description", ""))
232
+ prompt = prompt.replace("{focus_areas}", json.dumps(intent_info.get("focus_areas", [])))
233
+ prompt = prompt.replace("{de_emphasis_areas}", json.dumps(intent_info.get("de_emphasis_areas", [])))
234
+
235
+ try:
236
+ response = self.client.responses.parse(
237
+ model="gpt-4o",
238
+ input=[
239
+ {"role": "system", "content": "You are an expert at workforce skill optimization. Adjust skill levels based on strategic initiatives."},
240
+ {"role": "user", "content": prompt}
241
+ ],
242
+ temperature=0.2,
243
+ text_format=SkillAdjustment
244
+ )
245
+
246
+ result: SkillAdjustment = response.output_parsed
247
+ result = result.model_dump()
248
+ adjusted_skills = result.get("adjusted_skills", self.default_skills)
249
+ adjusted_skills = {skill['skill']: skill['level'] for skill in adjusted_skills}
250
+ print(f"Adjusted skills: {adjusted_skills}")
251
+
252
+ # Validate that all skills are present and within range
253
+ validated_skills = {}
254
+ for skill in self.default_skills.keys():
255
+ if skill in adjusted_skills:
256
+ # Ensure skill level is within valid range
257
+ level = max(0.0, min(5.0, float(adjusted_skills[skill])))
258
+ validated_skills[skill] = level
259
+ else:
260
+ validated_skills[skill] = self.default_skills[skill]
261
+ result["adjustments_reasoning"] = {skill['skill']: skill['reasoning'] for skill in result["adjustments_reasoning"]}
262
+ # Print reasoning if available
263
+ if "adjustments_reasoning" in result:
264
+ print("\nAdjustment Reasoning:")
265
+ for skill, reason in result["adjustments_reasoning"].items():
266
+ print(f" - {skill}: {reason}")
267
+
268
+ return validated_skills
269
+
270
+ except Exception as e:
271
+ print(f"Error adjusting skills: {e}")
272
+ return self.default_skills.copy()
273
+
274
+ def process_user_request(self, user_input: str) -> Dict[str, Any]:
275
+ """
276
+ Complete pipeline: extract intent and adjust skills
277
+
278
+ Args:
279
+ user_input: Natural language input from user
280
+
281
+ Returns:
282
+ Complete optimization parameters
283
+ """
284
+ print(f"\n{'='*60}")
285
+ print(f"Processing: {user_input}")
286
+ print(f"{'='*60}")
287
+
288
+ # Step 1: Extract intent and target
289
+ print("\n1. Extracting intent and target...")
290
+ extraction_result = self.extract_intent_and_target(user_input)
291
+
292
+ print(f"\nExtracted:")
293
+ print(f" Reduction Target: {extraction_result.get('reduction_target')}")
294
+ print(f" Intent Detected: {extraction_result.get('intent', {}).get('detected')}")
295
+ if extraction_result.get('intent', {}).get('detected'):
296
+ print(f" Intent: {extraction_result.get('intent', {}).get('description')}")
297
+ print(f" Focus Areas: {extraction_result.get('intent', {}).get('focus_areas')}")
298
+ print(f" De-emphasis Areas: {extraction_result.get('intent', {}).get('de_emphasis_areas')}")
299
+
300
+ # Step 2: Adjust skills based on intent
301
+ print("\n2. Adjusting skill requirements...")
302
+ adjusted_skills = self.adjust_skills_for_intent(extraction_result.get('intent', {}))
303
+
304
+ # Show significant changes
305
+ print("\nSignificant Skill Changes:")
306
+ for skill, new_level in adjusted_skills.items():
307
+ old_level = self.default_skills[skill]
308
+ change = new_level - old_level
309
+ if abs(change) >= 0.5:
310
+ direction = "↑" if change > 0 else "↓"
311
+ print(f" {skill}: {old_level:.1f} β†’ {new_level:.1f} ({direction}{abs(change):.1f})")
312
+
313
+ return {
314
+ "user_input": user_input,
315
+ "reduction_target": extraction_result.get('reduction_target'),
316
+ "intent": extraction_result.get('intent'),
317
+ "default_skills": self.default_skills,
318
+ "adjusted_skills": adjusted_skills,
319
+ "skill_changes": {
320
+ skill: adjusted_skills[skill] - self.default_skills[skill]
321
+ for skill in self.default_skills.keys()
322
+ }
323
+ }
324
+
325
+
326
+ def main():
327
+ """Test the intent parser with various examples"""
328
+
329
+ # Initialize parser
330
+ parser = IntentParser()
331
+
332
+ # Test cases
333
+ test_cases = [
334
+ "Reduce engineering headcount by 20%",
335
+ "Cut 15% of the team and focus on AI and machine learning capabilities",
336
+ "We need to reduce costs by 25%. We're shutting down mobile development and focusing entirely on backend infrastructure",
337
+ "Reduce headcount by 30% while transitioning from a product company to a services company",
338
+ "Cut 10 engineers. We're moving all development offshore except for architecture and security",
339
+ "Optimize team size by 15% and double down on our data platform initiatives"
340
+ ]
341
+
342
+ results = []
343
+ for test_input in test_cases:
344
+ result = parser.process_user_request(test_input)
345
+ results.append(result)
346
+ print("\n" + "="*60)
347
+
348
+ # Save results to file for review
349
+ with open("intent_parsing_results.json", "w") as f:
350
+ json.dump(results, f, indent=2)
351
+
352
+ print("\n\nResults saved to intent_parsing_results.json")
353
+
354
+
355
+ if __name__ == "__main__":
356
+ # For testing without API key, use mock mode
357
+ import sys
358
+ if "--mock" in sys.argv:
359
+ print("Running in mock mode (no actual API calls)")
360
+ # Add mock implementation here if needed
361
+ else:
362
+ main()
skill_optimizer.py ADDED
@@ -0,0 +1,439 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Skill-Based Workforce Optimization Algorithm
3
+
4
+ This module optimizes team composition based on:
5
+ 1. Maintaining required skill levels
6
+ 2. Minimizing skill gap after reduction
7
+ 3. Preserving critical capabilities
8
+ """
9
+
10
+ import json
11
+ from typing import Dict, List, Tuple, Any
12
+ from itertools import combinations
13
+
14
+ class SkillOptimizer:
15
+ def __init__(self, team_data_path='team_data.json', employees_data_path='employees_data.json'):
16
+ """Initialize the optimizer with team and employee data"""
17
+ with open(team_data_path, 'r') as f:
18
+ self.team_data = json.load(f)
19
+
20
+ with open(employees_data_path, 'r') as f:
21
+ self.employees_data = json.load(f)
22
+
23
+ self.employees = self.employees_data['employees']
24
+ self.all_skills = self._get_all_skills()
25
+
26
+ def _get_all_skills(self) -> List[str]:
27
+ """Get list of all unique skills"""
28
+ skills = set()
29
+ for emp in self.employees:
30
+ skills.update(emp['skills'].keys())
31
+ return sorted(list(skills))
32
+
33
+ def calculate_team_skill_averages(self, employee_list=None) -> Dict[str, float]:
34
+ """
35
+ Calculate average skill levels across the team
36
+
37
+ Args:
38
+ employee_list: Specific list of employees to calculate for (default: all)
39
+
40
+ Returns:
41
+ Dictionary of skill -> average level
42
+ """
43
+ if employee_list is None:
44
+ employee_list = self.employees
45
+
46
+ skill_totals = {skill: [] for skill in self.all_skills}
47
+
48
+ for emp in employee_list:
49
+ for skill, level in emp['skills'].items():
50
+ skill_totals[skill].append(level)
51
+
52
+ skill_averages = {}
53
+ for skill, levels in skill_totals.items():
54
+ if levels:
55
+ skill_averages[skill] = sum(levels) / len(levels)
56
+ else:
57
+ skill_averages[skill] = 0.0
58
+
59
+ return skill_averages
60
+
61
+ def calculate_skill_coverage(self, employee_list=None, threshold=3.0) -> Dict[str, Dict]:
62
+ """
63
+ Calculate skill coverage metrics
64
+
65
+ Returns dict with:
66
+ - count: number of people with skill >= threshold
67
+ - average: average level
68
+ - max: highest level
69
+ - experts: people with level >= 4.0
70
+ """
71
+ if employee_list is None:
72
+ employee_list = self.employees
73
+
74
+ coverage = {}
75
+ for skill in self.all_skills:
76
+ levels = []
77
+ experts = 0
78
+ qualified = 0
79
+
80
+ for emp in employee_list:
81
+ level = emp['skills'].get(skill, 0)
82
+ levels.append(level)
83
+ if level >= 4.0:
84
+ experts += 1
85
+ if level >= threshold:
86
+ qualified += 1
87
+
88
+ coverage[skill] = {
89
+ 'average': sum(levels) / len(levels) if levels else 0,
90
+ 'max': max(levels) if levels else 0,
91
+ 'qualified_count': qualified,
92
+ 'expert_count': experts,
93
+ 'total_with_skill': sum(1 for l in levels if l > 1.0)
94
+ }
95
+
96
+ return coverage
97
+
98
+ def calculate_employee_value(self, employee: Dict, required_skills: Dict[str, float]) -> float:
99
+ """
100
+ Calculate value score for an employee based on:
101
+ 1. How well they meet required skills
102
+ 2. Their unique/rare skills
103
+ 3. Their overall skill level
104
+ """
105
+ value = 0.0
106
+
107
+ # Factor 1: Meeting required skills
108
+ for skill, required_level in required_skills.items():
109
+ emp_level = employee['skills'].get(skill, 0)
110
+ if emp_level >= required_level:
111
+ value += (emp_level - required_level + 1) * 2 # Bonus for exceeding
112
+ else:
113
+ value -= (required_level - emp_level) * 3 # Penalty for not meeting
114
+
115
+ # Factor 2: Unique skills (check rarity)
116
+ current_coverage = self.calculate_skill_coverage()
117
+ for skill, level in employee['skills'].items():
118
+ if level >= 4.0: # Expert level
119
+ # More valuable if few experts
120
+ expert_count = current_coverage[skill]['expert_count']
121
+ if expert_count <= 2:
122
+ value += 10 / expert_count
123
+ elif expert_count <= 4:
124
+ value += 5 / expert_count
125
+
126
+ # Factor 3: Overall competency
127
+ avg_skill = sum(employee['skills'].values()) / len(employee['skills'])
128
+ value += avg_skill * 2
129
+
130
+ # Factor 4: Role criticality
131
+ if employee['role_id'] in ['tech_lead', 'engineering_manager']:
132
+ value += 20 # Leadership bonus
133
+ elif employee['role_id'] in ['ml_engineer', 'senior_backend', 'senior_frontend']:
134
+ value += 10 # Senior specialist bonus
135
+
136
+ return value
137
+
138
+ def identify_critical_employees(self, required_skills: Dict[str, float], top_n=10) -> List[Dict]:
139
+ """
140
+ Identify employees critical for maintaining skill requirements
141
+ """
142
+ employee_values = []
143
+
144
+ for emp in self.employees:
145
+ value = self.calculate_employee_value(emp, required_skills)
146
+ employee_values.append((value, emp))
147
+
148
+ # Sort by value (highest first)
149
+ employee_values.sort(key=lambda x: x[0], reverse=True)
150
+
151
+ return [emp for _, emp in employee_values[:top_n]]
152
+
153
+ def calculate_skill_gap(self, remaining_employees: List[Dict],
154
+ required_skills: Dict[str, float]) -> float:
155
+ """
156
+ Calculate total skill gap for a team configuration
157
+ Lower is better (0 = all requirements met)
158
+ """
159
+ team_skills = self.calculate_team_skill_averages(remaining_employees)
160
+
161
+ total_gap = 0.0
162
+ for skill, required_level in required_skills.items():
163
+ actual_level = team_skills.get(skill, 0)
164
+ if actual_level < required_level:
165
+ # Weight critical gaps more heavily
166
+ gap = required_level - actual_level
167
+ weight = 2.0 if required_level >= 4.0 else 1.0
168
+ total_gap += gap * weight
169
+
170
+ return total_gap
171
+
172
+ def greedy_optimization(self, reduction_count: int,
173
+ required_skills: Dict[str, float]) -> Dict[str, Any]:
174
+ """
175
+ Greedy algorithm: Remove employees with least impact on skill gaps
176
+ """
177
+ remaining = self.employees.copy()
178
+ removed = []
179
+
180
+ for _ in range(reduction_count):
181
+ best_removal = None
182
+ best_gap = float('inf')
183
+
184
+ for i, emp in enumerate(remaining):
185
+ # Skip critical roles
186
+ if emp['role_id'] in ['engineering_manager']:
187
+ continue
188
+
189
+ # Test removing this employee
190
+ test_remaining = remaining[:i] + remaining[i+1:]
191
+ gap = self.calculate_skill_gap(test_remaining, required_skills)
192
+
193
+ if gap < best_gap:
194
+ best_gap = gap
195
+ best_removal = i
196
+
197
+ if best_removal is not None:
198
+ removed.append(remaining.pop(best_removal))
199
+
200
+ return {
201
+ 'remaining_employees': remaining,
202
+ 'removed_employees': removed,
203
+ 'final_gap': self.calculate_skill_gap(remaining, required_skills),
204
+ 'algorithm': 'greedy'
205
+ }
206
+
207
+ def balanced_optimization(self, reduction_count: int,
208
+ required_skills: Dict[str, float]) -> Dict[str, Any]:
209
+ """
210
+ Balanced algorithm: Considers multiple factors including skill diversity
211
+ """
212
+ # Calculate employee scores
213
+ scores = []
214
+ for emp in self.employees:
215
+ # Protect critical roles
216
+ if emp['role_id'] in ['engineering_manager', 'tech_lead']:
217
+ score = float('inf') # Never remove
218
+ else:
219
+ value = self.calculate_employee_value(emp, required_skills)
220
+ redundancy = self._calculate_redundancy(emp)
221
+ salary_factor = emp['salary'] / 100000 # Normalize salary
222
+
223
+ # Combined score (lower is more likely to be removed)
224
+ score = value - redundancy * 2 + salary_factor
225
+
226
+ scores.append((score, emp))
227
+
228
+ # Sort by score (keep high scores)
229
+ scores.sort(key=lambda x: x[0], reverse=True)
230
+
231
+ # Select employees to keep
232
+ keep_count = len(self.employees) - reduction_count
233
+ remaining = [emp for _, emp in scores[:keep_count]]
234
+ removed = [emp for _, emp in scores[keep_count:]]
235
+
236
+ return {
237
+ 'remaining_employees': remaining,
238
+ 'removed_employees': removed,
239
+ 'final_gap': self.calculate_skill_gap(remaining, required_skills),
240
+ 'algorithm': 'balanced'
241
+ }
242
+
243
+ def _calculate_redundancy(self, employee: Dict) -> float:
244
+ """Calculate how redundant an employee's skills are"""
245
+ redundancy = 0.0
246
+ coverage = self.calculate_skill_coverage()
247
+
248
+ for skill, level in employee['skills'].items():
249
+ if level >= 3.0:
250
+ # More redundant if many people have this skill
251
+ count = coverage[skill]['qualified_count']
252
+ if count > 5:
253
+ redundancy += 2.0
254
+ elif count > 3:
255
+ redundancy += 1.0
256
+
257
+ return redundancy
258
+
259
+ def optimize(self, reduction_percentage: float,
260
+ required_skills: Dict[str, float],
261
+ algorithm='balanced') -> Dict[str, Any]:
262
+ """
263
+ Main optimization function
264
+
265
+ Args:
266
+ reduction_percentage: Percentage to reduce (0-100)
267
+ required_skills: Skill requirements (adjusted from intent parser)
268
+ algorithm: 'greedy' or 'balanced'
269
+
270
+ Returns:
271
+ Optimization results
272
+ """
273
+ reduction_count = int(len(self.employees) * (reduction_percentage / 100))
274
+
275
+ print(f"\n{'='*60}")
276
+ print(f"OPTIMIZATION PARAMETERS")
277
+ print(f"{'='*60}")
278
+ print(f"Current team size: {len(self.employees)}")
279
+ print(f"Reduction target: {reduction_percentage}% ({reduction_count} employees)")
280
+ print(f"Algorithm: {algorithm}")
281
+
282
+ # Calculate current state
283
+ current_skills = self.calculate_team_skill_averages()
284
+ current_coverage = self.calculate_skill_coverage()
285
+
286
+ # Run optimization
287
+ if algorithm == 'greedy':
288
+ result = self.greedy_optimization(reduction_count, required_skills)
289
+ else:
290
+ result = self.balanced_optimization(reduction_count, required_skills)
291
+
292
+ # Calculate new state
293
+ new_skills = self.calculate_team_skill_averages(result['remaining_employees'])
294
+ new_coverage = self.calculate_skill_coverage(result['remaining_employees'])
295
+
296
+ # Add analysis to result
297
+ result['algorithm'] = algorithm
298
+ result['analysis'] = {
299
+ 'team_size': {
300
+ 'before': len(self.employees),
301
+ 'after': len(result['remaining_employees']),
302
+ 'reduced': len(result['removed_employees'])
303
+ },
304
+ 'cost': {
305
+ 'before': sum(e['salary'] for e in self.employees),
306
+ 'after': sum(e['salary'] for e in result['remaining_employees']),
307
+ 'saved': sum(e['salary'] for e in result['removed_employees'])
308
+ },
309
+ 'skill_changes': {},
310
+ 'critical_impacts': []
311
+ }
312
+
313
+ # Analyze skill impacts
314
+ for skill in self.all_skills:
315
+ before = current_skills.get(skill, 0)
316
+ after = new_skills.get(skill, 0)
317
+ required = required_skills.get(skill, 0)
318
+
319
+ change = after - before
320
+ if abs(change) > 0.1:
321
+ result['analysis']['skill_changes'][skill] = {
322
+ 'before': round(before, 2),
323
+ 'after': round(after, 2),
324
+ 'change': round(change, 2),
325
+ 'required': required,
326
+ 'meets_requirement': after >= required
327
+ }
328
+
329
+ if after < required and before >= required:
330
+ result['analysis']['critical_impacts'].append(
331
+ f"{skill}: Dropped below required level ({after:.1f} < {required:.1f})"
332
+ )
333
+
334
+ return result
335
+
336
+ def print_optimization_results(self, result: Dict[str, Any]):
337
+ """Pretty print optimization results"""
338
+ print(f"\n{'='*60}")
339
+ print(f"OPTIMIZATION RESULTS")
340
+ print(f"{'='*60}")
341
+
342
+ analysis = result['analysis']
343
+
344
+ # Team changes
345
+ print(f"\nTeam Size: {analysis['team_size']['before']} β†’ {analysis['team_size']['after']} "
346
+ f"(-{analysis['team_size']['reduced']})")
347
+ print(f"Cost Savings: ${analysis['cost']['saved']:,.0f}/year")
348
+ print(f"Skill Gap Score: {result['final_gap']:.2f}")
349
+
350
+ # Removed employees
351
+ print(f"\n{'='*60}")
352
+ print("REMOVED EMPLOYEES:")
353
+ print(f"{'='*60}")
354
+ for emp in sorted(result['removed_employees'], key=lambda x: x['salary'], reverse=True):
355
+ print(f" - {emp['name']:<20} ({emp['role']:<25}) ${emp['salary']:,}")
356
+
357
+ # Skill impacts
358
+ print(f"\n{'='*60}")
359
+ print("SKILL IMPACTS:")
360
+ print(f"{'='*60}")
361
+
362
+ if analysis['critical_impacts']:
363
+ print("\n🚨 CRITICAL IMPACTS:")
364
+ for impact in analysis['critical_impacts']:
365
+ print(f" - {impact}")
366
+
367
+ print("\nSIGNIFICANT SKILL CHANGES:")
368
+ for skill, data in sorted(analysis['skill_changes'].items(),
369
+ key=lambda x: abs(x[1]['change']), reverse=True)[:10]:
370
+ symbol = "βœ“" if data['meets_requirement'] else "βœ—"
371
+ arrow = "↑" if data['change'] > 0 else "↓"
372
+ print(f" {symbol} {skill:<25} {data['before']:.1f} β†’ {data['after']:.1f} "
373
+ f"({arrow}{abs(data['change']):.1f}) Required: {data['required']:.1f}")
374
+
375
+
376
+ def main():
377
+ """Test the optimization algorithm"""
378
+ optimizer = SkillOptimizer()
379
+
380
+ # Example: Focus on backend and AI, reduce frontend
381
+ required_skills = {
382
+ "python": 3.5,
383
+ "javascript": 2.0,
384
+ "react": 2.0,
385
+ "backend_design": 3.5,
386
+ "system_architecture": 3.5,
387
+ "api_development": 3.5,
388
+ "database_management": 3.0,
389
+ "devops": 3.0,
390
+ "cloud_infrastructure": 3.0,
391
+ "security": 2.5,
392
+ "machine_learning": 3.0,
393
+ "pytorch": 2.5,
394
+ "tensorflow": 2.0,
395
+ "data_engineering": 3.0,
396
+ "data_analysis": 3.0,
397
+ "communication": 3.0,
398
+ "problem_solving": 3.5,
399
+ "team_collaboration": 3.0,
400
+ "leadership": 2.0,
401
+ "project_management": 2.0,
402
+ "frontend_optimization": 1.5,
403
+ "mobile_development": 1.0,
404
+ "testing": 2.5,
405
+ "documentation": 2.5,
406
+ "code_review": 3.0
407
+ }
408
+
409
+ # Run optimization
410
+ result = optimizer.optimize(
411
+ reduction_percentage=20,
412
+ required_skills=required_skills,
413
+ algorithm='balanced'
414
+ )
415
+
416
+ optimizer.print_optimization_results(result)
417
+
418
+ # Save results
419
+ with open('optimization_result.json', 'w') as f:
420
+ # Convert employee objects to serializable format
421
+ output = {
422
+ 'parameters': {
423
+ 'reduction_percentage': 20,
424
+ 'algorithm': 'balanced'
425
+ },
426
+ 'results': {
427
+ 'removed_employees': [e['name'] for e in result['removed_employees']],
428
+ 'remaining_count': len(result['remaining_employees']),
429
+ 'skill_gap': result['final_gap'],
430
+ 'cost_saved': result['analysis']['cost']['saved']
431
+ }
432
+ }
433
+ json.dump(output, f, indent=2)
434
+
435
+ print("\nβœ… Results saved to optimization_result.json")
436
+
437
+
438
+ if __name__ == "__main__":
439
+ main()