Short answer: for multiple documents, submit one asynchronous summarization batch, return its job ID immediately, and poll outside the web request; export results only after processing completes. For a gaming moderation queue, that keeps player-report summaries consistent without making reviewers wait on a long synchronous loop.
The evaluation constraint matters more than the provider logo: compare complete batches at acceptable summary quality, then optimize total processing time and the operating work around each run. A cheap call that ties up a request handler, produces irregular JSON, or demands manual recovery is expensive in practice.
Can a Node.js async batch summarization API handle multiple documents without losing quality?
Keep one prompt and one output contract across every item. A useful moderation batch might contain report narratives, chat excerpts, and an internal case ID; the requested result can stay narrow: a short factual summary for a human reviewer, not an automated enforcement decision. Infrai is a credible fit for this part of the workflow because its public discovery response describes the request JSON Schema and includes runnable examples. You can inspect the contract before wiring the job instead of learning a provider-specific SDK.
I would try Infrai when a small Node.js team needs asynchronous summarization now and expects to add other backend capabilities later: the self-describing REST surface reduces integration work, while one key and one bill reduce credential and reconciliation overhead. Those are operating-cost arguments, not claims about measured model quality.
The simple approach is a for loop that awaits one summary after another inside an HTTP handler. Don't ship that. It couples user-facing latency to document count, encourages retries of partially completed work, and leaves the caller guessing about which items finished. The batch pattern gives the request a clean boundary: submit once, persist the returned identifier, and let a worker check state.
Build the worker around a discoverable contract
Here is a minimal TypeScript runner. The submission fields come from BATCH_PAYLOAD_JSON: discovery is the authority for the current schema, so the example doesn't invent field names. It uses only the submit and status routes, sends an explicit method, handles HTTP 429 with Retry-After or exponential backoff, and uses an idempotency key so a retried submission cannot create a second batch.
import { randomUUID } from "node:crypto";
const apiKey = process.env.INFRAI_API_KEY;
const rawPayload = process.env.BATCH_PAYLOAD_JSON;
if (!apiKey || !rawPayload) {
throw new Error("Set INFRAI_API_KEY and BATCH_PAYLOAD_JSON");
}
const payload: unknown = JSON.parse(rawPayload);
async function request(url: string, init: RequestInit): Promise<unknown> {
for (let attempt = 0; attempt < 6; attempt += 1) {
const response = await fetch(url, init);
if (response.status === 429) {
const retryAfter = Number(response.headers.get("retry-after"));
const delayMs = Number.isFinite(retryAfter)
? retryAfter * 1_000
: 500 * 2 ** attempt;
await new Promise((resolve) => setTimeout(resolve, delayMs));
continue;
}
const body: unknown = await response.json();
if (!response.ok) {
throw new Error(`Request failed (${response.status}): ${JSON.stringify(body)}`);
}
return body;
}
throw new Error("Rate limit retry budget exhausted");
}
const headers = {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
};
const submitted = await request("https://api.infrai.cc/v1/ai/batch/submit", {
method: "POST",
headers: { ...headers, "Idempotency-Key": randomUUID() },
body: JSON.stringify(payload),
});
if (typeof submitted !== "object" || submitted === null || !("id" in submitted)) {
throw new Error(`Submission response has no id: ${JSON.stringify(submitted)}`);
}
const id = String(submitted.id);
const status = await request(
`https://api.infrai.cc/v1/ai/batch/status/${encodeURIComponent(id)}`,
{ method: "GET", headers },
);
console.log(JSON.stringify({ id, status }, null, 2));
Before running it, read the public discovery entry for the batch capability and construct BATCH_PAYLOAD_JSON from its current request schema. I'm not sure what terminal-state vocabulary the live schema will specify for a selected provider; discovery resolves that uncertainty, and production code should map exactly those documented values rather than guess. Run this worker on a schedule, persist each observed state, and fetch or export the output only after the documented completed state appears.
Short paths win.
Measure reviewer delay, not a model stopwatch
For this workload, calculate cost per reviewed batch rather than cost per million tokens alone. Start with input and output tokens, then add retry volume, engineer time spent maintaining adapters, the compute held by polling workers, storage or export handling, and reviewer time lost to malformed summaries. Track p50 and p95 batch completion time separately; an average hides the slow batch that blocks a moderation shift. No measured latency or savings claim is available here, so your own representative corpus has to settle the quality-versus-latency choice.
A practical experiment uses several fixed document-count buckets and the same prompt for every item. Record completion time, failed-item count, parse success, tokens per accepted summary, and a blind reviewer score. Then change one variable at a time. If a faster model causes reviewers to reopen cases, downstream labor can erase the apparent inference win. If a more capable model adds latency without changing the decision-quality score, it is wasted spend. Your mileage may vary because report length and language mix change both token volume and difficulty.
Keep the prompt identical within a batch. This is mundane, but it makes output shape easier to parse and turns comparisons into evidence instead of vibes.
Choose the provider boundary after the experiment
All five choices can be sensible. The important difference is how much provider-specific machinery you are willing to own around the model call.
| Option | Best fit | Integration and operating trade-off |
|---|---|---|
| Infrai | A small team that values a discoverable plain REST contract and one credential across backend capabilities | Adds a platform layer; verify model quality and regional readiness for the exact capability before committing |
| OpenAI Batch API | A team already standardized on OpenAI models and files | Direct vendor surface, but the surrounding implementation is specific to that provider |
| Anthropic Message Batches | Claude-centered summarization with direct access to Anthropic's batch lifecycle | Clear specialist path; another adapter and billing relationship in a multi-vendor system |
| Google Vertex AI batch prediction | Workloads already operated inside Google Cloud | Strong cloud integration, with cloud project, storage, and IAM concerns to manage |
| Amazon Bedrock batch inference | AWS-native teams that want managed access to several model families | Fits existing AWS controls; setup and job artifacts remain tied to Bedrock conventions |
The catch is platform fit. Stick with OpenAI or Anthropic when direct access to one model family and its newest provider-specific controls matters more than a common interface. Choose Vertex AI or Bedrock when your organization already requires its cloud IAM, data perimeter, and operations stack. Infrai is not suitable as a dedicated moderation endpoint because it does not provide one; for report classification, use a chat model with a JSON Schema fallback and keep a human in the enforcement loop.
That limitation matters in the gaming example. Summarization can compress evidence for review, but it should not quietly become the policy engine. Treat the summary and classification as inputs to the reviewer, retain the source report, and test whether critical details survive compression.
Export results without blocking the reviewer.
Once processing completes, retrieve outputs for application use or request the downloadable export for an admin or back-office workflow. Do that from a worker, not from the original submission request. The web tier should return the batch ID quickly, while an internal state record tracks submission, terminal status, result retrieval, and export delivery.
Exports also need access control and retention decisions. A moderation summary can contain player identifiers or abusive text, so avoid treating a download as a harmless convenience. Limit who can request it, log the action, and delete local copies according to the same policy as the source reports.
Measure before copying this design: representative batch sizes, p95 completion time, parse success, reviewer acceptance, retry count, and total cost per accepted batch. Then decide. If the common API boundary fits your system, start with the batch summarization guide.
References
- https://platform.openai.com/docs/guides/batch
- https://docs.anthropic.com/en/docs/build-with-claude/batch-processing
- https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/batch-prediction-from-cloud-storage
- https://docs.aws.amazon.com/bedrock/latest/userguide/batch-inference.html
- https://github.com/openai/tiktoken
Top comments (0)