Sync primary diagnosis from discharge table

This commit is contained in:
Codex
2026-05-27 15:42:49 +08:00
parent 627fce79fe
commit e0574d16a3
2 changed files with 53 additions and 11 deletions

View File

@@ -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

View File

@@ -68,9 +68,7 @@ const FIELD_KEYWORDS = {
discharge_dept: ["出院科别", "科室"],
hospital_days: ["住院天数"],
major_department: ["大科室"],
primary_diagnosis: ["主要诊断"],
primary_diagnosis_code: ["主要诊断编码", "疾病编码"],
discharge_diagnoses: ["出院诊断", "其他诊断", "诊断编码", "入院病情"],
discharge_diagnoses: ["出院诊断", "主要诊断", "主要诊断编码", "主要诊断入院病情", "其他诊断", "诊断编码", "入院病情"],
operations: ["手术", "操作", "麻醉", "切口"],
total_cost: ["总费用"],
self_pay_amount: ["自付"],