Text Prompt Moderation for AI Image Generation: Chat JSON Schema in Node.js A developer outlines a moderation strategy for AI image generation services, recommending that all user-controlled text fields be screened by a chat classifier returning strict allow, review, or block JSON before image generation proceeds. The approach uses a single gate to avoid double latency and keeps policy in application code, with a Node.js example using fetch and environment variables for API configuration. Short answer: moderate every user-controlled text field with a chat classifier that returns strict allow , review , or block JSON, and call image generation only after an allow decision. | Choice | Best fit | Main trade-off | |---|---|---| | Direct OpenAI account | The product is already standardized on one provider | The moderation gate stays coupled to that account and its model catalog | | Direct Anthropic account | The team already operates its own classifier integration there | Image generation may still require another provider relationship | | Direct Google Gemini account | The application is already built around Google's model stack | Switching later means revisiting provider-specific integration code | | OpenRouter | Model aggregation is the primary requirement | Confirm schema behavior and image support against its current documentation | | Infrai | A small team wants plain REST, no required SDK, and one key across broader backend work | It has no dedicated moderation endpoint, so chat classification is part of the application | For a marketplace that turns text prompts into images, I would start with the same decision rule I use for any one-person SaaS: keep policy in application code, outsource the undifferentiated model execution, and refuse to spend the latency budget twice without a reason. The classifier is required. A second classifier pass is not. Treat moderation as a gate, not a logging side effect. Send the raw prompt and every user-editable style field to a chat completion before generating an image. Ask for one small JSON object under a strict schema. Then branch in code: allow continues, review enters a review queue, and block stops. No dedicated endpoint is required for this design. The important boundary is all user-controlled text. Checking prompt while trusting style , negativePrompt , or a marketplace listing caption leaves an obvious bypass. Keep those fields separate in storage and in audit records, but classify them together so the model sees the effective instruction that the image generator will receive. The schema should be intentionally boring: an enum decision, a short array of policy labels, and a brief reason are enough. Don't ask the classifier for prose that another function must interpret. Machine-readable output turns a probabilistic judgment into a deterministic branch, while the review state preserves ambiguity instead of forcing every uncertain prompt into either approval or rejection. This is also where the marketplace policy belongs. A provider can run the classifier, but it cannot decide which borderline product images the marketplace wants to review. One gate. One branch. This Node.js example uses fetch , so there is no client library version to maintain. It expects AI API BASE URL , INFRAI API KEY , CHAT MODEL , and IMAGE MODEL in the environment. The base URL should identify the API host without a trailing slash. Model IDs stay in configuration because availability changes and should be read from the provider's current model catalog rather than copied from an article. I've kept the result to three labels on purpose. The code validates the returned JSON even though the request uses a strict response schema; enforcement belongs at both boundaries. js import { randomUUID } from "node:crypto"; type Decision = "allow" | "review" | "block"; type ModerationResult = { decision: Decision; labels: string ; reason: string; }; type ImageRequest = { prompt: string; style: string; negativePrompt: string; }; const baseUrl = required "AI API BASE URL" .replace /\/$/, "" ; const apiKey = required "INFRAI API KEY" ; const chatModel = required "CHAT MODEL" ; const imageModel = required "IMAGE MODEL" ; function required name: string : string { const value = process.env name ; if value throw new Error Missing environment variable: ${name} ; return value; } function retryDelay response: Response, attempt: number : number { const value = response.headers.get "retry-after" ; if value { const seconds = Number value ; if Number.isFinite seconds return Math.max 0, seconds 1 000 ; const timestamp = Date.parse value ; if Number.isFinite timestamp return Math.max 0, timestamp - Date.now ; } return 250 2 attempt; } async function postJson path: "/v1/chat/completions" | "/v1/images/generations", body: unknown, idempotencyKey: string, : Promise