diff --git a/患者首页处理/数据可视化网页端/app/main.py b/患者首页处理/数据可视化网页端/app/main.py index 5c30e68..c1de614 100644 --- a/患者首页处理/数据可视化网页端/app/main.py +++ b/患者首页处理/数据可视化网页端/app/main.py @@ -2349,8 +2349,10 @@ def build_ai_prompt(record: dict[str, Any], pdf_context: dict[str, Any], privacy 10. 入院途径、离院方式、入院病情等代码字段只核对代码本身;例如 PDF 显示“2(门诊)”而结构化字段为“2”就是一致,不要要求复核代码与中文标签关系。 11. 手术操作日期只有在日历日期确实早于入院日期时才算问题;同日或晚于入院日期均为正常,不要推测月份应改为其他月份。 12. 手术及操作编码允许带 x 和 001/002/005/006 等扩展后缀;如果原始内容显示“54.5100x ... 005”这类拆开的后缀,应建议写入完整编码“54.5100x005”,不要要求人工确认扩展码是否有效。 -13. remaining_issues 只写当前文档复核人应该特别注意的内容;不要写如何修改,不要重复 suggested_updates,不要写“无需补录/无需处理/首页原貌”这类已判定无问题的说明。 -14. 不要编造 PDF 中看不见的内容,不要输出置信度。 +13. 不要做 ICD 编码标准性、临床诊断与编码逻辑关系、入院病情是否“应全为1”等医学编码质量判断;本任务只核对 PDF 首页可见内容是否被结构化正确抽取。 +14. PDF 中 “-”、空白栏、未填写栏与结构化空值等价;如果首页原貌就是空白且没有可见值,不要把“需确认是否补录”写入 remaining_issues。 +15. remaining_issues 只写当前文档复核人应该特别注意的内容;不要写如何修改,不要重复 suggested_updates,不要写“无需补录/无需处理/首页原貌”这类已判定无问题的说明。 +16. 不要编造 PDF 中看不见的内容,不要输出置信度。 必须返回这个 JSON 结构: {{ @@ -2537,7 +2539,7 @@ def ai_text_pdf_prefix_issue(text: Any) -> bool: if not compact: return False 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,})", ] 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: if isinstance(value, dict): 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) if not text or not re.search(r"(手术操作日期|手术日期|手术时间)", text): return False - if not re.search(r"(早于入院|入院前|同一天|是否早于)", text): + if not re.search(r"(早于入院|入院前|同一天|是否早于|逻辑关系)", text): return False if re.search(r"PDF.{0,24}\d{4}[-/年]\d{1,2}[-/月]\d{1,2}.{0,24}结构化(?:字段|值)", text): 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) +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: return ( ai_pdf_prefix_truncation_issue(value) + or ai_incomplete_pdf_code_display_issue(value) or ai_code_label_consistent_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) )