FastAPI serves the upload page and API, and Tesseract runs in a separate
background function. Files pass between them through a volume. The app accepts
PDF, JPEG, and PNG files.
Source is in document_processing/.
The CLI installs once with uv tool install lazycloud-client. The commands
below download a standalone project and install its dependencies, with no
repository checkout. The rest of the guide runs from that directory through
uv run, which uses the project’s pinned SDK.
Prepare the app
uv sync installs FastAPI from pyproject.toml so the CLI can import the
application. Tesseract and Poppler install only in the remote image.
The app declares its shared volume in resources.py:
Both workloads include volumes=[data_volume], and LazyCloud creates or
reuses the volume when they start. The secret that signs job tokens needs an
initial value. Run the example’s Python setup module once:
configure.py calls Secret(JOB_TOKEN_SECRET_NAME).create(...) with a random
value and never prints it. It refuses to replace an existing secret, so if you
already configured this workspace, skip to deployment. The signing secret
protects individual results, and only the HTTP service receives it.
This example’s upload URL is public. Anyone with the URL can submit work
that uses your compute. Use test documents, stop the app when finished, and
add user authentication and upload rate limits before offering it to users.
Deploy and upload
Open the document-api URL from the deploy output and pick a document in the
upload form. The page submits it, shows job progress, and displays the
extracted text. The limits are 20 pages per PDF, 10 MiB per upload, and
200,000 characters per text result.
The worker removes the raw upload after processing, even when processing
fails. Click Delete result in the browser when you no longer need the text.
Results from abandoned jobs stay in the volume until you delete them.
Call the API from a script
Set the URL without a trailing slash. These commands need curl and jq:
This uploads a local sample.pdf and saves the returned job token without
printing it. Read the status:
Once status is complete, fetch the text:
The result route returns HTTP 409 until the task finishes. If the task fails,
inspect its error before retrying the upload. The token lets its holder read
or delete that one job and expires after 24 hours. Keep it out of logs and
URLs.
Delete the result once your script has saved it:
Deletion returns HTTP 409 while work is still running.
Diagnose a failed upload or job
For an HTTP error, inspect uv run lazycloud logs --deployment document-api -n 100.
For OCR failures, use:
The API and worker definitions live in app.py and worker.py. To adapt the
app, change resource sizes and upload limits there and in resources.py, and
add a retention job for abandoned results. Rotating
DOCUMENT_JOB_TOKEN_SECRET invalidates every outstanding job token.
Clean up
Delete the two deployments to stop accepting work:
If you created the volume and secret for this example, download any results
you need before removing them: