Image brief template: consistent Sume prompts with string.Template
Stop rewriting prompts by hand. Keep subject, style, lighting and constraints as fields, fill them from data and send the same shape to Sume's image endpoint.

To get consistent images from many prompts, write one brief template with named fields for subject, setting, style, lighting and constraints, then fill it from a dictionary or CSV row with Python's string.Template and send the result as prompt to Sume. When every prompt follows one shape, a difference in output comes from the one field you changed, which is the only way to tell whether a model or a wording made the difference.
Keep the template out of the API call. Parameters such as aspect_ratio and resolution are separate request fields, so do not write them into the prompt text.
Which fields belong in a brief?
| Field | Example | Goes in |
|---|---|---|
| Subject | A ceramic pour-over kettle | Prompt |
| Setting | On a pale oak counter | Prompt |
| Style and lighting | Soft window light, 50 mm look | Prompt |
| Avoid | No text, no logos | Prompt |
| Shape | 4:5 | aspect_ratio field |
| Size | 2K | resolution field |
What does the code look like?
safe_substitute leaves a missing field visible as $name instead of raising, which is easier to spot in a review pass than a half-built prompt. The check below refuses to send one.
import os, requests
from string import Template
BRIEF = Template(
"$subject, $setting. $style. Avoid: $avoid."
)
def build(row):
text = BRIEF.safe_substitute(row)
if "$" in text:
raise ValueError(f"unfilled field in: {text}")
return text
def generate(row, model="google/nano-banana-2"):
r = requests.post(
"https://api.sume.com/v1/images",
headers={"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"},
json={"model": model, "prompt": build(row), "aspect_ratio": row["ratio"]},
timeout=90,
)
r.raise_for_status()
return r.json()["data"][0]["url"]
if __name__ == "__main__":
print(generate({"subject": "A ceramic pour-over kettle", "setting": "on a pale oak counter", "style": "Soft window light", "avoid": "text and logos", "ratio": "4:5"}))How do I vary one field at a time?
Loop over a list of values for one field and hold the rest constant, then compare the results side by side. Pair this with the approval tracking in cost per approved ad image so wording changes are judged on pick rate and cost, not taste.
Should the template be versioned?
Yes. Put the template text and a version string in your repo and log the version next to each result. When a prompt wording changes, bump the version, so a later quality shift can be traced to the template and not to a model.
Sources
Related posts
More in Developers
- Image edit reference URL rejected? Public HTTPS checklist for Sume
Sume rejects localhost, private-network and non-HTTPS reference URLs, and a URL it cannot download fails as input_media_unreachable. Check yours in 12 lines.
- Image job progress bar: Sume has no percentage, so show job stages
ChatGPT Images 2.5 shows a progress percentage. Sume image jobs report queued, processing and completed plus events, and stream:true returns 400.
- Image quality defaults differ: OpenAI auto, Sume high, Ideogram medium
Omit quality and the tier differs: OpenAI defaults GPT Image 2.5 to auto, Sume to high, Ideogram 4.5 to medium, Image 1.0 to low. Pin it before you budget.
- image_size presets (landscape_16_9, square_hd): what Sume sends
Named image_size presets map to ratios on Ideogram, Grok, Imagen and Nano Banana, but pass through on GPT and FLUX. What auto means on each, checked in code.
Written by Sume