We are building a batch product description generator that turns raw JSON specs into human-readable marketing copy. This helps e-commerce teams and content managers eliminate manual copywriting for large catalogs. Because Oxlo.ai charges per request instead of per token, you can feed it verbose ingredient lists or lengthy technical specifications without the cost scaling.
What you'll need
- An Oxlo.ai API key from https://portal.oxlo.ai
- Python 3.10 or newer
- The OpenAI SDK
pip install openai
Step 1: Instantiate the client
I point the OpenAI SDK at Oxlo.ai and select Llama 3.3 70B as the general-purpose model. The client is a drop-in replacement, so the rest of the code looks exactly like the standard OpenAI examples.
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key="YOUR_OXLO_API_KEY"
)
MODEL = "llama-3.3-70b"
Step 2: Lock the generation style
The system prompt is the most important part of an NLG pipeline. I force a consistent voice, sentence count, and constraint set so every product sounds on-brand.
SYSTEM_PROMPT = """You are a senior product copywriter. Turn the provided JSON specs into a compelling product description.
Rules:
- Write exactly 3 sentences.
- Lead with the primary benefit, not the feature name.
- Avoid jargon. Use active voice.
- Do not mention the word "JSON" or "specs".
- Output plain text only, no markdown formatting."""
Step 3: Write the generation function
This helper serializes the specs dictionary and calls the Oxlo.ai chat endpoint. I set temperature to 0.7 to keep output creative but consistent.
import json
def generate_description(specs: dict) -> str:
user_message = json.dumps(specs, ensure_ascii=False)
response = client.chat.completions.create(
model=MODEL,
temperature=0.7,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
)
return response.choices[0].message.content.strip()
Step 4: Process a whole catalog
Real workloads process files, not single items. I read a JSONL file of specs, generate a description for each line, and append the result to an output file. Since Oxlo.ai uses request-based pricing, long input specs do not inflate the cost the way they would on token-based platforms.
from pathlib import Path
def process_catalog(input_path: Path, output_path: Path):
with open(input_path, "r", encoding="utf-8") as fin, \
open(output_path, "w", encoding="utf-8") as fout:
for line in fin:
specs = json.loads(line.strip())
description = generate_description(specs)
record = {
"sku": specs.get("sku"),
"description": description,
}
fout.write(json.dumps(record, ensure_ascii=False) + "\n")
print(f"Generated for {record['sku']}")
if __name__ == "__main__":
process_catalog(Path("specs.jsonl"), Path("descriptions.jsonl"))
Run it
Create a specs.jsonl file with two products and execute the script. Here is the sample input and the resulting output.
{"sku":"OXLO-001","name":"Mechanical Keyboard","switch_type":"Hot-swappable Gateron Brown","battery_life":"None, USB-C wired","features":["RGB per-key backlighting","Aluminum frame","QMK/VIA support"]}
{"sku":"OXLO-002","name":"Noise-Cancelling Headphones","driver_size":"40mm titanium","battery_life":"60 hours with ANC on","features":["Adaptive transparency mode","Multipoint Bluetooth 5.3","Fold-flat design"]}
Run the generator:
python generate_descriptions.py
Expected output inside descriptions.jsonl:
{"sku": "OXLO-001", "description": "Type for hours without fatigue thanks to tactile Gateron Brown switches you can swap out on the fly. The aircraft-grade aluminum frame and per-key RGB lighting give your desk a premium look that lasts. Full QMK and VIA support lets you remap every key exactly how you work."}
{"sku": "OXLO-002", "description": "Enjoy deep, uninterrupted focus for up to 60 hours with adaptive noise cancellation that adjusts to your environment. Titanium 40mm drivers deliver crisp highs and rich bass whether you are on a call or lost in a playlist. The fold-flat design and multipoint Bluetooth 5.3 make commuting and device switching effortless."}
Next steps
Swap in qwen-3-32b if you need multilingual descriptions for international storefronts, or switch to kimi-k2.6 for longer narrative content. You can also add a Pydantic validation layer on top of the output to enforce exact sentence counts or extract structured fields like "primary benefit" and "target audience" for A/B testing.
Top comments (0)