Make 10 osce question with images ppt from textbook of radiology for exam
chest X-ray pneumothorax radiology OSCE
pleural effusion chest X-ray radiology diagnosis
lobar pneumonia consolidation chest X-ray
pulmonary edema heart failure chest X-ray
Colles fracture wrist X-ray
bowel obstruction abdominal X-ray dilated loops
tension pneumothorax mediastinal shift X-ray
aortic dissection CT scan chest
hip fracture neck of femur X-ray elderly
free air under diaphragm perforation erect chest X-ray
pulmonary embolism CT pulmonary angiography saddle embolus
Genitourinary system
renal calculus kidney stone hydronephrosis CT scan radiology
renal cell carcinoma CT scan kidney mass radiology
bladder cancer transitional cell carcinoma CT cystogram
polycystic kidney disease ultrasound CT enlarged kidneys cysts
prostate cancer MRI enlarged prostate benign hypertrophy
ureteric stone hydroureter obstruction CT KUB
Wilms tumor nephroblastoma pediatric kidney mass CT
renal angiomyolipoma fat containing kidney lesion CT
horseshoe kidney IVU intravenous urogram congenital anomaly
testicular torsion ultrasound absent blood flow Doppler
mkdir -p /home/daytona/workspace/gu-radiology-osce && ls /home/daytona/workspace/gu-radiology-osce/
~/gu-radiology-osce/build_pptx.js
const pptxgen = require("pptxgenjs");
const { execSync } = require("child_process");
// ─── Colour palette ───────────────────────────────────────────────
const DARK_BG = "0A1628"; // deep navy
const ACCENT = "00C9A7"; // teal-green
const ACCENT2 = "F4A261"; // warm amber
const WHITE = "FFFFFF";
const LIGHT_BG = "0E1E38"; // slightly lighter navy for answer slides
const PALE_GRAY = "B0BEC5";
// ─── OSCE questions data ──────────────────────────────────────────
const questions = [
{
qNum: 1,
title: "Question 1",
scenario: "A 45-year-old male presents with severe left-sided loin-to-groin pain, haematuria and nausea. The non-contrast CT KUB shown was performed.",
prompt: "What is the diagnosis? Describe TWO key radiological findings.",
imageUrl: "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_38ee56af128323c2cd16f30bdeed1fe3cd45faae179a712ae3aeaea23934fddc.jpg",
imageCaption: "Non-contrast CT KUB – Axial view",
answerTitle: "Answer 1: Nephrolithiasis with Hydronephrosis",
diagnosis: "Left renal calculus with secondary hydronephrosis",
findings: [
"Hyperdense calculus (~12.7 × 9.8 mm) in the lower pole of the left kidney",
"Dilated renal pelvis / UPJ indicating obstructive hydronephrosis",
"Surrounding perirenal stranding may indicate ureteric obstruction"
],
teaching: "CT KUB (non-contrast) is the gold-standard for urolithiasis. Stones appear hyperdense (>100 HU). Look for secondary hydroureteronephrosis proximal to obstruction.",
source: "Grainger & Allison's Diagnostic Radiology"
},
{
qNum: 2,
title: "Question 2",
scenario: "A 58-year-old male presents with painless haematuria for 3 months. Contrast-enhanced CT abdomen is performed. He is a heavy smoker.",
prompt: "What is the most likely diagnosis? Name the cell type and the key imaging feature that suggests it.",
imageUrl: "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_e828b315918232abd7bcc3cc4b1a125e4777d9a8a4e246c310d8250d794a2455.jpg",
imageCaption: "Multi-phase CT abdomen – Left renal mass",
answerTitle: "Answer 2: Renal Cell Carcinoma (Clear Cell)",
diagnosis: "Clear cell renal cell carcinoma (ccRCC)",
findings: [
"Well-circumscribed solid renal mass causing contour lobulation",
"Marked heterogeneous enhancement in corticomedullary phase (hypervascular)",
"Washout of contrast in nephrographic & excretory phase",
"Internal areas of necrosis/varying attenuation"
],
teaching: "ccRCC is the most common subtype (~75%). The hallmark is avid enhancement then washout on multiphasic CT. Enhancement >20 HU from non-contrast to post-contrast phase is suspicious.",
source: "Grainger & Allison's Diagnostic Radiology"
},
{
qNum: 3,
title: "Question 3",
scenario: "A 6-year-old boy presents with an abdominal mass discovered incidentally by his mother. CT abdomen with contrast is shown. He is otherwise well with no fever.",
prompt: "What is the diagnosis? What is the peak age of presentation and the typical staging investigation?",
imageUrl: "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_c9167f7579996d0d5fec975f8e4848b31abbd4a3d8870e2f0886f1ce48491232.jpg",
imageCaption: "Contrast-enhanced CT abdomen – Paediatric",
answerTitle: "Answer 3: Wilms Tumour (Nephroblastoma)",
diagnosis: "Nephroblastoma (Wilms tumour) – left kidney",
findings: [
"Large, homogeneous solid mass replacing left renal architecture",
"Measures ~82 mm – significant mass effect on adjacent structures",
"Right kidney normal – no contralateral involvement",
"No evidence of vascular invasion in this image"
],
teaching: "Most common renal malignancy in children (peak 2–5 years). CT chest/abdomen/pelvis is used for staging. 10% bilateral. Associated with WAGR syndrome, Beckwith-Wiedemann syndrome.",
source: "Grainger & Allison's Diagnostic Radiology"
},
{
qNum: 4,
title: "Question 4",
scenario: "A 40-year-old woman with a known history of tuberous sclerosis complex undergoes routine CT surveillance. An incidental renal lesion is found.",
prompt: "What is this lesion? What is the characteristic CT finding that allows confident diagnosis?",
imageUrl: "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_e97bda69dbfa596835acf12230b96b2f0a392f6865f876b11bad9fed36bffcb0.jpg",
imageCaption: "Contrast-enhanced CT – Right renal mass",
answerTitle: "Answer 4: Renal Angiomyolipoma (AML)",
diagnosis: "Renal angiomyolipoma (AML) – right kidney",
findings: [
"Large heterogeneous renal mass with MACROSCOPIC FAT density areas",
"Fat attenuation values (< −10 HU) on non-contrast CT",
"Mixed attenuation: fat + soft tissue (smooth muscle + vessels)",
"Tumour distorting renal parenchyma extending into perirenal space"
],
teaching: "Macroscopic fat within a renal mass on CT is virtually pathognomonic of AML. Associated with tuberous sclerosis in ~20%. Risk of spontaneous haemorrhage (Wunderlich syndrome) if >4 cm. Embolisation is first-line treatment for bleeding AML.",
source: "Grainger & Allison's Diagnostic Radiology"
},
{
qNum: 5,
title: "Question 5",
scenario: "A 35-year-old man with a family history of renal disease presents with hypertension, bilateral flank pain and progressive renal impairment. Ultrasound and MRI are performed.",
prompt: "What is the diagnosis? Name the gene mutations involved and ONE systemic complication.",
imageUrl: "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_4cd9b55ccace7b3d5770456f3d8c9b898592e5fa67ddf65078e004246c5bac28.jpg",
imageCaption: "Multi-modal imaging – Ultrasound, CT and MRI",
answerTitle: "Answer 5: Autosomal Dominant Polycystic Kidney Disease (ADPKD)",
diagnosis: "ADPKD – bilateral multicystic nephromegaly",
findings: [
"US: bilateral enlarged kidneys with multiple anechoic cysts (architectural distortion)",
"CT: bilateral nephromegaly with countless hypodense cysts",
"MRI T1: hypointense cysts; T2: strikingly hyperintense cysts",
"Total kidney volume (TKV) expansion is a key biomarker"
],
teaching: "ADPKD caused by PKD1 (chr 16, 85%) or PKD2 (chr 4, 15%) mutations. Complications: intracranial berry aneurysms, hepatic cysts, mitral valve prolapse, hypertension. MRI TKV guides prognosis and tolvaptan therapy.",
source: "Grainger & Allison's Diagnostic Radiology"
},
{
qNum: 6,
title: "Question 6",
scenario: "A 65-year-old man presents with difficulty urinating, nocturia × 4, and a palpable bladder on examination. T2-weighted MRI pelvis is shown.",
prompt: "What does the MRI demonstrate? Describe how to measure the prostate volume on imaging.",
imageUrl: "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_899dadeeda93c18bb17f25c3fec7ea87787ff8f02a534335569dea30053c4c73.jpg",
imageCaption: "T2-weighted sagittal MRI – Male pelvis",
answerTitle: "Answer 6: Benign Prostatic Hyperplasia (BPH) with Middle Lobe",
diagnosis: "Benign prostatic hyperplasia with significant middle lobe hypertrophy",
findings: [
"Markedly enlarged prostate with heterogeneous T2 signal",
"Prominent intravesical protrusion of the prostatic middle lobe",
"Displacement of bladder neck and distortion of bladder base",
"No evidence of extracapsular extension"
],
teaching: "Prostate volume = (π/6) × AP × width × length (ellipsoid formula). Normal <30 mL. Intravesical prostatic protrusion (IPP) >10 mm predicts poor outcome with medical treatment. mpMRI with PI-RADS scoring used to exclude concurrent malignancy.",
source: "Grainger & Allison's Diagnostic Radiology"
},
{
qNum: 7,
title: "Question 7",
scenario: "A 55-year-old woman presents with haematuria and recurrent UTIs. Contrast-enhanced CT urogram is shown. Cystoscopy confirmed a mucosal lesion.",
prompt: "What is the diagnosis? Name the histological type and the most important prognostic factor.",
imageUrl: "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_95ef019a0510d081d8d716c94b1beef8e55c9fcff9f1930de8ceb51293e688f6.jpg",
imageCaption: "Contrast-enhanced CT pelvis – Bladder lesion",
answerTitle: "Answer 7: Bladder Cancer (Transitional Cell Carcinoma)",
diagnosis: "Transitional cell carcinoma (urothelial carcinoma) of the bladder",
findings: [
"Low-attenuation lobulated intraluminal mass at anterior-inferior bladder wall",
"Peripheral calcification/hyperdense outlining of lesion on axial view",
"Multifocal appearance suggesting synchronous lesions",
"Assessment of perivesical fat for extravesical extension is key"
],
teaching: "TCC is the most common bladder cancer (>90%). Key prognostic factor: muscle invasion (T2+). CT urography is standard for staging. Cystoscopy + TURBT is diagnostic and therapeutic for non-muscle invasive disease. Risk factors: smoking, aniline dyes, cyclophosphamide.",
source: "Grainger & Allison's Diagnostic Radiology"
},
{
qNum: 8,
title: "Question 8",
scenario: "A 25-year-old male presents to ED with sudden-onset severe right scrotal pain that began 3 hours ago. Colour Doppler ultrasound is performed urgently.",
prompt: "What is the diagnosis? What is the critical time window for surgical intervention?",
imageUrl: "https://cdn.orris.care/cdss_images/BAILY_1760538362600_48f4eb0e-0ab6-43c5-a70c-7b41658a20df.png",
imageCaption: "Colour Doppler Ultrasound – Bilateral testes",
answerTitle: "Answer 8: Testicular Torsion",
diagnosis: "Right testicular torsion – absent intratesticular blood flow",
findings: [
"Complete absence of Doppler flow signal in right testis",
"Left testis shows normal bilateral red/blue flow signals",
"Asymmetric perfusion is the hallmark of torsion",
"'Whirlpool sign' of spermatic cord may be seen"
],
teaching: "Surgical emergency. Salvage rate: ~100% if explored <6 hrs; ~50% at 12–24 hrs; near 0% at >24 hrs. Bell-clapper deformity is predisposing anatomy. Bilateral orchidopexy is performed at the same sitting. Do NOT delay surgery for imaging if clinical suspicion is high.",
source: "Bailey & Love's Short Practice of Surgery, 28th Ed."
},
{
qNum: 9,
title: "Question 9",
scenario: "An IVU (intravenous urogram) is performed in a 30-year-old male investigated for recurrent urinary tract infections. The image is shown.",
prompt: "What congenital anomaly is demonstrated? Where do the kidneys fuse and what vessel prevents ascent?",
imageUrl: "https://cdn.orris.care/cdss_images/roco_radiology_ROCO_19517_1766647158992.png",
imageCaption: "Intravenous Urogram (IVU) – Abdomen/pelvis",
answerTitle: "Answer 9: Horseshoe Kidney with PUJ Obstruction",
diagnosis: "Horseshoe kidney – lower pole fusion; right-sided PUJ obstruction",
findings: [
"Both kidneys show abnormal vertical axis with medially oriented lower poles",
"Lower poles fused across the midline anterior to the spine",
"Right collecting system: dilated blunted calyces – hydronephrosis",
"Left collecting system: normal morphology with contrast in ureter"
],
teaching: "Most common renal fusion anomaly (1:400). Lower poles fuse anterior to aorta; inferior mesenteric artery prevents full ascent. Associated complications: PUJ obstruction, stones, infection, risk of trauma. Diagnosed on IVU, CT or USS.",
source: "Grainger & Allison's Diagnostic Radiology"
},
{
qNum: 10,
title: "Question 10",
scenario: "A 50-year-old man presents with elevated PSA (12.8 ng/mL). Multiparametric MRI (mpMRI) prostate is performed, showing this result. No focal lesion or restricted diffusion is identified.",
prompt: "What is the PI-RADS score? What does a PI-RADS 1 score indicate clinically?",
imageUrl: "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_418d01814cb00393b0ff0074964319571db1365a47f5f804ac3dd1cb0d8f7be1.jpg",
imageCaption: "mpMRI Prostate – T2W, DWI/ADC, DCE sequences",
answerTitle: "Answer 10: BPH on mpMRI – PI-RADS 1",
diagnosis: "Enlarged prostate with BPH – PI-RADS v2.1 category 1",
findings: [
"T2W: heterogeneous enlarged transition zone – BPH nodules, volume ~151 mL",
"ADC map: no focal restricted diffusion (no low-signal areas)",
"DCE: no suspicious focal contrast-enhancing lesion",
"PI-RADS 1 = very low likelihood of clinically significant cancer"
],
teaching: "PI-RADS v2.1: 1 = very low risk; 2 = low; 3 = equivocal; 4 = high; 5 = very high. mpMRI sequences: T2W (anatomy), DWI/ADC (cellularity), DCE (vascularity). mpMRI can avoid unnecessary biopsy in PI-RADS 1–2. Used alongside PSA density and clinical risk.",
source: "Grainger & Allison's Diagnostic Radiology"
}
];
// ─── Helper: fetch images as base64 ──────────────────────────────
function fetchImages(urls) {
const result = execSync(
`node /home/daytona/skills/shared/scripts/fetch_images.js ${urls.map(u => `"${u}"`).join(" ")}`
).toString();
return JSON.parse(result);
}
// Fetch all images
console.log("Fetching images...");
const allUrls = questions.map(q => q.imageUrl);
const imgData = fetchImages(allUrls);
const imgMap = {};
imgData.forEach(item => { imgMap[item.url] = item; });
console.log("Images fetched:", imgData.filter(i => !i.error).length, "/ ", imgData.length);
// ─── Build presentation ───────────────────────────────────────────
let pres = new pptxgen();
pres.layout = "LAYOUT_16x9";
pres.title = "Genitourinary Radiology OSCE";
pres.author = "Radiology OSCE Bank";
// ────────────────────────────────────────────────────────────────
// TITLE SLIDE
// ────────────────────────────────────────────────────────────────
{
let sl = pres.addSlide();
sl.background = { color: DARK_BG };
// Top accent bar
sl.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: 10, h: 0.08, fill: { color: ACCENT } });
// Kidney icon graphic as decorative circles
sl.addShape(pres.ShapeType.ellipse, { x: 7.8, y: 1.0, w: 1.8, h: 2.6, fill: { color: "0E2340" }, line: { color: ACCENT, width: 2 } });
sl.addShape(pres.ShapeType.ellipse, { x: 8.0, y: 1.2, w: 0.8, h: 2.0, fill: { color: "0A1628" }, line: { color: ACCENT, width: 1 } });
sl.addText("GENITOURINARY SYSTEM", {
x: 0.5, y: 0.8, w: 7.2, h: 0.7,
fontSize: 11, bold: true, color: ACCENT, charSpacing: 4,
fontFace: "Arial"
});
sl.addText("Radiology OSCE", {
x: 0.5, y: 1.5, w: 7.2, h: 1.4,
fontSize: 44, bold: true, color: WHITE,
fontFace: "Arial"
});
sl.addText("10 Image-Based Questions", {
x: 0.5, y: 2.9, w: 7.2, h: 0.6,
fontSize: 22, color: PALE_GRAY,
fontFace: "Arial"
});
sl.addShape(pres.ShapeType.rect, { x: 0.5, y: 3.65, w: 3.5, h: 0.04, fill: { color: ACCENT2 } });
sl.addText("Kidney • Ureter • Bladder • Prostate • Scrotum", {
x: 0.5, y: 3.85, w: 9, h: 0.5,
fontSize: 14, color: PALE_GRAY, fontFace: "Arial"
});
sl.addText("Source: Grainger & Allison's Diagnostic Radiology", {
x: 0.5, y: 5.0, w: 9, h: 0.35,
fontSize: 10, color: "4A6080", fontFace: "Arial", italic: true
});
sl.addShape(pres.ShapeType.rect, { x: 0, y: 5.545, w: 10, h: 0.08, fill: { color: ACCENT } });
}
// ────────────────────────────────────────────────────────────────
// QUESTION + ANSWER SLIDES (pairs)
// ────────────────────────────────────────────────────────────────
questions.forEach((q, idx) => {
const img = imgMap[q.imageUrl];
const hasImage = img && !img.error;
// ── QUESTION SLIDE ──────────────────────────────────────────
{
let sl = pres.addSlide();
sl.background = { color: DARK_BG };
sl.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: 10, h: 0.06, fill: { color: ACCENT } });
// Question number badge
sl.addShape(pres.ShapeType.rect, { x: 0.35, y: 0.18, w: 1.0, h: 0.48, fill: { color: ACCENT }, rounding: true });
sl.addText(`Q${q.qNum}`, {
x: 0.35, y: 0.18, w: 1.0, h: 0.48,
fontSize: 18, bold: true, color: DARK_BG, align: "center", valign: "middle", fontFace: "Arial"
});
// Title
sl.addText(q.title.toUpperCase(), {
x: 1.5, y: 0.22, w: 8.2, h: 0.4,
fontSize: 10, bold: true, color: ACCENT, charSpacing: 3, fontFace: "Arial"
});
// Image (left panel)
if (hasImage) {
sl.addImage({ data: img.base64, x: 0.3, y: 0.82, w: 4.6, h: 3.6 });
sl.addText(q.imageCaption, {
x: 0.3, y: 4.45, w: 4.6, h: 0.3,
fontSize: 8.5, color: PALE_GRAY, italic: true, align: "center", fontFace: "Arial"
});
} else {
sl.addShape(pres.ShapeType.rect, { x: 0.3, y: 0.82, w: 4.6, h: 3.6, fill: { color: "0E2340" }, line: { color: ACCENT, width: 1 } });
sl.addText("Image Unavailable", { x: 0.3, y: 2.2, w: 4.6, h: 0.5, fontSize: 12, color: PALE_GRAY, align: "center" });
}
// Divider line
sl.addShape(pres.ShapeType.line, { x: 5.2, y: 0.82, w: 0, h: 4.2, line: { color: ACCENT, width: 0.8 } });
// Clinical scenario label
sl.addText("CLINICAL SCENARIO", {
x: 5.4, y: 0.82, w: 4.3, h: 0.28,
fontSize: 8, bold: true, color: ACCENT, charSpacing: 2, fontFace: "Arial"
});
sl.addText(q.scenario, {
x: 5.4, y: 1.12, w: 4.3, h: 1.5,
fontSize: 11.5, color: WHITE, fontFace: "Arial",
valign: "top", wrap: true
});
// Prompt box
sl.addShape(pres.ShapeType.rect, { x: 5.4, y: 2.75, w: 4.3, h: 0.06, fill: { color: ACCENT2 } });
sl.addText("QUESTION", {
x: 5.4, y: 2.85, w: 4.3, h: 0.28,
fontSize: 8, bold: true, color: ACCENT2, charSpacing: 2, fontFace: "Arial"
});
sl.addText(q.prompt, {
x: 5.4, y: 3.15, w: 4.3, h: 1.0,
fontSize: 12.5, bold: true, color: WHITE, fontFace: "Arial",
valign: "top", wrap: true
});
sl.addShape(pres.ShapeType.rect, { x: 0, y: 5.545, w: 10, h: 0.08, fill: { color: ACCENT } });
sl.addText(`Genitourinary Radiology OSCE | Q${q.qNum} of 10`, {
x: 0.3, y: 5.28, w: 9.4, h: 0.26,
fontSize: 8, color: "3A5070", align: "right", fontFace: "Arial"
});
}
// ── ANSWER SLIDE ─────────────────────────────────────────────
{
let sl = pres.addSlide();
sl.background = { color: LIGHT_BG };
sl.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: 10, h: 0.06, fill: { color: ACCENT2 } });
// Answer badge
sl.addShape(pres.ShapeType.rect, { x: 0.35, y: 0.18, w: 1.0, h: 0.48, fill: { color: ACCENT2 }, rounding: true });
sl.addText(`A${q.qNum}`, {
x: 0.35, y: 0.18, w: 1.0, h: 0.48,
fontSize: 18, bold: true, color: DARK_BG, align: "center", valign: "middle", fontFace: "Arial"
});
sl.addText(q.answerTitle.toUpperCase(), {
x: 1.5, y: 0.22, w: 8.2, h: 0.4,
fontSize: 10, bold: true, color: ACCENT2, charSpacing: 2, fontFace: "Arial"
});
// Diagnosis box
sl.addShape(pres.ShapeType.rect, { x: 0.35, y: 0.8, w: 9.3, h: 0.52, fill: { color: "0A2A1A" }, line: { color: ACCENT, width: 1 } });
sl.addText("DIAGNOSIS: " + q.diagnosis, {
x: 0.5, y: 0.8, w: 9.0, h: 0.52,
fontSize: 13, bold: true, color: ACCENT, valign: "middle", fontFace: "Arial"
});
// Left: Thumbnail image
if (hasImage) {
sl.addImage({ data: img.base64, x: 0.35, y: 1.48, w: 3.0, h: 2.3 });
} else {
sl.addShape(pres.ShapeType.rect, { x: 0.35, y: 1.48, w: 3.0, h: 2.3, fill: { color: "0E2340" }, line: { color: ACCENT, width: 1 } });
}
// Right: Findings
sl.addText("KEY RADIOLOGICAL FINDINGS", {
x: 3.6, y: 1.48, w: 6.0, h: 0.3,
fontSize: 8.5, bold: true, color: ACCENT, charSpacing: 2, fontFace: "Arial"
});
const findingItems = q.findings.map((f, i) => ({
text: f,
options: { bullet: { type: "number" }, color: WHITE, fontSize: 10.5, breakLine: i < q.findings.length - 1 }
}));
sl.addText(findingItems, {
x: 3.6, y: 1.82, w: 6.0, h: 1.9,
fontFace: "Arial", valign: "top"
});
// Teaching point
sl.addShape(pres.ShapeType.rect, { x: 0.35, y: 3.9, w: 9.3, h: 0.04, fill: { color: ACCENT2 } });
sl.addText("TEACHING POINT", {
x: 0.35, y: 4.0, w: 9.3, h: 0.28,
fontSize: 8, bold: true, color: ACCENT2, charSpacing: 2, fontFace: "Arial"
});
sl.addText(q.teaching, {
x: 0.35, y: 4.3, w: 9.3, h: 0.85,
fontSize: 10.5, color: PALE_GRAY, fontFace: "Arial", valign: "top", wrap: true, italic: true
});
sl.addShape(pres.ShapeType.rect, { x: 0, y: 5.545, w: 10, h: 0.08, fill: { color: ACCENT2 } });
sl.addText(`Source: ${q.source} | Genitourinary OSCE Answer ${q.qNum}`, {
x: 0.3, y: 5.28, w: 9.4, h: 0.26,
fontSize: 8, color: "3A5070", align: "right", fontFace: "Arial"
});
}
});
// ─── Write file ───────────────────────────────────────────────────
const outPath = "/home/daytona/workspace/gu-radiology-osce/GU_Radiology_OSCE_10Q.pptx";
pres.writeFile({ fileName: outPath }).then(() => {
console.log("✅ Saved:", outPath);
}).catch(err => {
console.error("Error:", err);
process.exit(1);
});
cd /home/daytona/workspace/gu-radiology-osce && node build_pptx.js 2>&1
ls -lh /home/daytona/workspace/gu-radiology-osce/GU_Radiology_OSCE_10Q.pptx
GU Radiology OSCE 10Q
Presentation · PPTX
| # | Topic | Modality | Key Teaching Point |
|---|---|---|---|
| 1 | Nephrolithiasis + Hydronephrosis | Non-contrast CT KUB | Hyperdense stone + dilated pelvis; CT is gold standard |
| 2 | Clear Cell Renal Cell Carcinoma | Multi-phase CT | Hypervascular enhancement then washout |
| 3 | Wilms Tumour (Nephroblastoma) | Contrast CT – paediatric | Most common renal malignancy in children 2–5 yrs |
| 4 | Renal Angiomyolipoma | CT abdomen | Macroscopic fat (<−10 HU) is pathognomonic |
| 5 | ADPKD | US + CT + MRI (T1/T2) | PKD1/PKD2 mutations; total kidney volume (TKV) biomarker |
| 6 | BPH with Middle Lobe | T2W sagittal MRI | Intravesical protrusion; ellipsoid volume formula |
| 7 | Bladder TCC | Contrast CT urogram | Muscle invasion (T2+) is key prognostic factor |
| 8 | Testicular Torsion | Colour Doppler USS | Absent ipsilateral flow; surgical emergency <6 hrs |
| 9 | Horseshoe Kidney + PUJ Obstruction | IVU | Lower pole fusion; inferior mesenteric artery prevents ascent |
| 10 | Prostate mpMRI – PI-RADS 1 | T2W + DWI + DCE | PI-RADS scoring; avoiding unnecessary biopsy |
Fast
.pptx fileGenerate a PDF quick-reference card for the GU presentation
~/gu-radiology-osce/build_refcard.py
"""
GU Radiology OSCE – Quick Reference Card (2 pages A4)
Uses ReportLab only.
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.platypus import (
SimpleDocTemplate, Table, TableStyle, Paragraph,
Spacer, HRFlowable, KeepTogether
)
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER
from reportlab.platypus import BaseDocTemplate, PageTemplate, Frame
# ── Palette ────────────────────────────────────────────────────────
NAVY = colors.HexColor("#0A1628")
TEAL = colors.HexColor("#00C9A7")
AMBER = colors.HexColor("#F4A261")
WHITE = colors.white
PALE = colors.HexColor("#B0BEC5")
LIGHT_ROW = colors.HexColor("#0E1E38")
ALT_ROW = colors.HexColor("#0A1E30")
TEXT_DARK = colors.HexColor("#1A2B3C")
W, H = A4 # 210 × 297 mm
# ── Styles ─────────────────────────────────────────────────────────
def sty(name, **kw):
base = dict(fontName="Helvetica", fontSize=9, leading=12,
textColor=colors.HexColor("#FFFFFF"), spaceAfter=2)
base.update(kw)
return ParagraphStyle(name, **base)
S_TITLE = sty("title", fontName="Helvetica-Bold", fontSize=22, textColor=TEAL, leading=26, spaceAfter=4)
S_SUB = sty("sub", fontName="Helvetica-Bold", fontSize=11, textColor=AMBER, leading=14, spaceAfter=2)
S_BODY = sty("body", fontName="Helvetica", fontSize=8, textColor=WHITE, leading=11, spaceAfter=1)
S_LABEL = sty("label", fontName="Helvetica-Bold", fontSize=7.5,textColor=TEAL, leading=10, spaceAfter=1)
S_TEACH = sty("teach", fontName="Helvetica-Oblique", fontSize=7.5, textColor=PALE, leading=10, spaceAfter=1)
S_HDR = sty("hdr", fontName="Helvetica-Bold", fontSize=8, textColor=NAVY, leading=10)
S_CELL = sty("cell", fontName="Helvetica", fontSize=7.5,textColor=WHITE, leading=10)
S_CELLB = sty("cellb", fontName="Helvetica-Bold", fontSize=7.5,textColor=TEAL, leading=10)
S_DIAG = sty("diag", fontName="Helvetica-Bold", fontSize=8, textColor=AMBER, leading=10)
S_SMALL = sty("small", fontName="Helvetica", fontSize=6.5,textColor=PALE, leading=9)
S_QNUM = sty("qnum", fontName="Helvetica-Bold", fontSize=10, textColor=NAVY, leading=12)
# ── Content data ───────────────────────────────────────────────────
questions = [
{
"n": "Q1", "topic": "Nephrolithiasis + Hydronephrosis",
"modality": "CT KUB (non-contrast)",
"scenario": "45M, severe loin-to-groin pain, haematuria",
"diagnosis": "Left renal calculus with obstructive hydronephrosis",
"findings": "Hyperdense calculus ~12.7 mm lower pole left kidney; dilated renal pelvis/UPJ; perirenal stranding",
"teaching": "CT KUB is gold standard. Stones >100 HU. Always look for secondary hydroureteronephrosis proximal to obstruction.",
},
{
"n": "Q2", "topic": "Renal Cell Carcinoma (Clear Cell)",
"modality": "Multi-phase contrast CT abdomen",
"scenario": "58M, painless haematuria 3/12, heavy smoker",
"diagnosis": "Clear cell RCC – left kidney",
"findings": "Solid renal mass; marked heterogeneous enhancement corticomedullary phase; washout nephrographic phase; areas of necrosis",
"teaching": "ccRCC (~75% of RCC). Hallmark: avid enhancement then washout. Enhancement >20 HU non-contrast→post-contrast is suspicious.",
},
{
"n": "Q3", "topic": "Wilms Tumour (Nephroblastoma)",
"modality": "Contrast CT abdomen – paediatric",
"scenario": "6-year-old, incidental abdominal mass, well child",
"diagnosis": "Nephroblastoma – left kidney (82 mm)",
"findings": "Large homogeneous solid mass replacing left renal architecture; mass effect on adjacent structures; normal contralateral kidney",
"teaching": "Most common paediatric renal malignancy, peak 2–5 yrs. 10% bilateral. Associated: WAGR, Beckwith-Wiedemann syndromes. CT chest/abdomen/pelvis for staging.",
},
{
"n": "Q4", "topic": "Renal Angiomyolipoma",
"modality": "Contrast CT abdomen",
"scenario": "40F, tuberous sclerosis complex, routine surveillance",
"diagnosis": "Renal AML – right kidney (fat-containing)",
"findings": "Heterogeneous renal mass; macroscopic fat attenuation areas (<−10 HU); mixed fat + soft-tissue components; perirenal extension",
"teaching": "Macroscopic CT fat is virtually pathognomonic of AML. ~20% associated with tuberous sclerosis. Risk of Wunderlich syndrome if >4 cm → embolisation.",
},
{
"n": "Q5", "topic": "ADPKD",
"modality": "Ultrasound + CT + MRI (T1 & T2)",
"scenario": "35M, FHx renal disease, hypertension, rising creatinine",
"diagnosis": "Autosomal Dominant Polycystic Kidney Disease",
"findings": "US: bilateral nephromegaly, multiple anechoic cysts; CT: countless hypodense cysts; MRI T1: hypointense cysts; T2: hyperintense cysts",
"teaching": "PKD1 (chr16, 85%) or PKD2 (chr4, 15%). Complications: intracranial aneurysms, hepatic cysts, MVP, HTN. TKV guides tolvaptan therapy.",
},
{
"n": "Q6", "topic": "Benign Prostatic Hyperplasia",
"modality": "T2W sagittal MRI – male pelvis",
"scenario": "65M, nocturia ×4, difficulty voiding, palpable bladder",
"diagnosis": "BPH with significant middle lobe hypertrophy",
"findings": "Markedly enlarged prostate, heterogeneous T2 signal; intravesical middle lobe protrusion; displacement of bladder neck",
"teaching": "Prostate volume = (π/6) × AP × width × length. Normal <30 mL. Intravesical prostatic protrusion >10 mm → poor response to medical therapy.",
},
{
"n": "Q7", "topic": "Bladder TCC (Urothelial Carcinoma)",
"modality": "Contrast CT urogram",
"scenario": "55F, haematuria + recurrent UTIs, cystoscopy: mucosal lesion",
"diagnosis": "Transitional cell carcinoma – bladder",
"findings": "Low-attenuation lobulated intraluminal mass anterior bladder wall; peripheral calcification; multifocal lesions; assess perivesical fat for T3",
"teaching": "TCC >90% of bladder cancers. Key prognostic factor: muscle invasion (T2+). CT urography for staging. Risk factors: smoking, aniline dyes, cyclophosphamide.",
},
{
"n": "Q8", "topic": "Testicular Torsion",
"modality": "Colour Doppler Ultrasound",
"scenario": "25M, sudden severe right scrotal pain 3 hrs ago",
"diagnosis": "Right testicular torsion – absent intratesticular flow",
"findings": "Complete absence of Doppler signal right testis; normal bilateral flow left testis; asymmetric perfusion; 'whirlpool sign' spermatic cord",
"teaching": "SURGICAL EMERGENCY. Salvage: ~100% <6 hrs; ~50% at 12–24 hrs; ~0% >24 hrs. Bell-clapper deformity predisposes. Bilateral orchidopexy at same sitting.",
},
{
"n": "Q9", "topic": "Horseshoe Kidney + PUJ Obstruction",
"modality": "Intravenous Urogram (IVU)",
"scenario": "30M, recurrent UTIs, investigated for congenital anomaly",
"diagnosis": "Horseshoe kidney with right-sided PUJ obstruction",
"findings": "Abnormal axis both kidneys; lower poles fused midline anterior to spine; right: dilated blunted calyces (hydronephrosis); left: normal drainage",
"teaching": "Most common renal fusion anomaly (1:400). IMA prevents full ascent. Complications: PUJ obstruction, calculi, infection, trauma risk.",
},
{
"n": "Q10", "topic": "Prostate mpMRI – PI-RADS 1",
"modality": "mpMRI: T2W + DWI/ADC + DCE",
"scenario": "50M, elevated PSA 12.8 ng/mL, no palpable lesion",
"diagnosis": "BPH – PI-RADS v2.1 category 1 (very low risk)",
"findings": "T2W: enlarged heterogeneous transition zone, BPH nodules, vol ~151 mL; ADC: no restricted diffusion; DCE: no focal enhancement",
"teaching": "PI-RADS 1=very low; 2=low; 3=equivocal; 4=high; 5=very high. mpMRI avoids unnecessary biopsy in PI-RADS 1–2. Consider PSA density + clinical risk.",
},
]
# ── Build PDF ──────────────────────────────────────────────────────
OUT = "/home/daytona/workspace/gu-radiology-osce/GU_Radiology_OSCE_QuickRef.pdf"
doc = SimpleDocTemplate(
OUT,
pagesize=A4,
leftMargin=12*mm, rightMargin=12*mm,
topMargin=14*mm, bottomMargin=12*mm,
title="GU Radiology OSCE – Quick Reference",
author="Radiology OSCE Bank",
)
# Background canvas callback
def on_page(canvas, doc):
canvas.saveState()
canvas.setFillColor(NAVY)
canvas.rect(0, 0, W, H, fill=1, stroke=0)
# Header bar
canvas.setFillColor(TEAL)
canvas.rect(0, H - 10*mm, W, 10*mm, fill=1, stroke=0)
canvas.setFont("Helvetica-Bold", 10)
canvas.setFillColor(NAVY)
canvas.drawCentredString(W/2, H - 7*mm, "GU RADIOLOGY OSCE • QUICK REFERENCE CARD")
# Footer bar
canvas.setFillColor(TEAL)
canvas.rect(0, 0, W, 7*mm, fill=1, stroke=0)
canvas.setFont("Helvetica", 7)
canvas.setFillColor(NAVY)
canvas.drawString(14*mm, 2.5*mm, "Source: Grainger & Allison's Diagnostic Radiology | Radiology OSCE Bank")
canvas.drawRightString(W - 14*mm, 2.5*mm, f"Page {doc.page}")
canvas.restoreState()
# ── Story ──────────────────────────────────────────────────────────
story = []
# Title block
story.append(Paragraph("Genitourinary System", S_TITLE))
story.append(Paragraph("10-Station OSCE • Image-Based Questions • Diagnoses & Teaching Points", S_SUB))
story.append(HRFlowable(width="100%", thickness=1, color=AMBER, spaceAfter=6))
# Build table rows
col_w = [10*mm, 30*mm, 28*mm, 23*mm, 50*mm, 38*mm]
# Total = 179mm — fits within 186mm usable width; adjust last col
col_w = [10*mm, 32*mm, 28*mm, 24*mm, 48*mm, 40*mm]
header = [
Paragraph("#", S_HDR),
Paragraph("Topic", S_HDR),
Paragraph("Modality", S_HDR),
Paragraph("Scenario", S_HDR),
Paragraph("Key Findings", S_HDR),
Paragraph("Teaching Point", S_HDR),
]
rows = [header]
for i, q in enumerate(questions):
bg = LIGHT_ROW if i % 2 == 0 else ALT_ROW
row = [
Paragraph(q["n"], S_CELLB),
[Paragraph(q["topic"], S_CELLB), Paragraph(q["diagnosis"], S_DIAG)],
Paragraph(q["modality"], S_CELL),
Paragraph(q["scenario"], S_CELL),
Paragraph(q["findings"], S_CELL),
Paragraph(q["teaching"], S_TEACH),
]
rows.append(row)
tbl = Table(rows, colWidths=col_w, repeatRows=1)
tbl.setStyle(TableStyle([
# Header
("BACKGROUND", (0, 0), (-1, 0), TEAL),
("TEXTCOLOR", (0, 0), (-1, 0), NAVY),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, 0), 8),
("BOTTOMPADDING", (0, 0), (-1, 0), 5),
("TOPPADDING", (0, 0), (-1, 0), 5),
# Alternating rows
*[("BACKGROUND", (0, r), (-1, r), LIGHT_ROW if r % 2 == 1 else ALT_ROW)
for r in range(1, len(rows))],
# Padding all
("TOPPADDING", (0, 1), (-1, -1), 4),
("BOTTOMPADDING", (0, 1), (-1, -1), 4),
("LEFTPADDING", (0, 0), (-1, -1), 4),
("RIGHTPADDING", (0, 0), (-1, -1), 4),
# Grid
("LINEBELOW", (0, 0), (-1, 0), 0.5, TEAL),
("LINEBELOW", (0, 1), (-1, -1), 0.3, colors.HexColor("#1A3050")),
("VALIGN", (0, 0), (-1, -1), "TOP"),
# Q# column highlight
("BACKGROUND", (0, 1), (0, -1), colors.HexColor("#0A2A3A")),
("ALIGN", (0, 0), (0, -1), "CENTER"),
]))
story.append(tbl)
story.append(Spacer(1, 6*mm))
# Bottom quick-lookup strip: modalities at a glance
story.append(HRFlowable(width="100%", thickness=1, color=TEAL, spaceAfter=4))
story.append(Paragraph("MODALITY QUICK-LOOKUP", sty("ml", fontName="Helvetica-Bold", fontSize=8, textColor=TEAL, leading=11)))
story.append(Spacer(1, 2*mm))
modal_data = [
["CT KUB (non-contrast)", "First-line for urolithiasis. Stones >100 HU. Assess for hydroureteronephrosis."],
["Multi-phase CT abdomen", "Non-contrast → corticomedullary → nephrographic → excretory. RCC: avid enhancement + washout."],
["Contrast CT urogram", "Gold standard for urothelial tumours. Assess bladder, ureters, pelvicalyceal systems."],
["Ultrasound (renal)", "First-line in children & pregnancy. Assess size, echogenicity, hydronephrosis, cysts."],
["Colour Doppler USS (scrotum)", "Absent intratesticular flow = torsion until proven otherwise. Immediate surgery if high suspicion."],
["mpMRI prostate", "T2W (anatomy) + DWI/ADC (cellularity) + DCE (vascularity). PI-RADS 1–5 scoring."],
["IVU / IVP", "Demonstrates collecting system anatomy. Used for congenital anomalies, PUJ obstruction."],
["MRI (T2W renal)", "Cysts: hyperintense on T2. Best for complex cysts (Bosniak classification), ADPKD TKV."],
]
mcol = [46*mm, 136*mm]
mrows = [[Paragraph(r[0], sty("mk", fontName="Helvetica-Bold", fontSize=7.5, textColor=AMBER, leading=10)),
Paragraph(r[1], sty("mv", fontName="Helvetica", fontSize=7.5, textColor=WHITE, leading=10))]
for r in modal_data]
mtbl = Table(mrows, colWidths=mcol)
mtbl.setStyle(TableStyle([
*[("BACKGROUND", (0, r), (-1, r), LIGHT_ROW if r % 2 == 0 else ALT_ROW) for r in range(len(mrows))],
("TOPPADDING", (0, 0), (-1, -1), 3),
("BOTTOMPADDING", (0, 0), (-1, -1), 3),
("LEFTPADDING", (0, 0), (-1, -1), 5),
("RIGHTPADDING", (0, 0), (-1, -1), 5),
("LINEBELOW", (0, 0), (-1, -1), 0.25, colors.HexColor("#1A3050")),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("LINEAFTER", (0, 0), (0, -1), 0.5, TEAL),
]))
story.append(mtbl)
# Build
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print("✅ Saved:", OUT)
cd /home/daytona/workspace/gu-radiology-osce && python build_refcard.py 2>&1
ls -lh /home/daytona/workspace/gu-radiology-osce/GU_Radiology_OSCE_QuickRef.pdf
GU Radiology OSCE QuickRef
PDF Document · PDF
| Column | Content |
|---|---|
| # | Q1–Q10 badge |
| Topic | Bold topic + diagnosis in amber |
| Modality | Imaging technique used |
| Scenario | 1-line clinical vignette |
| Key Findings | Radiological signs to spot |
| Teaching Point | Italic exam-ready pearl |