Sync primary diagnosis from discharge table
This commit is contained in:
@@ -146,9 +146,6 @@ FIELD_GROUPS: list[dict[str, Any]] = [
|
||||
"fields": [
|
||||
("outpatient_diagnosis", "门急诊诊断", "text", None),
|
||||
("outpatient_diagnosis_code", "门急诊诊断编码", "text", None),
|
||||
("primary_diagnosis", "主要诊断", "text", None),
|
||||
("primary_diagnosis_code", "主要诊断编码", "text", None),
|
||||
("primary_admission_condition", "主要诊断入院病情", "text", None),
|
||||
("discharge_diagnoses", "出院诊断", "json", None),
|
||||
("injury_poisoning_external_cause", "损伤中毒外部原因", "text", None),
|
||||
("injury_poisoning_code", "损伤中毒疾病编码", "text", None),
|
||||
@@ -385,9 +382,6 @@ AI_REDACT_PATTERNS = (
|
||||
AI_UPLOAD_FIELDS = [
|
||||
"outpatient_diagnosis",
|
||||
"outpatient_diagnosis_code",
|
||||
"primary_diagnosis",
|
||||
"primary_diagnosis_code",
|
||||
"primary_admission_condition",
|
||||
"discharge_diagnoses",
|
||||
"operations",
|
||||
"pathology_diagnosis",
|
||||
@@ -1808,6 +1802,35 @@ def json_changed_fields(field: str, old_value: Any, new_value: Any) -> list[dict
|
||||
]
|
||||
|
||||
|
||||
def main_diagnosis_row_index(rows: list[Any]) -> int:
|
||||
for index, row in enumerate(rows):
|
||||
if isinstance(row, dict) and str(row.get("诊断类别") or "").strip() == "主要诊断":
|
||||
return index
|
||||
return 0
|
||||
|
||||
|
||||
def main_diagnosis_from_discharge_diagnoses(value: Any) -> dict[str, str]:
|
||||
rows = value if isinstance(value, list) else []
|
||||
if not rows:
|
||||
return {"primary_diagnosis": "", "primary_diagnosis_code": "", "primary_admission_condition": ""}
|
||||
index = main_diagnosis_row_index(rows)
|
||||
row = rows[index] if index < len(rows) and isinstance(rows[index], dict) else {}
|
||||
return {
|
||||
"primary_diagnosis": str(row.get("出院诊断") or row.get("诊断名称") or "").strip(),
|
||||
"primary_diagnosis_code": str(row.get("疾病编码") or row.get("诊断编码") or "").strip(),
|
||||
"primary_admission_condition": str(row.get("入院病情") or "").strip(),
|
||||
}
|
||||
|
||||
|
||||
def sync_primary_diagnosis_updates(updates: dict[str, Any], before: dict[str, Any]) -> None:
|
||||
if "discharge_diagnoses" not in updates:
|
||||
return
|
||||
derived = main_diagnosis_from_discharge_diagnoses(updates.get("discharge_diagnoses"))
|
||||
for field, value in derived.items():
|
||||
if comparable(before.get(field)) != comparable(value):
|
||||
updates[field] = value
|
||||
|
||||
|
||||
def build_record_updates(
|
||||
record_id: int,
|
||||
fields: dict[str, Any],
|
||||
@@ -1838,6 +1861,8 @@ def build_record_updates(
|
||||
if "inpatient_no" in updates and not str(updates["inpatient_no"] or "").strip():
|
||||
raise HTTPException(status_code=400, detail="患者号不能为空")
|
||||
|
||||
sync_primary_diagnosis_updates(updates, before)
|
||||
|
||||
manual_note = manual_note.strip()
|
||||
if manual_note:
|
||||
current = before.get("review_notes") or []
|
||||
@@ -2343,7 +2368,7 @@ def build_ai_prompt(record: dict[str, Any], pdf_context: dict[str, Any], privacy
|
||||
5. 只有仍需要复核或纠正的问题,classification 返回 "problem",并写入 remaining_issues。
|
||||
6. 如果手术表格中能看到“手术及操作编码”列但对应单元格为空,写“编码栏可见但为空白”,不要写“编码区域未在首页显示”;单元格本来为空且无需补录时不要因此判为 problem。
|
||||
7. 手术操作名称可能因为换行被结构化解析截断;如果 PDF定位文本或局部截图中显示完整多行名称,请把完整名称放入 suggested_updates。
|
||||
8. 门急诊诊断编码只能用于 outpatient_diagnosis_code;不要把门急诊诊断编码复制到 primary_diagnosis_code 或 discharge_diagnoses[].疾病编码,除非出院诊断表格对应“疾病编码”单元格本身清楚显示该编码。
|
||||
8. 门急诊诊断编码只能用于 outpatient_diagnosis_code;主要诊断请修正 discharge_diagnoses 中“诊断类别=主要诊断”的行,不要把门急诊诊断编码复制到 discharge_diagnoses[].疾病编码,除非出院诊断表格对应“疾病编码”单元格本身清楚显示该编码。
|
||||
9. remaining_issues 只写当前文档复核人应该特别注意的内容;不要写如何修改,不要重复 suggested_updates,不要写“无需补录/无需处理/首页原貌”这类已判定无问题的说明。
|
||||
10. 不要编造 PDF 中看不见的内容,不要输出置信度。
|
||||
|
||||
@@ -2353,7 +2378,7 @@ def build_ai_prompt(record: dict[str, Any], pdf_context: dict[str, Any], privacy
|
||||
"summary": "一句话结论,60字以内",
|
||||
"method": "AI视觉核验:PDF文本定位+局部截图,对照复核定位和结构化字段",
|
||||
"suggested_updates": [
|
||||
{{"field": "字段名或路径,例如 primary_diagnosis_code 或 operations[0].麻醉方式", "value": "PDF中应写入的值", "reason": "20字以内"}}
|
||||
{{"field": "字段名或路径,例如 discharge_diagnoses[0].疾病编码 或 operations[0].麻醉方式", "value": "PDF中应写入的值", "reason": "20字以内"}}
|
||||
],
|
||||
"remaining_issues": ["AI觉得有必要复核的内容,最多3条;无则返回空数组"],
|
||||
"evidence": [
|
||||
@@ -2660,8 +2685,22 @@ def ai_outpatient_code_leak(path: tuple[str, int | None, str | None], value: Any
|
||||
return bool(target_is_diagnosis_code)
|
||||
|
||||
|
||||
PRIMARY_DIAGNOSIS_AI_TARGETS = {
|
||||
"primary_diagnosis": "出院诊断",
|
||||
"主要诊断": "出院诊断",
|
||||
"主要诊断名称": "出院诊断",
|
||||
"primary_diagnosis_code": "疾病编码",
|
||||
"主要诊断编码": "疾病编码",
|
||||
"primary_admission_condition": "入院病情",
|
||||
"主要诊断入院病情": "入院病情",
|
||||
}
|
||||
|
||||
|
||||
def ai_update_path(field_text: str, item: dict[str, Any]) -> tuple[str, int | None, str | None] | None:
|
||||
text = str(field_text or "").strip()
|
||||
for keyword, column in sorted(PRIMARY_DIAGNOSIS_AI_TARGETS.items(), key=lambda entry: len(entry[0]), reverse=True):
|
||||
if keyword in text:
|
||||
return ("discharge_diagnoses", -1, column)
|
||||
if text in EDITABLE_FIELDS:
|
||||
return (text, None, None)
|
||||
for name, meta in FIELD_META.items():
|
||||
@@ -2726,6 +2765,10 @@ def ai_suggested_updates(result: dict[str, Any], before: dict[str, Any]) -> tupl
|
||||
continue
|
||||
rows = old_value if isinstance(old_value, list) else []
|
||||
rows = [dict(row) if isinstance(row, dict) else {} for row in rows]
|
||||
if index == -1 and field == "discharge_diagnoses":
|
||||
if not rows:
|
||||
rows = [{"诊断类别": "主要诊断", "出院诊断": "", "疾病编码": "", "入院病情": ""}]
|
||||
index = main_diagnosis_row_index(rows)
|
||||
if index < 0 or index >= len(rows):
|
||||
continue
|
||||
compare_old = rows[index].get(key)
|
||||
@@ -2750,6 +2793,7 @@ def ai_suggested_updates(result: dict[str, Any], before: dict[str, Any]) -> tupl
|
||||
}
|
||||
)
|
||||
|
||||
sync_primary_diagnosis_updates(updates, before)
|
||||
return updates, changed_fields
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user