← All projects

Faculty of Pharmacy, Universitas Islam Sultan Agung

ResepCerdas

deployed, no users recorded

Evaluated on synthetic prescriptions; not yet cleared for real patient data.

Faculty of Pharmacy, Universitas Islam Sultan Agung

A prescription is written in Latin shorthand, and the patient has to take it correctly.

It turns a photographed prescription into corrected drug lines, then checks each line with 34 deterministic administrative, pharmaceutical, and clinical rules. No screening verdict comes from a language model.

End to end62 seconds, one pass
resepcerdas / full run

One pass through all four steps: a photographed prescription is read, corrected by the pharmacist, screened by the 34 checks, and printed as a patient label.

Delivered interface
resepcerdas / unggah

A photographed prescription becomes four structured drug lines. The satellite states that reading the photo is the only place a language model is used, and that no screening verdict comes from it.

Illustrative product mockup drawn from the project's own tokens, status chips and finding titles. The prescription and the pharmacist's notes are from the project's synthetic corpus and the identities are masked; the pharmacist appears as a role, never as a named person.

Measured

34
deterministic checks: 10 administrative, 10 pharmaceutical, 14 clinical
19 / 19
fields read on both benchmark fixtures, clean and degraded — synthetic handwriting, not a doctor's own
2.2 s
extraction latency on the clean fixture, 2.3 s on the degraded one
10 of 40
prescription images hand-labelled; the other 30, including all 20 real ones, are unlabelled
2,008
drugs seeded, with 484,719 interaction pairs and 7,862 searchable names
0
screening verdicts from a language model; the three screening layers are deterministic

Delivered

Six-stage pipeline over one object+

Input policy, vision extraction, then three screening layers and the label. Extraction builds one Prescription and every later stage only appends signals to it, so what the machine examined is reconstructable from the object alone.

One file per check+

Each of the 34 checks is a file named after its rule, exporting a function of (prescription, knowledge base). A check never opens a database connection, which is what lets it be tested against a plain object with no database at all.

The whole grid persisted, not just the problems+

Every verdict from every run is stored, including the ones that passed and the ones that did not apply, so the record answers what the machine actually examined rather than leaving that to be re-derived.

Knowledge base behind a domain boundary+

Checks ask domain questions — the dose reference for this line — never SQL questions. The boundary is built once per request and memoised, so 34 checks across several drugs do not each re-query.

Fail-closed reading+

An unreadable or non-prescription photo is refused rather than guessed at, and a drug line with no dose reference is shown as not yet screened rather than as safe. Absence of a finding is never rendered as a green light.

An advisory read that cannot become a verdict+

A language model may write an advisory note, but only into a slot the deterministic layers left marked as not checked, and it is authoritative for nothing. The constraint is enforced by the stage that runs it rather than asked of a prompt.

Drug knowledge bases built offline+

Three datasets — the Indonesian national formulary, openFDA labels and a drugs.com scrape — normalised into one record shape by a Python pipeline and flattened into a single searchable name table at seed time.

One worker, no second service+

Next.js compiled through OpenNext onto a single Cloudflare Worker, with SQLite at the edge for both the app tables and the drug knowledge base, object storage for the photographs, and a key-value cache keyed by image hash so the same photo is never read twice.

Phone-first test suite+

End-to-end specs run only on an iPhone and a Pixel, because the pharmacist's surface is a phone. Every page is asserted against three floors: no horizontal overflow, no text under 12px, and minimum control heights by tier.