Refine DICOM UPP relation loading

This commit is contained in:
Codex
2026-05-28 09:19:29 +08:00
parent 4fe6466e20
commit 92ca5e5b38
5 changed files with 217 additions and 51 deletions

View File

@@ -24,6 +24,7 @@ PGUSER = os.getenv("PGUSER", "his_user")
PGDATABASE = os.getenv("PGDATABASE", "pacs_db")
PACS_TABLE = os.getenv("PACS_TABLE", "pacs_dicom_files")
PACS_SUMMARY_TABLE = os.getenv("PACS_SUMMARY_TABLE", "pacs_dicom_study_summaries")
PACS_ANNOTATION_TABLE = os.getenv("PACS_ANNOTATION_TABLE", "pacs_dicom_series_annotations")
UPP_ASSET_TABLE = os.getenv("UPP_ASSET_TABLE", "upp_exam_assets")
UPP_STL_TABLE = os.getenv("UPP_STL_TABLE", "upp_stl_files")
USER_TABLE = os.getenv("VISUALIZER_USER_TABLE", "db_visualizer_users")
@@ -42,6 +43,7 @@ def ident(name: str) -> str:
PACS_TABLE_SQL = ident(PACS_TABLE)
PACS_SUMMARY_TABLE_SQL = ident(PACS_SUMMARY_TABLE)
PACS_ANNOTATION_TABLE_SQL = ident(PACS_ANNOTATION_TABLE)
UPP_ASSET_TABLE_SQL = ident(UPP_ASSET_TABLE)
UPP_STL_TABLE_SQL = ident(UPP_STL_TABLE)
USER_TABLE_SQL = ident(USER_TABLE)
@@ -185,6 +187,52 @@ def relation_cte() -> str:
SELECT *
FROM public.{PACS_SUMMARY_TABLE_SQL}
),
a_label_raw AS (
SELECT
a.ct_number,
CASE part.value
WHEN 'head_neck' THEN '头颈部'
WHEN 'chest' THEN '胸部-' || CASE COALESCE(NULLIF(a.chest_window, ''), 'unknown')
WHEN 'lung' THEN '肺窗'
WHEN 'mediastinal' THEN '纵隔窗'
ELSE '无法判别'
END
WHEN 'upper_abdomen' THEN '上腹部-' || CASE COALESCE(NULLIF(a.upper_abdomen_phase, ''), 'unknown')
WHEN 'plain' THEN '平扫'
WHEN 'arterial' THEN '动脉期'
WHEN 'portal_venous' THEN '门脉期'
WHEN 'delayed' THEN '延迟期'
ELSE '无法判别'
END
WHEN 'lower_abdomen' THEN '下腹部'
WHEN 'pelvis' THEN '盆腔'
ELSE NULL
END AS label,
CASE part.value
WHEN 'head_neck' THEN 1
WHEN 'chest' THEN 2
WHEN 'upper_abdomen' THEN 3
WHEN 'lower_abdomen' THEN 4
WHEN 'pelvis' THEN 5
ELSE 99
END AS sort_key
FROM public.{PACS_ANNOTATION_TABLE_SQL} a
CROSS JOIN LATERAL jsonb_array_elements_text(a.body_parts) AS part(value)
WHERE COALESCE(a.skipped, false) IS NOT TRUE
),
a_label_distinct AS (
SELECT ct_number, label, min(sort_key) AS sort_key
FROM a_label_raw
WHERE label IS NOT NULL
GROUP BY ct_number, label
),
a_labels AS (
SELECT
ct_number,
to_jsonb(array_agg(label ORDER BY sort_key, label)) AS dicom_annotation_labels
FROM a_label_distinct
GROUP BY ct_number
),
u_raw AS (
SELECT
u.*,
@@ -253,6 +301,7 @@ def relation_cte() -> str:
ps.undetermined_series,
ps.completed,
ps.body_parts,
COALESCE(a_labels.dicom_annotation_labels, '[]'::jsonb) AS dicom_annotation_labels,
to_jsonb(array_remove(ARRAY[
CASE WHEN ps.body_parts ? 'head_neck' THEN '头颈部' END,
CASE WHEN ps.body_parts ? 'chest' THEN '胸部' END,
@@ -297,6 +346,7 @@ def relation_cte() -> str:
FROM keys k
LEFT JOIN p ON p.ct_key = k.ct_key
LEFT JOIN ps ON ps.ct_number = p.ct_number
LEFT JOIN a_labels ON a_labels.ct_number = p.ct_number
LEFT JOIN u ON u.ct_key = k.ct_key
LEFT JOIN s ON s.ct_key = k.ct_key
)
@@ -401,6 +451,7 @@ def settings(user: dict[str, str] = Depends(admin_user)) -> dict[str, Any]:
"tables": {
"dicom": PACS_TABLE,
"dicom_summary": PACS_SUMMARY_TABLE,
"dicom_annotations": PACS_ANNOTATION_TABLE,
"upp_assets": UPP_ASSET_TABLE,
"upp_stl": UPP_STL_TABLE,
},
@@ -489,6 +540,7 @@ def status(user: dict[str, str] = Depends(current_user)) -> dict[str, Any]:
"tables": {
"dicom": PACS_TABLE,
"dicom_summary": PACS_SUMMARY_TABLE,
"dicom_annotations": PACS_ANNOTATION_TABLE,
"upp_assets": UPP_ASSET_TABLE,
"upp_stl": UPP_STL_TABLE,
},
@@ -503,6 +555,7 @@ def relations(
algorithm_model: str = "",
dicom_part: str = "",
limit: int = Query(default=300, ge=1, le=1000),
offset: int = Query(default=0, ge=0),
user: dict[str, str] = Depends(current_user),
) -> list[dict[str, Any]]:
where = relation_where(q, status, algorithm_model, dicom_part)
@@ -517,7 +570,7 @@ def relations(
study_description, exam_description, algorithm_model, upp_status,
pacs_series_count, dicom_file_count, annotated_series, undetermined_series, completed,
list_present, list_record_count, stl_file_count, stl_file_count_agg,
body_parts, dicom_body_parts, segment_categories, segment_families,
body_parts, dicom_body_parts, dicom_annotation_labels, segment_categories, segment_families,
pacs_updated_at, upp_updated_at, stl_updated_at
FROM relation
{where}
@@ -528,6 +581,7 @@ def relations(
COALESCE(study_time, '') DESC,
ct_key
LIMIT {int(limit)}
OFFSET {int(offset)}
""",
timeout=24,
)