Read and extract information from prescription label images. Triggered by "read this prescription", "what does this label say?", "Cleo, read this Rx", or any request to interpret a prescription label photo. Extracts NDC, drug name, directions, prescriber, pharmacy, and other details, then optionally runs an FDB lookup on the NDC.
Two-pass cross-model verification for high-confidence extraction:
sph-cleo-rx/<site-id>/), results saved as JSON with a slot for human correctionsDifferent architectures, different training, different failure modes. When both agree → high confidence. When they disagree → flag for human review.
All scripts are in .
skills/cleo-prescription-reader/scripts/node skills/cleo-prescription-reader/scripts/rx_read.js <image-path> [--site-id <id>] [--no-ndc] [--output-dir <dir>]
Runs the complete flow: S3 upload → GPT-4o extraction → Claude Sonnet verification → NDC lookup → save results.
--site-id — folder in S3 bucket (default: default). Examples: aegis-qa, aegis-cala--no-ndc — skip the FDB NDC lookup step--output-dir — where to save result JSON (default: data/rx-results/)# Pass 1 only: GPT-4o extraction
node skills/cleo-prescription-reader/scripts/rx_extract.js <image-path> [--site-id <id>]
# Pass 2 only: Claude Sonnet verification
node skills/cleo-prescription-reader/scripts/rx_verify.js <image-path> <extraction-json-file>
If the user sends an image in chat, save it to a temp file first.
node skills/cleo-prescription-reader/scripts/rx_read.js /tmp/rx-image.jpg --site-id default
Present results in two sections:
📋 **Prescription Label**
**Patient**
- **Name:** {first_name} {middle_name} {last_name}
**Medication**
- **NDC:** {ndc, formatted 5-4-2 with dashes}
- **Drug:** {drug name and strength}
- **Directions:** {sig / directions for use}
- **Quantity:** {quantity dispensed}
- **Days Supply:** {days supply}
- **Refills:** {refills remaining}
- **RX #:** {prescription number}
- **Date Filled:** {fill date}
- **Expiration:** {expiration date if visible}
- **Manufacturer:** {manufacturer if visible}
- **Pill Description:** {color, shape, imprint if visible}
**Prescriber**
- **Name:** {doctor name and credentials}
- **NPI:** {prescriber NPI}
- **DEA:** {DEA number}
**Pharmacy**
- **Name:** {pharmacy name}
- **Address:** {pharmacy address}
- **Phone:** {pharmacy phone}
- **NPI:** {pharmacy NPI}
XXXXX-XXXX-XX (5-4-2)🔍 **Verification (Claude Sonnet 4)**
- **Overall Score:** {overall_score}/100
- **NDC:** {score}/100 {flag if any}
- **Drug:** {score}/100
- **Directions:** {score}/100 {flag if any}
...
Only show fields with flags or scores below 90. If all scores are 90+, just show the overall score.
Format using the standard cleo-ndc-lookup template. Skip if no NDC was found or --no-ndc was used.
If the image contains multiple labels, extract each one separately with its own sections, separated by a divider (---).
sph-cleo-rxsph-cleo-rx/<site-id>/<timestamp>-<hash>.<ext>default. Examples: aegis-qa, aegis-cala{
"id": "rx-<timestamp>-<hash>",
"site_id": "default",
"timestamp": "ISO-8601",
"image": {
"local_path": "/tmp/rx-image.jpg",
"s3_uri": "s3://sph-cleo-rx/default/...",
"s3_key": "default/..."
},
"pass1_extraction": {
"model": "gpt-4o",
"temperature": 0.0,
"extraction": { ... }
},
"pass2_verification": {
"model": "claude-sonnet-4-20250514",
"temperature": 0.3,
"verification": { ... }
},
"ndc_lookup": { ... },
"human_correction": null
}
The human_correction field is a slot for storing manual corrections, enabling a feedback loop to improve prompts over time.