CP-SAT (OR-Tools) shift scheduling for a weekly grid. The FastAPI service accepts a 3D schedule matrix and a demand matrix, then returns optimized schedules in the same shape.
python3 -m pip install -r requirements.txt
uvicorn shift_optimizer.api:app --reloadschedule:[employees][days][slots]with 0/1 entries (slots default to 30-minute increments viaslot_minutes).demandinputs (choose one):demand:[days][slots]integer headcount.demand_percent_by_hour:[24]percentages summing to ~100; scaled so the max hour equalsdemand_peak; expanded to slots per hour.demand_percent_by_day_hour:[days][24]percentages per day/hour; scaled so each day’s max hour equalsdemand_peak; expanded to slots per hour.
- Optional knobs:
demand_peak(peak headcount for percentage inputs),target_hours_per_employee(hours, applies to all employees),target_workdays_per_employee,min_rest_hours,max_shift_blocks_per_day,coverage_mode(soft|min|exact),allowed_shift_lengths,allowed_shift_starts,prefer_current_schedule_weight,hours_mismatch_weight,workdays_mismatch_weight,rest_violation_weight,understaff_weight,overstaff_weight,wrap_week,k.
Example payload:
{
"schedule": [
[
[0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 1, 1],
[1, 1, 0, 0, 0, 0]
]
],
"demand": [
[1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1]
],
"slot_minutes": 30,
"coverage_mode": "soft",
"k": 1
}{
"slot_minutes": 30,
"solutions": [
{
"objective_value": 0.0,
"schedule": [[[...]]],
"coverage": [[...]],
"understaff": [[...]],
"overstaff": [[...]],
"employee_hours_slots": {"employee_0": 4},
"employee_hours_hours": {"employee_0": 2.0}
}
]
}The CLI solver (python -m shift_optimizer solve --config ...) remains available for JSON configs; HTML/CSV reporting has been removed.