| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- """
- BIO tagging schema for labor arbitration case element extraction.
- 15 entity types, 31 labels total (15 x B/I + O).
- """
- from __future__ import annotations
- from typing import Any
- # Entity types with their BIO prefixes
- ENTITY_TYPES = [
- "APPLICANT_NAME", # 申请人姓名
- "RESPONDENT_NAME", # 被申请人名称
- "ENTRY_DATE", # 入职日期
- "LEAVE_DATE", # 离职日期
- "FILING_DATE", # 立案日期
- "MONTH_SALARY", # 月工资标准
- "CLAIM_AMOUNT", # 主张金额
- "WORKER_POSITION", # 劳动者岗位
- "ARBITRATION_ORG", # 仲裁机构
- "LAW_REF", # 法律条款引用
- "CASE_NUMBER", # 案号
- "EVIDENCE", # 证据材料
- "TERMINATION_REASON", # 解除原因
- "OVERTIME_DESC", # 加班描述
- "WORK_DURATION", # 工作年限
- ]
- # Build label list: O + B-ENTITY + I-ENTITY for each type
- LABELS = ["O"]
- LABEL2ID = {"O": 0}
- for entity in ENTITY_TYPES:
- b_label = f"B-{entity}"
- i_label = f"I-{entity}"
- LABELS.append(b_label)
- LABELS.append(i_label)
- LABEL2ID[b_label] = len(LABEL2ID)
- LABEL2ID[i_label] = len(LABEL2ID)
- ID2LABEL = {v: k for k, v in LABEL2ID.items()}
- NUM_LABELS = len(LABELS)
- def get_entity_spans_from_bio(
- tokens: list[str],
- labels: list[int],
- ) -> list[dict[str, Any]]:
- """Convert BIO tag sequence back to entity spans."""
- spans = []
- current_entity = None
- current_tokens = []
- current_start = -1
- for i, (token, label_id) in enumerate(zip(tokens, labels)):
- label = ID2LABEL.get(label_id, "O")
- if label.startswith("B-"):
- if current_entity is not None:
- spans.append({
- "entity": current_entity,
- "text": "".join(current_tokens),
- "start": current_start,
- "end": i,
- })
- current_entity = label[2:]
- current_tokens = [token]
- current_start = i
- elif label.startswith("I-") and current_entity == label[2:]:
- current_tokens.append(token)
- else:
- if current_entity is not None:
- spans.append({
- "entity": current_entity,
- "text": "".join(current_tokens),
- "start": current_start,
- "end": i,
- })
- current_entity = None
- current_tokens = []
- current_start = -1
- if current_entity is not None:
- spans.append({
- "entity": current_entity,
- "text": "".join(current_tokens),
- "start": current_start,
- "end": len(tokens),
- })
- return spans
- def spans_to_bio(
- tokens: list[str],
- spans: list[dict[str, Any]],
- ) -> list[int]:
- """Convert entity spans to BIO tag sequence."""
- labels = ["O"] * len(tokens)
- for span in spans:
- entity = span["entity"]
- start = span["start"]
- end = span["end"]
- b_key = f"B-{entity}"
- i_key = f"I-{entity}"
- if b_key in LABEL2ID:
- labels[start] = b_key
- for i in range(start + 1, min(end, len(tokens))):
- labels[i] = i_key
- return [LABEL2ID[l] for l in labels]
- # Mapping from entity types to flat schema field keys (for converting
- # extracted spans into the element dictionary expected by the backend)
- ENTITY_TO_FIELD = {
- "APPLICANT_NAME": "applicant_name",
- "RESPONDENT_NAME": "respondent_name",
- "ENTRY_DATE": "entry_date",
- "LEAVE_DATE": "leave_date",
- "FILING_DATE": "filing_date",
- "MONTH_SALARY": "month_salary",
- "CLAIM_AMOUNT": "claims", # merges into claims.amount_total
- "WORKER_POSITION": "worker_position",
- "ARBITRATION_ORG": "arbitration_org",
- "LAW_REF": "law_refs", # list field
- "CASE_NUMBER": "case_number",
- "EVIDENCE": "evidence_materials", # list field
- "TERMINATION_REASON": "termination_reason",
- "OVERTIME_DESC": "overtime_desc",
- "WORK_DURATION": "work_duration_text",
- }
|