| import gradio as gr |
| import json |
| from ortools.sat.python import cp_model |
|
|
| def solve_task_order(requirements_text): |
| |
| requirements_text = requirements_text.lower() |
| lines = [l.strip() for l in requirements_text.strip().splitlines() if l.strip()] |
| if not lines: |
| return "No requirements specified." |
| |
| prerequisites = [] |
| all_tasks = set() |
| for req in lines: |
| if "requires" not in req: |
| return f"Error: Each line must be like 'TaskA requires TaskB'. Bad line: {req}" |
| before, _, after = req.partition(" requires ") |
| before, after = before.strip(), after.strip() |
| prerequisites.append((before, after)) |
| all_tasks |= {before, after} |
| task_list = sorted(all_tasks) |
| task_to_idx = {task: i for i, task in enumerate(task_list)} |
| n_tasks = len(task_list) |
| |
| |
| model = cp_model.CpModel() |
| order = [model.NewIntVar(0, n_tasks - 1, f'order_{task}') for task in task_list] |
| model.AddAllDifferent(order) |
| constraints_satisfied = [] |
| for before, after in prerequisites: |
| bidx = task_to_idx[before] |
| aidx = task_to_idx[after] |
| ok = model.NewBoolVar(f'prereq_{before}_after_{after}') |
| model.Add(order[aidx] < order[bidx]).OnlyEnforceIf(ok) |
| model.Add(order[aidx] >= order[bidx]).OnlyEnforceIf(ok.Not()) |
| constraints_satisfied.append(ok) |
| model.Maximize(sum(constraints_satisfied)) |
| solver = cp_model.CpSolver() |
| status = solver.Solve(model) |
| if status not in (cp_model.OPTIMAL, cp_model.FEASIBLE): |
| return "No feasible schedule could be found (cycle or conflict?)" |
| idx_to_task = {solver.Value(o): task for o, task in zip(order, task_list)} |
| schedule = [idx_to_task[i] for i in range(n_tasks)] |
| |
| display = "\n".join(f"{i+1}. {task}" for i, task in enumerate(schedule)) |
| output_json = json.dumps(schedule, indent=2) |
| satisfied = int(solver.ObjectiveValue()) |
| summary = f"Number of constraints satisfied: {satisfied} / {len(prerequisites)}" |
| return f"{display}\n\nJSON:\n{output_json}\n\n{summary}" |
|
|
| example_input = """\ |
| Sleep requires dinner |
| Sleep requires toothbrushing |
| Dinner requires prep |
| Dinner requires clean_dining_room |
| Prep requires shopping |
| Shopping requires money |
| Clean_dining_room requires cleaning_time |
| """ |
|
|
| title = "Task Order Solver (Google OR-Tools Scheduler)" |
| description = ( |
| "Enter requirements like 'A requires B' (one per line). " |
| "The scheduler will order tasks so that as many requirements as possible are satisfied. " |
| "100% satisfaction is guaranteed if there are no cycles." |
| ) |
|
|
| iface = gr.Interface( |
| fn=solve_task_order, |
| inputs=gr.Textbox(lines=12, label="Paste 'A requires B' constraints here"), |
| outputs=gr.Textbox(label="Task order (Numbered, JSON, Stats)"), |
| title=title, |
| description=description, |
| examples=[[example_input]], |
| ) |
|
|
| if __name__ == "__main__": |
| iface.launch() |
|
|