method_acronym.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. """Short method names / acronyms (DiAD, LoRA, Mamba) — avoid broad keyword expansion."""
  2. from __future__ import annotations
  3. import re
  4. from typing import Any
  5. _METHOD_ACRONYM_RE = re.compile(r"^[A-Za-z][A-Za-z0-9\-]{1,15}$")
  6. def is_method_acronym_token(text: str) -> bool:
  7. """如 DiAD、LoRA、Mamba(无空格、偏短、含大小写或全大写)。"""
  8. t = (text or "").strip()
  9. if not t or " " in t:
  10. return False
  11. if not _METHOD_ACRONYM_RE.match(t):
  12. return False
  13. if t.isupper() and len(t) >= 2:
  14. return True
  15. if re.search(r"[A-Z]", t) and re.search(r"[a-z]", t):
  16. return True
  17. if len(t) <= 8 and re.search(r"[A-Z]{2,}", t):
  18. return True
  19. return len(t) <= 6 and t[0].isupper()
  20. def title_matches_method_acronym(title: str, acronym: str) -> bool:
  21. if not acronym:
  22. return False
  23. ac = acronym.strip()
  24. flags = 0 if (re.search(r"[a-z]", ac) and re.search(r"[A-Z]", ac)) else re.I
  25. return bool(re.search(rf"\b{re.escape(ac)}\b", title or "", flags))
  26. def derive_full_title_from_named_method(paper: Any, acronym: str) -> str | None:
  27. """从「DiAD: A Diffusion-based ...」提取正式标题用于会场版检索。"""
  28. title = str(getattr(paper, "title", None) or "").strip()
  29. if not title or not acronym:
  30. return None
  31. m = re.match(rf"^{re.escape(acronym.strip())}\s*[:\\-]\s*(.+)$", title, re.I)
  32. if not m:
  33. return None
  34. full = m.group(1).strip()
  35. return full if len(full) >= 12 else None
  36. def resolve_method_acronym(query: str, keywords: list[str] | None) -> str | None:
  37. q = (query or "").strip()
  38. if is_method_acronym_token(q):
  39. return q
  40. kws = [str(k).strip() for k in (keywords or []) if str(k).strip()]
  41. if len(kws) == 1 and is_method_acronym_token(kws[0]):
  42. return kws[0]
  43. return None
  44. def paper_matches_method_query(
  45. paper: Any,
  46. acronym: str,
  47. *,
  48. canonical_titles: list[str] | None = None,
  49. pinned_arxiv_ids: list[str] | None = None,
  50. venue: str | None = None,
  51. ) -> bool:
  52. """方法缩写查询:标题含缩写、锚定标题模糊匹配、或 pinned arXiv。"""
  53. from ...core.search.paper_searcher import PaperSearcher
  54. title = str(getattr(paper, "title", None) or "")
  55. blob = f"{title} {getattr(paper, 'abstract', None) or ''}"
  56. acronym_hit = title_matches_method_acronym(blob, acronym)
  57. venue_hit = bool(
  58. venue and PaperSearcher._paper_matches_venue_proceedings(paper, venue)
  59. )
  60. title_l = title.lower()
  61. canonical_hit = False
  62. for ct in canonical_titles or []:
  63. ctl = (ct or "").strip().lower()
  64. if len(ctl) >= 12 and (ctl in title_l or title_l in ctl):
  65. canonical_hit = True
  66. break
  67. arxiv_id = str(getattr(paper, "arxiv_id", None) or getattr(paper, "arxivId", None) or "")
  68. url = str(getattr(paper, "url", None) or getattr(paper, "source_url", None) or "")
  69. hay = f"{arxiv_id} {url}".lower()
  70. pinned_hit = any(
  71. (aid or "").strip().lower() in hay for aid in (pinned_arxiv_ids or []) if (aid or "").strip()
  72. )
  73. named_method = bool(
  74. re.match(rf"^{re.escape(acronym.strip())}\s*[:\\-]", title.strip(), re.I)
  75. )
  76. if pinned_hit or canonical_hit:
  77. return True
  78. if venue:
  79. if venue_hit and acronym_hit:
  80. return True
  81. if named_method and acronym_hit:
  82. return True
  83. return False
  84. return acronym_hit