Show undetermined study series count
This commit is contained in:
@@ -313,6 +313,7 @@ def ensure_study_summary_table() -> None:
|
||||
series_count integer NOT NULL DEFAULT 0,
|
||||
annotated_series integer NOT NULL DEFAULT 0,
|
||||
unannotated_series integer NOT NULL DEFAULT 0,
|
||||
undetermined_series integer NOT NULL DEFAULT 0,
|
||||
body_parts jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
completed boolean NOT NULL DEFAULT false,
|
||||
completed_by text,
|
||||
@@ -322,6 +323,8 @@ def ensure_study_summary_table() -> None:
|
||||
);
|
||||
ALTER TABLE public.pacs_dicom_study_summaries
|
||||
ADD COLUMN IF NOT EXISTS body_parts jsonb NOT NULL DEFAULT '[]'::jsonb;
|
||||
ALTER TABLE public.pacs_dicom_study_summaries
|
||||
ADD COLUMN IF NOT EXISTS undetermined_series integer NOT NULL DEFAULT 0;
|
||||
ALTER TABLE public.pacs_dicom_study_summaries
|
||||
ADD COLUMN IF NOT EXISTS completed boolean NOT NULL DEFAULT false;
|
||||
ALTER TABLE public.pacs_dicom_study_summaries
|
||||
@@ -511,6 +514,19 @@ def annotation_overview_by_study() -> dict[str, dict[str, Any]]:
|
||||
OR NULLIF(a.notes, '') IS NOT NULL
|
||||
OR a.ai_result IS NOT NULL
|
||||
)::int AS annotated_series,
|
||||
count(DISTINCT a.series_instance_uid) FILTER (
|
||||
WHERE a.skipped IS NOT TRUE
|
||||
AND (
|
||||
(
|
||||
a.body_parts ? 'upper_abdomen'
|
||||
AND COALESCE(NULLIF(a.upper_abdomen_phase, ''), 'unknown') = 'unknown'
|
||||
)
|
||||
OR (
|
||||
a.body_parts ? 'chest'
|
||||
AND COALESCE(NULLIF(a.chest_window, ''), 'unknown') = 'unknown'
|
||||
)
|
||||
)
|
||||
)::int AS undetermined_series,
|
||||
COALESCE(
|
||||
jsonb_agg(DISTINCT part.value) FILTER (WHERE part.value IS NOT NULL),
|
||||
'[]'::jsonb
|
||||
@@ -534,7 +550,7 @@ def summary_rows_by_study() -> dict[str, dict[str, Any]]:
|
||||
"""
|
||||
SELECT
|
||||
ct_number, series_count, annotated_series, unannotated_series,
|
||||
body_parts, completed, completed_by, completed_at, completion_updated_at, refreshed_at
|
||||
undetermined_series, body_parts, completed, completed_by, completed_at, completion_updated_at, refreshed_at
|
||||
FROM public.pacs_dicom_study_summaries
|
||||
""",
|
||||
timeout=8,
|
||||
@@ -594,6 +610,8 @@ def studies(_: str = Depends(require_auth), q: str = "", limit: int = 200) -> li
|
||||
row["series_count"] = total_series
|
||||
row["annotated_series"] = min(total_series, int((summary or {}).get("annotated_series") if summary else annotation_summary.get("annotated_series", 0)))
|
||||
row["unannotated_series"] = max(0, total_series - int(row["annotated_series"]))
|
||||
undetermined_source = annotation_summary.get("undetermined_series", (summary or {}).get("undetermined_series", 0))
|
||||
row["undetermined_series"] = min(total_series, int(undetermined_source or 0))
|
||||
row["body_parts"] = valid_parts((summary or {}).get("body_parts") or annotation_summary.get("body_parts") or [])
|
||||
row["completed"] = bool((summary or {}).get("completed", False))
|
||||
row["completed_by"] = (summary or {}).get("completed_by", "")
|
||||
@@ -1122,11 +1140,27 @@ def study_summary_payload(data: dict[str, Any]) -> dict[str, Any]:
|
||||
or row.get("annotation", {}).get("notes")
|
||||
or row.get("annotation", {}).get("ai_model")
|
||||
)
|
||||
undetermined = sum(
|
||||
1
|
||||
for row in series_list
|
||||
if not row.get("annotation", {}).get("skipped")
|
||||
and (
|
||||
(
|
||||
"upper_abdomen" in valid_parts(row.get("annotation", {}).get("body_parts") or [])
|
||||
and row.get("annotation", {}).get("upper_abdomen_phase") == "unknown"
|
||||
)
|
||||
or (
|
||||
"chest" in valid_parts(row.get("annotation", {}).get("body_parts") or [])
|
||||
and row.get("annotation", {}).get("chest_window") == "unknown"
|
||||
)
|
||||
)
|
||||
)
|
||||
return {
|
||||
"ct_number": data.get("study", {}).get("ct_number", ""),
|
||||
"series_count": total,
|
||||
"annotated_series": annotated,
|
||||
"unannotated_series": max(0, total - annotated),
|
||||
"undetermined_series": undetermined,
|
||||
"body_parts": body_parts,
|
||||
"summary_updated_at": time.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
}
|
||||
@@ -1138,13 +1172,14 @@ def save_study_summary(summary: dict[str, Any]) -> None:
|
||||
pg_scalar(
|
||||
f"""
|
||||
INSERT INTO public.pacs_dicom_study_summaries (
|
||||
ct_number, series_count, annotated_series, unannotated_series, body_parts, refreshed_at
|
||||
ct_number, series_count, annotated_series, unannotated_series, undetermined_series, body_parts, refreshed_at
|
||||
)
|
||||
VALUES (
|
||||
{sql_literal(summary.get('ct_number', ''))},
|
||||
{int(summary.get('series_count') or 0)},
|
||||
{int(summary.get('annotated_series') or 0)},
|
||||
{int(summary.get('unannotated_series') or 0)},
|
||||
{int(summary.get('undetermined_series') or 0)},
|
||||
{sql_literal(json.dumps(valid_parts(summary.get('body_parts') or []), ensure_ascii=False))}::jsonb,
|
||||
now()
|
||||
)
|
||||
@@ -1152,6 +1187,7 @@ def save_study_summary(summary: dict[str, Any]) -> None:
|
||||
series_count = EXCLUDED.series_count,
|
||||
annotated_series = EXCLUDED.annotated_series,
|
||||
unannotated_series = EXCLUDED.unannotated_series,
|
||||
undetermined_series = EXCLUDED.undetermined_series,
|
||||
body_parts = EXCLUDED.body_parts,
|
||||
refreshed_at = now()
|
||||
""",
|
||||
|
||||
Reference in New Issue
Block a user