(
rows: List[Dict[str, Any]],
label_rows: List[Dict[str, Any]],
*,
top_k: int,
roles_file: Path,
input_dir: Path,
)
| 515 | |
| 516 | |
| 517 | def rerank_episodes( |
| 518 | rows: List[Dict[str, Any]], |
| 519 | label_rows: List[Dict[str, Any]], |
| 520 | *, |
| 521 | top_k: int, |
| 522 | roles_file: Path, |
| 523 | input_dir: Path, |
| 524 | ) -> Tuple[List[Dict[str, Any]], Dict[str, Any]]: |
| 525 | roles = load_roles(roles_file) |
| 526 | user_metadata = load_user_metadata(input_dir) |
| 527 | profile_map = build_profile_map(user_metadata, roles, rows) |
| 528 | label_map = build_label_map(label_rows) |
| 529 | |
| 530 | output_rows: List[Dict[str, Any]] = [] |
| 531 | grouped = group_by_episode(rows) |
| 532 | method_stats = { |
| 533 | "method_key": METHOD_KEY, |
| 534 | "method_name": METHOD_NAME, |
| 535 | "episodes": 0, |
| 536 | "top_k": top_k, |
| 537 | "uses_dynamic_feedback": False, |
| 538 | "uses_reading_reports": False, |
| 539 | "users": {}, |
| 540 | } |
| 541 | |
| 542 | for episode_id, episode_rows in sorted(grouped.items(), key=episode_sort_key): |
| 543 | if not episode_rows: |
| 544 | continue |
| 545 | user_id = str(episode_rows[0].get("user_id") or "").strip() |
| 546 | profile = profile_map.get(user_id, {"profile_text": "", "directions": [], "terms": []}) |
| 547 | |
| 548 | day_texts = [paper_text(row) for row in episode_rows] |
| 549 | idf = build_idf_from_texts([profile.get("profile_text", ""), *profile.get("terms", []), *day_texts]) |
| 550 | state = make_state(profile, idf) |
| 551 | |
| 552 | scored_rows: List[Tuple[float, str, Dict[str, Any], Dict[str, Any]]] = [] |
| 553 | for row in episode_rows: |
| 554 | identity = paper_identity(row) |
| 555 | score_payload = score_row(row, idf, state) |
| 556 | scored_rows.append((score_payload["system_score"], identity, row, score_payload)) |
| 557 | |
| 558 | scored_rows.sort( |
| 559 | key=lambda item: ( |
| 560 | -float(item[0]), |
| 561 | str(item[2].get("date") or ""), |
| 562 | str(item[2].get("title") or ""), |
| 563 | hashlib.sha1(item[1].encode("utf-8")).hexdigest(), |
| 564 | ) |
| 565 | ) |
| 566 | |
| 567 | for rank, (_, _, row, score_payload) in enumerate(scored_rows, start=1): |
| 568 | label = label_map.get(label_key(row), {}) |
| 569 | output_rows.append(clone_output_row(row, label, score_payload, rank, top_k)) |
| 570 | |
| 571 | method_stats["episodes"] += 1 |
| 572 | |
| 573 | for user_id, profile in profile_map.items(): |
| 574 | method_stats["users"][user_id] = { |
no test coverage detected