Return paper numbers already selected for this user/push. Feedback can arrive incrementally in chat, for example "1 2 3" followed by "4". The second message should amend the same selection state instead of treating 1-3 as newly skipped.
(user_id: str, push_id: str, papers: List[Dict])
| 368 | |
| 369 | |
| 370 | def get_existing_selected_numbers(user_id: str, push_id: str, papers: List[Dict]) -> Set[int]: |
| 371 | """Return paper numbers already selected for this user/push. |
| 372 | |
| 373 | Feedback can arrive incrementally in chat, for example "1 2 3" followed by |
| 374 | "4". The second message should amend the same selection state instead of |
| 375 | treating 1-3 as newly skipped. |
| 376 | """ |
| 377 | paper_id_to_number: Dict[int, int] = {} |
| 378 | for index, paper in enumerate(papers or [], start=1): |
| 379 | paper_id = paper.get("id") |
| 380 | if paper_id is None: |
| 381 | continue |
| 382 | try: |
| 383 | paper_id_to_number[int(paper_id)] = index |
| 384 | except (TypeError, ValueError): |
| 385 | continue |
| 386 | |
| 387 | selected_numbers: Set[int] = set() |
| 388 | conn = db_ops.get_connection() |
| 389 | cursor = conn.cursor() |
| 390 | cursor.execute( |
| 391 | """ |
| 392 | SELECT paper_id, metadata |
| 393 | FROM behavior_logs |
| 394 | WHERE user_id = ? |
| 395 | AND push_id = ? |
| 396 | AND action = 'selected' |
| 397 | AND action_type = 'selected' |
| 398 | ORDER BY id ASC |
| 399 | """, |
| 400 | (user_id, push_id), |
| 401 | ) |
| 402 | rows = cursor.fetchall() |
| 403 | conn.close() |
| 404 | |
| 405 | max_paper_num = len(papers or []) |
| 406 | for row in rows: |
| 407 | metadata: Dict[str, Any] = {} |
| 408 | raw_metadata = row["metadata"] if "metadata" in row.keys() else None |
| 409 | if raw_metadata: |
| 410 | try: |
| 411 | parsed = json.loads(raw_metadata) |
| 412 | if isinstance(parsed, dict): |
| 413 | metadata = parsed |
| 414 | except (TypeError, json.JSONDecodeError): |
| 415 | metadata = {} |
| 416 | |
| 417 | paper_number = metadata.get("paper_number") |
| 418 | try: |
| 419 | normalized_number = int(paper_number) |
| 420 | except (TypeError, ValueError): |
| 421 | normalized_number = None |
| 422 | |
| 423 | if normalized_number is None: |
| 424 | paper_id = row["paper_id"] if "paper_id" in row.keys() else None |
| 425 | try: |
| 426 | normalized_number = paper_id_to_number.get(int(paper_id)) |
| 427 | except (TypeError, ValueError): |