Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -249,8 +249,6 @@ for ep in range(1, EPOCHS + 1):
|
|
| 249 |
if ep % 5 == 0:
|
| 250 |
lr_now = opt.param_groups[0]["lr"]
|
| 251 |
extra = f" hor={stats_va.get('maeH', float('nan')):.3f}" if "maeH" in stats_va else ""
|
| 252 |
-
print(f"epoch {ep:03d} | lr={lr_now:.2e} | train_loss={tot_loss:.3f} | "
|
| 253 |
-
f"val MAE: imp={stats_va['maeI']:.3f} dur={stats_va['maeD']:.3f}{extra}")
|
| 254 |
|
| 255 |
# ---- early stopping on summed MAE ----
|
| 256 |
if total_val < best_val - 1e-4:
|
|
@@ -260,7 +258,6 @@ for ep in range(1, EPOCHS + 1):
|
|
| 260 |
else:
|
| 261 |
bad += 1
|
| 262 |
if bad >= patience:
|
| 263 |
-
print("early stopping.")
|
| 264 |
break
|
| 265 |
|
| 266 |
# ---- TEST with best checkpoint ----
|
|
@@ -270,10 +267,6 @@ stats_te = eval_block(
|
|
| 270 |
(H_te_all_t if H_te_all_t is not None else None),
|
| 271 |
(mH_te_t if mH_te_t is not None else None)
|
| 272 |
)
|
| 273 |
-
print("[TEST] MAE imp={maeI:.3f} (rho={rhoI:.3f}) | MAE dur={maeD:.3f} (rho={rhoD:.3f})".format(**stats_te))
|
| 274 |
-
if "maeH" in stats_te:
|
| 275 |
-
print("[TEST] MAE hor={maeH:.3f} (rho={rhoH:.3f})".format(**stats_te))
|
| 276 |
-
print("saved model -> mtl_net.pt")
|
| 277 |
|
| 278 |
# ============================================================
|
| 279 |
# 0) Setup: device, seeds, helper
|
|
@@ -324,8 +317,6 @@ i_tr = idx[:n_train]
|
|
| 324 |
i_va = idx[n_train:n_train+n_val]
|
| 325 |
i_te = idx[n_train+n_val:]
|
| 326 |
|
| 327 |
-
print(f"[Split] train={len(i_tr)} val={len(i_va)} test={len(i_te)}")
|
| 328 |
-
|
| 329 |
# ============================================================
|
| 330 |
# 2) Standardize X using ONLY the train set, then tensorize
|
| 331 |
# ============================================================
|
|
@@ -348,8 +339,6 @@ else:
|
|
| 348 |
H_tr_all_t = H_va_all_t = H_te_all_t = None
|
| 349 |
mH_tr_t = mH_va_t = mH_te_t = None
|
| 350 |
|
| 351 |
-
print(f"[Check tensors] Xt_tr={Xt_tr.shape} Xt_va={Xt_va.shape} Xt_te={Xt_te.shape}")
|
| 352 |
-
|
| 353 |
# ============================================================
|
| 354 |
# 3) Model: Multi-Task MLP (shared trunk + 3 heads)
|
| 355 |
# Slightly wider trunk; textbook uncertainty weighting (0.5 factor)
|
|
@@ -484,9 +473,6 @@ for ep in range(1, EPOCHS + 1):
|
|
| 484 |
if ep % 5 == 0:
|
| 485 |
lr_now = opt.param_groups[0]["lr"]
|
| 486 |
extraH = f" hor={stats_va.get('maeH', float('nan')):.3f}" if "maeH" in stats_va else ""
|
| 487 |
-
print(f"epoch {ep:03d} | lr={lr_now:.2e} | train_loss={tot_loss:.3f} | "
|
| 488 |
-
f"val MAE: imp={stats_va['maeI']:.3f} dur={stats_va['maeD']:.3f}{extraH} | "
|
| 489 |
-
f"rhoI={stats_va['rhoI']:.3f} rhoD={stats_va['rhoD']:.3f}")
|
| 490 |
|
| 491 |
# ---- early stopping on summed MAE ----
|
| 492 |
if total_val < best_val - 1e-4:
|
|
@@ -496,13 +482,11 @@ for ep in range(1, EPOCHS + 1):
|
|
| 496 |
else:
|
| 497 |
bad += 1
|
| 498 |
if bad >= patience:
|
| 499 |
-
print("early stopping.")
|
| 500 |
break
|
| 501 |
|
| 502 |
# ============================================================
|
| 503 |
# 6) TEST with best checkpoint + final confirmation
|
| 504 |
# ============================================================
|
| 505 |
-
print(f"[Final split check] train={Xt_tr.shape[0]} val={Xt_va.shape[0]} test={Xt_te.shape[0]}")
|
| 506 |
|
| 507 |
net.load_state_dict(torch.load("mtl_net.pt", map_location=device))
|
| 508 |
stats_te = eval_block(
|
|
@@ -510,10 +494,6 @@ stats_te = eval_block(
|
|
| 510 |
(H_te_all_t if H_te_all_t is not None else None),
|
| 511 |
(mH_te_t if mH_te_t is not None else None)
|
| 512 |
)
|
| 513 |
-
print("[TEST] MAE imp={maeI:.3f} (rho={rhoI:.3f}) | MAE dur={maeD:.3f} (rho={rhoD:.3f})".format(**stats_te))
|
| 514 |
-
if "maeH" in stats_te:
|
| 515 |
-
print("[TEST] MAE hor={maeH:.3f} (rho={rhoH:.3f})".format(**stats_te))
|
| 516 |
-
print("saved model -> mtl_net.pt")
|
| 517 |
|
| 518 |
from datetime import datetime, timedelta, timezone
|
| 519 |
import numpy as np
|
|
@@ -615,10 +595,14 @@ def priority_score(I, H_hours, due_dt, now=None, wI=0.70, wDeadline=0.25, wDur=0
|
|
| 615 |
p01 = wI*(float(I)/10.0) + wDeadline*deadline_pressure + wDur*dur_pressure
|
| 616 |
return round(1 + 9*p01, 1)
|
| 617 |
|
|
|
|
|
|
|
| 618 |
def reorder_tasks(tasks_string, user_due_iso=None):
|
|
|
|
| 619 |
tasks = [t.strip() for t in str(tasks_string).splitlines() if t.strip()]
|
| 620 |
if not tasks:
|
| 621 |
-
|
|
|
|
| 622 |
|
| 623 |
# split/normalize user dates (string or list)
|
| 624 |
if isinstance(user_due_iso, str) or user_due_iso is None:
|
|
@@ -643,34 +627,33 @@ def reorder_tasks(tasks_string, user_due_iso=None):
|
|
| 643 |
with torch.no_grad():
|
| 644 |
rI, rD, rH = net(torch.from_numpy(Xs).to(device))
|
| 645 |
I = torch.clamp(rI, 1.0, 10.0).cpu().numpy()
|
| 646 |
-
H = torch.expm1(rD).clamp(0.25, 12.0).cpu().numpy()
|
| 647 |
-
Hd = torch.expm1(rH).clamp(0.0, 30.0).cpu().numpy()
|
| 648 |
|
| 649 |
now = datetime.now(timezone.utc)
|
| 650 |
assumed_local_tz = timezone.utc
|
| 651 |
|
| 652 |
rows = []
|
| 653 |
for t, due_s, i_imp, h_hrs, h_days in zip(tasks, due_lines, I, H, Hd):
|
| 654 |
-
# parse user date
|
| 655 |
due_user_utc, had_time = parse_user_due_utc(due_s, local_tz=assumed_local_tz) if due_s else (None, False)
|
| 656 |
|
| 657 |
-
#
|
| 658 |
if due_user_utc is not None:
|
| 659 |
due_for_scores = due_user_utc
|
| 660 |
display_due_str = _fmt_utc_for_display(due_user_utc, had_time)
|
| 661 |
else:
|
| 662 |
due_for_scores = _due_from_model(now, float(h_days)) or _due_from_heuristic(now, float(i_imp), float(h_hrs))
|
| 663 |
-
# suggested is always shown as UTC date
|
| 664 |
display_due_str = _fmt_utc_for_display(due_for_scores, False)
|
| 665 |
|
| 666 |
-
|
| 667 |
-
U = float(np.clip(np.log1p(float(h_hrs)/hours_left), 0.0, 1.0))
|
| 668 |
P = priority_score(float(i_imp), float(h_hrs), due_for_scores, now=now)
|
| 669 |
|
| 670 |
rows.append({
|
| 671 |
"task": t,
|
| 672 |
"display_due": display_due_str,
|
| 673 |
"suggested_due_iso": due_for_scores.isoformat(),
|
|
|
|
| 674 |
"priority_1to10": P,
|
| 675 |
})
|
| 676 |
|
|
@@ -678,73 +661,75 @@ def reorder_tasks(tasks_string, user_due_iso=None):
|
|
| 678 |
["priority_1to10", "suggested_due_iso"], ascending=[False, True]
|
| 679 |
).reset_index(drop=True)
|
| 680 |
|
| 681 |
-
|
| 682 |
-
|
| 683 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 684 |
|
| 685 |
import re
|
| 686 |
|
| 687 |
-
import gradio # For building the interface
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 688 |
|
| 689 |
-
with
|
|
|
|
|
|
|
|
|
|
|
|
|
| 690 |
|
| 691 |
-
|
| 692 |
-
gradio.Markdown(
|
| 693 |
-
"# Automated Task Prioritizer"
|
| 694 |
-
)
|
| 695 |
-
gradio.Markdown(
|
| 696 |
-
"This app will take your to-do list and reorder it based on importance, urgency, and duration."
|
| 697 |
-
)
|
| 698 |
|
| 699 |
-
|
| 700 |
-
|
| 701 |
-
|
| 702 |
-
|
| 703 |
-
|
| 704 |
-
|
| 705 |
-
|
| 706 |
-
# Add a button to click to run the interface
|
| 707 |
-
run_btn = gradio.Button("Prioritize")
|
| 708 |
-
# Finally, add a few examples
|
| 709 |
-
|
| 710 |
-
gradio.Examples(
|
| 711 |
-
examples=[
|
| 712 |
-
["finish lab report before monday\n"
|
| 713 |
-
"email TA about grading\n"
|
| 714 |
-
"practice dance combo 20 minutes\n"
|
| 715 |
-
"apply to 3 jobs\n"
|
| 716 |
-
"review calculus problem set (10 problems)\n"
|
| 717 |
-
"call dentist to schedule appointment\n"
|
| 718 |
-
"draft 1-page cover letter\n"
|
| 719 |
-
"wash dishes\n"
|
| 720 |
-
"organize notes for history essay\n"
|
| 721 |
-
"watch tv show",
|
| 722 |
-
"10/6/25\n"
|
| 723 |
-
"10/4/25\n"
|
| 724 |
-
"10/4/25\n"
|
| 725 |
-
"\n"
|
| 726 |
-
"10/8/25\n"
|
| 727 |
-
"10/3/25\n"
|
| 728 |
-
"10/11/25\n"
|
| 729 |
-
"10/3/25\n"
|
| 730 |
-
"10/5/25\n"]
|
| 731 |
-
|
| 732 |
-
],
|
| 733 |
-
inputs=[sample_tasks, due_dates],
|
| 734 |
-
label="Example",
|
| 735 |
-
examples_per_page=1,
|
| 736 |
-
cache_examples=False,
|
| 737 |
-
)
|
| 738 |
-
|
| 739 |
-
with gradio.Tab("Prioritized List"):
|
| 740 |
-
# These are the outputs. We use both a dataframe (for tabular info) and a markdown box
|
| 741 |
-
# for info from the LLM
|
| 742 |
-
with gradio.Row():
|
| 743 |
-
priority_task = gradio.Textbox(label="Prioritized Task List", lines=10)
|
| 744 |
-
date = gradio.Textbox(label="Due Date", interactive=False, lines=10)
|
| 745 |
-
|
| 746 |
-
# Run the calculations when the button is clicked
|
| 747 |
-
run_btn.click(fn=reorder_tasks, inputs=[sample_tasks, due_dates], outputs=[priority_task, date]) # Add days_left to outputs
|
| 748 |
|
| 749 |
if __name__ == "__main__":
|
| 750 |
demo.launch(debug=True)
|
|
|
|
| 249 |
if ep % 5 == 0:
|
| 250 |
lr_now = opt.param_groups[0]["lr"]
|
| 251 |
extra = f" hor={stats_va.get('maeH', float('nan')):.3f}" if "maeH" in stats_va else ""
|
|
|
|
|
|
|
| 252 |
|
| 253 |
# ---- early stopping on summed MAE ----
|
| 254 |
if total_val < best_val - 1e-4:
|
|
|
|
| 258 |
else:
|
| 259 |
bad += 1
|
| 260 |
if bad >= patience:
|
|
|
|
| 261 |
break
|
| 262 |
|
| 263 |
# ---- TEST with best checkpoint ----
|
|
|
|
| 267 |
(H_te_all_t if H_te_all_t is not None else None),
|
| 268 |
(mH_te_t if mH_te_t is not None else None)
|
| 269 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 270 |
|
| 271 |
# ============================================================
|
| 272 |
# 0) Setup: device, seeds, helper
|
|
|
|
| 317 |
i_va = idx[n_train:n_train+n_val]
|
| 318 |
i_te = idx[n_train+n_val:]
|
| 319 |
|
|
|
|
|
|
|
| 320 |
# ============================================================
|
| 321 |
# 2) Standardize X using ONLY the train set, then tensorize
|
| 322 |
# ============================================================
|
|
|
|
| 339 |
H_tr_all_t = H_va_all_t = H_te_all_t = None
|
| 340 |
mH_tr_t = mH_va_t = mH_te_t = None
|
| 341 |
|
|
|
|
|
|
|
| 342 |
# ============================================================
|
| 343 |
# 3) Model: Multi-Task MLP (shared trunk + 3 heads)
|
| 344 |
# Slightly wider trunk; textbook uncertainty weighting (0.5 factor)
|
|
|
|
| 473 |
if ep % 5 == 0:
|
| 474 |
lr_now = opt.param_groups[0]["lr"]
|
| 475 |
extraH = f" hor={stats_va.get('maeH', float('nan')):.3f}" if "maeH" in stats_va else ""
|
|
|
|
|
|
|
|
|
|
| 476 |
|
| 477 |
# ---- early stopping on summed MAE ----
|
| 478 |
if total_val < best_val - 1e-4:
|
|
|
|
| 482 |
else:
|
| 483 |
bad += 1
|
| 484 |
if bad >= patience:
|
|
|
|
| 485 |
break
|
| 486 |
|
| 487 |
# ============================================================
|
| 488 |
# 6) TEST with best checkpoint + final confirmation
|
| 489 |
# ============================================================
|
|
|
|
| 490 |
|
| 491 |
net.load_state_dict(torch.load("mtl_net.pt", map_location=device))
|
| 492 |
stats_te = eval_block(
|
|
|
|
| 494 |
(H_te_all_t if H_te_all_t is not None else None),
|
| 495 |
(mH_te_t if mH_te_t is not None else None)
|
| 496 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 497 |
|
| 498 |
from datetime import datetime, timedelta, timezone
|
| 499 |
import numpy as np
|
|
|
|
| 595 |
p01 = wI*(float(I)/10.0) + wDeadline*deadline_pressure + wDur*dur_pressure
|
| 596 |
return round(1 + 9*p01, 1)
|
| 597 |
|
| 598 |
+
from datetime import datetime, timezone
|
| 599 |
+
|
| 600 |
def reorder_tasks(tasks_string, user_due_iso=None):
|
| 601 |
+
now = datetime.now(timezone.utc)
|
| 602 |
tasks = [t.strip() for t in str(tasks_string).splitlines() if t.strip()]
|
| 603 |
if not tasks:
|
| 604 |
+
# Return empty boxes and clear checkboxes
|
| 605 |
+
return "", "", "", gr.update(choices=[], value=[])
|
| 606 |
|
| 607 |
# split/normalize user dates (string or list)
|
| 608 |
if isinstance(user_due_iso, str) or user_due_iso is None:
|
|
|
|
| 627 |
with torch.no_grad():
|
| 628 |
rI, rD, rH = net(torch.from_numpy(Xs).to(device))
|
| 629 |
I = torch.clamp(rI, 1.0, 10.0).cpu().numpy()
|
| 630 |
+
H = torch.expm1(rD).clamp(0.25, 12.0).cpu().numpy() # duration (hrs), 0.25–12
|
| 631 |
+
Hd = torch.expm1(rH).clamp(0.0, 30.0).cpu().numpy() # horizon (days), 0–30
|
| 632 |
|
| 633 |
now = datetime.now(timezone.utc)
|
| 634 |
assumed_local_tz = timezone.utc
|
| 635 |
|
| 636 |
rows = []
|
| 637 |
for t, due_s, i_imp, h_hrs, h_days in zip(tasks, due_lines, I, H, Hd):
|
| 638 |
+
# parse user date (if provided)
|
| 639 |
due_user_utc, had_time = parse_user_due_utc(due_s, local_tz=assumed_local_tz) if due_s else (None, False)
|
| 640 |
|
| 641 |
+
# choose due_for_scores and display string
|
| 642 |
if due_user_utc is not None:
|
| 643 |
due_for_scores = due_user_utc
|
| 644 |
display_due_str = _fmt_utc_for_display(due_user_utc, had_time)
|
| 645 |
else:
|
| 646 |
due_for_scores = _due_from_model(now, float(h_days)) or _due_from_heuristic(now, float(i_imp), float(h_hrs))
|
|
|
|
| 647 |
display_due_str = _fmt_utc_for_display(due_for_scores, False)
|
| 648 |
|
| 649 |
+
# priority score
|
|
|
|
| 650 |
P = priority_score(float(i_imp), float(h_hrs), due_for_scores, now=now)
|
| 651 |
|
| 652 |
rows.append({
|
| 653 |
"task": t,
|
| 654 |
"display_due": display_due_str,
|
| 655 |
"suggested_due_iso": due_for_scores.isoformat(),
|
| 656 |
+
"duration_hrs": float(h_hrs), # keep raw number for sorting/formatting
|
| 657 |
"priority_1to10": P,
|
| 658 |
})
|
| 659 |
|
|
|
|
| 661 |
["priority_1to10", "suggested_due_iso"], ascending=[False, True]
|
| 662 |
).reset_index(drop=True)
|
| 663 |
|
| 664 |
+
choices = [f"{i+1}. {t}" for i, t in enumerate(out["task"].tolist())]
|
| 665 |
+
|
| 666 |
+
# Prepare the three text outputs
|
| 667 |
+
task_lines = "\n".join(out["task"].tolist())
|
| 668 |
+
due_lines_out = "\n".join(out["display_due"].tolist())
|
| 669 |
+
duration_lines = "\n".join(f"{d:.1f}" for d in out["duration_hrs"].tolist())
|
| 670 |
+
|
| 671 |
+
# IMPORTANT: don't wipe user selections each run
|
| 672 |
+
checkbox_update = gr.update(choices=choices)
|
| 673 |
+
|
| 674 |
+
return task_lines, due_lines_out, duration_lines, checkbox_update
|
| 675 |
|
| 676 |
import re
|
| 677 |
|
| 678 |
+
import gradio as gr # For building the interface
|
| 679 |
+
|
| 680 |
+
with gr.Blocks() as demo:
|
| 681 |
+
gr.Markdown("# Automated Task Prioritizer")
|
| 682 |
+
gr.Markdown("This app will take your to-do list and reorder it based on importance, urgency, and duration.")
|
| 683 |
+
|
| 684 |
+
with gr.Tab("Task Entry"):
|
| 685 |
+
with gr.Row():
|
| 686 |
+
sample_tasks = gr.Textbox(label="Task List", lines=10, placeholder="One task per line")
|
| 687 |
+
due_dates = gr.Textbox(label="Due Date", lines=10, placeholder="One date per line (optional)")
|
| 688 |
+
|
| 689 |
+
run_btn = gr.Button("Prioritize")
|
| 690 |
+
|
| 691 |
+
gr.Examples(
|
| 692 |
+
examples=[[
|
| 693 |
+
"finish lab report before monday\n"
|
| 694 |
+
"email TA about grading\n"
|
| 695 |
+
"practice dance combo 20 minutes\n"
|
| 696 |
+
"apply to 3 jobs\n"
|
| 697 |
+
"review calculus problem set (10 problems)\n"
|
| 698 |
+
"call dentist to schedule appointment\n"
|
| 699 |
+
"draft 1-page cover letter\n"
|
| 700 |
+
"wash dishes\n"
|
| 701 |
+
"organize notes for history essay\n"
|
| 702 |
+
"watch tv show",
|
| 703 |
+
"10/6/25\n"
|
| 704 |
+
"10/4/25\n"
|
| 705 |
+
"10/4/25\n"
|
| 706 |
+
"\n"
|
| 707 |
+
"10/8/25\n"
|
| 708 |
+
"10/3/25\n"
|
| 709 |
+
"10/11/25\n"
|
| 710 |
+
"10/3/25\n"
|
| 711 |
+
"10/5/25\n"
|
| 712 |
+
]],
|
| 713 |
+
inputs=[sample_tasks, due_dates],
|
| 714 |
+
label="Example",
|
| 715 |
+
examples_per_page=1,
|
| 716 |
+
cache_examples=False,
|
| 717 |
+
)
|
| 718 |
|
| 719 |
+
with gr.Tab("Prioritized List"):
|
| 720 |
+
with gr.Row():
|
| 721 |
+
priority_task = gr.Textbox(label="Prioritized Task List", lines=10, interactive=False)
|
| 722 |
+
date_box = gr.Textbox(label="Due Date", lines=10, interactive=False)
|
| 723 |
+
durations_box = gr.Textbox(label="Duration (hrs)", lines=10, interactive=False)
|
| 724 |
|
| 725 |
+
done_boxes = gr.CheckboxGroup(label="Mark completed tasks", interactive=True) # <-- ensure interactive
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 726 |
|
| 727 |
+
# Wire up
|
| 728 |
+
run_btn.click(
|
| 729 |
+
fn=reorder_tasks,
|
| 730 |
+
inputs=[sample_tasks, due_dates],
|
| 731 |
+
outputs=[priority_task, date_box, durations_box, done_boxes]
|
| 732 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 733 |
|
| 734 |
if __name__ == "__main__":
|
| 735 |
demo.launch(debug=True)
|