I want to revise a drug per day. So, let's start with antibiotics. As, I am General practitioner, I want to revise and get updates on each drugs . What do u say?
Which antibiotic class or specific drug would you like to start with today? ยท How detailed should the revision be?
penicillin amoxicillin clinical use resistance
penicillin antibiotic 2025 2026 clinical updates resistance GP prescribing
penicillin beta-lactam mechanism of action bacterial cell wall

A medical pathophysiology diagram illustrating the mechanism of action of Catharanthus roseus root ethanolic extract (EECRR) in sensitizing multiple antibiotic-resistant Staphylococcus aureus (MAR-SA) to ampicillin. The flowchart transitions from left to right, starting with a bacterial colony of MAR-SA and a test tube representing the extract. It branches into two treatment pathways: 'Ampicillin + 1/2 MIC EECRR', which results in decreased cell viability, and 'Ampicillin + MIC EECRR', which leads to cell death (indicated by a red cross). The right side of the diagram provides a molecular level illustration of a MAR-SA cell. It demonstrates that the EECRR treatment inhibits penicillin-binding protein 2a (PBP2a), which normally blocks ampicillin. By suppressing PBP2a expression and causing plasmid DNA damage, the extract allows ampicillin to bind to PBP2, disrupting the bacterial cell wall integrity. Key labels include PBP2a, PBP2, ampicillin, plasmid, and DNA damage. This visual summarizes an antimicrobial research study on overcoming antibiotic resistance using botanical extracts.

A diagnostic biochemical image displaying a SDS-PAGE gel fluorescence scan from a Bocillin competition assay. The visual demonstrates the inhibition of Pseudomonas aeruginosa Penicillin-Binding Protein 3 (PBP3) by the cyclic boronate inhibitor, vaborbactam. The gel shows a series of horizontal protein bands representing PBP3 labeled with a fluorescent Bocillin reporter. From right to left, the lanes correspond to increasing concentrations of vaborbactam (0, 0.05, 0.1, 0.25, 0.5, 1.0, 1.25, 1.5, and 1.75 mM). A clear, concentration-dependent decrease in band intensity is visible; the highest fluorescence intensity is at 0 mM (absence of inhibitor), while the lowest intensity is observed at 1.75 mM. This trend illustrates competitive binding between vaborbactam and the fluorescent reporter for the PBP3 active site. The educational focus is on the biochemical validation of non-beta-lactam antibiotic inhibitors against bacterial cell wall synthesis targets.

This composite educational graphic presents a microbiology analysis of bacterial cell wall synthesis using autoradiography and grain distribution profiling. It consists of three panels (a, b, and c), each featuring an electron micrograph of Escherichia coli alongside a corresponding quantitative graph. Panels (a) and (b) demonstrate filamentous bacteria exhibiting abnormal cell morphology with multiple visible constrictions. The associated line graphs, which plot 'Grains / ยตm cell length' against 'Normalized cell length', show two distinct peaks labeled 'PIPS' (Penicillin-Insensitive Peptidoglycan Synthesis). These peaks correlate spatially with the cellular constrictions, indicating localized peptidoglycan incorporation sites when Penicillin-Binding Protein 3 (PBP3) is inhibited or non-functional. Panel (c) displays normally dividing bacterial cells with shorter, rod-shaped morphology. The corresponding graph shows a single, sharp central peak at a normalized cell length of 0.5, representing focused peptidoglycan synthesis at the standard mid-cell division site. This comparison highlights the topography of cell envelope growth and the distinction between normal septal synthesis and penicillin-insensitive mechanisms in cell division mutants.
Sources: Goodman & Gilman's Pharmacological Basis of Therapeutics | Katzung's Basic & Clinical Pharmacology 16e | CDC Antibiotic Stewardship Report 2025 | IDSA AMR Guidance 2026
| Class | Key Drugs | Spectrum |
|---|---|---|
| Natural penicillins | Penicillin G (IV), Penicillin V (oral), Benzathine Pen G (IM) | Narrow - Gram+, spirochetes |
| Antistaphylococcal | Oxacillin, Nafcillin, Dicloxacillin | Narrow - MSSA only |
| Aminopenicillins | Ampicillin, Amoxicillin | Broader - some Gram- added |
| + ฮฒ-lactamase inhibitor | Amoxicillin-Clavulanate (Co-amoxiclav), Ampicillin-Sulbactam | Broad - overcomes resistance |
| Antipseudomonal | Piperacillin-Tazobactam (Pip-Taz) | Extended Gram- + Pseudomonas |
| Parameter | Details |
|---|---|
| Absorption | Amoxicillin - good oral bioavailability (~80%), can be taken with food. Ampicillin and Pen V - 30-55%, must be given on empty stomach (1-2 hrs before or after meals) |
| Distribution | Widely distributed into tissues, joint/pleural/pericardial fluid, bile. Poor penetration into: CSF (normal meninges <1% of plasma), prostate, phagocytic cells, intraocular fluid. CSF penetration improves to ~5% with meningeal inflammation |
| Protein binding | Variable. Nafcillin/Dicloxacillin - highly protein-bound. Amoxicillin/Ampicillin - lower binding |
| Metabolism | Minimal hepatic metabolism. Nafcillin is the exception - primarily biliary excretion |
| Elimination | Predominantly renal - glomerular filtration AND tubular secretion. Short half-life: 30-90 minutes for most penicillins |
| Dose adjustment | Reduce dose in significant renal impairment (except Nafcillin) |
| Probenecid interaction | Blocks renal tubular secretion of penicillins โ prolongs half-life and raises drug levels. Still used occasionally for gonorrhoea or syphilis regimens |
| Indication | Adult Dose | Duration | Notes |
|---|---|---|---|
| Streptococcal pharyngitis | 500 mg TDS or 1g BD | 5-7 days | Still first-line; penicillin V is an option |
| Community-acquired pneumonia (mild, low-risk) | 1g TDS | 5 days | For suspected pneumococcal; use with azithromycin if atypicals suspected |
| Acute otitis media | 500 mg TDS | 5-7 days | High-dose 80-90 mg/kg/day in children |
| Acute sinusitis (bacterial) | 500 mg TDS | 5 days | Only for bacterial, not viral |
| H. pylori eradication | As part of triple/quadruple therapy | 10-14 days | See regimens below |
| Indication | Adult Dose | Duration |
|---|---|---|
| Otitis media (treatment failure/severe) | 625 mg TDS or 1g BD | 5-7 days |
| Exacerbation of chronic bronchitis | 625 mg TDS | 5 days |
| Sinusitis (with ฮฒ-lactamase risk) | 625 mg BD/TDS | 5 days |
| UTI (Co-amoxiclav, second-line) | 625 mg TDS | 7 days |
| Animal bites | 625 mg TDS | 5-7 days |
| Cellulitis (mild, community-acquired) | 625 mg TDS | 5-7 days |
2025-2026 Update (Wales/UK): National guidance now targets โฅ75% of amoxicillin prescriptions to be 5-day courses rather than 7 days. Evidence shows equivalent clinical outcomes with reduced antibiotic exposure and AMR risk. (GOV.Wales AMR 2025-2027)
| Indication | Dose | Schedule |
|---|---|---|
| Streptococcal pharyngitis | 1.2 million units IM | Single dose |
| Syphilis (primary/secondary/latent early <1yr) | 2.4 million units IM | Single dose |
| Syphilis (late latent/>1yr) | 2.4 million units IM | Weekly x 3 weeks |
| Rheumatic fever prophylaxis | 1.2 million units IM | Every 3-4 weeks |
| Mechanism | Details | Clinical Example |
|---|---|---|
| ฮฒ-lactamase production | Most common. Enzyme cleaves the ฮฒ-lactam ring | S. aureus, H. influenzae, E. coli. Overcome with clavulanate/sulbactam/tazobactam |
| Altered PBPs | PBP mutations reduce penicillin binding affinity | MRSA (PBP2a - mecA gene); Penicillin-resistant S. pneumoniae. ฮฒ-lactamase inhibitors do NOT help here |
| Efflux pumps / Reduced permeability | Drug pumped out or can't enter the cell | Gram-negative bacteria (P. aeruginosa); combined with ฮฒ-lactamase |
2026 IDSA AMR Guidance note: ESBLs (Extended-Spectrum ฮฒ-Lactamases) inactivate most penicillins, cephalosporins, and aztreonam. ESBL-producing Enterobacterales generally remain susceptible to carbapenems. (IDSA AMR Guidance 2026)
| Effect | Frequency | Details |
|---|---|---|
| Hypersensitivity reactions | Most important | Ranges from maculopapular rash (~5%) to urticaria, serum sickness, to life-threatening anaphylaxis (<0.05%) |
| GI disturbance | Common with Co-amoxiclav | Nausea, diarrhoea - especially clavulanate component. Take with food for Co-amoxiclav |
| C. difficile | Less common than clindamycin/FQ | Still a risk, especially in elderly/hospitalized |
| Neurotoxicity (rare) | High-dose IV | Seizures with very high doses (e.g., >20 MU/day penicillin G), especially in renal impairment |
| Haematological | Rare | Haemolytic anaemia, neutropaenia, thrombocytopaenia with prolonged use |
| Electrolyte disturbance | IV formulations | High-dose IV piperacillin can cause hypokalaemia |
| Drug | Interaction | Clinical Significance |
|---|---|---|
| Probenecid | Blocks tubular secretion โ raises penicillin levels | Used intentionally for syphilis/gonorrhoea regimens |
| Warfarin / Anticoagulants | Broad-spectrum penicillins alter gut flora โ reduce Vit K โ potentiate anticoagulation | Monitor INR |
| Oral contraceptives | Theoretical reduction in efficacy (old data, largely dismissed) | Advise per local guidance |
| Methotrexate | Penicillins reduce renal MTX excretion โ toxicity risk | Avoid combination or monitor MTX levels closely |
| Allopurinol | Increases incidence of ampicillin rash | Rash rate rises from 5% to ~20% |
PENICILLINS = "BLAST the Cell Wall"
B - Bactericidal (cell wall synthesis inhibitor)
L - ฮฒ-Lactam ring is the pharmacophore
A - Allergy is the #1 concern (anaphylaxis possible)
S - Spectrum varies by subclass (narrow โ broad)
T - Time-dependent killing (T > MIC is key PK/PD)
| Natural Pen | Aminopenicillins | Co-amoxiclav | Antistaphylococcal | |
|---|---|---|---|---|
| MRSA? | No | No | No | No (only MSSA) |
| Pseudomonas? | No | No | No | No |
| H. influenzae? | No | Some strains | Yes | No |
| S. aureus (MSSA)? | No (resist) | No | Yes | Yes (DOC) |
| Streptococci? | Yes (DOC) | Yes | Yes | Yes |
| Spirochetes? | Yes (DOC) | Yes | Yes | No |
Time-dependent killing (T > MIC is key PK/PD)- what does this mean?
antibiotic pharmacodynamics time-dependent concentration-dependent killing MIC graph
| Model | What drives killing | Key parameter | Examples |
|---|---|---|---|
| Time-dependent | How long drug stays above MIC | T > MIC | Penicillins, Cephalosporins, Carbapenems, Macrolides, Linezolid |
| Concentration-dependent | How high the peak goes vs. MIC | Cmax : MIC | Aminoglycosides, Fluoroquinolones |
| AUC-dependent | Total drug exposure over time vs. MIC | AUC : MIC | Vancomycin, Daptomycin, Fluoroquinolones |
Scenario A: Give a HUGE dose once
Drug level: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ (high peak, then drops below MIC)
โ MIC threshold
Effect: Kills bacteria during the high phase... then bacteria REGROW when drug drops
Scenario B: Give smaller doses MORE frequently (or spread out the same dose)
Drug level: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ MIC threshold
Effect: Drug stays above MIC for longer โ sustained bacterial killing โ
| ฮฒ-Lactam Group | Target (fT > MIC) | Meaning |
|---|---|---|
| Penicillins | 40-50% of dosing interval | Drug must be above MIC for โฅ40-50% of the time between doses |
| Cephalosporins | 60-70% of dosing interval | |
| Carbapenems | โฅ40% of dosing interval |
"f" stands for the free (unbound) fraction - only drug not bound to protein is active.
Dose at 8am โ 2pm โ 8pm (every 8 hours = 480 min dosing interval)
Drug concentration over 8 hours:
โ Peak
| \
| \
- - - - -|- - -------- โ MIC
| \
| \___ (falls below MIC near end of interval)
Time above MIC = ~4 hours out of 8 = 50% โ
(just hits target for penicillins)
๐ Penicillins: "Keep it dripping, not spiking" - it's the time spent above the MIC that kills bacteria, not how high the peak goes.
| ฮฒ-Lactams (Pen, Ceph) | Aminoglycosides (Gentamicin) | Vancomycin | |
|---|---|---|---|
| Key parameter | T > MIC | Cmax : MIC | AUC : MIC |
| Strategy | Dose frequently | Dose high, once daily | Monitor trough/AUC |
| Analogy | Slow sustained rain | One heavy downpour | Total rainfall over 24h |
Explain me the next two methods concentration and AUC dependent also like above.

Low peak dose (e.g. 3mg/kg):
โ Cmax (3x MIC)
| \
- - - - -|- -------- โ MIC
| \___
Effect: Some killing, bacteria may survive and regrow โ
High peak dose (e.g. 7mg/kg):
โ Cmax (10x MIC)
| \
| \
- - - - - - - - - -------- โ MIC
\___
Effect: Rapid, massive bacterial kill โ
PAE = Even after drug concentration drops BELOW the MIC, bacteria remain stunned and suppressed for 1-4 hours before they start regrowing.
Once-daily gentamicin: HIGH peak (kill) โ long trough (kidney recovery + PAE still working)
โ
LESS nephrotoxicity + BETTER killing โ
Three-times-daily gentamicin (old approach): lower peaks + sustained drug in kidney
โ
MORE nephrotoxicity + LESS killing โ
| Drug | Target Cmax:MIC | Dosing Strategy |
|---|---|---|
| Gentamicin | โฅ8-10x | Once daily (5-7 mg/kg) |
| Amikacin | โฅ8-10x | Once daily |
| Tobramycin | โฅ8-10x | Once daily |
| Metronidazole | High Cmax | Standard dosing |
Drug concentration
โ
|โโโโ
|โโโโโโ
|โโโโโโโโโ
- - - - -|โโโโโโโโโโโโ- - - โ MIC
| โโโโโโโโโ
|_____________________________โ Time
The AUC = the ENTIRE shaded area (โ) above AND below the MIC line
AUC/MIC = this total area รท the MIC value
| Drug | Organism | AUC/MIC Target |
|---|---|---|
| Vancomycin | MRSA, S. aureus | AUCโโ 400-600 mgยทh/L |
| Fluoroquinolones | S. pneumoniae | AUC/MIC >30 |
| Fluoroquinolones | Gram-negative bacteria | AUC/MIC >125 |
"Recent evidence strongly suggests moving away from serum trough vancomycin monitoring to a PK/PD target of AUC to MIC ratio. An AUCโโ of 400-600 mgยทh/L is associated with clinical efficacy."
- Harriet Lane Handbook 23e
| Drug | Primary target | Monitoring |
|---|---|---|
| Vancomycin | AUCโโ/MIC 400-600 | Trough OR AUC-guided (preferred now) |
| Levofloxacin | AUC/MIC >30 (GPC), >125 (GNR) | Clinical response |
| Ciprofloxacin | AUC/MIC >125 (GNR) | Clinical response |
| Moxifloxacin | AUC/MIC | Clinical response |
| Daptomycin | AUC/MIC | Clinical response |
| Tigecycline | AUC/MIC | Clinical response |
| Time-Dependent | Concentration-Dependent | AUC-Dependent | |
|---|---|---|---|
| What drives killing | Duration above MIC | Height of peak vs. MIC | Total exposure (peak + duration) |
| Key parameter | T > MIC | Cmax : MIC | AUC : MIC |
| Ceiling effect? | YES - killing saturates at 4x MIC | NO - higher peak = more kill | NO - more exposure = more kill |
| Optimal dosing | Frequent small doses / extended infusion | Infrequent large doses | Once or twice daily |
| Drug-free trough? | Dangerous (bacteria regrow) | Fine - PAE covers the gap | Fine to have trough periods |
| PAE? | Minimal (ฮฒ-lactams) | Long (aminoglycosides) | Moderate |
| Examples | Penicillins, Cephalosporins, Carbapenems | Gentamicin, Amikacin | Vancomycin, Fluoroquinolones, Daptomycin |
| Analogy | Steady drip irrigation | One powerful flood | Total rainfall measurement |
| Scenario | PK/PD Lesson |
|---|---|
| Patient missed 2 doses of amoxicillin | Dangerous - T > MIC drops, bacteria regrow. Stress compliance |
| Prescribing ciprofloxacin for UTI | Once daily 500mg fine - AUC/MIC model means one big dose works |
| Gentamicin in hospital | Once-daily dosing is BETTER than TDS - higher kill, less toxicity |
| Patient on vancomycin for MRSA | Ask for AUC monitoring, not just trough levels (current 2025 standard) |
| Levofloxacin 500mg OD vs 250mg BD | Same total dose - but OD achieves higher Cmax/MIC AND similar AUC - OD preferred |
๐
ฃ Time > MIC = ฮฒ-Lactams โ "Keep it STEADY" (drip, drip, drip)
๐
Cmax/MIC = Aminoglycosides โ "Hit it HARD once" (one big punch)
๐
AUC/MIC = Vancomycin/FQ โ "Total EXPOSURE matters" (count all hours)
Create a quick reference PDF comparing all 3 PK/PD models with dosing strategies
ls -la /tmp/workspace/ 2>/dev/null || mkdir -p /tmp/workspace && echo "workspace ready"
mkdir -p /tmp/workspace/pkpd-reference && cat > /tmp/workspace/pkpd-reference/generate_pdf.py << 'PYEOF' from reportlab.lib.pagesizes import A4 from reportlab.lib import colors from reportlab.lib.units import cm, mm from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY from reportlab.platypus import ( SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable, KeepTogether ) from reportlab.graphics.shapes import Drawing, Rect, Line, String, Polygon, Circle from reportlab.graphics import renderPDF from reportlab.graphics.charts.lineplots import LinePlot from reportlab.graphics.widgets.markers import makeMarker import math # โโ Colour palette โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ C_NAVY = colors.HexColor('#1B2A4A') C_TEAL = colors.HexColor('#0F7C8A') C_AMBER = colors.HexColor('#E07B2A') C_GREEN = colors.HexColor('#2A7A3B') C_LRED = colors.HexColor('#C0392B') C_LTBLUE = colors.HexColor('#D6EAF8') C_LTAMBER = colors.HexColor('#FEF9E7') C_LTGREEN = colors.HexColor('#EAFAF1') C_LTYELL = colors.HexColor('#FDFEFE') C_GREY = colors.HexColor('#7F8C8D') C_LGREY = colors.HexColor('#F2F3F4') C_WHITE = colors.white C_BLACK = colors.HexColor('#1C1C1C') C_MICRED = colors.HexColor('#E74C3C') W, H = A4 # 595.27 x 841.89 pts # โโ Document โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ doc = SimpleDocTemplate( '/tmp/workspace/pkpd-reference/PKPD_Antibiotic_Reference.pdf', pagesize=A4, leftMargin=1.5*cm, rightMargin=1.5*cm, topMargin=1.5*cm, bottomMargin=1.8*cm, title='Antibiotic PK/PD Models โ Quick Reference', author='Orris Medical AI', subject='Pharmacokinetics / Pharmacodynamics' ) styles = getSampleStyleSheet() def sty(name, **kw): s = ParagraphStyle(name, **kw) return s S_TITLE = sty('Title2', fontName='Helvetica-Bold', fontSize=20, textColor=C_WHITE, alignment=TA_CENTER, spaceAfter=2) S_SUBTITLE = sty('Sub', fontName='Helvetica', fontSize=10, textColor=C_WHITE, alignment=TA_CENTER, spaceAfter=0) S_SECHEAD = sty('SecHead', fontName='Helvetica-Bold', fontSize=12, textColor=C_WHITE, alignment=TA_CENTER, spaceAfter=4) S_BODY = sty('Body2', fontName='Helvetica', fontSize=8.5, textColor=C_BLACK, leading=12, spaceAfter=3) S_BOLD = sty('Bold2', fontName='Helvetica-Bold', fontSize=8.5, textColor=C_BLACK, leading=12) S_SMALL = sty('Small', fontName='Helvetica', fontSize=7.5, textColor=C_GREY, leading=10) S_CELLHEAD = sty('CH', fontName='Helvetica-Bold', fontSize=8, textColor=C_WHITE, alignment=TA_CENTER) S_CELL = sty('CL', fontName='Helvetica', fontSize=8, textColor=C_BLACK, alignment=TA_LEFT, leading=11) S_CELLC = sty('CC', fontName='Helvetica', fontSize=8, textColor=C_BLACK, alignment=TA_CENTER, leading=11) S_PEARLS = sty('Pearl', fontName='Helvetica', fontSize=8, textColor=C_BLACK, leading=12, leftIndent=6) # โโ Curve drawing helper โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ def make_curve_drawing(model, w=160, h=90): """Draw a mini PK curve for each model.""" d = Drawing(w, h) pad_l, pad_b, pad_r, pad_t = 18, 14, 8, 8 gw = w - pad_l - pad_r gh = h - pad_b - pad_t mic_y = pad_b + gh * 0.28 # MIC line position def tx(t): return pad_l + t * gw # t in [0,1] def cy(c): return pad_b + c * gh # c in [0,1] # Axes d.add(Line(pad_l, pad_b, pad_l, pad_b+gh, strokeColor=C_GREY, strokeWidth=0.7)) d.add(Line(pad_l, pad_b, pad_l+gw, pad_b, strokeColor=C_GREY, strokeWidth=0.7)) # Axis labels d.add(String(2, pad_b+gh//2, 'Conc.', fontSize=5.5, fillColor=C_GREY, textAnchor='middle')) d.add(String(pad_l+gw//2, 1, 'Time', fontSize=5.5, fillColor=C_GREY, textAnchor='middle')) # MIC dashed line seg = 4 x = pad_l while x < pad_l + gw: d.add(Line(x, mic_y, min(x+seg, pad_l+gw), mic_y, strokeColor=C_MICRED, strokeWidth=0.9, strokeDashArray=[3,2])) x += seg*2 d.add(String(pad_l+gw+1, mic_y-2, 'MIC', fontSize=5, fillColor=C_MICRED, textAnchor='start')) if model == 'time': # Two doses showing T>MIC windows for offset in [0, 0.47]: pts = [] for i in range(60): t = i/59 raw = math.exp(-6*(t-0.08)**2) if t > 0.04 else 0 c = 0.55 * raw pts.append((tx(t*0.44 + offset), cy(c))) for i in range(len(pts)-1): d.add(Line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1], strokeColor=C_TEAL, strokeWidth=1.4)) # T>MIC bracket x1, x2 = tx(0.07), tx(0.38) d.add(Line(x1, mic_y+2, x2, mic_y+2, strokeColor=C_TEAL, strokeWidth=1.2, strokeDashArray=[2,1])) d.add(String((x1+x2)/2, mic_y+4, 'T > MIC', fontSize=5.5, fillColor=C_TEAL, textAnchor='middle')) elif model == 'conc': # Single high spike pts = [] for i in range(80): t = i/79 if t < 0.05: c = t/0.05 * 0.92 else: c = 0.92 * math.exp(-5*(t-0.05)) pts.append((tx(t), cy(c))) for i in range(len(pts)-1): d.add(Line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1], strokeColor=C_AMBER, strokeWidth=1.4)) # Cmax arrow peak_x = tx(0.05) peak_y = cy(0.92) d.add(Line(peak_x+2, peak_y, peak_x+2, mic_y, strokeColor=C_AMBER, strokeWidth=1, strokeDashArray=[2,2])) d.add(String(peak_x+4, (peak_y+mic_y)/2, 'Cmax/MIC', fontSize=5.5, fillColor=C_AMBER, textAnchor='start')) # PAE bracket # find where curve drops below MIC pae_start = tx(0.42) pae_end = tx(0.62) d.add(Line(pae_start, mic_y-5, pae_end, mic_y-5, strokeColor=C_GREEN, strokeWidth=1)) d.add(Line(pae_start, mic_y-3, pae_start, mic_y-7, strokeColor=C_GREEN, strokeWidth=0.8)) d.add(Line(pae_end, mic_y-3, pae_end, mic_y-7, strokeColor=C_GREEN, strokeWidth=0.8)) d.add(String((pae_start+pae_end)/2, mic_y-12, 'PAE', fontSize=5.5, fillColor=C_GREEN, textAnchor='middle')) elif model == 'auc': # Moderate curve, shade AUC pts = [] for i in range(80): t = i/79 if t < 0.07: c = t/0.07 * 0.72 else: c = 0.72 * math.exp(-3.5*(t-0.07)) pts.append((tx(t), cy(c))) # Fill AUC area (simplified - draw polygon) poly_pts = [(pad_l, pad_b)] for p in pts: poly_pts.append(p) poly_pts.append((tx(1), pad_b)) poly_flat = [] for p in poly_pts: poly_flat.extend(p) d.add(Polygon(poly_flat, fillColor=colors.HexColor('#D5F5E3'), strokeColor=None, fillOpacity=0.5)) for i in range(len(pts)-1): d.add(Line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1], strokeColor=C_GREEN, strokeWidth=1.4)) # AUC label inside shaded region d.add(String(tx(0.35), cy(0.18), 'AUC/MIC', fontSize=5.5, fillColor=C_GREEN, textAnchor='middle')) return d # โโ PAGE BACKGROUND helper (via canvas) โโโโโโโโโโโโโโโโโโโโโโโโโโ def header_footer(canvas, doc): canvas.saveState() # Top header bar canvas.setFillColor(C_NAVY) canvas.rect(0, H-2.6*cm, W, 2.6*cm, fill=1, stroke=0) # Title canvas.setFillColor(C_WHITE) canvas.setFont('Helvetica-Bold', 18) canvas.drawCentredString(W/2, H-1.5*cm, 'Antibiotic PK/PD Models โ Quick Reference') canvas.setFont('Helvetica', 9) canvas.drawCentredString(W/2, H-2.1*cm, 'For General Practitioners | Time-Dependent ยท Concentration-Dependent ยท AUC-Dependent') # Bottom bar canvas.setFillColor(C_NAVY) canvas.rect(0, 0, W, 1.2*cm, fill=1, stroke=0) canvas.setFillColor(C_WHITE) canvas.setFont('Helvetica', 7.5) canvas.drawString(1.5*cm, 0.45*cm, 'Sources: Harrison\'s Principles 22e ยท Goodman & Gilman ยท Fishman\'s Pulmonary Diseases ยท Harriet Lane 23e') canvas.drawRightString(W-1.5*cm, 0.45*cm, 'Orris Medical AI | August 2026') canvas.restoreState() # โโ Build content โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ story = [] story.append(Spacer(1, 2.8*cm)) # space below header bar # โโ INTRO ROW โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ intro_text = ( "Antibiotic efficacy depends not only on <b>which</b> drug you prescribe, but on <b>how</b> you dose it. " "Three pharmacodynamic (PD) models govern bacterial killing, each requiring a different dosing strategy. " "Understanding these models explains dosing frequency, monitoring parameters, and why the same total daily " "dose given differently can succeed or fail." ) intro_style = ParagraphStyle('intro', fontName='Helvetica', fontSize=9, textColor=C_BLACK, leading=13, alignment=TA_JUSTIFY, borderColor=C_TEAL, borderWidth=1, borderPadding=8, backColor=colors.HexColor('#EAF7FB')) story.append(Paragraph(intro_text, intro_style)) story.append(Spacer(1, 0.35*cm)) # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ # SECTION CARDS โ one per model # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ models = [ { 'color': C_TEAL, 'light': colors.HexColor('#EAF7FB'), 'emoji': 'โฑ', 'title': 'Model 1 โ Time-Dependent Killing', 'param': 'T > MIC', 'param_full': 'Time drug concentration stays above MIC', 'what': 'Killing rate saturates once concentration reaches ~4ร MIC. Going higher adds nothing. Only staying ABOVE the MIC longer increases effect.', 'target': 'Penicillins: 40โ50% ยท Cephalosporins: 60โ70% ยท Carbapenems: โฅ40% of dosing interval above MIC', 'drugs': [ ('Amoxicillin / Pen V', 'TDS or QDS', 'Must maintain T>MIC; TDS > BD'), ('Benzylpenicillin (IV)', 'q4โ6h or CI', 'Short tยฝ; continuous infusion in ICU'), ('Cephalexin', 'QDS', 'Higher freq than cefixime (longer tยฝ)'), ('Ceftriaxone', 'ODโBD', 'Long tยฝ 6โ9h allows once daily'), ('Meropenem (IV)', 'q8h or ext. infusion', 'Extended 3โ4h infusion maximises T>MIC'), ('Piperacillin-Tazobactam', 'q6โ8h or CI', 'Extended infusion for resistant organisms'), ], 'strategy': 'Dose FREQUENTLY or use extended/continuous IV infusions to keep drug above MIC.', 'trap': 'Doubling the dose without increasing frequency does NOT improve killing. Missing doses causes bacterial regrowth.', 'pae': 'Minimal PAE against Gram-negatives โ cannot rely on drug-free interval.', 'monitoring': 'Clinical response; ensure compliance; extend infusion time for high-MIC organisms.', 'analogy': '๐ฟ Steady drip irrigation โ constant water supply, not one big flood', 'curve': 'time', }, { 'color': C_AMBER, 'light': colors.HexColor('#FEF5E7'), 'emoji': '๐บ', 'title': 'Model 2 โ Concentration-Dependent Killing', 'param': 'Cmax : MIC', 'param_full': 'Peak drug concentration relative to MIC', 'what': 'The HIGHER the peak above MIC, the faster and more completely bacteria are killed. No ceiling โ higher peak = better kill. Drug-free trough is safe (even beneficial).', 'target': 'Cmax/MIC โฅ 8โ12ร for aminoglycosides ยท Once-daily dosing achieves optimal peak', 'drugs': [ ('Gentamicin', '5โ7 mg/kg OD (IV)', 'OD > TDS โ higher peak, less nephrotoxicity'), ('Amikacin', '15โ20 mg/kg OD (IV)', 'Monitor trough <5 mg/L; peak 56โ64 mg/L'), ('Tobramycin', '5โ7 mg/kg OD (IV)', 'Similar to gentamicin'), ('Metronidazole', 'Standard dosing', 'Some concentration-dependent features'), ], 'strategy': 'Give INFREQUENT but LARGE doses to maximise peak (Cmax). Once-daily > multiple small doses.', 'trap': 'Old TDS aminoglycoside dosing = lower peaks (less killing) + sustained trough (more nephrotoxicity). Avoid.', 'pae': 'Prolonged PAE 1โ4h against Gram-negatives โ drug-free trough is SAFE and reduces kidney exposure.', 'monitoring': 'Trough level before next dose: target <1 mg/L (gentamicin). Peak 1h post-infusion if needed.', 'analogy': '๐ฅ One powerful knockout punch โ intensity matters, not duration', 'curve': 'conc', }, { 'color': C_GREEN, 'light': colors.HexColor('#EAFAF1'), 'emoji': '๐', 'title': 'Model 3 โ AUC-Dependent Killing', 'param': 'AUC : MIC', 'param_full': 'Total drug exposure (area under curve) relative to MIC', 'what': 'Total drug exposure over 24h drives killing โ accounts for BOTH peak height AND duration. Neither alone is sufficient; the integrated area under the concentration-time curve predicts efficacy.', 'target': 'Vancomycin: AUCโโ/MIC 400โ600 ยท Fluoroquinolones vs S. pneumoniae: >30 ยท vs Gram-negatives: >125', 'drugs': [ ('Vancomycin (IV)', 'Individualised dosing', 'AUC-guided monitoring now preferred over trough'), ('Levofloxacin', '500 mg OD', 'OD better than BD โ higher AUC/MIC & Cmax/MIC'), ('Ciprofloxacin', '500โ750 mg BD', 'AUC/MIC >125 for Gram-negatives'), ('Moxifloxacin', '400 mg OD', 'Superior tissue penetration; AUC-driven'), ('Daptomycin (IV)', '4โ6 mg/kg OD', 'AUC/MIC + Cmax/MIC; OD dosing'), ('Tigecycline (IV)', '50 mg BD after LD', 'AUC-dependent; broad spectrum'), ], 'strategy': 'Optimise TOTAL EXPOSURE. OD or BD dosing achieves adequate AUC while maintaining practical schedule.', 'trap': 'Vancomycin: old trough-only monitoring (target 15โ20 mg/L) is now replaced by AUC/MIC-guided dosing to balance efficacy and reduce nephrotoxicity.', 'pae': 'Moderate PAE; the drug-free interval is tolerated due to residual post-antibiotic suppression.', 'monitoring': 'Vancomycin: AUCโโ target 400โ600 mgยทh/L (2-point sampling or Bayesian). Fluoroquinolones: clinical response.', 'analogy': '๐ง Total rainfall over 24h โ both the downpour and the drizzle count', 'curve': 'auc', }, ] for m in models: col = m['color'] bg = m['light'] items = [] # โโ Section header bar โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ hdr_data = [[Paragraph(f"<b>{m['title']}</b>", S_SECHEAD)]] hdr_tbl = Table(hdr_data, colWidths=[doc.width]) hdr_tbl.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), col), ('ROWBACKGROUNDS', (0,0), (-1,-1), [col]), ('TOPPADDING', (0,0), (-1,-1), 6), ('BOTTOMPADDING', (0,0), (-1,-1), 6), ('LEFTPADDING', (0,0), (-1,-1), 8), ('ROUNDEDCORNERS', [4,4,0,0]), ])) items.append(hdr_tbl) # โโ Two-column layout: curve + key facts โโโโโโโโโโโโโโโโโโโโ curve_d = make_curve_drawing(m['curve'], w=150, h=85) facts_para = Paragraph( f"<b>Key Parameter:</b> <font color='#{col.hexval()[1:]}' size=10><b>{m['param']}</b></font><br/>" f"<i>{m['param_full']}</i><br/><br/>" f"<b>How it works:</b> {m['what']}<br/><br/>" f"<b>Target:</b> <font color='#{col.hexval()[1:]}'>{m['target']}</font>", ParagraphStyle('facts', fontName='Helvetica', fontSize=8, leading=11.5, textColor=C_BLACK, spaceAfter=2) ) two_col = Table( [[curve_d, facts_para]], colWidths=[155, doc.width - 155] ) two_col.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), bg), ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), ('TOPPADDING', (0,0), (-1,-1), 6), ('BOTTOMPADDING', (0,0), (-1,-1), 6), ('LEFTPADDING', (0,0), (0,-1), 6), ('RIGHTPADDING', (-1,0), (-1,-1), 8), ])) items.append(two_col) # โโ Drug table โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ drug_rows = [[ Paragraph('<b>Drug</b>', S_CELLHEAD), Paragraph('<b>Dosing Schedule</b>', S_CELLHEAD), Paragraph('<b>Clinical Note</b>', S_CELLHEAD), ]] for drug, dose, note in m['drugs']: drug_rows.append([ Paragraph(drug, S_CELL), Paragraph(f"<font color='#{col.hexval()[1:]}'><b>{dose}</b></font>", S_CELL), Paragraph(note, S_CELL), ]) drug_tbl = Table(drug_rows, colWidths=[doc.width*0.3, doc.width*0.28, doc.width*0.42]) row_colors = [bg if i%2==0 else C_WHITE for i in range(len(drug_rows))] ts = TableStyle([ ('BACKGROUND', (0,0), (-1,0), col), ('TEXTCOLOR', (0,0), (-1,0), C_WHITE), ('TOPPADDING', (0,0), (-1,-1), 4), ('BOTTOMPADDING', (0,0), (-1,-1), 4), ('LEFTPADDING', (0,0), (-1,-1), 5), ('RIGHTPADDING', (0,0), (-1,-1), 5), ('LINEBELOW', (0,0), (-1,-1), 0.3, colors.HexColor('#BFC9CA')), ('GRID', (0,0), (-1,-1), 0.3, colors.HexColor('#D5DBDB')), ]) for i in range(1, len(drug_rows)): if i%2==0: ts.add('BACKGROUND', (0,i), (-1,i), bg) else: ts.add('BACKGROUND', (0,i), (-1,i), C_WHITE) drug_tbl.setStyle(ts) items.append(drug_tbl) # โโ Strategy / Traps / Monitoring row โโโโโโโโโโโโโโโโโโโโโโโโ bottom_data = [[ Paragraph(f"<b>โ Dosing Strategy</b><br/>{m['strategy']}", S_CELL), Paragraph(f"<b>โ ๏ธ Common Trap</b><br/>{m['trap']}", S_CELL), Paragraph(f"<b>๐ Monitoring</b><br/>{m['monitoring']}", S_CELL), ]] bot_tbl = Table(bottom_data, colWidths=[doc.width/3]*3) bot_tbl.setStyle(TableStyle([ ('BACKGROUND', (0,0), (0,-1), colors.HexColor('#EBF5FB')), ('BACKGROUND', (1,0), (1,-1), colors.HexColor('#FEF9E7')), ('BACKGROUND', (2,0), (2,-1), colors.HexColor('#EAFAF1')), ('TOPPADDING', (0,0), (-1,-1), 5), ('BOTTOMPADDING', (0,0), (-1,-1), 5), ('LEFTPADDING', (0,0), (-1,-1), 6), ('RIGHTPADDING', (0,0), (-1,-1), 6), ('LINEAFTER', (0,0), (1,-1), 0.5, C_LGREY), ('VALIGN', (0,0), (-1,-1), 'TOP'), ])) items.append(bot_tbl) # โโ PAE + Analogy row โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ pae_data = [[ Paragraph(f"<b>Post-Antibiotic Effect (PAE):</b> {m['pae']}", S_CELL), Paragraph(f"<b>Analogy:</b> {m['analogy']}", S_CELL), ]] pae_tbl = Table(pae_data, colWidths=[doc.width*0.55, doc.width*0.45]) pae_tbl.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), bg), ('TOPPADDING', (0,0), (-1,-1), 4), ('BOTTOMPADDING', (0,0), (-1,-1), 5), ('LEFTPADDING', (0,0), (-1,-1), 6), ('RIGHTPADDING', (0,0), (-1,-1), 6), ('LINEAFTER', (0,0), (0,-1), 0.5, C_LGREY), ('ROUNDEDCORNERS', [0,0,4,4]), ])) items.append(pae_tbl) story.append(KeepTogether(items)) story.append(Spacer(1, 0.4*cm)) # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ # MASTER COMPARISON TABLE # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ story.append(HRFlowable(width='100%', thickness=1.5, color=C_NAVY)) story.append(Spacer(1, 0.2*cm)) comp_head = ParagraphStyle('comphead', fontName='Helvetica-Bold', fontSize=11, textColor=C_NAVY, alignment=TA_CENTER, spaceAfter=6) story.append(Paragraph('Master Comparison Table', comp_head)) comp_rows = [ [ Paragraph('<b>Feature</b>', S_CELLHEAD), Paragraph('<b>โฑ Time-Dependent</b>', S_CELLHEAD), Paragraph('<b>๐บ Conc.-Dependent</b>', S_CELLHEAD), Paragraph('<b>๐ AUC-Dependent</b>', S_CELLHEAD), ], ['Key PD Parameter', Paragraph('<b>T > MIC</b>', ParagraphStyle('g', fontName='Helvetica-Bold', fontSize=8, textColor=C_TEAL, alignment=TA_CENTER)), Paragraph('<b>Cmax : MIC</b>', ParagraphStyle('g', fontName='Helvetica-Bold', fontSize=8, textColor=C_AMBER, alignment=TA_CENTER)), Paragraph('<b>AUC : MIC</b>', ParagraphStyle('g', fontName='Helvetica-Bold', fontSize=8, textColor=C_GREEN, alignment=TA_CENTER)), ], ['What drives killing', 'Duration above MIC', 'Height of peak vs. MIC', 'Total exposure over 24h'], ['Ceiling effect?', 'โ Yes โ saturates at 4ร MIC', 'โ No โ higher peak = more kill', 'โ No โ more total exposure = more kill'], ['Optimal dose schedule', 'Frequent (TDS/QDS) or extended infusion', 'Infrequent, large bolus (OD)', 'OD or BD to accumulate AUC'], ['Drug-free trough safe?', 'โ No โ bacteria regrow', 'โ Yes โ PAE covers gap', 'โ Yes โ partial PAE'], ['PAE', 'Minimal (especially Gram-neg)', 'Prolonged 1โ4h (Gram-neg)', 'Moderate'], ['Key examples', 'Penicillins, Cephalosporins, Carbapenems', 'Gentamicin, Amikacin, Tobramycin', 'Vancomycin, Fluoroquinolones, Daptomycin'], ['Monitoring focus', 'T>MIC %; compliance', 'Trough <1 mg/L; peak if needed', 'AUCโโ/MIC 400โ600 (vanco)'], ['Missing a dose harms?', 'โ โ Major harm', 'โ ๏ธ Moderate', 'โ ๏ธ Moderate'], ['Analogy', '๐ฟ Steady drip', '๐ฅ One knockout punch', '๐ง Total rainfall'], ] cw = [doc.width*0.22, doc.width*0.26, doc.width*0.26, doc.width*0.26] comp_tbl = Table(comp_rows, colWidths=cw) comp_ts = TableStyle([ ('BACKGROUND', (0,0), (-1,0), C_NAVY), ('TEXTCOLOR', (0,0), (-1,0), C_WHITE), ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'), ('FONTSIZE', (0,0), (-1,-1), 8), ('ALIGN', (0,0), (-1,-1), 'CENTER'), ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), ('TOPPADDING', (0,0), (-1,-1), 4), ('BOTTOMPADDING', (0,0), (-1,-1), 4), ('LEFTPADDING', (0,0), (-1,-1), 4), ('RIGHTPADDING', (0,0), (-1,-1), 4), ('GRID', (0,0), (-1,-1), 0.4, colors.HexColor('#AEB6BF')), ('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'), ('BACKGROUND', (1,2), (1,-1), colors.HexColor('#EAF7FB')), ('BACKGROUND', (2,2), (2,-1), colors.HexColor('#FEF5E7')), ('BACKGROUND', (3,2), (3,-1), colors.HexColor('#EAFAF1')), ('BACKGROUND', (0,2), (0,-1), C_LGREY), # Alternating slight shade on header col ]) # Alternating rows for feature col for i in range(1, len(comp_rows)): if i % 2 == 0: comp_ts.add('BACKGROUND', (0,i), (0,i), colors.HexColor('#D5DBDB')) comp_tbl.setStyle(comp_ts) story.append(comp_tbl) story.append(Spacer(1, 0.4*cm)) # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ # GP CLINICAL PEARLS BOX # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ pearls_head = ParagraphStyle('ph', fontName='Helvetica-Bold', fontSize=10, textColor=C_WHITE, alignment=TA_CENTER) pearls = [ "1. <b>Amoxicillin TDS โ Amoxicillin OD</b> โ penicillins need T>MIC; once daily fails despite same total dose.", "2. <b>Gentamicin once-daily is standard</b> โ one large dose achieves Cmax/MIC โฅ8โ12 AND reduces nephrotoxicity via drug-free trough.", "3. <b>Vancomycin monitoring has changed (2023โ2026)</b> โ AUCโโ 400โ600 mgยทh/L is now the target, not just trough 15โ20 mg/L.", "4. <b>Levofloxacin 500 mg OD > 250 mg BD</b> โ same total dose but OD achieves higher Cmax/MIC and adequate AUC/MIC.", "5. <b>Meropenem extended infusion (3โ4h)</b> โ in ICU for resistant Gram-negatives, extending the infusion time dramatically improves T>MIC.", "6. <b>Missing ฮฒ-lactam doses = treatment failure</b> โ bacteria regrow rapidly once T>MIC is lost; stress compliance at every consult.", "7. <b>Rising MICs shrink your T>MIC window</b> โ this is why high-dose amoxicillin (80โ90 mg/kg/day) is used for AOM in children.", ] pearl_paras = [[Paragraph(p, S_PEARLS)] for p in pearls] pearl_tbl = Table(pearl_paras, colWidths=[doc.width]) pearl_tbl.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), colors.HexColor('#F8F9FA')), ('TOPPADDING', (0,0), (-1,-1), 3), ('BOTTOMPADDING', (0,0), (-1,-1), 3), ('LEFTPADDING', (0,0), (-1,-1), 8), ('LINEBELOW', (0,0), (-1,-2), 0.3, colors.HexColor('#D5DBDB')), ])) pearl_header = Table( [[Paragraph('๐ฉบ GP Clinical Pearls', pearls_head)]], colWidths=[doc.width] ) pearl_header.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), C_NAVY), ('TOPPADDING', (0,0), (-1,-1), 5), ('BOTTOMPADDING', (0,0), (-1,-1), 5), ('LEFTPADDING', (0,0), (-1,-1), 8), ])) story.append(KeepTogether([pearl_header, pearl_tbl])) # โโ Memory peg โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ story.append(Spacer(1, 0.3*cm)) mem_text = ( "<b>Memory Peg:</b> " "<font color='#0F7C8A'>โฑ T > MIC = ฮฒ-Lactams โ Keep it STEADY (drip, drip, drip)</font> | " "<font color='#E07B2A'>๐บ Cmax/MIC = Aminoglycosides โ Hit it HARD once (one big punch)</font> | " "<font color='#2A7A3B'>๐ AUC/MIC = Vancomycin/FQ โ Total EXPOSURE matters (count all hours)</font>" ) story.append(Paragraph(mem_text, ParagraphStyle('mem', fontName='Helvetica', fontSize=8, leading=12, alignment=TA_CENTER, borderColor=C_NAVY, borderWidth=1, borderPadding=7, backColor=colors.HexColor('#F2F3F4')))) # โโ Build โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ doc.build(story, onFirstPage=header_footer, onLaterPages=header_footer) print("PDF generated successfully.") PYEOF echo "Script written."
cd /tmp/workspace/pkpd-reference && python generate_pdf.py
hexval() returns #0f7c8a but col.hexval()[1:] gives x0f7c8a (with the # already stripped but letter-cased wrong). I'll fix by using explicit hex strings instead.cat > /tmp/workspace/pkpd-reference/generate_pdf.py << 'PYEOF' from reportlab.lib.pagesizes import A4 from reportlab.lib import colors from reportlab.lib.units import cm from reportlab.lib.styles import ParagraphStyle from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY from reportlab.platypus import ( SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable, KeepTogether ) from reportlab.graphics.shapes import Drawing, Line, String, Polygon import math # โโ Colour palette โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ C_NAVY = colors.HexColor('#1B2A4A') C_TEAL = colors.HexColor('#0F7C8A') C_AMBER = colors.HexColor('#E07B2A') C_GREEN = colors.HexColor('#2A7A3B') C_MICRED = colors.HexColor('#E74C3C') C_GREY = colors.HexColor('#7F8C8D') C_LGREY = colors.HexColor('#F2F3F4') C_DGREY = colors.HexColor('#D5DBDB') C_WHITE = colors.white C_BLACK = colors.HexColor('#1C1C1C') # explicit hex strings for inline markup HEX_TEAL = '#0F7C8A' HEX_AMBER = '#E07B2A' HEX_GREEN = '#2A7A3B' HEX_NAVY = '#1B2A4A' W, H = A4 doc = SimpleDocTemplate( '/tmp/workspace/pkpd-reference/PKPD_Antibiotic_Reference.pdf', pagesize=A4, leftMargin=1.5*cm, rightMargin=1.5*cm, topMargin=2.8*cm, bottomMargin=1.8*cm, title='Antibiotic PK/PD Models โ Quick Reference', author='Orris Medical AI', subject='Pharmacokinetics / Pharmacodynamics' ) def sty(name, **kw): return ParagraphStyle(name, **kw) S_SECHEAD = sty('SecHead', fontName='Helvetica-Bold', fontSize=12, textColor=C_WHITE, alignment=TA_CENTER) S_CELLHEAD = sty('CH', fontName='Helvetica-Bold', fontSize=8, textColor=C_WHITE, alignment=TA_CENTER) S_CELL = sty('CL', fontName='Helvetica', fontSize=8, textColor=C_BLACK, alignment=TA_LEFT, leading=11) S_PEARLS = sty('Pearl', fontName='Helvetica', fontSize=8, textColor=C_BLACK, leading=12, leftIndent=6) S_INTRO = sty('Intro', fontName='Helvetica', fontSize=9, textColor=C_BLACK, leading=13, alignment=TA_JUSTIFY, borderColor=C_TEAL, borderWidth=1, borderPadding=8, backColor=colors.HexColor('#EAF7FB')) def make_curve_drawing(model, w=150, h=88): d = Drawing(w, h) pad_l, pad_b, pad_r, pad_t = 20, 16, 10, 8 gw = w - pad_l - pad_r gh = h - pad_b - pad_t mic_y = pad_b + gh * 0.30 def tx(t): return pad_l + t * gw def cy(c): return pad_b + c * gh # Axes d.add(Line(pad_l, pad_b, pad_l, pad_b+gh, strokeColor=C_GREY, strokeWidth=0.7)) d.add(Line(pad_l, pad_b, pad_l+gw, pad_b, strokeColor=C_GREY, strokeWidth=0.7)) d.add(String(3, pad_b+gh//2, 'Conc', fontSize=5.5, fillColor=C_GREY, textAnchor='middle')) d.add(String(pad_l+gw//2, 2, 'Time', fontSize=5.5, fillColor=C_GREY, textAnchor='middle')) # MIC dashed line x = pad_l while x < pad_l + gw - 2: d.add(Line(x, mic_y, min(x+4, pad_l+gw), mic_y, strokeColor=C_MICRED, strokeWidth=0.9, strokeDashArray=[3,2])) x += 8 d.add(String(pad_l+gw+1, mic_y-2, 'MIC', fontSize=5, fillColor=C_MICRED)) if model == 'time': curve_col = C_TEAL for offset in [0.0, 0.48]: pts = [] for i in range(60): t = i/59 * 0.44 raw = math.exp(-7*(t-0.07)**2) if t > 0.02 else 0 c = 0.58 * raw pts.append((tx(t + offset), cy(c))) for i in range(len(pts)-1): d.add(Line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1], strokeColor=curve_col, strokeWidth=1.4)) # T>MIC bracket x1, x2 = tx(0.04), tx(0.37) d.add(Line(x1, mic_y+3, x2, mic_y+3, strokeColor=curve_col, strokeWidth=1.1, strokeDashArray=[2,1])) d.add(String((x1+x2)/2, mic_y+5.5, 'T > MIC', fontSize=5.5, fillColor=curve_col, textAnchor='middle')) elif model == 'conc': curve_col = C_AMBER pts = [] for i in range(80): t = i/79 c = (t/0.06) * 0.90 if t < 0.06 else 0.90 * math.exp(-4.5*(t-0.06)) pts.append((tx(t), cy(c))) for i in range(len(pts)-1): d.add(Line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1], strokeColor=curve_col, strokeWidth=1.4)) peak_x = tx(0.06); peak_y = cy(0.90) d.add(Line(peak_x+2, peak_y, peak_x+2, mic_y, strokeColor=curve_col, strokeWidth=0.9, strokeDashArray=[2,2])) d.add(String(peak_x+4, (peak_y+mic_y)/2+2, 'Cmax/MIC', fontSize=5.5, fillColor=curve_col)) # PAE bracket ps = tx(0.43); pe = tx(0.63) d.add(Line(ps, mic_y-6, pe, mic_y-6, strokeColor=C_GREEN, strokeWidth=1)) d.add(Line(ps, mic_y-3, ps, mic_y-9, strokeColor=C_GREEN, strokeWidth=0.7)) d.add(Line(pe, mic_y-3, pe, mic_y-9, strokeColor=C_GREEN, strokeWidth=0.7)) d.add(String((ps+pe)/2, mic_y-13.5, 'PAE', fontSize=5.5, fillColor=C_GREEN, textAnchor='middle')) elif model == 'auc': curve_col = C_GREEN pts = [] for i in range(80): t = i/79 c = (t/0.08)*0.74 if t < 0.08 else 0.74 * math.exp(-3.2*(t-0.08)) pts.append((tx(t), cy(c))) poly_flat = [pad_l, pad_b] for p in pts: poly_flat.extend(p) poly_flat.extend([tx(1), pad_b]) d.add(Polygon(poly_flat, fillColor=colors.HexColor('#D5F5E3'), strokeColor=None, fillOpacity=0.5)) for i in range(len(pts)-1): d.add(Line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1], strokeColor=curve_col, strokeWidth=1.4)) d.add(String(tx(0.38), cy(0.12), 'AUC/MIC', fontSize=5.5, fillColor=curve_col, textAnchor='middle')) return d def header_footer(canvas, doc): canvas.saveState() canvas.setFillColor(C_NAVY) canvas.rect(0, H-2.6*cm, W, 2.6*cm, fill=1, stroke=0) canvas.setFillColor(C_WHITE) canvas.setFont('Helvetica-Bold', 17) canvas.drawCentredString(W/2, H-1.45*cm, 'Antibiotic PK/PD Models โ Quick Reference') canvas.setFont('Helvetica', 9) canvas.drawCentredString(W/2, H-2.05*cm, 'For General Practitioners | Time-Dependent ยท Concentration-Dependent ยท AUC-Dependent') canvas.setFillColor(C_NAVY) canvas.rect(0, 0, W, 1.2*cm, fill=1, stroke=0) canvas.setFillColor(C_WHITE) canvas.setFont('Helvetica', 7) canvas.drawString(1.5*cm, 0.45*cm, "Sources: Harrison's Principles 22e | Goodman & Gilman | Fishman's Pulmonary Diseases | Harriet Lane 23e") canvas.drawRightString(W-1.5*cm, 0.45*cm, 'Orris Medical AI | August 2026') canvas.restoreState() story = [] # Intro story.append(Paragraph( "Antibiotic efficacy depends not only on <b>which</b> drug you prescribe, but on <b>how</b> you dose it. " "Three pharmacodynamic (PD) models govern bacterial killing, each requiring a different dosing strategy. " "Understanding these models explains dosing frequency, monitoring parameters, and why the same total daily " "dose given differently can succeed or fail.", S_INTRO)) story.append(Spacer(1, 0.3*cm)) models = [ dict( col=C_TEAL, bg=colors.HexColor('#EAF7FB'), hex_col=HEX_TEAL, title='Model 1 โ Time-Dependent Killing (T > MIC)', param='T > MIC', param_full='Time drug concentration stays above MIC', what='Killing rate <b>saturates</b> once concentration reaches ~4x MIC. Going higher adds nothing. Only staying ABOVE the MIC <b>longer</b> increases effect.', target='Penicillins: 40-50% | Cephalosporins: 60-70% | Carbapenems: 40%+ of dosing interval above MIC', drugs=[ ('Amoxicillin / Pen V', 'TDS or QDS', 'Must maintain T>MIC; TDS > BD for efficacy'), ('Benzylpenicillin (IV)', 'q4-6h or CI', 'Short t1/2; continuous infusion used in ICU'), ('Cephalexin', 'QDS', 'Higher freq needed; shorter t1/2 than ceftriaxone'), ('Ceftriaxone (IV/IM)', 'OD or BD', 'Long t1/2 6-9h allows once-daily dosing'), ('Meropenem (IV)', 'q8h or extended 3-4h', 'Extended infusion maximises T>MIC for resistant bugs'), ('Piperacillin-Tazobactam', 'q6-8h or CI', 'Extended infusion for high-MIC organisms in ICU'), ], strategy='Dose <b>FREQUENTLY</b> or use extended / continuous IV infusions to keep drug above MIC for target % of interval.', trap='Doubling the dose <b>without</b> increasing frequency does NOT improve killing once above 4x MIC. Missing doses causes rapid bacterial regrowth.', pae='Minimal PAE against Gram-negatives. Cannot rely on drug-free interval. Must maintain T>MIC.', monitoring='Clinical response + compliance. Extend infusion time for high-MIC resistant organisms.', analogy='Steady drip irrigation โ constant supply, not one big flood', curve='time', ), dict( col=C_AMBER, bg=colors.HexColor('#FEF5E7'), hex_col=HEX_AMBER, title='Model 2 โ Concentration-Dependent Killing (Cmax : MIC)', param='Cmax : MIC', param_full='Peak drug concentration relative to MIC', what='The <b>HIGHER</b> the peak above MIC, the faster and more completely bacteria are killed. No ceiling effect. Drug-free trough is safe and even reduces toxicity.', target='Aminoglycosides: Cmax/MIC >= 8-12x | Once-daily dosing achieves optimal peak concentration', drugs=[ ('Gentamicin (IV)', '5-7 mg/kg OD', 'OD beats TDS โ higher peak + less nephrotoxicity'), ('Amikacin (IV)', '15-20 mg/kg OD', 'Trough target <5 mg/L; peak 56-64 mg/L'), ('Tobramycin (IV)', '5-7 mg/kg OD', 'Same model as gentamicin; monitor trough'), ('Metronidazole', 'Standard TDS/BD', 'Some concentration-dependent features; anaerobic cover'), ], strategy='Give <b>INFREQUENT but LARGE</b> doses. Maximise Cmax/MIC with once-daily bolus. Avoid splitting into smaller frequent doses.', trap='Old TDS aminoglycoside dosing = lower peaks (less killing) + sustained high trough (more nephrotoxicity). Once-daily is now standard.', pae='Prolonged PAE 1-4h against Gram-negatives. Drug-free trough is SAFE and allows kidney tubular cells to recover.', monitoring='Trough level before next dose: target <1 mg/L (gentamicin). Peak 1h post-infusion if needed (target 8-12x MIC).', analogy='One knockout punch โ intensity matters, not duration', curve='conc', ), dict( col=C_GREEN, bg=colors.HexColor('#EAFAF1'), hex_col=HEX_GREEN, title='Model 3 โ AUC-Dependent Killing (AUC : MIC)', param='AUC : MIC', param_full='Total drug exposure (area under curve) relative to MIC', what='Total drug exposure over 24h drives killing โ accounts for BOTH peak height AND duration. Neither alone is sufficient. The integrated area under the concentration-time curve predicts efficacy.', target='Vancomycin: AUC24 400-600 mg.h/L | Fluoroquinolones vs S. pneumoniae: AUC/MIC >30 | vs Gram-negatives: >125', drugs=[ ('Vancomycin (IV)', 'Individualised AUC-guided', 'AUC/MIC monitoring NOW preferred over trough-only'), ('Levofloxacin', '500 mg OD', 'OD better than BD โ higher Cmax/MIC + adequate AUC/MIC'), ('Ciprofloxacin', '500-750 mg BD', 'AUC/MIC >125 for Gram-negatives'), ('Moxifloxacin', '400 mg OD', 'Superior tissue penetration; AUC/MIC driven'), ('Daptomycin (IV)', '4-6 mg/kg OD', 'Combined AUC/MIC + Cmax/MIC; once-daily dosing'), ('Tigecycline (IV)', '50 mg BD after LD', 'AUC-dependent; broad-spectrum for resistant infections'), ], strategy='Optimise <b>TOTAL EXPOSURE</b>. OD or BD dosing accumulates adequate AUC. Bayesian dosing used for vancomycin.', trap='Vancomycin: old trough-only monitoring (15-20 mg/L) is now replaced by AUC/MIC-guided dosing (AUC24 400-600). Trough-only can miss under- or over-exposure.', pae='Moderate PAE. Drug-free interval tolerated due to residual post-antibiotic suppression of bacterial growth.', monitoring='Vancomycin: AUC24 target 400-600 mg.h/L via 2-point sampling or Bayesian software (2023+ standard). Fluoroquinolones: clinical response.', analogy='Total rainfall over 24h โ both the downpour and the drizzle count', curve='auc', ), ] for m in models: col = m['col']; bg = m['bg']; hx = m['hex_col'] items = [] # Header hdr = Table([[Paragraph(f"<b>{m['title']}</b>", S_SECHEAD)]], colWidths=[doc.width]) hdr.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), col), ('TOPPADDING', (0,0), (-1,-1), 6), ('BOTTOMPADDING', (0,0), (-1,-1), 6), ('LEFTPADDING', (0,0), (-1,-1), 8), ])) items.append(hdr) # Curve + key facts facts = Paragraph( f"<b>Key Parameter:</b> <font color='{hx}' size='10'><b>{m['param']}</b></font><br/>" f"<i>{m['param_full']}</i><br/><br/>" f"<b>How it works:</b> {m['what']}<br/><br/>" f"<b>PD Target:</b> <font color='{hx}'>{m['target']}</font>", ParagraphStyle('facts', fontName='Helvetica', fontSize=8, leading=12, textColor=C_BLACK) ) two_col = Table([[make_curve_drawing(m['curve'], w=150, h=88), facts]], colWidths=[155, doc.width-155]) two_col.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), bg), ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), ('TOPPADDING', (0,0), (-1,-1), 6), ('BOTTOMPADDING', (0,0), (-1,-1), 6), ('LEFTPADDING', (0,0), (0,0), 4), ('LEFTPADDING', (1,0), (1,0), 6), ('RIGHTPADDING', (0,0), (-1,-1), 6), ])) items.append(two_col) # Drug table drug_rows = [[Paragraph('<b>Drug</b>', S_CELLHEAD), Paragraph('<b>Dosing Schedule</b>', S_CELLHEAD), Paragraph('<b>Clinical Note</b>', S_CELLHEAD)]] for drug, dose, note in m['drugs']: drug_rows.append([ Paragraph(drug, S_CELL), Paragraph(f"<font color='{hx}'><b>{dose}</b></font>", S_CELL), Paragraph(note, S_CELL), ]) dtbl = Table(drug_rows, colWidths=[doc.width*0.30, doc.width*0.28, doc.width*0.42]) dts = TableStyle([ ('BACKGROUND', (0,0), (-1,0), col), ('TOPPADDING', (0,0), (-1,-1), 4), ('BOTTOMPADDING', (0,0), (-1,-1), 4), ('LEFTPADDING', (0,0), (-1,-1), 5), ('RIGHTPADDING', (0,0), (-1,-1), 5), ('GRID', (0,0), (-1,-1), 0.3, C_DGREY), ]) for i in range(1, len(drug_rows)): dts.add('BACKGROUND', (0,i), (-1,i), bg if i%2==0 else C_WHITE) dtbl.setStyle(dts) items.append(dtbl) # Strategy / Trap / Monitoring bot = Table([[ Paragraph(f"<b>Dosing Strategy</b><br/>{m['strategy']}", S_CELL), Paragraph(f"<b>Common Trap</b><br/>{m['trap']}", S_CELL), Paragraph(f"<b>Monitoring</b><br/>{m['monitoring']}", S_CELL), ]], colWidths=[doc.width/3]*3) bot.setStyle(TableStyle([ ('BACKGROUND', (0,0), (0,0), colors.HexColor('#EBF5FB')), ('BACKGROUND', (1,0), (1,0), colors.HexColor('#FEF9E7')), ('BACKGROUND', (2,0), (2,0), colors.HexColor('#EAFAF1')), ('TOPPADDING', (0,0), (-1,-1), 5), ('BOTTOMPADDING', (0,0), (-1,-1), 5), ('LEFTPADDING', (0,0), (-1,-1), 6), ('RIGHTPADDING', (0,0), (-1,-1), 6), ('LINEAFTER', (0,0), (1,0), 0.5, C_LGREY), ('VALIGN', (0,0), (-1,-1), 'TOP'), ])) items.append(bot) # PAE + Analogy pae = Table([[ Paragraph(f"<b>Post-Antibiotic Effect (PAE):</b> {m['pae']}", S_CELL), Paragraph(f"<b>Analogy:</b> {m['analogy']}", S_CELL), ]], colWidths=[doc.width*0.55, doc.width*0.45]) pae.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), bg), ('TOPPADDING', (0,0), (-1,-1), 4), ('BOTTOMPADDING', (0,0), (-1,-1), 5), ('LEFTPADDING', (0,0), (-1,-1), 6), ('RIGHTPADDING', (0,0), (-1,-1), 6), ('LINEAFTER', (0,0), (0,0), 0.5, C_LGREY), ])) items.append(pae) story.append(KeepTogether(items)) story.append(Spacer(1, 0.35*cm)) # โโ Master comparison table โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ story.append(HRFlowable(width='100%', thickness=1.5, color=C_NAVY)) story.append(Spacer(1, 0.15*cm)) story.append(Paragraph('<b>Master Comparison Table</b>', ParagraphStyle('mct', fontName='Helvetica-Bold', fontSize=11, textColor=C_NAVY, alignment=TA_CENTER, spaceAfter=5))) def cp(txt, col=None): c = col or C_BLACK return Paragraph(txt, ParagraphStyle('cp', fontName='Helvetica', fontSize=8, textColor=c, alignment=TA_CENTER, leading=11)) def lp(txt): return Paragraph(f'<b>{txt}</b>', ParagraphStyle('lp', fontName='Helvetica-Bold', fontSize=8, textColor=C_BLACK, alignment=TA_LEFT)) comp_rows = [ [Paragraph('<b>Feature</b>', S_CELLHEAD), Paragraph('<b>Time-Dependent</b>', S_CELLHEAD), Paragraph('<b>Conc.-Dependent</b>', S_CELLHEAD), Paragraph('<b>AUC-Dependent</b>', S_CELLHEAD)], [lp('Key parameter'), cp('T > MIC', C_TEAL), cp('Cmax : MIC', C_AMBER), cp('AUC : MIC', C_GREEN)], [lp('What drives killing'), cp('Duration above MIC'), cp('Height of peak vs. MIC'), cp('Total exposure over 24h')], [lp('Ceiling effect?'), cp('YES โ saturates at 4x MIC'), cp('NO โ higher peak = more kill'), cp('NO โ more total exposure = more kill')], [lp('Dosing strategy'), cp('Frequent / extended infusion'), cp('Infrequent large bolus (OD)'), cp('OD or BD')], [lp('Drug-free trough safe?'), cp('NO โ bacteria regrow'), cp('YES โ PAE covers gap'), cp('YES โ partial PAE')], [lp('PAE'), cp('Minimal (Gram-neg)'), cp('Prolonged 1-4h (Gram-neg)'), cp('Moderate')], [lp('Key examples'), cp('Penicillins, Cephalosporins, Carbapenems'), cp('Gentamicin, Amikacin, Tobramycin'), cp('Vancomycin, Fluoroquinolones, Daptomycin')], [lp('Monitoring'), cp('Compliance; T>MIC %'), cp('Trough <1 mg/L'), cp('AUC24 400-600 (vancomycin)')], [lp('Missing dose impact'), cp('Major harm'), cp('Moderate'), cp('Moderate')], [lp('Analogy'), cp('Steady drip'), cp('Knockout punch'), cp('Total rainfall')], ] cw = [doc.width*0.22, doc.width*0.26, doc.width*0.26, doc.width*0.26] ctbl = Table(comp_rows, colWidths=cw) cts = TableStyle([ ('BACKGROUND', (0,0), (-1,0), C_NAVY), ('FONTSIZE', (0,0), (-1,-1), 8), ('ALIGN', (0,0), (-1,-1), 'CENTER'), ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), ('TOPPADDING', (0,0), (-1,-1), 4), ('BOTTOMPADDING', (0,0), (-1,-1), 4), ('LEFTPADDING', (0,0), (-1,-1), 4), ('RIGHTPADDING', (0,0), (-1,-1), 4), ('GRID', (0,0), (-1,-1), 0.4, C_DGREY), ('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'), ('ALIGN', (0,1), (0,-1), 'LEFT'), ]) for i in range(1, len(comp_rows)): cts.add('BACKGROUND', (1,i), (1,i), colors.HexColor('#EAF7FB') if i%2==1 else colors.HexColor('#D6EEF2')) cts.add('BACKGROUND', (2,i), (2,i), colors.HexColor('#FEF5E7') if i%2==1 else colors.HexColor('#FDEBD0')) cts.add('BACKGROUND', (3,i), (3,i), colors.HexColor('#EAFAF1') if i%2==1 else colors.HexColor('#D5F5E3')) cts.add('BACKGROUND', (0,i), (0,i), C_LGREY if i%2==1 else C_DGREY) ctbl.setStyle(cts) story.append(ctbl) story.append(Spacer(1, 0.35*cm)) # โโ GP Clinical Pearls โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ pearl_hdr = Table( [[Paragraph('<b>GP Clinical Pearls</b>', ParagraphStyle('ph', fontName='Helvetica-Bold', fontSize=10, textColor=C_WHITE, alignment=TA_CENTER))]], colWidths=[doc.width]) pearl_hdr.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), C_NAVY), ('TOPPADDING', (0,0), (-1,-1), 5), ('BOTTOMPADDING', (0,0), (-1,-1), 5), ])) story.append(pearl_hdr) pearls = [ f"1. <b>Amoxicillin TDS not OD</b> โ penicillins are time-dependent; once-daily fails despite the same total dose.", f"2. <b>Gentamicin once-daily is standard</b> โ achieves Cmax/MIC >=8-12 AND reduces nephrotoxicity via the drug-free trough.", f"3. <b>Vancomycin monitoring (2023-2026 update)</b> โ AUC<sub rise='2'>24</sub>/MIC target 400-600 mg.h/L is now preferred over trough-only monitoring.", f"4. <b>Levofloxacin 500 mg OD > 250 mg BD</b> โ same total dose but OD gives higher Cmax/MIC and adequate AUC/MIC.", f"5. <b>Meropenem extended infusion (3-4h) in ICU</b> โ for high-MIC resistant Gram-negatives; maximises T>MIC without extra dose.", f"6. <b>Missing beta-lactam doses = treatment failure</b> โ bacteria regrow rapidly once T>MIC is lost. Stress compliance.", f"7. <b>Rising MICs shrink the T>MIC window</b> โ reason for high-dose amoxicillin (80-90 mg/kg/day) in paediatric AOM.", ] pearl_rows = [[Paragraph(p, S_PEARLS)] for p in pearls] ptbl = Table(pearl_rows, colWidths=[doc.width]) ptbl.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), colors.HexColor('#F8F9FA')), ('TOPPADDING', (0,0), (-1,-1), 3), ('BOTTOMPADDING', (0,0), (-1,-1), 3), ('LEFTPADDING', (0,0), (-1,-1), 8), ('LINEBELOW', (0,0), (-1,-2), 0.3, C_DGREY), ])) story.append(ptbl) story.append(Spacer(1, 0.3*cm)) # Memory peg story.append(Paragraph( f"<b>Memory Peg:</b> " f"<font color='{HEX_TEAL}'>T>MIC = Beta-Lactams: Keep it STEADY</font> | " f"<font color='{HEX_AMBER}'>Cmax/MIC = Aminoglycosides: Hit it HARD once</font> | " f"<font color='{HEX_GREEN}'>AUC/MIC = Vancomycin/FQ: Total EXPOSURE matters</font>", ParagraphStyle('mem', fontName='Helvetica', fontSize=8.5, leading=12, alignment=TA_CENTER, borderColor=C_NAVY, borderWidth=1, borderPadding=7, backColor=C_LGREY))) doc.build(story, onFirstPage=header_footer, onLaterPages=header_footer) print("PDF generated successfully.") PYEOF cd /tmp/workspace/pkpd-reference && python generate_pdf.py
ls -lh /tmp/workspace/pkpd-reference/PKPD_Antibiotic_Reference.pdf
PKPD Antibiotic Reference
PDF Document ยท PDF
Create a quick reference PDF comparing all 3 PK/PD models with dosing strategies
PKPD Antibiotic Reference
PDF Document ยท PDF