इमेज ऑटो-जनरेट कैसे करें: टेम्पलेट, jobs और webhooks
इस सवाल के ज़्यादातर जवाब किसी टेक्स्ट बॉक्स का स्क्रीनशॉट होते हैं। prompt टाइप कीजिए, बटन दबाइए, इंतज़ार कीजिए, डाउनलोड कीजिए, फिर से वही। यह automation नहीं है। यह आप ही हैं, हाथ से काम करते हुए, बस ज़्यादा तेज़।
अपने-आप होने का मतलब है बीच में कोई इंसान नहीं। डेटा की एक पंक्ति आती है, एक इमेज निकलती है, और किसी ने उसे होते नहीं देखा। इसके लिए चार हिस्से चाहिए: छेदों वाला एक prompt टेम्पलेट, छेद भरने के लिए डेटा, एक ऐसी queue जो बिना अटके काम ले ले, और नतीजा रखने के लिए कोई टिकाऊ जगह। बीच वाला API हम चलाते हैं, इसलिए हम वे pipelines भी देखते हैं जो लोग बनाते हैं और वे भी जो लॉन्च के तीन हफ़्ते बाद चुपचाप टूट जाती हैं।

वह बात जो कोई सबसे पहले नहीं बताता: यह अब सस्ता है
नंबर से शुरू कीजिए, क्योंकि वही बदलता है कि आप क्या बनाने को तैयार होंगे।
Nano Banana 2 Lite से हज़ार इमेज $23.80 की पड़ती हैं। यानी 1,000 × $0.0238, 26 अगस्त 2026 की हमारी कीमत पर। एक लाख प्रोडक्ट शॉट — एक असली कैटलॉग, हर SKU, हर colourway — $2,380 के।
जिन टियरों के बीच आप चुनेंगे, उन पर यही वॉल्यूम:
| इमेज | Nano Banana 2 Lite | Nano Banana 2 | Nano Banana Pro |
|---|---|---|---|
| 100 | $2.38 | $4.00 | $7.50 |
| 1,000 | $23.80 | $40.00 | $75.00 |
| 10,000 | $238.00 | $400.00 | $750.00 |
| 100,000 | $2,380.00 | $4,000.00 | $7,500.00 |
कीमतें और प्रोडक्ट की शर्तें समय के साथ बदल सकती हैं; खरीद का फ़ैसला लेने से पहले हर provider की मौजूदा कीमत जाँच लें। Google Batch या Flex प्राइसिंग किसी स्टैंडर्ड on-demand API request के सीधे बराबर नहीं है, क्योंकि उसमें scheduling, उपलब्धता और प्रोसेसिंग की शर्तें अलग होती हैं; इसलिए उसे इस तुलना में शामिल नहीं किया गया है। यह एक सीमित दायरे की तुलना है — यह दावा नहीं किया जा रहा कि E2X हर कॉन्फ़िगरेशन में दुनिया का सबसे सस्ता विकल्प है।
इमेज जनरेशन को ऑटोमेट करने का तरीक़ा पूछने वाले ज़्यादातर लोग मन ही मन इसकी कीमत "आज़माने के लिए भी बहुत महँगा" लगा चुके होते हैं। यह $23.80 का सवाल है। बना डालिए।
क़दम 1: prompt लिखना बंद कीजिए, टेम्पलेट लिखना शुरू कीजिए
एक बार टाइप किया गया prompt एक वाक्य है। दस हज़ार बार मशीन से चलने वाला prompt slots वाला टेम्पलेट है, और यही फ़र्क़ पूरा काम है।
नियम: जो कुछ बदलता है वह slot में जाता है, जो कुछ एक जैसा रहना चाहिए वह तय टेक्स्ट में। यह सरहद ग़लत खींची तो पूरा सेट खिसक जाता है — आधी इमेज सफ़ेद पर, आधी धूसर पर, क्योंकि "background" बदलने वाले हिस्से में रिस गया।
TEMPLATE = (
"Studio product photograph of a {product_name} in {colour}, "
"centred on a plain warm-grey backdrop, soft directional key light "
"from the upper left, shallow depth of field, editorial catalog styling, "
"no text, no logos, no people"
)
दो slots। लाइटिंग, backdrop, framing और मनाही वाली बातें जमी हुई हैं। जमा हुआ यही आधा हिस्सा 400 इमेज को 400 दुर्घटनाओं की बजाय एक ही photoshoot जैसा दिखाता है।
बदलने वाले आधे हिस्से से चार चीज़ें बाहर रखिए: माध्यम, रोशनी की दिशा, background, और negative निर्देश। यही आपकी visual पहचान हैं। अगर ये हर पंक्ति पर हिलेंगी, तो पहचान बची ही नहीं।

prompt लिखने की कारीगरी ख़ुद एक अलग पोस्ट है। automation के लिए जो मायने रखता है वह शक्ल है: तय फ़्रेम, नाम वाले छेद, कोई चौंकाने वाली चीज़ नहीं।
क़दम 2: असली प्रोडक्ट डेटा है
टेम्पलेट मामूली चीज़ है। काम डेटा में बसता है, और वह डेटा आमतौर पर आपके पास पहले से होता है।
- कोई प्रोडक्ट कैटलॉग टेबल। हर SKU की एक पंक्ति, नाम, रंग, material, category के कॉलम।
- ब्लॉग पोस्ट का CMS export, जहाँ title और topic हर लेख के header इमेज के slots बन जाते हैं।
- आपके ऐप्लिकेशन डेटाबेस की पंक्तियाँ — यूज़र की बनाई लिस्टिंग, इवेंट पेज, रेसिपी।
- ad वेरिएंट की एक स्प्रेडशीट: छह headlines गुणा चार backgrounds यानी चौबीस इमेज, और इतना brief कोई हाथ से नहीं लिखता।
स्रोत जो भी हो, API तक पहुँचने से पहले उसे dictionaries की एक सूची में normalise कीजिए, और हर पंक्ति पर एक स्थिर ID रखिए। नतीजों को रिकॉर्ड से मिलाने के लिए वह चाहिए, और उसे छोड़ देना ठीक उसी पल चुभता है जब कोई webhook आता है।
क़दम 3: submit कीजिए, इंतज़ार मत कीजिए
हमारा API जानबूझकर asynchronous है। आप एक job POST करते हैं, आपको फ़ौरन एक job ID वापस मिलती है, और जनरेशन हमारी तरफ़ होता है।
curl -X POST https://api.e2x.ai/v1/jobs/submit \
-H "Authorization: Bearer $E2X_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "google/nano-banana-2-lite/text-to-image",
"input": {
"prompt": "Studio product photograph of a walnut desk lamp in matte black...",
"aspect_ratio": "1:1"
},
"webhookUrl": "https://your-app.example.com/hooks/e2x"
}'
एक टेबल को jobs में बदलने वाला walker क़रीब तीस लाइन का है। यह CSV पढ़ता है, हर पंक्ति पर टेम्पलेट भरता है, submit करता है, और job ID को पंक्ति की ID के सामने दर्ज कर देता है ताकि कुछ भी अनाथ न रह जाए।
import csv
import os
import time
import requests
API = "https://api.e2x.ai/v1"
HEADERS = {
"Authorization": f"Bearer {os.environ['E2X_API_KEY']}",
"Content-Type": "application/json",
}
TEMPLATE = (
"Studio product photograph of a {product_name} in {colour}, "
"centred on a plain warm-grey backdrop, soft directional key light "
"from the upper left, shallow depth of field, editorial catalog styling, "
"no text, no logos, no people"
)
MAX_IMAGES = 500 # पक्की छत, लागत वाला सेक्शन देखिए
UNIT_COST = 0.0238 # Nano Banana 2 Lite, 26 अगस्त 2026 को जाँचा हुआ
def submit(row):
body = {
"model": "google/nano-banana-2-lite/text-to-image",
"input": {
"prompt": TEMPLATE.format(**row),
"aspect_ratio": "1:1",
},
"webhookUrl": "https://your-app.example.com/hooks/e2x",
}
for attempt in range(4):
r = requests.post(f"{API}/jobs/submit", json=body, headers=HEADERS, timeout=30)
if r.status_code < 300:
return r.json()["data"]["jobId"]
if r.status_code == 429 or r.status_code >= 500:
time.sleep(2 ** attempt)
continue
raise RuntimeError(f"row {row['id']} rejected: {r.status_code} {r.text}")
raise RuntimeError(f"row {row['id']} still failing after 4 attempts")
with open("catalog.csv") as fh:
rows = list(csv.DictReader(fh))[:MAX_IMAGES]
print(f"submitting {len(rows)} jobs, budget ${len(rows) * UNIT_COST:.2f}")
submitted = {}
for row in rows:
try:
submitted[row["id"]] = submit(row)
except RuntimeError as err:
print(f"skipped: {err}")
print(f"{len(submitted)}/{len(rows)} accepted")
ग़ौर कीजिए कि यह loop क्या नहीं करता: किसी पंक्ति के फ़ेल होने पर रुकता नहीं। 500 का batch जिसमें पंक्ति 212 का colour null है, उसे आपको 499 इमेज और एक दर्ज किया हुआ skip देना चाहिए — रात तीन बजे stack trace और शून्य इमेज नहीं।
slug दिखने से ज़्यादा मायने रखता है। google/nano-banana-2-lite/text-to-image capability suffix ढोता है; Nano Banana 2 का text slug सादा google/nano-banana-2 है, बिना किसी suffix के। अंदाज़ा लगाने की कीमत उस pipeline पर 404 है जो बाक़ी हर लिहाज़ से पूरी दिखती है। हर मॉडल अपनी पैरामीटर सूची एक मशीन-पठनीय spec फ़ाइल में छापता है।
क़दम 4: polling के बजाय webhook, और वजह यह है
आप poll कर सकते हैं। GET /v1/jobs/{JOB_ID} pending, processing, completed, failed या cancelled लौटाता है, और एक-बार के स्क्रिप्ट के लिए यह ठीक है।
pipeline के लिए यह ग़लत चुनाव है, और वजह ख़ूबसूरती नहीं है। polling आपकी प्रोसेस की उम्र को batch की सबसे धीमी job से बाँध देती है। Lite का एक generation हमारी तरफ़ क़रीब 60 सेकंड चलता है। 500 submit कीजिए और poller को उतनी देर ज़िंदा रहना होगा, state थामे हुए, जितनी देर पूँछ लेती है — किसी deploy के आर-पार, container के रीस्टार्ट के आर-पार, आप जिस भी serverless प्लैटफ़ॉर्म पर हैं उसके 15 मिनट के timeout के आर-पार। और जब वह मरता है, तो इसी इकलौते रिकॉर्ड को थामे मरता है कि कौन-सी jobs हवा में थीं।
webhook इसे उलट देता है। आप submit करके बाहर निकल जाते हैं। बाद में एक POST आता है जिसमें पूरी हो चुकी job होती है, और आप बिना किसी state के ठीक उसी एक job को सँभाल लेते हैं।
// Express handler. Idempotent: वही jobId दो बार आ सकती है।
app.post("/hooks/e2x", express.json(), async (req, res) => {
res.status(200).end(); // पहले acknowledge, काम बाद में
const job = req.body.data;
if (job.status !== "completed") {
await markFailed(job.jobId, job.error?.message ?? "unknown");
return;
}
const already = await findAsset(job.jobId);
if (already) return;
await storeImage(job.jobId, job.outputs[0].url);
});
poll तब कीजिए जब आप स्क्रिप्ट हाथ से चला रहे हों और उसे देख रहे हों। webhook तब लीजिए जब कोई नहीं देख रहा — और automation की परिभाषा यही है।
क़दम 5: output URL अस्थायी है, और pipelines यहीं टूटती हैं
बात यही है। बाक़ी सब सरसरी तौर पर पढ़ लीजिए, यह सेक्शन दो बार पढ़िए।
data.outputs[0].url एक delivery URL है, स्टोरेज नहीं। यह अभी काम करता है। हमेशा नहीं करेगा। जो कुछ भी इसे स्थायी मानता है — कोई product_image_url कॉलम, कोई CMS फ़ील्ड, क्लाइंट को ईमेल किया गया कोई लिंक — staging में ठीक-ठाक रेंडर होता है और दो हफ़्ते बाद टूटे इमेज आइकॉन दिखाता है।
यह ख़राबी बदमाश इसलिए है कि देर से आती है। लिखते वक़्त कुछ भी error नहीं देता। टेस्ट पास होते हैं। batch 500 सफलताएँ बताता है। फिर सबसे पुराने रिकॉर्ड से शुरू करके इमेज ग़ायब होने लगती हैं, और जब तक किसी की नज़र पड़ती है तब तक आप उन्हें पूरी job दोबारा चलाए बिना बना भी नहीं सकते, क्योंकि prompt भी कभी सहेजे नहीं गए थे।
bytes डाउनलोड कीजिए। उन्हें अपने bucket में रखिए। अपना URL स्टोर कीजिए।

import requests
import boto3
s3 = boto3.client("s3")
def store_image(job_id, row_id, source_url):
img = requests.get(source_url, timeout=60)
img.raise_for_status()
key = f"products/{row_id}.jpg"
s3.put_object(
Bucket="my-assets",
Key=key,
Body=img.content,
ContentType=img.headers.get("content-type", "image/jpeg"),
)
return f"https://cdn.example.com/{key}"
जब वहाँ हैं ही, तो इमेज के साथ prompt भी सहेज लीजिए। एक टेक्स्ट कॉलम, और यही "उस वेरिएंट को दोबारा बनाओ" और "शुरू से करो" के बीच का फ़र्क़ है।
पहले दिन से रखने लायक़ दो और आदतें। जाँचिए कि डाउनलोड में इमेज bytes आए हैं, कोई error पेज नहीं — क्योंकि HTML वाला 200 भी ख़ुशी-ख़ुशी आपके bucket में लिख जाएगा। और स्टोरेज की key हमारी job ID पर नहीं, अपनी पंक्ति की ID पर रखिए, ताकि दोबारा बनाने पर सही ऑब्जेक्ट ऊपर लिखा जाए, अनाथ न पड़े।
क़दम 6: वॉल्यूम पर असल में क्या बिगड़ता है
छोटे batches सब कुछ छिपा लेते हैं। कुछ सौ के पार जाते ही जो सामने आता है, वह यह है।
अधूरे batches सामान्य हैं। किसी भी बड़े run का कुछ हिस्सा फ़ेल होता है — कोई prompt जो content filter से टकरा जाए, कोई बिगड़ी हुई पंक्ति, कोई क्षणिक upstream error। 500 में से 497 को ही सफलता मानिए, और सिर्फ़ उन तीन पंक्तियों के लिए एक कमांड वाला retry रखिए।
Retries को ख़र्च की छत चाहिए। बिना सीमा वाला retry loop एक ऐसा bug है जो बिल बनाता है। $0.0238 प्रति शॉट तब तक हानिरहित लगता है जब तक कोई अटका हुआ loop उसे चालीस हज़ार बार न चला दे। कोड में एक पक्की गिनती डालिए — ऊपर वाली MAX_IMAGES लाइन यहाँ का सबसे सस्ता बीमा है।
Idempotency वैकल्पिक नहीं है। webhooks एक से ज़्यादा बार पहुँच सकते हैं। जो handler एक ही job ID पर दो बार चलने के लिए सुरक्षित नहीं है, वह आपको दोहरे assets और दोहरी पंक्तियाँ देगा, और पता सबसे व्यस्त हफ़्ते में चलेगा।
लागत को मासिक इनवॉइस नहीं, ज़िंदा काउंटर चाहिए। हमारे API में पैसे के मान micro-cents में लौटते हैं — 1,000,000 यानी $1। हर batch पर उन्हें जोड़िए और batch बंद होते ही कुल दर्ज कीजिए। हर रात "412 इमेज, $9.81" बताने वाली pipeline वह है जिसका ऑडिट किसी को नहीं करना पड़ता।
Aspect ratio के डिफ़ॉल्ट आपको चौंकाएँगे। Lite का डिफ़ॉल्ट 1:1 है, जबकि Nano Banana 2 और Pro का 9:16। इसे टेम्पलेट में pin कीजिए वरना आधा कैटलॉग चुपचाप portrait हो जाएगा।
watermark फ़ाइल के साथ सफ़र करता है। Google अपने इमेज मॉडलों से निकली हर चीज़ में SynthID ठोंक देता है। वह अदृश्य है, वह कोई flag नहीं है, और आपकी pipeline बाद में bytes के साथ जो भी करे, वह बचा रहता है। आपकी तरफ़ ब्रैंड या लीगल जो भी देखता है, उसे AI-जनित assets पर pipeline बनने से पहले मुहर लगानी चाहिए — 20,000 ऑब्जेक्ट bucket में लिख देने के बाद नहीं।

pipeline किस मॉडल पर टिकाएँ
डिफ़ॉल्ट Nano Banana 2 Lite रखिए और उससे तभी हटिए जब कोई ठोस चीज़ मजबूर करे।
यह हिसाब है, हिचक नहीं। $0.0238 पर यह हमारी बेची हुई सबसे सस्ती चीज़ है जो इमेज बनाती है, जिस मूल Nano Banana की उसने जगह ली उससे पूरी एक पीढ़ी नई है, और pipeline वाले वॉल्यूम पर कीमत का फ़र्क़ चक्रवृद्धि होकर उसी इकलौते नंबर में बदल जाता है जिसे finance देखता है। इसके पास चार ऐसे aspect ratios भी हैं जो और किसी के पास नहीं — 1:4, 4:1, 1:8 और 8:1 — यानी ठीक वही जो banners और खड़ी rails बनाते वक़्त चाहिए। एक झोल: resolution पैरामीटर है ही नहीं, और उसे भेजना चुपचाप नज़रअंदाज़ नहीं होता, error देता है।
इन चार सूरतों में इससे हटिए, और वरना नहीं:
- 1K से ऊपर output. Lite सिर्फ़ 1K है। Nano Banana 2 $0.04 बेस पर 4K तक जाता है, 2K पर ×1.5 और 4K पर ×2 के साथ।
- इमेज में पढ़ने लायक़ टेक्स्ट। कीमत लिखे प्रोडक्ट कार्ड, स्थानीय भाषा वाले infographics। यह $0.075 पर Nano Banana Pro पर रहता है, जहाँ 1K और 2K की कीमत एक है — 2K ले लीजिए, वह मुफ़्त है।
- पारदर्शी backgrounds. Cut-outs और स्टिकर शीट को
background: transparentचाहिए, और हमारे कैटलॉग में यह एक ही कॉल में सिर्फ़ GPT Image 2 करता है। 1K के लिए $0.0525 का बजट रखिए, कच्चा कैटलॉग नंबर नहीं —qualityहर टियर पर 7 से गुणा करता है। - कई फ़्रेमों में वही चेहरा या वही बोतल। यह reference-इमेज की समस्या है, वॉल्यूम की नहीं, और इसकी consistency पर अपनी अलग पोस्ट है।
मिले-जुले workloads के लिए थोक Lite पर चलाइए और डेटा के एक कॉलम के आधार पर टेक्स्ट या fidelity माँगने वाले 2% को Pro पर मोड़ दीजिए। एक pipeline, दो मॉडल, और Pro की कीमत सिर्फ़ वहाँ जहाँ वह कुछ कमाती है।
submit और poll contract की पैरामीटर-दर-पैरामीटर सैर के लिए Nano Banana Pro API ट्यूटोरियल देखिए, और टियर-दर-टियर ब्यौरे के लिए मॉडल तुलना। ये दोनों मानकर चलते हैं कि आप मॉडल चुन चुके हैं। अगर नहीं चुना, तो text-to-image मॉडल अपनी कीमतों के साथ सूचीबद्ध हैं, और कैटलॉग उसमें वीडियो वाला हिस्सा भी जोड़ देता है।
पूरी चीज़, क्रम से
slots वाला टेम्पलेट। स्थिर IDs वाला डेटा। एक पक्की छत के नीचे jobs के तौर पर submit। webhook लीजिए। bytes डाउनलोड करके अपने स्टोरेज में। failures और ख़र्च दर्ज कीजिए। छह क़दम, कोई भी मुश्किल नहीं, और जो हमेशा छूटता है वह पाँचवाँ है।
अक्सर पूछे जाने वाले सवाल
इमेज ऑटो-जनरेट कैसे करते हैं?
अपना prompt नाम वाले slots के टेम्पलेट की तरह लिखिए, उन slots को किसी डेटा स्रोत से भरिए — जैसे प्रोडक्ट कैटलॉग या CSV — और हर भरे हुए prompt को किसी इमेज API पर asynchronous job के रूप में submit कीजिए। नतीजा polling के बजाय webhook पर लीजिए, फिर इमेज के bytes अपने स्टोरेज में डाउनलोड कीजिए। इस पूरे चक्र में कहीं इंसान की ज़रूरत नहीं — यही इसे तेज़ हस्तचालित काम की बजाय अपने-आप होने वाला काम बनाता है।
1,000 इमेज अपने-आप बनाने में कितना ख़र्च आता है?
26 अगस्त 2026 की E2X कीमतों पर Nano Banana 2 Lite से 1,000 इमेज $23.80 की पड़ती हैं, क्योंकि हर request $0.0238 की है। उतना ही वॉल्यूम Nano Banana 2 पर $40.00 और Nano Banana Pro पर $75.00 का है। ऊँची resolutions इसके ऊपर से गुणा होती हैं, लेकिन स्टैंडर्ड 1K output के लिए प्रति-इमेज नंबर ही पूरा हिसाब है।
इमेज जनरेशन jobs के लिए मुझे webhook लेना चाहिए या poll करना चाहिए?
बिना निगरानी चलने वाली हर चीज़ के लिए webhook लीजिए। polling आपकी प्रोसेस की उम्र को batch की सबसे धीमी job से बाँध देती है, इसलिए कोई deploy या serverless timeout उस poller को उसी वक़्त मार देता है जब वह इकलौता रिकॉर्ड थामे होता है कि कौन-सी jobs अब भी चल रही हैं। webhook आपको submit करके निकल जाने देता है, और फिर हर पूरी हुई job को बिना state के सँभालने देता है। जिस स्क्रिप्ट को आप चलते हुए देख रहे हैं, उसके लिए polling ठीक है।
मेरी बनाई हुई इमेज कुछ समय बाद लोड होना क्यों बंद कर देती हैं?
क्योंकि आपने इमेज के बजाय API का output URL स्टोर किया। वह URL अस्थायी delivery है, स्टोरेज नहीं, इसलिए उसे रखने वाला कॉलम पहले सही रेंडर होता है और बाद में टूट जाता है। job पूरी होते ही bytes डाउनलोड कीजिए, उन्हें अपने bucket में लिखिए, अपना URL स्टोर कीजिए। इमेज pipeline के टूटी हुई ship होने का सबसे आम तरीक़ा यही है।
किसी स्वचालित इमेज pipeline का डिफ़ॉल्ट मॉडल कौन-सा होना चाहिए?
Nano Banana 2 Lite, $0.0238 प्रति इमेज पर। यह हमारे कैटलॉग का सबसे सस्ता इमेज मॉडल है और मूल Nano Banana से एक पीढ़ी नया, और batch वॉल्यूम पर कीमत बाक़ी हर बात पर भारी पड़ती है। Nano Banana 2 पर सिर्फ़ 1K से ऊपर output के लिए जाइए, Nano Banana Pro पर सिर्फ़ पढ़ने लायक़ in-image टेक्स्ट के लिए, और GPT Image 2 पर सिर्फ़ पारदर्शी backgrounds के लिए।
batch की कुछ इमेज फ़ेल हो जाएँ तो क्या होता है?
कुछ हमेशा होंगी, और pipeline को इसे घातक नहीं, सामान्य मानना चाहिए। किसी पंक्ति के ठुकराए जाने के बाद भी submit करते रहिए, फ़ेल हुई IDs उनकी errors के साथ दर्ज कीजिए, और एक ऐसा retry रास्ता बनाइए जो सिर्फ़ failures चलाए। retry की कोशिशों पर सीमा रखिए, क्योंकि हर कोशिश असली शुल्क है।