DEV Community

Qandil Tariq
Qandil Tariq

Posted on

Build an OCR Action pipeline with Kotlin: ML Kit (Android) + Ktor (server) + KMP roadmap

LetterLens scans a paper letter, extracts text with ML Kit, classifies it, pulls deadlines, and returns what/when/next. Android UI is Jetpack Compose; the API is Ktor; and the core parsing is moving to Kotlin Multiplatform.

Demo: https://youtube.com/shorts/lvZbWHVL1h4

Repo: https://github.com/Qandil11/LetterLens

Architecture (minimal)

Android app: Compose + ML Kit OCR → sends extracted text

Ktor server: /explain returns { type, deadline, summary, actions, citations }

KMP (WIP): move parsing/classifier into :shared for reuse

Run it locally (quickstart)

// Start the server
./gradlew :server:run
// healthcheck
curl http://127.0.0.1:8080/health

Device networking options

Emulator: base URL = http://10.0.2.2:8080/

Physical device (USB):

adb reverse tcp:8080 tcp:8080

base URL = http://127.0.0.1:8080/

Physical device (Wi-Fi): use your Mac/PC LAN IP, e.g. http://192.168.x.y:8080/

<!-- app/src/debug/AndroidManifest.xml -->
<application android:usesCleartextTraffic="true" />

Tiny Ktor module (sketch)

fun Application.module() {
install(ContentNegotiation) { json() }
routing {
get("/health") { call.respond(mapOf("ok" to true)) }
post("/explain") {
val req = call.receive<ExplainReq>()
val type = classify(req.text, req.hint)
val deadline = extractDeadline(req.text, type)
val (summary, actions, citations) = explainForType(type, req.text)
call.respond(ExplainRes(type, deadline, summary, actions, citations))
}
}
}

Why KMP here?

The classification/date parsing is pure Kotlin → easy to share across Android/iOS/desktop.

Keeps the server thin; long-term we can ship fully on-device.

Roadmap

Swap rule-based classifier for a compact model

Expand letter libraries (NHS/Council/HMRC/DVLA/UKVI)

Accessibility polish and offline mode

Tags: #android #kotlin #kmp #jetpackcompose #ktor #mlkit #ocr #nlp #govtech

Top comments (0)