Documentation Index
Fetch the complete documentation index at: https://runcrate.ai/docs/llms.txt
Use this file to discover all available pages before exploring further.
Generate structured, SEO-ready product descriptions from raw product data using DeepSeek-V3 with the Vercel AI SDK’s Output.object.
Vercel AI SDK — structured output
import { runcrate } from '@runcrate/ai';
import { generateText, Output } from 'ai';
import { z } from 'zod';
const ProductListing = z.object({
title: z.string().describe('SEO product title, 50-70 chars'),
shortDescription: z.string().describe('One-sentence hook, under 160 chars'),
longDescription: z.string().describe('2-3 paragraph description'),
bulletPoints: z.array(z.string()).describe('5-7 feature bullets'),
metaDescription: z.string().describe('Meta description, under 155 chars'),
tags: z.array(z.string()).describe('5-10 product tags'),
});
const { output } = await generateText({
model: runcrate('deepseek-ai/DeepSeek-V3'),
output: Output.object({ schema: ProductListing }),
prompt: `Generate a product listing for:
Name: AeroFit Pro Wireless Earbuds
Category: Audio / Earbuds
Specs: Bluetooth 5.3, ANC, 32-hour battery, IPX5, 6mm drivers
Price: $79.99`,
});
console.log(output.title);
console.log(output.bulletPoints);
Next.js API route
// app/api/generate-listing/route.ts
import { runcrate } from '@runcrate/ai';
import { generateText, Output } from 'ai';
import { z } from 'zod';
const ProductListing = z.object({
title: z.string(), shortDescription: z.string(), longDescription: z.string(),
bulletPoints: z.array(z.string()), metaDescription: z.string(), tags: z.array(z.string()),
});
export async function POST(req: Request) {
const { name, category, specs, price } = await req.json();
const { output } = await generateText({
model: runcrate('deepseek-ai/DeepSeek-V3'),
output: Output.object({ schema: ProductListing }),
prompt: `Generate an SEO product listing.\nName: ${name}\nCategory: ${category}\nSpecs: ${specs}\nPrice: ${price}\n\nBe specific. Avoid superlatives.`,
});
return Response.json(output);
}
Python — JSON mode
from runcrate import Runcrate
import json
client = Runcrate(api_key="rc_live_YOUR_API_KEY")
response = client.models.chat_completion(
model="deepseek-ai/DeepSeek-V3",
messages=[
{"role": "system", "content": "Generate SEO product listings. Return valid JSON only."},
{"role": "user", "content": "JSON fields: title, shortDescription, longDescription, bulletPoints, metaDescription, tags\n\nProduct: AeroFit Pro Wireless Earbuds\nSpecs: Bluetooth 5.3, ANC, 32hr battery, IPX5\nPrice: $79.99"}
],
response_format={"type": "json_object"},
)
listing = json.loads(response.choices[0].message.content)
print(f"Title: {listing['title']}")
Batch generation
import json, csv
# Using the same client from above
with open("products.csv") as f:
products = list(csv.DictReader(f))
results = []
for p in products:
response = client.models.chat_completion(
model="deepseek-ai/DeepSeek-V3",
messages=[
{"role": "system", "content": "Generate SEO product listings. Return valid JSON only."},
{"role": "user", "content": f"Fields: title, shortDescription, longDescription, bulletPoints, metaDescription, tags\n\nName: {p['name']}\nSpecs: {p['specs']}\nPrice: {p['price']}"}
],
response_format={"type": "json_object"},
)
results.append(json.loads(response.choices[0].message.content))
with open("listings.json", "w") as f:
json.dump(results, f, indent=2)
Tips
- Structured output.
Output.object with Zod is the most reliable way to get typed JSON from the AI SDK.
- JSON mode in Python. Pass
response_format={"type": "json_object"} and mention “JSON” in the system prompt.
- SEO title. Google displays 50-60 characters. Front-load the product name.