redact-04-connect-ocr, after redact-03-local-service
What actually travels?
When you upload a PDF or screenshot, the starter app already turns every page into a PNG image in the browser. Those images are what the service will read. Each page goes as its own request: the PNG bytes encoded as base64 text, the page’s width and height in pixels, and your privacy settings. Sending pages one at a time keeps every request small and lets the screen say Reading page 2 of 5 locally… as it goes. It also means one bad page can’t take the whole document down with it. The service checks the image before the model sees it. It decodes the PNG, measures it, and refuses it if the size doesn’t match what the browser said. That matters later: OCR’s boxes are only meaningful against the exact image it read.What if there’s no model?
The service might not be running, the model might fail to load, or the machine might be offline on first use. None of that should stop someone from redacting a document by hand, which the app could already do in lesson 01. So every failure in this lesson ends in the same place: the review screen, with a short message and the manual tools. This rule runs through the rest of the course: AI is an aid, never a gate. More on it: About Redact’s trust boundary.1. Get this lesson’s code
Stop the app and the service if they’re running. From the repository root,redact-course, bring in this lesson’s commit:
2. Read the analyzer
Openqvac-service/qvac-analyzer.ts.
It implements lesson 03’s DocumentAnalyzer with QVAC.
It loads the model once, on first use.
loading ??= means that if two pages arrive while the model is still loading, both wait for the same load instead of starting two.
If loading fails, loading is cleared so the next request tries again.
It checks the page before reading it.
sharp and compares it with what the browser claimed.
It reads the page and checks the answer.
ocrMs, how long OCR took.
3. Read how the service starts QVAC
Openqvac-service/index.ts:
QVAC_CONFIG_PATH is lesson 02’s trick: keep the models in redact/.qvac/models.
SNAP_USER_COMMON gives QVAC’s background worker its own home folder inside the app, so it doesn’t share ~/.qvac with anything else (Where QVAC writes files).
The runtime object is a thin wrapper around the SDK; it’s what lets the tests swap in a fake.
4. Read the browser side
Opensrc/features/redact/RedactApp.tsx and find prepare.
After the pages are rasterized, it asks for health and then sends every page:
5. Start the service and the app
In one terminal:Redact QVAC service listening on http://127.0.0.1:4317.
In a second terminal, in the same redact folder:
6. Upload a page
Choosepublic/test-files/redact/chat-private.png, select Private, and select Prepare for review.
The screen shows Preparing locally and Reading page 1 of 1 locally….
There’s also a Loading the local OCR model and reading each page… message in between, but it usually flashes past too quickly to read.
The model loads from .qvac/models, which you filled in lesson 02, so this takes about 20–30 seconds.
7. See the evidence
The review screen opens. In the right-hand column a new panel reads 12 text regions found locally. It lists each line with its recognition score, for exampleMaya Chen and maya.chen@example com, each followed by something like 93% recognition.
Notice what hasn’t changed: Safe-share preview is still uncovered, and there are no outlines on the page yet.
OCR found text; nothing has been decided.
Check the service from a third terminal:
state is now ready.
The model stays loaded, so the next file skips the loading step and only the reading takes time.
8. Cover something by hand
Drag acrossMaya Chen on Original.
The mark appears and the preview turns black there, just as in lesson 01.
Select Done, then Save copy, and open the file to confirm.
9. Turn the service off
Stop the service withCtrl+C in its terminal.
It unloads the model and exits without printing an error.
In the app, select Redact another document, upload chat-private.png again, choose Private, and select Prepare for review.
The review screen still opens, with the message Local analysis is unavailable. You can still redact by hand.
There’s no OCR panel this time.
Draw a mark, select Done and Save copy: the copy is saved as before.
If something goes wrong
- The service exits with
Redact QVAC service failed:while starting: read the rest of the line. If it mentions the model, runnpm run qvac:ocr-smokefrom lesson 02 to check the download on its own. - The service prints
Redact QVAC analyze-page failed: Raster dimensions do not match the request: the browser and service disagree about the page size, which shouldn’t happen with the test files. Upload a fresh file rather than reusing one mid-analysis. - The app always shows “Local analysis is unavailable”: check the service is running on 4317 with
curl http://127.0.0.1:4317/health.
10. Check your work
Stop the dev server, then run:npm test reports Tests 46 passed (46).
qvac-analyzer.test.ts drives the analyzer with a fake runtime: it checks that the model loads once, that a size mismatch is refused, and that malformed OCR blocks never leave the service.
So what just happened?
A page left the browser, crossed to a process on your own machine, was read by QVAC, and came back as text with positions. When that process was missing, the app said so in one line and let you carry on by hand.Try it yourself
Uploadpublic/test-files/redact/statement-multipage.pdf.
Watch the message count through the pages, then use Next → on the review screen to see each page’s own OCR panel.
Where to next
- Every file in this checkpoint:
redact/atredact-04-connect-ocr - About running AI on your own machine