Spaces:
Running
Running
Commit Β·
0db3acb
1
Parent(s): 023fff0
cotchange
Browse files
app.py
CHANGED
|
@@ -6,7 +6,7 @@ import os
|
|
| 6 |
import re
|
| 7 |
import json
|
| 8 |
|
| 9 |
-
BASE = os.path.dirname(os.path.abspath(__file__))
|
| 10 |
STAY_POINTS = os.path.join(BASE, "data", "stay_points_sampled.csv")
|
| 11 |
POI_PATH = os.path.join(BASE, "data", "poi_sampled.csv")
|
| 12 |
DEMO_PATH = os.path.join(BASE, "data", "demographics_sampled.csv")
|
|
@@ -115,46 +115,47 @@ def build_mobility_summary(agent_sp):
|
|
| 115 |
obs_end = agent_sp["end_datetime"].max().strftime("%Y-%m-%d")
|
| 116 |
days = (agent_sp["end_datetime"].max() - agent_sp["start_datetime"].min()).days
|
| 117 |
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
f"Observation Period: {obs_start} to {obs_end} ({days} days)",
|
| 122 |
-
f"Total Stay Points: {len(agent_sp)}",
|
| 123 |
-
f"Unique Locations: {agent_sp['name'].nunique()}",
|
| 124 |
-
"",
|
| 125 |
-
"LOCATION PATTERNS",
|
| 126 |
-
"----------------",
|
| 127 |
-
]
|
| 128 |
-
for i, (name, row) in enumerate(top5.iterrows(), 1):
|
| 129 |
-
lines += [f"{i}. {name}",
|
| 130 |
-
f" Visits: {int(row['visits'])} times",
|
| 131 |
-
f" Average Duration: {int(row['avg_dur'])} minutes", ""]
|
| 132 |
|
|
|
|
| 133 |
agent_sp2 = agent_sp.copy()
|
| 134 |
agent_sp2["hour"] = agent_sp2["start_datetime"].dt.hour
|
| 135 |
def tod(h):
|
| 136 |
-
if 5 <= h < 12: return "
|
| 137 |
-
if 12 <= h < 17: return "
|
| 138 |
-
if 17 <= h < 21: return "
|
| 139 |
-
return "
|
| 140 |
agent_sp2["tod"] = agent_sp2["hour"].apply(tod)
|
| 141 |
-
|
| 142 |
agent_sp2["is_weekend"] = agent_sp2["start_datetime"].dt.dayofweek >= 5
|
| 143 |
wd_pct = int((~agent_sp2["is_weekend"]).mean() * 100)
|
| 144 |
|
| 145 |
-
lines
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
return "\n".join(lines)
|
| 151 |
|
| 152 |
|
| 153 |
-
def build_weekly_checkin(agent_sp):
|
| 154 |
-
lines = ["WEEKLY CHECK-IN SUMMARY", "======================="]
|
| 155 |
agent_sp2 = agent_sp.copy()
|
| 156 |
agent_sp2["date"] = agent_sp2["start_datetime"].dt.date
|
| 157 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
dow = grp["start_datetime"].iloc[0].strftime("%A")
|
| 159 |
label = "Weekend" if grp["start_datetime"].iloc[0].dayofweek >= 5 else "Weekday"
|
| 160 |
lines.append(f"\n--- {dow}, {date} ({label}) ---")
|
|
@@ -166,6 +167,8 @@ def build_weekly_checkin(agent_sp):
|
|
| 166 |
f"({int(row['duration_min'])} mins): "
|
| 167 |
f"{row['name']} - {row['act_label']}"
|
| 168 |
)
|
|
|
|
|
|
|
| 169 |
return "\n".join(lines)
|
| 170 |
|
| 171 |
|
|
@@ -432,18 +435,41 @@ def on_select(agent_id):
|
|
| 432 |
return map_html, raw_text, demo_text, chain_html
|
| 433 |
|
| 434 |
|
| 435 |
-
def
|
| 436 |
-
|
| 437 |
agent_id = int(agent_id)
|
| 438 |
s1, s2, s3 = get_cot(agent_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 439 |
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 447 |
|
| 448 |
|
| 449 |
# ββ UI ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -470,28 +496,43 @@ with gr.Blocks(title="HiCoTraj Demo", theme=gr.themes.Soft()) as app:
|
|
| 470 |
gr.Markdown("### Trajectory Map")
|
| 471 |
map_out = gr.HTML()
|
| 472 |
gr.Markdown("### NUMOSIM Raw Data")
|
| 473 |
-
|
| 474 |
-
|
| 475 |
-
|
| 476 |
-
|
|
|
|
|
|
|
| 477 |
|
| 478 |
with gr.Column(scale=1):
|
| 479 |
gr.Markdown("### Hierarchical Chain-of-Thought Reasoning")
|
| 480 |
-
|
| 481 |
-
|
|
|
|
| 482 |
|
| 483 |
agent_dd.change(
|
| 484 |
-
fn=
|
| 485 |
-
outputs=[map_out, raw_out, demo_label, chain_out]
|
| 486 |
)
|
| 487 |
app.load(
|
| 488 |
-
fn=
|
| 489 |
-
outputs=[map_out, raw_out, demo_label, chain_out]
|
| 490 |
)
|
| 491 |
run_btn.click(
|
| 492 |
-
fn=
|
| 493 |
-
outputs=chain_out
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 494 |
)
|
| 495 |
|
| 496 |
-
|
| 497 |
-
app.launch(share=True)
|
|
|
|
| 6 |
import re
|
| 7 |
import json
|
| 8 |
|
| 9 |
+
BASE = os.path.dirname(os.path.abspath(__file__)) if "__file__" in dir() else os.getcwd()
|
| 10 |
STAY_POINTS = os.path.join(BASE, "data", "stay_points_sampled.csv")
|
| 11 |
POI_PATH = os.path.join(BASE, "data", "poi_sampled.csv")
|
| 12 |
DEMO_PATH = os.path.join(BASE, "data", "demographics_sampled.csv")
|
|
|
|
| 115 |
obs_end = agent_sp["end_datetime"].max().strftime("%Y-%m-%d")
|
| 116 |
days = (agent_sp["end_datetime"].max() - agent_sp["start_datetime"].min()).days
|
| 117 |
|
| 118 |
+
# Top activity types
|
| 119 |
+
act_counts = agent_sp["act_label"].value_counts().head(3)
|
| 120 |
+
top_acts = ", ".join(f"{a} ({n})" for a, n in act_counts.items())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
|
| 122 |
+
# Time of day
|
| 123 |
agent_sp2 = agent_sp.copy()
|
| 124 |
agent_sp2["hour"] = agent_sp2["start_datetime"].dt.hour
|
| 125 |
def tod(h):
|
| 126 |
+
if 5 <= h < 12: return "Morning"
|
| 127 |
+
if 12 <= h < 17: return "Afternoon"
|
| 128 |
+
if 17 <= h < 21: return "Evening"
|
| 129 |
+
return "Night"
|
| 130 |
agent_sp2["tod"] = agent_sp2["hour"].apply(tod)
|
| 131 |
+
peak_tod = agent_sp2["tod"].value_counts().idxmax()
|
| 132 |
agent_sp2["is_weekend"] = agent_sp2["start_datetime"].dt.dayofweek >= 5
|
| 133 |
wd_pct = int((~agent_sp2["is_weekend"]).mean() * 100)
|
| 134 |
|
| 135 |
+
lines = [
|
| 136 |
+
f"Period: {obs_start} ~ {obs_end} ({days} days)",
|
| 137 |
+
f"Stay points: {len(agent_sp)} | Unique locations: {agent_sp['name'].nunique()}",
|
| 138 |
+
f"Weekday/Weekend: {wd_pct}% / {100-wd_pct}% | Peak time: {peak_tod}",
|
| 139 |
+
f"Top activities: {top_acts}",
|
| 140 |
+
"",
|
| 141 |
+
"Top Locations:",
|
| 142 |
+
]
|
| 143 |
+
for i, (name, row) in enumerate(top5.iterrows(), 1):
|
| 144 |
+
lines.append(f" {i}. {name} β {int(row['visits'])} visits, avg {int(row['avg_dur'])} min")
|
| 145 |
+
|
| 146 |
return "\n".join(lines)
|
| 147 |
|
| 148 |
|
| 149 |
+
def build_weekly_checkin(agent_sp, max_days=None):
|
|
|
|
| 150 |
agent_sp2 = agent_sp.copy()
|
| 151 |
agent_sp2["date"] = agent_sp2["start_datetime"].dt.date
|
| 152 |
+
all_dates = sorted(agent_sp2["date"].unique())
|
| 153 |
+
dates_to_show = all_dates[:max_days] if max_days else all_dates
|
| 154 |
+
total_days = len(all_dates)
|
| 155 |
+
|
| 156 |
+
lines = ["WEEKLY CHECK-IN SUMMARY", "======================="]
|
| 157 |
+
for date in dates_to_show:
|
| 158 |
+
grp = agent_sp2[agent_sp2["date"] == date]
|
| 159 |
dow = grp["start_datetime"].iloc[0].strftime("%A")
|
| 160 |
label = "Weekend" if grp["start_datetime"].iloc[0].dayofweek >= 5 else "Weekday"
|
| 161 |
lines.append(f"\n--- {dow}, {date} ({label}) ---")
|
|
|
|
| 167 |
f"({int(row['duration_min'])} mins): "
|
| 168 |
f"{row['name']} - {row['act_label']}"
|
| 169 |
)
|
| 170 |
+
if max_days and total_days > max_days:
|
| 171 |
+
lines.append(f"\n... ({total_days - max_days} more days)")
|
| 172 |
return "\n".join(lines)
|
| 173 |
|
| 174 |
|
|
|
|
| 435 |
return map_html, raw_text, demo_text, chain_html
|
| 436 |
|
| 437 |
|
| 438 |
+
def run_step(agent_id, step):
|
| 439 |
+
"""Reveal one stage per click. step: 0->1->2->done(-1)"""
|
| 440 |
agent_id = int(agent_id)
|
| 441 |
s1, s2, s3 = get_cot(agent_id)
|
| 442 |
+
next_step = step + 1
|
| 443 |
+
if next_step == 1:
|
| 444 |
+
html = render_chain(s1, "", "", status="running2")
|
| 445 |
+
label = "βΆ Stage 2: Behavioral Analysis"
|
| 446 |
+
return html, 1, gr.update(value=label)
|
| 447 |
+
elif next_step == 2:
|
| 448 |
+
html = render_chain(s1, s2, "", status="running3")
|
| 449 |
+
label = "βΆ Stage 3: Demographic Inference"
|
| 450 |
+
return html, 2, gr.update(value=label)
|
| 451 |
+
else:
|
| 452 |
+
html = render_chain(s1, s2, s3, status="done")
|
| 453 |
+
return html, -1, gr.update(value="βΊ Reset")
|
| 454 |
+
|
| 455 |
+
|
| 456 |
+
def handle_btn(agent_id, step):
|
| 457 |
+
if step == -1:
|
| 458 |
+
html = render_chain("", "", "", status="idle")
|
| 459 |
+
return html, 0, gr.update(value="βΆ Stage 1: Feature Extraction")
|
| 460 |
+
return run_step(agent_id, step)
|
| 461 |
|
| 462 |
+
|
| 463 |
+
def on_select_reset(agent_id):
|
| 464 |
+
agent_id_int = int(agent_id)
|
| 465 |
+
agent_sp = sp[sp["agent_id"] == agent_id_int].sort_values("start_datetime")
|
| 466 |
+
agent_demo = demo[demo["agent_id"] == agent_id_int].iloc[0]
|
| 467 |
+
map_html = build_map(agent_sp)
|
| 468 |
+
demo_text = build_demo_text(agent_demo)
|
| 469 |
+
summary = build_mobility_summary(agent_sp)
|
| 470 |
+
raw_text = build_weekly_checkin(agent_sp, max_days=2)
|
| 471 |
+
chain_html = render_chain("", "", "", status="idle")
|
| 472 |
+
return map_html, summary, raw_text, demo_text, chain_html, 0, gr.update(value="βΆ Stage 1: Feature Extraction")
|
| 473 |
|
| 474 |
|
| 475 |
# ββ UI ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 496 |
gr.Markdown("### Trajectory Map")
|
| 497 |
map_out = gr.HTML()
|
| 498 |
gr.Markdown("### NUMOSIM Raw Data")
|
| 499 |
+
with gr.Tabs():
|
| 500 |
+
with gr.Tab("Summary"):
|
| 501 |
+
summary_out = gr.Textbox(lines=10, interactive=False, label="")
|
| 502 |
+
with gr.Tab("Raw Data"):
|
| 503 |
+
raw_out = gr.Textbox(lines=10, interactive=False, label="")
|
| 504 |
+
show_all_btn = gr.Button("Show All Days", size="sm", variant="secondary")
|
| 505 |
|
| 506 |
with gr.Column(scale=1):
|
| 507 |
gr.Markdown("### Hierarchical Chain-of-Thought Reasoning")
|
| 508 |
+
step_state = gr.State(value=0)
|
| 509 |
+
run_btn = gr.Button("βΆ Stage 1: Feature Extraction", variant="primary")
|
| 510 |
+
chain_out = gr.HTML(value=render_chain("", "", "", status="idle"))
|
| 511 |
|
| 512 |
agent_dd.change(
|
| 513 |
+
fn=on_select_reset, inputs=agent_dd,
|
| 514 |
+
outputs=[map_out, summary_out, raw_out, demo_label, chain_out, step_state, run_btn]
|
| 515 |
)
|
| 516 |
app.load(
|
| 517 |
+
fn=on_select_reset, inputs=agent_dd,
|
| 518 |
+
outputs=[map_out, summary_out, raw_out, demo_label, chain_out, step_state, run_btn]
|
| 519 |
)
|
| 520 |
run_btn.click(
|
| 521 |
+
fn=handle_btn, inputs=[agent_dd, step_state],
|
| 522 |
+
outputs=[chain_out, step_state, run_btn]
|
| 523 |
+
)
|
| 524 |
+
|
| 525 |
+
def toggle_raw(agent_id, current_text):
|
| 526 |
+
agent_id_int = int(agent_id)
|
| 527 |
+
agent_sp = sp[sp["agent_id"] == agent_id_int].sort_values("start_datetime")
|
| 528 |
+
if "more days" in current_text:
|
| 529 |
+
return build_weekly_checkin(agent_sp), gr.update(value="Show Less")
|
| 530 |
+
else:
|
| 531 |
+
return build_weekly_checkin(agent_sp, max_days=2), gr.update(value="Show All Days")
|
| 532 |
+
|
| 533 |
+
show_all_btn.click(
|
| 534 |
+
fn=toggle_raw, inputs=[agent_dd, raw_out],
|
| 535 |
+
outputs=[raw_out, show_all_btn]
|
| 536 |
)
|
| 537 |
|
| 538 |
+
app.launch(show_error=True)
|
|
|