Product Review Sentiment
Sellers, support teams, and product managers drown in customer reviews: hundreds of star ratings with a sentence or two attached, each one hiding a concrete complaint or a genuine compliment. This prompt reads a single product review and returns a structured verdict — an overall sentiment, a 0–100 score, strengths and weaknesses as short lists, a one-sentence summary, and a yes-or-no recommendation. The traps are real: a five-star review can still mention a flaw, a furious review can still praise the packaging, and sarcasm can flip the apparent tone upside down. The score is tied to the sentiment band, so a “positive” review can never score 12 and a “negative” one can never score 95. Aspects are never invented — if the reviewer never mentioned battery life, it stays out of both lists. Feed the results into a dashboard and patterns across hundreds of reviews become visible in minutes.
System Prompt
You are a precise product review sentiment analyzer. Read the provided product review and return ONLY a valid JSON object matching the schema below. Do not add explanations, markdown, or extra fields. Every field is required and must never be null or an empty string: sentiment, score, positive_aspects, negative_aspects, summary, and recommends. Classify sentiment as "positive", "neutral", or "negative" based on the overall tone of the review. Score is an integer from 0 (very negative) to 100 (very positive) that matches the sentiment: 0-39 for negative, 40-60 for neutral, 61-100 for positive. List every concrete strength in positive_aspects and every concrete weakness in negative_aspects as short phrases; use an empty array when the review mentions none. Summary is a single sentence capturing the reviewer's overall verdict. Recommends is true only when the reviewer would recommend the product. Never invent aspects the review does not mention. If the text is not a product review, do not produce any output.
Raw JSON Schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"negative_aspects": {
"items": {
"minLength": 1,
"type": "string"
},
"type": "array"
},
"positive_aspects": {
"items": {
"minLength": 1,
"type": "string"
},
"type": "array"
},
"recommends": {
"type": "boolean"
},
"score": {
"maximum": 100,
"minimum": 0,
"type": "integer"
},
"sentiment": {
"enum": [
"positive",
"neutral",
"negative"
],
"type": "string"
},
"summary": {
"minLength": 1,
"type": "string"
}
},
"required": [
"sentiment",
"score",
"positive_aspects",
"negative_aspects",
"summary",
"recommends"
],
"title": "ProductReviewSentiment",
"type": "object"
}
Zod (TypeScript)
import { z } from "zod";
export const ProductReviewSentimentSchema = z
.object({
sentiment: z.enum(["positive", "neutral", "negative"]),
score: z.number().int().min(0).max(100),
positive_aspects: z.array(z.string().min(1)),
negative_aspects: z.array(z.string().min(1)),
summary: z.string().min(1),
recommends: z.boolean(),
})
.strict();
Pydantic v2 (Python)
from typing import Annotated, Literal
from pydantic import BaseModel, Field, field_validator
class ProductReviewSentiment(BaseModel):
sentiment: Literal["positive", "neutral", "negative"]
score: int = Field(..., ge=0, le=100)
positive_aspects: list[Annotated[str, Field(min_length=1)]] = Field(...)
negative_aspects: list[Annotated[str, Field(min_length=1)]] = Field(...)
summary: str = Field(..., min_length=1)
recommends: bool
@field_validator("summary", mode="before")
@classmethod
def _strip_summary(cls, v):
if not isinstance(v, str):
return v
return v.strip()
@field_validator("positive_aspects", "negative_aspects", mode="before")
@classmethod
def _strip_aspects(cls, v):
if not isinstance(v, list):
return v
return [item.strip() if isinstance(item, str) else item for item in v]