Broaden AI review cleanup rules
This commit is contained in:
@@ -2349,8 +2349,10 @@ def build_ai_prompt(record: dict[str, Any], pdf_context: dict[str, Any], privacy
|
|||||||
10. 入院途径、离院方式、入院病情等代码字段只核对代码本身;例如 PDF 显示“2(门诊)”而结构化字段为“2”就是一致,不要要求复核代码与中文标签关系。
|
10. 入院途径、离院方式、入院病情等代码字段只核对代码本身;例如 PDF 显示“2(门诊)”而结构化字段为“2”就是一致,不要要求复核代码与中文标签关系。
|
||||||
11. 手术操作日期只有在日历日期确实早于入院日期时才算问题;同日或晚于入院日期均为正常,不要推测月份应改为其他月份。
|
11. 手术操作日期只有在日历日期确实早于入院日期时才算问题;同日或晚于入院日期均为正常,不要推测月份应改为其他月份。
|
||||||
12. 手术及操作编码允许带 x 和 001/002/005/006 等扩展后缀;如果原始内容显示“54.5100x ... 005”这类拆开的后缀,应建议写入完整编码“54.5100x005”,不要要求人工确认扩展码是否有效。
|
12. 手术及操作编码允许带 x 和 001/002/005/006 等扩展后缀;如果原始内容显示“54.5100x ... 005”这类拆开的后缀,应建议写入完整编码“54.5100x005”,不要要求人工确认扩展码是否有效。
|
||||||
13. remaining_issues 只写当前文档复核人应该特别注意的内容;不要写如何修改,不要重复 suggested_updates,不要写“无需补录/无需处理/首页原貌”这类已判定无问题的说明。
|
13. 不要做 ICD 编码标准性、临床诊断与编码逻辑关系、入院病情是否“应全为1”等医学编码质量判断;本任务只核对 PDF 首页可见内容是否被结构化正确抽取。
|
||||||
14. 不要编造 PDF 中看不见的内容,不要输出置信度。
|
14. PDF 中 “-”、空白栏、未填写栏与结构化空值等价;如果首页原貌就是空白且没有可见值,不要把“需确认是否补录”写入 remaining_issues。
|
||||||
|
15. remaining_issues 只写当前文档复核人应该特别注意的内容;不要写如何修改,不要重复 suggested_updates,不要写“无需补录/无需处理/首页原貌”这类已判定无问题的说明。
|
||||||
|
16. 不要编造 PDF 中看不见的内容,不要输出置信度。
|
||||||
|
|
||||||
必须返回这个 JSON 结构:
|
必须返回这个 JSON 结构:
|
||||||
{{
|
{{
|
||||||
@@ -2537,7 +2539,7 @@ def ai_text_pdf_prefix_issue(text: Any) -> bool:
|
|||||||
if not compact:
|
if not compact:
|
||||||
return False
|
return False
|
||||||
patterns = [
|
patterns = [
|
||||||
r"PDF(?:显示|中显示|可见|值)?(?:为|是|[::])?([A-Za-z0-9][A-Za-z0-9.+\-*/xX]*)[,,;;。、]?(?:结构化字段|结构化值|字段|系统字段)(?:为|是|[::])?([A-Za-z0-9][A-Za-z0-9.+\-*/xX]*)",
|
r"PDF(?:显示|中显示|可见|值)?(?:为|是|[::])?[\"'“”‘’]?([A-Za-z0-9][A-Za-z0-9.+\-*/xX]*)[\"'“”‘’]?[,,;;。、]?(?:结构化字段|结构化值|字段|系统字段)(?:为|是|[::])?[\"'“”‘’]?([A-Za-z0-9][A-Za-z0-9.+\-*/xX]*)",
|
||||||
r"PDF[^,,;;。]*?([A-Za-z0-9][A-Za-z0-9.+\-*/xX]{2,})[^,,;;。]*?(?:结构化字段|结构化值|字段|系统字段)[^,,;;。]*?([A-Za-z0-9][A-Za-z0-9.+\-*/xX]{2,})",
|
r"PDF[^,,;;。]*?([A-Za-z0-9][A-Za-z0-9.+\-*/xX]{2,})[^,,;;。]*?(?:结构化字段|结构化值|字段|系统字段)[^,,;;。]*?([A-Za-z0-9][A-Za-z0-9.+\-*/xX]{2,})",
|
||||||
]
|
]
|
||||||
return any(
|
return any(
|
||||||
@@ -2547,6 +2549,40 @@ def ai_text_pdf_prefix_issue(text: Any) -> bool:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def ai_code_tokens(value: Any) -> list[str]:
|
||||||
|
text = str(value or "")
|
||||||
|
tokens = re.findall(r"[A-Za-z]?\d{1,3}\.[A-Za-z0-9xX.*+]{2,}", text)
|
||||||
|
return [token.strip(",,;;。))]】'\"“”‘’") for token in tokens]
|
||||||
|
|
||||||
|
|
||||||
|
def ai_has_prefix_code_pair(value: Any) -> bool:
|
||||||
|
tokens = ai_code_tokens(value)
|
||||||
|
for left in tokens:
|
||||||
|
for right in tokens:
|
||||||
|
if left == right:
|
||||||
|
continue
|
||||||
|
if ai_pdf_value_is_structured_prefix(left, right):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def ai_incomplete_pdf_code_display_issue(value: Any) -> bool:
|
||||||
|
text = ai_join_text(value)
|
||||||
|
if not text or not re.search(r"(编码|ICD|疾病编码|手术操作编码|手术及操作编码)", text, flags=re.IGNORECASE):
|
||||||
|
return False
|
||||||
|
if not re.search(r"(PDF|截图|显示|文本定位|局部截图)", text):
|
||||||
|
return False
|
||||||
|
if not re.search(r"(截断|不完整|简写|缩写|末位|前半|完整编码|显示为)", text):
|
||||||
|
return False
|
||||||
|
if re.search(r"(空白|缺失|漏填|未填|错填|明显不符|明显不匹配)", text):
|
||||||
|
return False
|
||||||
|
if ai_has_prefix_code_pair(text):
|
||||||
|
return True
|
||||||
|
if re.search(r"(在PDF中可见|PDF中可见|与PDF一致)", text) and "完整编码" in text:
|
||||||
|
return True
|
||||||
|
return bool(re.search(r"(截断|显示不完整|简写格式|缩写形式|显示为简写|显示为截断)", text))
|
||||||
|
|
||||||
|
|
||||||
def ai_pdf_prefix_truncation_issue(value: Any) -> bool:
|
def ai_pdf_prefix_truncation_issue(value: Any) -> bool:
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
pdf_value = value.get("pdf_value") or value.get("pdf") or value.get("PDF值") or value.get("图片值")
|
pdf_value = value.get("pdf_value") or value.get("pdf") or value.get("PDF值") or value.get("图片值")
|
||||||
@@ -2651,7 +2687,7 @@ def ai_operation_date_not_early_issue(value: Any) -> bool:
|
|||||||
text = ai_join_text(value)
|
text = ai_join_text(value)
|
||||||
if not text or not re.search(r"(手术操作日期|手术日期|手术时间)", text):
|
if not text or not re.search(r"(手术操作日期|手术日期|手术时间)", text):
|
||||||
return False
|
return False
|
||||||
if not re.search(r"(早于入院|入院前|同一天|是否早于)", text):
|
if not re.search(r"(早于入院|入院前|同一天|是否早于|逻辑关系)", text):
|
||||||
return False
|
return False
|
||||||
if re.search(r"PDF.{0,24}\d{4}[-/年]\d{1,2}[-/月]\d{1,2}.{0,24}结构化(?:字段|值)", text):
|
if re.search(r"PDF.{0,24}\d{4}[-/年]\d{1,2}[-/月]\d{1,2}.{0,24}结构化(?:字段|值)", text):
|
||||||
return False
|
return False
|
||||||
@@ -2677,11 +2713,97 @@ def ai_operation_date_not_early_issue(value: Any) -> bool:
|
|||||||
return all(item_date >= admission_date for item_date in operation_dates)
|
return all(item_date >= admission_date for item_date in operation_dates)
|
||||||
|
|
||||||
|
|
||||||
|
def ai_code_format_confirmation_issue(value: Any) -> bool:
|
||||||
|
text = ai_join_text(value)
|
||||||
|
if not text or not re.search(r"(编码|ICD|疾病编码|手术操作编码|手术及操作编码)", text, flags=re.IGNORECASE):
|
||||||
|
return False
|
||||||
|
if not re.search(r"(标准ICD|标准编码|编码格式|格式规范|编码规范|编码规则|扩展码|附加码|后缀|星号|含\*)", text):
|
||||||
|
return False
|
||||||
|
if re.search(r"(病理诊断|手术|操作)", text):
|
||||||
|
return not bool(re.search(r"(不匹配|不符|明显|错填|错误|缺失|漏填|空白|未填)", text))
|
||||||
|
if re.search(r"(不匹配|不符|明显|错填|错误|应为|正确编码|缺失|漏填|空白|未填|ICD-O|形态学)", text):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def ai_admission_condition_confirmation_issue(value: Any) -> bool:
|
||||||
|
text = ai_join_text(value)
|
||||||
|
if not text or "入院病情" not in text:
|
||||||
|
return False
|
||||||
|
if re.search(r"(缺失|漏填|错填|错误|不符|不匹配|空白|未填)", text):
|
||||||
|
return False
|
||||||
|
return bool(re.search(r"(是否为|规范值|符合规范|全部为|均为|结合病程|符合实际|需确认)", text))
|
||||||
|
|
||||||
|
|
||||||
|
def ai_blank_same_as_empty_issue(value: Any) -> bool:
|
||||||
|
text = ai_join_text(value)
|
||||||
|
if not text:
|
||||||
|
return False
|
||||||
|
if re.search(r"(原始内容含|应录入|录入为|补录为|PDF显示为[\"'“”‘’]?[A-Za-z]?\d{1,3}\.)", text):
|
||||||
|
return False
|
||||||
|
if re.search(r"(未在.*(显示|截图|提供)|无法确认|是否可见)", text):
|
||||||
|
return False
|
||||||
|
blank_text = bool(re.search(r"(空白|为空|留空|未填写|确实无|确实未填写|\"-\"|'-'|保持空白)", text))
|
||||||
|
if not blank_text:
|
||||||
|
return False
|
||||||
|
safe_targets = (
|
||||||
|
"手术及操作编码",
|
||||||
|
"手术操作编码",
|
||||||
|
"手术编码",
|
||||||
|
"手术级别",
|
||||||
|
"麻醉医师",
|
||||||
|
"I助",
|
||||||
|
"II助",
|
||||||
|
"病理诊断编码",
|
||||||
|
"病理号",
|
||||||
|
"其他诊断",
|
||||||
|
"右侧",
|
||||||
|
)
|
||||||
|
if not any(target in text for target in safe_targets):
|
||||||
|
return False
|
||||||
|
if re.search(r"(主要诊断|门急诊诊断|出院时间|入院时间|姓名|住院号|病案号)", text):
|
||||||
|
return False
|
||||||
|
if re.search(r"(漏填|缺失|需补录|人工补录|编码员补录|医师补填|必须补)", text) and not re.search(r"(是否需补录|是否后续补录|需确认是否)", text):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def ai_dash_empty_equivalent_issue(value: Any) -> bool:
|
||||||
|
text = ai_join_text(value)
|
||||||
|
return bool(re.search(r"PDF显示为[\"'“”‘’]?-+[\"'“”‘’]?.{0,30}结构化(留空|为空|空白)", text))
|
||||||
|
|
||||||
|
|
||||||
|
def ai_same_date_format_issue(value: Any) -> bool:
|
||||||
|
text = ai_join_text(value)
|
||||||
|
if not text or not re.search(r"(PDF|结构化)", text) or not re.search(r"(日期|时间|年份)", text):
|
||||||
|
return False
|
||||||
|
if re.search(r"(不一致|不符|差异|哪个正确|同一住院|同一患者)", text) and not re.search(r"(年份|格式)", text):
|
||||||
|
return False
|
||||||
|
dates = [item_date for item_date, _position in ai_dates_in_text(text)]
|
||||||
|
if len(dates) < 2:
|
||||||
|
return False
|
||||||
|
return len(set(dates)) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def ai_already_suggested_update_issue(value: Any) -> bool:
|
||||||
|
text = ai_join_text(value)
|
||||||
|
if not text:
|
||||||
|
return False
|
||||||
|
return bool(re.search(r"(已建议|已修正|已更新|已补全|已补齐|已更正|需确认.*已修正|需确认.*已更新)", text))
|
||||||
|
|
||||||
|
|
||||||
def ai_false_positive_issue(value: Any) -> bool:
|
def ai_false_positive_issue(value: Any) -> bool:
|
||||||
return (
|
return (
|
||||||
ai_pdf_prefix_truncation_issue(value)
|
ai_pdf_prefix_truncation_issue(value)
|
||||||
|
or ai_incomplete_pdf_code_display_issue(value)
|
||||||
or ai_code_label_consistent_issue(value)
|
or ai_code_label_consistent_issue(value)
|
||||||
or ai_operation_date_not_early_issue(value)
|
or ai_operation_date_not_early_issue(value)
|
||||||
|
or ai_same_date_format_issue(value)
|
||||||
|
or ai_code_format_confirmation_issue(value)
|
||||||
|
or ai_admission_condition_confirmation_issue(value)
|
||||||
|
or ai_blank_same_as_empty_issue(value)
|
||||||
|
or ai_dash_empty_equivalent_issue(value)
|
||||||
|
or ai_already_suggested_update_issue(value)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user