redact-02-first-ocr, after redact-01-starter
First, which kind of model?
“AI model” covers very different tools. A language model reads and writes text. A speech model turns audio into text, an embedding model turns text into numbers you can compare, and a decision model like the one we’ll meet in lesson 06 answers questions you define. So the first question is always the same: what kind of data do you have? Most of the clever models only read text. Anything else, an image, a scan, a recording, has to become text first.Why OCR, not a vision model?
For images there are two options, and they answer different questions. A vision-language model looks at the picture and describes it: “a chat between Maya Chen and a colleague about a contract”. OCR transcribes it: every line of text, exactly, with a box around where it sits. Redact needs the second. To cover a phone number we need its characters, to decide it’s private, and its position, to draw a black box over exactly those pixels. A vision model can tell you there’s a phone number; it can’t reliably tell you which 300 pixels to paint. OCR is also small and fast. QVAC’s English OCR is two files, about 98 MB, and reads a page in roughly 20 seconds on a laptop. The same reasoning goes for audio: if you needed to know when each word was said, you’d want a transcription model that returns timestamps, not one that only summarises. More on this choice, for any app: Choosing the right model for your data.How QVAC’s OCR works
It runs in two stages. A detector finds the regions of the image that look like text. A recognizer reads the characters inside each region. You get back a list of blocks. Each block has thetext, a bbox (the box’s pixel corners in the image) and a confidence between 0 and 1.
Confidence means “how sure am I about these characters”, not “is this private”; that’s a separate question, and a separate model, later.
We’ll run it from a small script, outside the app.
If anything goes wrong with installing or downloading, it goes wrong here, on its own, where it’s easy to see.
1. Get this lesson’s code
Stop the app if it’s running. From the repository root,redact-course, bring in this lesson’s commit and install the new package:
npm ci takes a few minutes.
To see every change, open the comparison on GitHub.
The commit touches four files you’ll care about:
2. Read the script before running it
Openqvac-service/ocr-smoke.mjs.
It does five things, in this order.
It picks the image and fingerprints it.
public/test-files/redact/chat-private.png.
The SHA-256 digest ties the output to this exact file, so you can tell later which image a result came from.
It tells QVAC where to keep models, before loading QVAC.
.qvac/config.json with a cacheDirectory inside the app, points QVAC_CONFIG_PATH at it, and only then imports the SDK.
That keeps Redact’s models in redact/.qvac/models instead of a shared folder in your home directory.
QVAC’s background worker still keeps a little of its own state, a download registry and temporary files, in ~/.qvac (Where QVAC writes files).
It loads the OCR model.
OCR_LATIN is a catalog name for the detector and recognizer pair; the first call downloads them.
langList: ["en"] reads English, magRatio: 1.5 enlarges the image a little so small text is easier to detect, and defaultRotationAngles lets the recognizer try sideways text.
loadModel returns a modelId, which every later call uses.
It reads the image.
paragraph: false keeps each line as its own block instead of merging nearby lines.
We want lines: a phone number should be its own box, not part of a paragraph.
It cleans up, even when something fails.
unloadModel frees the memory but keeps the downloaded files (clearStorage: false).
close stops QVAC’s background worker so the script can exit.
3. Run it
redact/.qvac/models.
Otherwise the first run downloads the two model files, about 98 MB, which takes a minute or two depending on your connection, then reads the image.
On a first run, QVAC’s download logs come first, many lines starting [QVACRegistryClient] [INFO] Downloading blob….
They go to the same output and can’t be redirected, so the JSON comes at the end.
It starts like this:
QVAC OCR smoke failed:.
The usual causes are an interrupted npm ci (run it again) or no internet on the first run (the model has to download once).
If the message mentions ENOENT and stat "…/.qvac", your ~/.qvac is a broken link or isn’t writable: replace it with a real folder (mkdir ~/.qvac once the old link is gone).
4. Read the blocks
Scroll throughblocks.
There are 12, one per line or phrase in the image:
example.com, and its confidence is lower than the clean lines around it.
Small mistakes like this are normal, and the rest of the course is built to live with them.
Notice too that the private details aren’t always whole lines.
“phone is +1 415 555 0184.” mixes ordinary words with a number; we’ll come back to that in lesson 06.
Each bbox is four numbers: the top-left and bottom-right corners, in pixels of this image.
They’re what will let us draw boxes in exactly the right place, in lesson 05.
5. Run it again
stats, something like:
redact/.qvac/models.
There are two files: …craft_mlt_25k.gguf is the detector and …latin_g2.gguf the recognizer.
6. Check your work
npm test reports Tests 35 passed (35).
These tests check the path logic in local-config.ts; they don’t run the model.
Your proof that the model works is the output of step 3.
So what just happened?
A model ran on your own machine and turned a picture into text with positions. It downloaded once, then worked from a folder inside the app. Nothing about the image left your computer.Try it yourself
Run the script on the photo-quality version of the same chat:confidence values with the PNG.
Where to next
- Every file in this checkpoint:
redact/atredact-02-first-ocr - About local OCR and OCR boxes and rotation