Converts free-text radiology narratives into structured findings and impression — with measurements, laterality, anatomy, and follow-up recommendations — after OpenMed NER. Use when the user has a CT/MRI/X-ray/ultrasound/mammography report and needs the sections split (technique, comparison, findings, impression), lesion measurements and laterality captured, BI-RADS / Lung-RADS assessment categories pulled, or incidental findings and recommended follow-up tracked. Trigger keywords: radiology report, findings, impression, RadLex, DICOM-SR, BI-RADS, Lung-RADS, ACR, laterality, measurement, nodule, incidental finding, follow-up, structured reporting. Pairs after OpenMed: run openmed.analyze_text on the report (Anatomy/Disease/measurement entities), then assemble structured findings. De-identify the report first. Decision-support only — not a diagnostic medical device.
88%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
A radiology report is prose, but its meaning is structured: a technique, a comparison, a list of findings (each with anatomy, laterality, and a measurement), and an impression that may carry an assessment category (BI-RADS, Lung-RADS) and a follow-up recommendation. This skill turns the narrative into that structure so findings are trackable — especially incidental findings that need downstream follow-up.
OpenMed extracts the anatomy, disease/finding, and measurement spans on-device; this skill organizes them into sectioned, coded findings. It is decision-support, not a diagnostic device — every structured finding must be attributable back to its source sentence for radiologist review.
{technique, comparison, findings[], impression} with measurements and
laterality.import openmed
report = (
"TECHNIQUE: CT chest without contrast.\n"
"COMPARISON: CT 2023-11-02.\n"
"FINDINGS: A 8 mm solid nodule is noted in the right upper lobe, "
"unchanged. No pleural effusion.\n"
"IMPRESSION: 8 mm right upper lobe nodule, stable. Lung-RADS 2. "
"Recommend annual low-dose CT screening."
)
# 1) De-identify the report on-device first (synthetic example shown).
deid = openmed.deidentify(report, policy="hipaa_safe_harbor")
text = deid.deidentified_text
# 2) Run NER for anatomy / finding / measurement spans.
ents = openmed.analyze_text(
text,
model_name="anatomy_detection_superclinical", # Anatomy category
output_format="dict",
)["entities"]
# 3) Split sections by header, then attach entities + measurements per finding.
import re
SECTION = re.compile(r"(?im)^(TECHNIQUE|COMPARISON|FINDINGS|IMPRESSION)\s*:")
sections, last, name = {}, 0, None
for m in SECTION.finditer(text):
if name: sections[name] = text[last:m.start()].strip()
name, last = m.group(1).upper(), m.end()
if name: sections[name] = text[last:].strip()
structured = {
"technique": sections.get("TECHNIQUE"),
"comparison": sections.get("COMPARISON"),
"findings": _split_findings(sections.get("FINDINGS", "")), # one per sentence
"impression": sections.get("IMPRESSION"),
"measurements": re.findall(r"\b\d+(?:\.\d+)?\s?(?:mm|cm)\b", text),
"laterality": sorted({w for w in ("right", "left", "bilateral")
if re.search(rf"\b{w}\b", text, re.I)}),
"assessment": (re.search(r"\b(?:BI-RADS|Lung-RADS)\s*\d[A-C]?\b", text, re.I)
or [None])[0] if re.search(r"RADS", text, re.I) else None,
"follow_up": _extract_followup(sections.get("IMPRESSION", "")),
}_split_findings / _extract_followup are your sentence splitter and a
recommendation matcher ("recommend …", "follow-up in N months"); keep each
finding tied to its source sentence offsets.
openmed.deidentify(report, policy=...); structure
from deidentified_text. Patient name, MRN, accession, and dates go before
anything is stored or shared.analyze_text for anatomy and finding entities; capture measurements
("8 mm", "1.2 cm") and laterality ("right", "left", "bilateral") near each
finding.{anatomy, finding, laterality, measurement, change_vs_prior, source_offsets}. "Unchanged",
"stable", "increased", "new" capture temporal change against the comparison.OpenMed's analyze_text returns a dict; result["entities"] items carry
text, label, confidence, start, end.
extracting-clinical-entities: Anatomy and Disease/finding entities
populate each structured finding; keep offsets so every field traces to a
source sentence.extracting-lab-tables / OCR: if the report is a scan, OCR it first
(openmed.multimodal.ocr.ocr), then run NER on the recognized text.segmenting-clinical-sections: reuse section detection if your reports
don't use canonical headers.building-patient-timelines: dated findings + change-vs-prior feed a
longitudinal view (e.g. nodule size over time).extracting-dicom-metadata: pair the structured findings with the
study's DICOM metadata when assembling a DICOM-SR object.deidentifying-clinical-text (openmed.deidentify)
before any export. Everything runs on-device.resolving-clinical-context
(openmed.clinical) for negation/hedging before asserting a finding.maziyarpanahi/openmed
7456108
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.