Skip to main content

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.