rule_extractor.py 4.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. """
  2. 基于规则的劳动仲裁要素抽取(独立模块,供混合抽取器等复用)。
  3. 案由六分类与 app.extractor.classify_template_primary_cause 一致。
  4. """
  5. from __future__ import annotations
  6. import re
  7. from typing import Any
  8. # 支持包内导入与将 app 目录加入 PYTHONPATH 后的裸导入(与任务说明一致)
  9. try:
  10. from app.extractor import parse_amount
  11. except ImportError:
  12. from extractor import parse_amount # type: ignore
  13. from app.extractor import (
  14. classify_template_primary_cause,
  15. extract_applicant_name,
  16. extract_claims,
  17. extract_contract_type,
  18. extract_entry_date,
  19. extract_law_refs,
  20. extract_leave_date,
  21. extract_month_salary,
  22. extract_overtime_desc,
  23. extract_respondent_name,
  24. extract_termination_reason,
  25. merge_dispute_template_fields,
  26. )
  27. from app.extractor import _amount_near_keywords as amount_near_keywords # noqa: SLF001
  28. from app.extractor import _clean_text as clean_text # noqa: SLF001
  29. from app.extractor import _yes_no_from_text # noqa: SLF001
  30. _DEFAULT_CAUSE = "劳动关系纠纷类"
  31. class RuleBasedExtractor:
  32. """规则抽取器:案由分类 + 通用/劳动合同/社保/法条 + 仲裁请求(规则版)。"""
  33. def extract_all(self, text: str) -> dict[str, Any]:
  34. t = clean_text(text or "")
  35. primary_cause_type = classify_template_primary_cause(t) or _DEFAULT_CAUSE
  36. applicant = extract_applicant_name(t)
  37. respondent = extract_respondent_name(t)
  38. entry_date = extract_entry_date(t)
  39. leave_date = extract_leave_date(t)
  40. month_salary_standard = extract_month_salary(t)
  41. overtime_fact = extract_overtime_desc(t)
  42. termination_reason = extract_termination_reason(t)
  43. labor_contract_signed = _yes_no_from_text(
  44. t,
  45. ["签订劳动合同", "订立书面劳动合同", "有书面合同", "已签订劳动合同"],
  46. ["未签订劳动合同", "未订立书面劳动合同", "无书面合同", "未签订书面劳动合同"],
  47. )
  48. contract_type = extract_contract_type(t)
  49. double_wage_related = "是" if any(x in t for x in ("二倍工资", "双倍工资", "未签劳动合同")) else None
  50. social_insurance_enrolled = _yes_no_from_text(
  51. t,
  52. ["已缴纳社保", "参加社会保险", "缴纳五险", "有社保", "已参保"],
  53. ["未缴纳社保", "未参加社会保险", "未缴社保", "无社保", "未参保"],
  54. )
  55. social_insurance_amount = amount_near_keywords(t, ("保险待遇", "社保待遇", "补缴", "社会保险费"))
  56. if social_insurance_amount is None:
  57. for frag in re.split(r"[\n。;]+", t):
  58. if any(k in frag for k in ("社保", "社会保险", "五险")):
  59. social_insurance_amount = parse_amount(frag)
  60. if social_insurance_amount is not None:
  61. break
  62. law_refs = extract_law_refs(t)
  63. claims = extract_claims(t)
  64. base: dict[str, Any] = {
  65. "primary_cause_type": primary_cause_type,
  66. "applicant_name": applicant,
  67. "respondent_name": respondent,
  68. "entry_date": entry_date,
  69. "leave_date": leave_date,
  70. "month_salary_standard": month_salary_standard,
  71. "overtime_fact": overtime_fact,
  72. "termination_reason": termination_reason,
  73. "labor_contract_signed": labor_contract_signed,
  74. "contract_type": contract_type,
  75. "double_wage_related": double_wage_related,
  76. "social_insurance_enrolled": social_insurance_enrolled,
  77. "social_insurance_amount": social_insurance_amount,
  78. "law_refs": law_refs,
  79. "claims": claims,
  80. }
  81. # 与现有模板扁平字段对齐,便于后续层级/画像复用
  82. base.update(merge_dispute_template_fields(t, base))
  83. base["primary_cause_type"] = base.get("tmpl_primary_cause") or primary_cause_type
  84. base["tmpl_primary_cause"] = base["primary_cause_type"]
  85. return base