排序并分类论文 Args: papers: 论文列表 profile: 用户画像 weights: 权重配置 Returns: 带分类的论文列表
(
papers: List[Dict],
profile: Dict,
weights: Dict,
progress_callback: Optional[Callable[[Dict[str, Any]], None]] = None,
)
| 1406 | |
| 1407 | |
| 1408 | def sort_and_categorize( |
| 1409 | papers: List[Dict], |
| 1410 | profile: Dict, |
| 1411 | weights: Dict, |
| 1412 | progress_callback: Optional[Callable[[Dict[str, Any]], None]] = None, |
| 1413 | ) -> List[PaperWithScore]: |
| 1414 | """ |
| 1415 | 排序并分类论文 |
| 1416 | |
| 1417 | Args: |
| 1418 | papers: 论文列表 |
| 1419 | profile: 用户画像 |
| 1420 | weights: 权重配置 |
| 1421 | |
| 1422 | Returns: |
| 1423 | 带分类的论文列表 |
| 1424 | """ |
| 1425 | def emit(event: Dict[str, Any]) -> None: |
| 1426 | if not callable(progress_callback): |
| 1427 | return |
| 1428 | try: |
| 1429 | progress_callback(event) |
| 1430 | except Exception as exc: |
| 1431 | print(f" Progress callback error: {exc}") |
| 1432 | |
| 1433 | result = [] |
| 1434 | for paper in papers: |
| 1435 | score = calculate_paper_score(paper, profile, weights) |
| 1436 | relevance_signal = compute_relevance_signal(paper, profile) |
| 1437 | drift_bonus, drift_topics = compute_drift_bonus(paper, profile, weights) |
| 1438 | reading_signal_bonus, reading_signal_topics = compute_reading_signal_bonus(paper, profile, weights) |
| 1439 | score = min(1.0, score + drift_bonus + reading_signal_bonus) |
| 1440 | category = categorize_paper(score, paper, profile, weights) |
| 1441 | result.append( |
| 1442 | PaperWithScore( |
| 1443 | paper=paper, |
| 1444 | score=score, |
| 1445 | category=category, |
| 1446 | relevance_signal=relevance_signal, |
| 1447 | drift_bonus=drift_bonus, |
| 1448 | drift_topics=drift_topics, |
| 1449 | reading_signal_bonus=reading_signal_bonus, |
| 1450 | reading_signal_topics=reading_signal_topics, |
| 1451 | ) |
| 1452 | ) |
| 1453 | |
| 1454 | emit({"phase": "scored", "count": len(result)}) |
| 1455 | |
| 1456 | # 先按分数粗排,再按分类结果做硬优先级重排 |
| 1457 | result.sort(key=lambda x: x.score, reverse=True) |
| 1458 | |
| 1459 | result = categorize_papers_by_rank(result, profile, weights) |
| 1460 | result.sort(key=_hard_priority_tuple, reverse=True) |
| 1461 | result = apply_source_diversity_quota(result, weights) |
| 1462 | result = apply_mmr_topic_diversity(result, weights) |
| 1463 | result = apply_push_count_limit(result, weights) |
| 1464 | result.sort(key=_hard_priority_tuple, reverse=True) |
| 1465 | for rank, item in enumerate(result, start=1): |
no test coverage detected