Skip to main content
This notebook shows how to use the ZeroGPU Batch API to tag a CSV of customer reviews in a single asynchronous job. You hand the API a reviews.csv with one review per row, and you get back a tagged.csv with a sentiment label and a short list of topics for every row, plus a recoverable list of any rows that failed. By combining the Batch API’s OpenAI-compatible JSONL flow with LFM2.5-1.2B-Instruct, this notebook walks you through a practical pattern where thousands of rows are tagged overnight at a fraction of the cost of synchronous calls, keyed back to their source rows by custom_id. For the full reference, see the Batch API quickstart. For another end-to-end workflow, see: Screen resumes with LangChain and ZeroGPU. In this notebook, you’ll explore:
  • ZeroGPU Batch API: An asynchronous, OpenAI-compatible endpoint that takes thousands of /v1/chat/completions requests as a single JSONL file and returns the results within a completion window, at a lower per-request cost than synchronous calls. Here it tags every row of a customer-review CSV in one overnight job.
  • ZeroGPU: An ultra-fast, compute-efficient inference provider for apps and agents. We run purpose-built small and nano language models across an edge-powered network for the high-volume, purpose-specific tasks your app or agent runs constantly. Plug in our OpenAI-compatible API and you’re live - zero GPU infrastructure, serverless, auto-scaling by default.
  • LFM2.5-1.2B-Instruct: A small, fast instruct model that handles short-form classification well, keeping per-row cost low while still producing open-vocabulary topics and a JSON tag. See the model card for context window and playground.
This setup not only demonstrates a practical application of large-scale review tagging, but also provides a flexible framework that can be adapted to other real-world scenarios requiring high-volume, asynchronous classification over tabular data.

Run this example

Run it in Google Colab and execute cells top to bottom β€” no setup required. 🏷️ Run in Google Colab β†’ The notebook generates the dataset, builds the JSONL file, and runs the full Batch API workflow automatically.

πŸŽ₯ Watch the Video Guide

Prefer a quick walkthrough? Watch the full demo here:

πŸ“¦ Installation

First, install requests, the only dependency for driving the Batch API from Python. You reach ZeroGPU through its OpenAI-compatible REST surface, so no SDK is required:
The cURL examples below also use jq to pretty-print JSON responses. For the full lifecycle, see the Batch API quickstart.

πŸ”‘ Setting Up API Keys

You’ll need to set up your ZeroGPU API key so that every Batch API call authenticates. This ensures the upload, create, poll, and download calls can reach ZeroGPU securely. A Project ID is optional: supply one only if you want to scope the batch to a specific project. You can go to here to get an API key and Project ID from ZeroGPU. The key starts with zgpu-api- and the Project ID (UUID) is on the project settings page.
Python
This cookbook calls the raw REST surface with the x-api-key and x-project-id headers (x-project-id is optional - it scopes requests to a project). If you use an SDK client, authentication is handled for you. The cURL examples read the same values from your shell environment, and you can leave ZEROGPU_PROJECT_ID unset:
Python
For a fixed, short taxonomy, a classifier head like deberta-v3-small for sentiment or zlm-v1-iab-classify-edge for IAB topics is cheaper and slots into the same batch flow. Reach for LFM only when you need open-vocabulary topics or a free-form rationale. πŸŽ‰ ZeroGPU tags a review in a single call, returning a clean JSON object you can parse straight into a row, the building block for tagging an entire CSV at once!

πŸŒ™ Tag a CSV of Reviews Overnight

This section takes a CSV of customer reviews and produces a tagged copy plus a recoverable list of failures, with the Batch API running every row as one asynchronous job while you sleep. Your support tool exports reviews.csv, one review per row. You want a sentiment label and a short list of topics for every row, but calling the model synchronously across thousands of rows is slow and costly. Instead you submit them as a single batch, poll until it finishes, and merge the results back by custom_id. The job has five steps: prepare the data, build a JSONL request file, upload it, create the batch, then poll and download the results.

Step 1: Prepare the input CSV

The dataset is generated directly in the Colab notebook, so you do not need to prepare any files manually. Each row includes a unique review_id and a free-text review. One row is intentionally malformed (empty review) to demonstrate how invalid input is handled. Keep the review_id column unique. It is what links a tagged row back to its source, and duplicates are rejected at create time.

Step 2: Build the JSONL, one request per row

The notebook builds this JSONL file programmatically from the CSV, so you do not need to create it manually. We pin the same JSON-only system prompt on every line:
A single JSONL line for r-001 looks like this:
Row r-007 has no review text. The builder skips it locally rather than spending a request on a line the API would reject, and records it as a local skip.

Step 3: Upload the file and create the batch

Upload the JSONL with purpose=batch, then create the batch against /v1/chat/completions:
Validation runs at create time: the Batch API parses every line before POST /v1/batches returns, so a duplicate custom_id, a line over 1 MB, or "stream": true rejects the whole batch with a 400 that points at the offending line. Fix the JSONL locally and resubmit; nothing is charged for a rejected create.

Step 4: Poll until the batch finishes

Poll GET /v1/batches/{id} until the batch reaches a terminal state. A batch ends in one of four: completed, failed, expired, or cancelled. Only completed guarantees an output_file_id, and even a completed batch can carry a populated error_file_id when some lines failed. Don’t poll faster than every 30 seconds; the status only changes on minute-scale transitions.
Python

Step 5: Download and merge into a tagged CSV

The full script below reads the CSV, builds the JSONL (skipping the empty row), uploads, creates, polls, downloads the output and error files, and merges everything back into tagged.csv by custom_id. Failed rows land in failed.csv for inspection.
tag_reviews.py
A successful output line looks like this:
The script keys results by custom_id, then walks the original CSV in order to attach tags. This means the row order of tagged.csv is identical to reviews.csv, even though the Batch API returned results in arbitrary order, and rows that failed land with empty sentiment and topics columns instead of being dropped silently. reviews.csv goes in:
tagged.csv comes out:
Row r-007 carries through with empty tags because it was filtered locally before upload, so it never reached the API. Even a completed batch can have a populated error_file_id when some lines failed but the batch as a whole ran. A failed line carries a null response and a populated error. If you skip the local filter and let the API reject the empty row, the error file carries a line like this:
Do not re-run the whole job. Build a follow-up JSONL from the original input.jsonl, keyed by the custom_ids that appear in the error file, then upload and create a new batch the same way as before:
recover.py
Common per-line error codes: invalid_request_error (repair the line locally and retry), rate_limit_exceeded (wait, raise quota, then retry the failed custom_ids), model_error (transient, safe to retry as-is), and timeout (shorten the input or lower max_tokens, then retry). For a malformed row like r-007, the right fix is upstream: drop or backfill it before building the JSONL, which is exactly what build_jsonl already does. See the Errors reference for the full table. πŸŽ‰ From one JSONL upload, the Batch API tagged every review row, returned results keyed by custom_id, and surfaced failures as a recoverable list, all in a single overnight job that costs a fraction of synchronous calls.

🌟 Highlights

This notebook has guided you through setting up and running a ZeroGPU Batch API workflow for tagging a CSV of customer reviews with sentiment and topics. You can adapt and expand this example for various other scenarios requiring high-volume, asynchronous classification over tabular data. Key tools utilized in this notebook include:
  • ZeroGPU Batch API: An asynchronous, OpenAI-compatible endpoint that takes thousands of /v1/chat/completions requests as a single JSONL file and returns the results within a completion window, at a lower per-request cost than synchronous calls. Here it tags every row of a customer-review CSV in one overnight job.
  • ZeroGPU: An ultra-fast, compute-efficient inference provider for apps and agents. We run purpose-built small and nano language models across an edge-powered network for the high-volume, purpose-specific tasks your app or agent runs constantly. Plug in our OpenAI-compatible API and you’re live - zero GPU infrastructure, serverless, auto-scaling by default.
  • LFM2.5-1.2B-Instruct: A small, fast instruct model that handles short-form classification well, keeping per-row cost low while still producing open-vocabulary topics and a JSON tag. See the model card for context window and playground.
This comprehensive setup allows you to adapt and expand the example for various scenarios requiring high-volume, asynchronous classification over tabular data.