解析用户回复,提取选中的论文编号 支持格式: - "1 2 4 6 7 9 11" (空格分隔) - "1-5 6 9 11" (范围 + 单个编号) - "1,2,4,6,7,9,11" (逗号分隔) - 混合格式:"1-3 5 7-9 11" - 快捷命令:"all lock"(所有必读)、"all red"(所有高度相关) Args: reply: 用户回复文本 papers: 论文列表(用于快捷命令) Returns: 选中的编号集合
(reply: str, papers: List[Dict] = None)
| 232 | |
| 233 | |
| 234 | def parse_user_reply(reply: str, papers: List[Dict] = None) -> Set[int]: |
| 235 | """ |
| 236 | 解析用户回复,提取选中的论文编号 |
| 237 | |
| 238 | 支持格式: |
| 239 | - "1 2 4 6 7 9 11" (空格分隔) |
| 240 | - "1-5 6 9 11" (范围 + 单个编号) |
| 241 | - "1,2,4,6,7,9,11" (逗号分隔) |
| 242 | - 混合格式:"1-3 5 7-9 11" |
| 243 | - 快捷命令:"all lock"(所有必读)、"all red"(所有高度相关) |
| 244 | |
| 245 | Args: |
| 246 | reply: 用户回复文本 |
| 247 | papers: 论文列表(用于快捷命令) |
| 248 | |
| 249 | Returns: |
| 250 | 选中的编号集合 |
| 251 | """ |
| 252 | selected: Set[int] = set() |
| 253 | max_paper_num = len(papers) if papers else 200 |
| 254 | |
| 255 | # 快捷命令处理 |
| 256 | reply_lower = reply.lower().strip() |
| 257 | |
| 258 | if reply_lower == "all lock": |
| 259 | # 选择必读清单论文 |
| 260 | if papers: |
| 261 | for i, paper in enumerate(papers): |
| 262 | if paper.get("category") == "must_read": |
| 263 | selected.add(i + 1) # 编号从 1 开始 |
| 264 | return selected |
| 265 | |
| 266 | if reply_lower == "all red": |
| 267 | # 选择所有高度相关论文 |
| 268 | if papers: |
| 269 | for i, paper in enumerate(papers): |
| 270 | if paper.get("category") == "high_relevant": |
| 271 | selected.add(i + 1) # 编号从 1 开始 |
| 272 | return selected |
| 273 | |
| 274 | if reply_lower == "none": |
| 275 | # 都不选 |
| 276 | return selected |
| 277 | |
| 278 | # 规范化:将逗号、顿号等替换为空格 |
| 279 | normalized = re.sub(r"[,,、;;]", " ", reply) |
| 280 | |
| 281 | # 提取所有 token(由空格分隔的部分) |
| 282 | tokens = normalized.split() |
| 283 | |
| 284 | for token in tokens: |
| 285 | token = token.strip() |
| 286 | if not token: |
| 287 | continue |
| 288 | |
| 289 | # 检查是否是范围格式(如 "1-5") |
| 290 | range_match = re.match(r"^(\d+)-(\d+)$", token) |
| 291 | if range_match: |
no test coverage detected