Skip to main content
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: