मुख्य सामग्री पर जाएँ

Qwen-Image-Edit-2509 ट्यूटोरियल: स्टूडियो-रेडी प्रोडक्ट एंगल्स जनरेट करें

Qwen-Image-Edit-2509 और LoRA की मदद से एक फोटो को कई प्रोडक्ट शॉट्स में बदलें। कुछ ही सेकंड में Amazon, Etsy और ऑनलाइन स्टोर्स के लिए एकसमान स्टूडियो एंगल्स बनाएं।
· 9 मि॰ पढ़ें

AI के साथ खोजें

सोलो सेलर्स और छोटे ब्रांड्स के पास अक्सर पूरे प्रोडक्ट फोटोशूट का बजट नहीं होता। इस गाइड में, हम एक Gradio ऐप बनाएंगे और चलाएंगे जो एक सिंगल इनपुट इमेज को ई-कॉमर्स-रेडी, मल्टी-एंगल प्रोडक्ट रेंडर्स (वाइड, मैक्रो, ±45°, टॉप-डाउन) में बदलता है Qwen-Image-Edit-2509 का उपयोग करते हुए, जिसमें LoRA-आधारित वर्चुअल कैमरा कंट्रोल्स हैं ताकि AI प्रोडक्ट फोटोग्राफी को दोहराने योग्य बनाया जा सके।

बैकएंड में, हम यह उपयोग करते हैं:

  • बेस मॉडल: Qwen/Qwen-Image-Edit-2509 (Apache-2.0)
  • एंगल कंट्रोल LoRA: dx8152/Qwen-Edit-2509-Multiple-angles
  • वैकल्पिक स्पीड LoRA: lightx2v/Qwen-Image-Lightning

इस ट्यूटोरियल में, आप सीखेंगे कि कैसे:

  • Qwen एडिट पाइपलाइन लोड करें और एक से अधिक LoRA को स्टैक करें।
  • मजबूत एंगल मैक्रोज़ के साथ कैमरा मूव्स नियंत्रित करें।
  • क्रिएटर्स और ईकॉमर्स टीमों के लिए क्लीन Gradio UI बनाएं।
  • आसान हैंडऑफ के लिए सभी परिणाम ZIP के रूप में एक्सपोर्ट करें।

यदि आप डीप लर्निंग में इमेज डेटा कैसे प्रोसेस होता है, इसके बारे में और सीखना चाहते हैं, तो Image Processing in Python स्किल ट्रैक देखें। 

एकाधिक एंगल्स LoRA के साथ Qwen Image Edit क्यों?

Qwen-Image-Edit-2509, Qwen का नवीनतम इमेज-एडिटिंग मॉडल है जिसमें बेहतर स्थिरता और मल्टी-इमेज एडिटिंग है। Multiple-Angles LoRA विश्वसनीय “वर्चुअल कैमरा” कंट्रोल जोड़ता है ताकि आप कह सकें:

  • 将镜头转为广角镜头 (वाइड-एंगल में बदलें)
  • 将镜头转为特写镜头 (क्लोज़-अप में बदलें)
  • 将镜头向左旋转45度 (45° बाएं घुमाएं)
  • 将镜头转为俯视 (टॉप-डाउन व्यू)

ये कमांड्स एक ही प्रोडक्ट को लगातार फिर से फ्रेम करते हैं, किसी नए प्रोडक्ट की कल्पना किए बिना।

Qwen Image Edit चरण-दर-चरण ट्यूटोरियल: एक Product Shot Booster बनाना 

इस गाइड में, हम एक ऐसा ऐप बनाएंगे जो एक सिंगल प्रोडक्ट इमेज को स्टूडियो-रेडी एंगल सेट में बदलता है (जैसे वाइड, क्लोज़-अप, 45° लेफ्ट/राइट और टॉप-डाउन), साथ में वैकल्पिक लाइफस्टाइल प्रीसेट्स और फास्ट प्रीव्यू मोड। यह Qwen/Qwen-Image-Edit-2509 मॉडल और Multiple-Angles LoRA का उपयोग करता है, जिसे Gradio UI में रैप किया गया है।

हम एनवायरनमेंट सेटअप से मॉडल लोडिंग, जेनरेशन हेल्पर्स और वेब UI तक जाएंगे।

चरण 1: पूर्वापेक्षाएँ

सबसे पहले सभी रनटाइम डिपेंडेंसीज़ इंस्टॉल करें। हम UI के लिए CUDA व्हील्स के साथ PyTorch, Hugging Face टूलिंग, Diffusers लाइब्रेरी, Gradio, और इमेज हैंडलिंग के लिए Pillow/OpenCV का उपयोग करते हैं।

pip install -q torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install -q transformers>=4.44.0 accelerate>=0.33.0 safetensors>=0.4.3
pip install -q pillow>=10.2.0 huggingface_hub>=0.24.0 opencv-python-headless>=4.9.0.80
pip install -q numpy>=1.26.0 gradio>=4.0.0
pip install -q git+https://github.com/huggingface/diffusers

प्रत्येक पूर्वापेक्षा क्या करती है, यह रहा:

  • CUDA व्हील्स: PyTorch लाइन GPU एक्सेलरेशन के लिए NVIDIA CUDA 12.1 व्हील्स की ओर इंगित करती है।
  • Transformers और Diffusers: Transformers कॉन्फ़िग्स और टोकनाइज़र्स मैनेज करता है जबकि Diffusers QwenImageEditPlusPipeline उपलब्ध कराता है।
  • Safetensors: यह एक सुरक्षित टेन्सर फ़ॉर्मेट प्रदान करते हैं (Pickle से तेज़ और सुरक्षित)।
  • OpenCV-headless और Pillow: यह प्री/पोस्ट-प्रोसेसिंग के लिए मज़बूत इमेज I/O और रिसाइज़िंग प्रदान करता है।
  • Gradio: यह एक तेज़ वेब UI है जो लोकली और Colab में काम करता है।

एनवायरनमेंट तैयार होने के बाद, हम Hugging Face में ऑथेंटिकेट कर सकते हैं (वैकल्पिक) और मॉडल्स लोड कर सकते हैं।

चरण 2: Hugging Face ऑथेंटिकेशन

कुछ मॉडल्स या एडॉप्टर्स के लिए HuggingFace से ऑथेंटिकेशन की आवश्यकता हो सकती है। यह स्टेप सेशन के लिए एक बार आपको लॉगिन कर देता है।

from huggingface_hub import login
import os
HF_TOKEN = "Your_HF_Token"  # @param {type:"string"}
if HF_TOKEN:
    login(token=HF_TOKEN)
    print("Logged in to Hugging Face")
else:
    print("WARNING: No token provided. Continuing without authentication")

अपने HuggingFace अकाउंट में लॉगिन करें और अकाउंट सेटिंग्स में Access Tokens देखें। Create new token पर क्लिक करें और Read टोकन टाइप के साथ नया टोकन जनरेट करें। आवश्यक अनुमतियाँ चुनें और नया टोकन बनाएं।

HF Access code

प्रोडक्शन/Colab में टोकन को हार्डकोड न करें, इसके बजाय एनवायरनमेंट वेरिएबल्स या Colab “Secrets” का उपयोग करें।

चरण 3: मॉडल लोड करें और पाइपलाइन सेटअप करें

इस सेक्शन में, हम Qwen-Image-Edit पाइपलाइन सेटअप करेंगे, एंगल्स LoRA लोड करेंगे, और GPU-अवेयर सेटिंग्स के साथ एक Fast टॉगल जोड़ेंगे। ध्यान दें कि यह कोड हाई-RAM A100 GPU पर कुशलता से चलता है।

चरण 3.1:  इम्पोर्ट्स और GPU कॉन्फ़िग

अब, हम कोर लाइब्रेरीज़ इम्पोर्ट करेंगे और GPU डिटेक्ट करेंगे ताकि स्थिरता के लिए प्रिसिशन, अटेंशन स्लाइसिंग और VAE स्लाइसिंग ऑटोमैटिकली सेट हो सकें।

import io
import zipfile
from typing import List, Tuple, Optional
import gc
import torch
from PIL import Image
from diffusers import QwenImageEditPlusPipeline
import gradio as gr
def get_gpu_config():
    if not torch.cuda.is_available():
        return {
            'device': 'cpu',
            'dtype': torch.float32,
            'gpu_name': 'CPU',
            'vram_gb': 0,
            'max_batch': 1,
            'enable_attention_slicing': True,
            'enable_vae_slicing': True,
        }
    gpu_name = torch.cuda.get_device_name(0)
    vram_gb = torch.cuda.get_device_properties(0).total_memory / 1e9 
    if 'T4' in gpu_name or vram_gb < 20:
        return {
            'device': 'cuda',
            'dtype': torch.bfloat16,
            'gpu_name': gpu_name,
            'vram_gb': vram_gb,
            'max_batch': 1,
            'enable_attention_slicing': True,
            'enable_vae_slicing': True,
        }
    else:
        return {
            'device': 'cuda',
            'dtype': torch.bfloat16,
            'gpu_name': gpu_name,
            'vram_gb': vram_gb,
            'max_batch': 2,
            'enable_attention_slicing': False,
            'enable_vae_slicing': False,
        }
gpu_config = get_gpu_config()
HF_BASE_MODEL = "Qwen/Qwen-Image-Edit-2509"
LORA_ANGLES = "dx8152/Qwen-Edit-2509-Multiple-angles"
LORA_LIGHTNING = "lightx2v/Qwen-Image-Lightning"
ANGLE_MACROS = {
    "Wide-angle": "将镜头转为广角镜头",
    "Close-up": "将镜头转为特写镜头",
    "Forward": "将镜头向前移动",
    "Left": "将镜头向左移动",
    "Right": "将镜头向右移动",
    "Down": "将镜头向下移动",
    "Rotate 45° Left": "将镜头向左旋转45度",
    "Rotate 45° Right": "将镜头向右旋转45度",
    "Top-down": "将镜头转为俯视",
}
BACKGROUND_PRESETS = {
    "(None)": None,
    "Pure Studio (white seamless)": "in a professional studio with seamless white background, soft shadows, product centered",
    "Soft Gray Studio": "in a professional studio with seamless soft gray background, gentle vignette, softbox lighting",
    "Lifestyle (cozy desk)": "on a cozy wooden desk near a window, soft natural light, minimal props",
    "Lifestyle (marble)": "on a clean white marble surface, bright daylight, subtle reflections",
    "Lifestyle (outdoor)": "outdoors on a neutral table, soft shade, bokeh background",
}
ASPECT_RATIOS = {
    "1:1 (Square)": (1024, 1024),
    "4:3 (Standard)": (1024, 768),
    "3:4 (Portrait)": (768, 1024),
    "16:9 (Widescreen)": (1024, 576),
    "9:16 (Mobile)": (576, 1024),
    "3:2 (Photo)": (1024, 683),
    "2:3 (Portrait Photo)": (683, 1024),
}

ऊपर दिए गए कोड ब्लॉक्स के मुख्य घटक यह हैं:

  • GPU ऑटो-कॉन्फ़िग (get_gpu_config फ़ंक्शन): हम उपलब्ध एक्सेलरेटर को डिटेक्ट करते हैं और एक छोटा कॉन्फ़िग डिक्शनरी रिटर्न करते हैं जो डिवाइस (cpu/cuda), dtype (जैसे GPU पर bfloat16), और मेमोरी बिहेवियर चुनने में काम आता है:
    • CPU पर, हम डिफॉल्ट रूप से float32 लेते हैं और सुरक्षा के लिए attention/VAE स्लाइसिंग सक्षम करते हैं।
    • T4 / <20 GB VRAM पर, हम bfloat16 रखते हैं लेकिन OOM से बचने के लिए स्लाइसिंग सक्षम करते हैं।
    • 20 GB+ GPUs (जैसे A100) पर, हम स्लाइसिंग अक्षम करते हैं और स्पीड के लिए बड़ा बैच अलाउ करते हैं।
  • मॉडल IDs और एडॉप्टर्स: हम Qwen-Image-Edit-2509 को कोर एडिटर के रूप में लोड करते हैं, साथ में कैमरा कंट्रोल के लिए Multiple-angles LoRA, और वैकल्पिक रूप से Fast Mode पर टॉगल करने पर Lightning LoRA को ब्लेंड करते हैं।  
    • HF_BASE_MODEL = "Qwen/Qwen-Image-Edit-2509" मुख्य इमेज-एडिटिंग बैकबोन है।
    • LORA_ANGLES = "dx8152/Qwen-Edit-2509-Multiple-angles" “वर्चुअल कैमरा” कंट्रोल जोड़ता है।
    • LORA_LIGHTNING = "lightx2v/Qwen-Image-Lightning" फास्ट प्रीव्यू के लिए वैकल्पिक स्पीड एडॉप्टर है।

नोट: HQ Mode के लिए केवल एंगल्स एडॉप्टर सक्रिय रहता है।

  • एंगल मैक्रोज़: ANGLE_MACROS “Wide-angle” या “Top-down” जैसे लेबल्स को समकक्ष चीनी कमांड्स से मैप करता है जिन्हें एंगल्स LoRA विश्वसनीय रूप से समझता है। ये कमांड्स वर्चुअल कैमरा को लगातार (move/rotate/zoom) मूव करते हैं, पहचान बदले बिना।
  • बैकग्राउंड प्रीसेट्स: BACKGROUND_PRESETS छोटे अंग्रेज़ी अंश हैं जैसे “marble surface”, “soft gray studio”, जिन्हें हम फाइनल प्रॉम्प्ट में मर्ज करते हैं। ये एंगल मैक्रोज़ से स्वतंत्र हैं और सीन को नियंत्रित करते हैं।
  • आस्पेक्ट रेशियो (ASPECT_RATIOS): ये हमें कैनवस (1:1, 4:3, 16:9 आदि) जनरेट करने देते हैं और इन्फरेंस से पहले इनपुट को रिसाइज़ या सेंटर-क्रॉप करते हैं ताकि आउटपुट्स को पोस्ट-जनरेशन क्रॉपिंग की आवश्यकता न रहे।

अब हमारे पास GPU और एडॉप्टर्स सेट हो गए हैं। अगला कदम Diffusers पाइपलाइन को इंस्टैंशिएट करना और LoRA को अटैच करना है।

चरण 3.2: पाइपलाइन

अब हम बेस Qwen Edit पाइपलाइन लोड करेंगे, GPU के अनुसार मेमोरी ऑप्टिमाइज़ेशन सक्षम करेंगे, और Multiple-Angles LoRA को स्टैक करेंगे। हम एक मोड स्विच भी लागू करते हैं ताकि फास्ट प्रीव्यू के लिए वैकल्पिक रूप से Lightning LoRA जोड़ सकें।

pipe = QwenImageEditPlusPipeline.from_pretrained(
    HF_BASE_MODEL,
    torch_dtype=gpu_config['dtype'],
)
pipe = pipe.to(gpu_config['device'])
if gpu_config['enable_attention_slicing']:
    pipe.enable_attention_slicing()
if gpu_config['enable_vae_slicing']:
    pipe.enable_vae_slicing()
pipe.load_lora_weights(LORA_ANGLES, adapter_name="angles")
current_mode = {"fast": False}
def set_pipeline_mode(use_lightning: bool):
    global current_mode  
    if use_lightning and not current_mode["fast"]:
        pipe.load_lora_weights(LORA_LIGHTNING, adapter_name="lightning")
        pipe.set_adapters(["angles", "lightning"], adapter_weights=[1.0, 1.0])
        current_mode["fast"] = True
    elif not use_lightning and current_mode["fast"]:
        pipe.set_adapters(["angles"], adapter_weights=[1.0])
        current_mode["fast"] = False
    elif not use_lightning and not current_mode["fast"]:
        pipe.set_adapters(["angles"], adapter_weights=[1.0])
set_pipeline_mode(False)

ऊपर का कोड Product Shot Booster ऐप के लिए पाइपलाइन सेटअप लेयर है, जो निम्न कार्य करता है:

  • पाइपलाइन इनिशियलाइज़ेशन: यह QwenImageEditPlusPipeline को बेस मॉडल (Qwen/Qwen-Image-Edit-2509) से इंस्टैंशिएट करता है, डिटेक्टेड डिवाइस (CPU/GPU) पर शिफ्ट करता है, और आपके हार्डवेयर के आधार पर टेन्सर प्रिसिशन (torch_dtype) सेट करता है।
  • मेमोरी सेफ़्टी: छोटे GPUs पर, यह पीक VRAM कम करने और आउट-ऑफ-मे_memory एरर्स से बचने के लिए attention और VAE स्लाइसिंग सक्षम करता है, जिसमें थोड़ी स्पीड-ऑफ का समझौता होता है।
  • LoRA कॉम्पोज़िशन: यह Multiple-angles LoRA को लोड करता है ताकि दोहराने योग्य “वर्चुअल कैमरा” कंट्रोल्स (move/rotate/zoom) मिलें और वैकल्पिक रूप से तेज प्रीव्यू के लिए Lightning LoRA को ब्लेंड करता है।
  • मोड स्विचिंग लॉजिक: set_pipeline_mode() हेल्पर फ़ंक्शन और current_mode फ़्लैग HQ बनाम Fast स्टेट्स मैनेज करते हैं, बेकार के Lightning रीलोड्स को रोकते हैं और आपको एडॉप्टर्स टॉगल करने देते हैं।

अब पाइपलाइन तैयार है। आइए जेनरेशन फ़ंक्शंस और Gradio UI की वायरिंग पर बढ़ते हैं।

चरण 4: जेनरेशन फ़ंक्शंस

जेनरेशन फ़ंक्शंस प्रॉम्प्ट बनाकर, टार्गेट आस्पेक्ट रेशियो में रिसाइज़ करके, चुने गए एंगल्स पर पाइपलाइन चलाकर, और परिणामों को ज़िप फ़ाइल में पैकेज करके जेनरेशन को संचालित करते हैं।

चरण 4.1: प्रॉम्प्ट कंपोज़र और  इमेज रिसाइज़ हेल्पर्स

मॉडल को कॉल करने से पहले, हम दो स्टेटलेस हेल्पर्स के साथ इनपुट्स को सामान्य करते हैं:

  • compose_prompt() फ़ंक्शन: यह फ़ंक्शन कैमरा एंगल, बैकग्राउंड प्रीसेट, कस्टम सीन और स्टाइल नोट्स से एक सिंगल इंस्ट्रक्शन स्ट्रिंग बनाता है। संक्षिप्त क्लॉज़ Qwen की इंस्ट्रक्शन पार्सिंग को स्थिर रखते हैं और किसी एक भाग को ज़्यादा वेट देने से बचाते हैं।
  • resize_image() फ़ंक्शन: यह सोर्स इमेज को टार्गेट आस्पेक्ट रेशियो में फिट करता है, स्केल-टू-कवर स्ट्रैटेजी अपनाता है, उच्च-गुणवत्ता डाउन/अप-स्केलिंग के लिए Lanczos रीसम्पलिंग करता है, और सेंटर क्रॉप करता है ताकि मुख्य विषय फ़्रेम में रहे।
def compose_prompt(angle_phrase: str,
                   bg_preset_text: Optional[str],
                   custom_scene: str,
                   extra_style: str) -> str:
    parts = [angle_phrase]
    if bg_preset_text:
        parts.append(f"{bg_preset_text}")
    if custom_scene.strip():
        parts.append(custom_scene.strip())
    if extra_style.strip():
        parts.append(extra_style.strip())
    return " | ".join(parts)
def resize_image(img: Image.Image, target_size: Tuple[int, int]) -> Image.Image:
    target_w, target_h = target_size
    orig_w, orig_h = img.size
    scale = max(target_w / orig_w, target_h / orig_h)
    new_w = int(orig_w * scale)
    new_h = int(orig_h * scale)
    img = img.resize((new_w, new_h), Image.Resampling.LANCZOS) 
    left = (new_w - target_w) // 2
    top = (new_h - target_h) // 2
    img = img.crop((left, top, left + target_w, top + target_h))    
    return img

उपरोक्त दो फ़ंक्शंस निम्न कार्य करते हैं:

  • कम्पोज़ेबल प्रॉम्प्ट: हम भागों को " | " से जोड़ते हैं ताकि क्लॉज़ विज़ुअली अलग रहें, जबकि Qwen-Edit विराम-चिह्न संभालता है और बिना आख़िरी क्लॉज़ की ओर झुके एकसमान पार्सिंग देता है। हम यूज़र टेक्स्ट पर .strip() भी लगाते हैं ताकि खाली फ़्रैगमेंट न आएं।
  • स्केल-टू-कवर गणित: यह सुनिश्चित करता है कि रिसाइज़ की गई इमेज दोनों आयामों में टार्गेट कैनवस को पूरी तरह कवर करे।
  • Lanczos रीसम्पलिंग: यह एक उच्च-गुणवत्ता फ़िल्टर है जो डाउनसैंपलिंग पर बारीक डिटेल्स बचाए रखता है और अपस्केलिंग पर एलियसिंग घटाता है।
  • सेंटर क्रॉप: रिसाइज़ के बाद, हम बिल्कुल टार्गेट कैनवस को सेंटर से क्रॉप करते हैं ताकि सामान्य कम्पोज़िशन बनी रहे और अनचाहे ऑफ-सेंटर ट्रिम न हों।

हेल्पर्स तैयार होने के साथ, अब हम मल्टी-एंगल जेनरेशन लूप चला सकते हैं और परिणामों को पैकेज कर सकते हैं।

चरण 4.2: इमेजेज जनरेट करें 

अगले चरण में, हम इनपुट्स वैलिडेट करते हैं, इमेज को चुने गए आस्पेक्ट के अनुरूप करते हैं, चुने गए एंगल्स पर लूप चलाते हैं, और पाइपलाइन को inference_mode में रन करते हैं। अंत में, हम सभी जनरेटेड इमेजेज के साथ एक ज़िप फ़ाइल रिटर्न करते हैं।

def generate_images(
    source_img: Image.Image,
    angle_keys: List[str],
    bg_key: str,
    custom_scene: str,
    extra_style: str,
    aspect_ratio: str,
    use_lightning: bool,
    seed: int,
    steps: int,
    guidance_scale: float,
    true_cfg_scale: float,
    images_per_prompt: int,
    progress=gr.Progress()
) -> List[Image.Image]:   
    if source_img is None:
        return [], "WARNING: Please upload an image first!"    
    if not angle_keys:
        return [], "WARNING: Please select at least one angle!"  
    target_size = ASPECT_RATIOS[aspect_ratio]
    source_img = resize_image(source_img, target_size)  
    set_pipeline_mode(use_lightning)
    results = []
    generator = torch.manual_seed(seed)  
    bg_preset_text = BACKGROUND_PRESETS.get(bg_key)    
    total_angles = len(angle_keys)    
    for idx, angle_name in enumerate(angle_keys):
        progress((idx + 1) / total_angles, f"Generating {angle_name}...") 
        angle_phrase = ANGLE_MACROS[angle_name]
        full_prompt = compose_prompt(angle_phrase, bg_preset_text, custom_scene, extra_style)   
        inputs = {
            "image": [source_img],
            "prompt": full_prompt,
            "generator": generator,
            "true_cfg_scale": true_cfg_scale,
            "negative_prompt": " ",
            "num_inference_steps": steps,
            "guidance_scale": guidance_scale,
            "num_images_per_prompt": images_per_prompt,
            "height": target_size[1],
            "width": target_size[0],
        }     
        with torch.inference_mode():
            out = pipe(**inputs)   
        for img_idx, im in enumerate(out.images):
            results.append(im) 
        if 'T4' in gpu_config['gpu_name']:
            torch.cuda.empty_cache()
    return results
def create_zip(images: List[Image.Image]) -> Optional[str]:
    if not images:
        return None
    zip_path = "/content/product_shot_booster.zip"
    with zipfile.ZipFile(zip_path, mode="w", compression=zipfile.ZIP_DEFLATED) as zf:
        zf.writestr("manifest.txt", "Product Shot Booster Export\nGenerated angles exported as PNG files.\n")
        for idx, img in enumerate(images):
            buf = io.BytesIO()
            img.save(buf, format="PNG")
            zf.writestr(f"angle_{idx+1:03d}.png", buf.getvalue())
    return zip_path

generate_images() फ़ंक्शन मल्टी-एंगल जेनरेशन और एक्सपोर्ट को इस प्रकार लागू करता है:

  • वैलिडेट, नॉर्मलाइज़, और कॉन्फ़िगर: यह यह जांचता है कि इमेज अपलोड की गई है और एंगल्स चुने गए हैं, फिर चुने गए आस्पेक्ट के अनुसार इमेज को फिट करता है (रिसाइज़ और सेंटर क्रॉप), और set_pipeline_mode(use_lightning) के माध्यम से HQ बनाम Fast मोड टॉगल करता है। 
  • कुशल इन्फरेंस: हर एंगल के लिए, यह एंगल मैक्रो, बैकग्राउंड प्रीसेट, सीन और स्टाइल सहित एक सिंगल इंस्ट्रक्शन स्ट्रिंग बनाता है। फिर Diffusers इनपुट तैयार करता है और मेमोरी बचाने के लिए torch.inference_mode() के तहत निष्पादित करता है। लो-VRAM GPUs (जैसे T4) पर, प्रति एंगल torch.cuda.empty_cache() जैसी कॉल्स फ़्रैगमेंटेशन कम करने में सहायक होती हैं।
  • UI फ़ीडबैक के साथ परिणाम समेकित करना: अंत में यह जैसे-जैसे हर एंगल पूरा होता है, Gradio प्रोग्रेस अपडेट करता है और सभी आउटपुट्स को एक लिस्ट में इकट्ठा करता है ताकि आगे ज़िपिंग की जा सके।

create_zip(images) फ़ंक्शन एक पोर्टेबल एक्सपोर्ट प्रदान करता है, जो एक संक्षिप्त manifest.txt लिखता है और इन-मे_memory (BytesIO) के माध्यम से इमेजेज को एन्कोड करके ZIP बनाता है, और यदि कोई इमेज नहीं है तो None रिटर्न करता है।

जेनरेशन और पैकेजिंग फ़ाइनल होने के साथ, UI एक मल्टी-एंगल पास ट्रिगर कर सकता है और पूरे एंगल पैक का वन-क्लिक डाउनलोड ऑफ़र कर सकता है।

चरण 5: Gradio UI

यह UI उपयोगकर्ताओं को प्रोडक्ट इमेज अपलोड करने, एंगल्स और आस्पेक्ट रेशियो चुनने, बैकग्राउंड प्रीसेट चुनने, स्टाइल नोट्स सेट करने, और चलते-फिरते मल्टी-एंगल इमेजेज जनरेट करने देता है। 

with gr.Blocks(title="Product Shot Booster", theme=gr.themes.Soft()) as demo:
    gr.Markdown("<h1 style='text-align: center;font-weight: bold;'>Product Shot Booster</h1>")
    with gr.Row():
        with gr.Column(scale=1):
            input_image = gr.Image(
                label="Product Image",
                type="pil",
                height=300
            ) 
            angle_choices = gr.CheckboxGroup(
                choices=list(ANGLE_MACROS.keys()),
                value=["Wide-angle", "Close-up", "Rotate 45° Left", "Rotate 45° Right", "Top-down"],
                label="Camera Angles"
            ) 
            aspect_ratio = gr.Dropdown(
                choices=list(ASPECT_RATIOS.keys()),
                value="1:1 (Square)",
                label="Aspect Ratio"
            )
            bg_preset = gr.Dropdown(
                choices=list(BACKGROUND_PRESETS.keys()),
                value="(None)",
                label="Background"
            ) 
            custom_scene = gr.Textbox(
                label="Custom Scene",
                placeholder="e.g., 'on a matte black table with soft reflections'",
                lines=2
            )    
            extra_style = gr.Textbox(
                label="Style Notes",
                value="studio-grade lighting, high clarity, ecommerce-ready composition",
                lines=2
            )
        with gr.Column(scale=2):
            output_gallery = gr.Gallery(
                  label="Generated Images",
                  show_label=True,
                  columns=3,
                  height="auto",
                  object_fit="contain"
              )

            info_output = gr.Markdown("")
            zip_output = gr.File(label="Download ZIP")
    with gr.Accordion("Advanced Settings", open=False):
        with gr.Row():
            use_lightning = gr.Checkbox(
                label="Fast Mode (Lightning LoRA)",
                value=('T4' in gpu_config['gpu_name']),
                info="Enable for faster generation (recommended for T4)"
            )   
            seed = gr.Number(
                label="Seed",
                value=123,
                precision=0
            )  
            steps = gr.Slider(
                label="Inference Steps",
                minimum=10,
                maximum=60,
                value=28,
                step=1
            )
        with gr.Row():
            guidance_scale = gr.Slider(
                label="Guidance Scale",
                minimum=0.0,
                maximum=8.0,
                value=1.0,
                step=0.1
            )
            true_cfg_scale = gr.Slider(
                label="True CFG Scale",
                minimum=0.0,
                maximum=10.0,
                value=4.0,
                step=0.1
            ) 
            images_per_prompt = gr.Slider(
                label="Images per Angle",
                minimum=1,
                maximum=4,
                value=1,
                step=1
            )
    generate_btn = gr.Button("Generate", variant="primary", size="lg")
    def generate_and_zip(*args):
      images = generate_images(*args)
      zip_file = create_zip(images) if images else None
      return images, zip_file 
    generate_btn.click(
        fn=generate_and_zip,
        inputs=[
            input_image,
            angle_choices,
            bg_preset,
            custom_scene,
            extra_style,
            aspect_ratio,
            use_lightning,
            seed,
            steps,
            guidance_scale,
            true_cfg_scale,
            images_per_prompt
        ],
        outputs=[output_gallery, zip_output]
    )
demo.launch(share=True, debug=True, show_error=True)

Demo

उपरोक्त कोड एक इंटरैक्टिव Gradio ऐप बनाता है जो एक सिंगल जेनरेट एक्शन को इन्फरेंस से वायर करता है और एक शेयर करने योग्य वेब UI एक्सपोज़ करता है, इस प्रकार:

  • इनपुट्स (बायाँ कॉलम): बाएं पेन में मॉडल के लिए आवश्यक सब कुछ लिया जाता है—प्रोडक्ट फोटो अपलोड करने के लिए gr.Image, कैमरा एंगल्स के लिए gr.CheckboxGroup, आस्पेक्ट रेशियो और बैकग्राउंड प्रीसेट्स के लिए दो gr.Dropdowns, और लुक फाइन-ट्यून करने के लिए कस्टम सीन और स्टाइल नोट्स हेतु दो gr.Textbox फ़ील्ड्स।
  • आउटपुट्स (दायाँ कॉलम): gr.Gallery सभी जनरेटेड एंगल्स को ग्रिड में दिखाता है ताकि आप एक नज़र में कम्पोज़िशन्स की तुलना कर सकें, और gr.File कंपोनेंट तेज़ डाउनलोड के लिए PNGs का ZIP ऑफ़र करता है।
  • एडवांस्ड सेटिंग्स: एक gr.Checkbox T4-क्लास GPUs पर तेज़ प्रीव्यू के लिए Fast Mode (Lightning LoRA) टॉगल करता है, जबकि Seed और Steps, पुनरुत्पादन क्षमता और गुणवत्ता/समय ट्रेड-ऑफ समायोजित करते हैं। Guidance और True-CFG एडिट स्ट्रेंथ बनाम आइडेंटिटी स्थिरता को दिशा देते हैं, और Images per Angle आपको एक ही बार में प्रति कैमरा मैक्रो कई वेरिएंट बनाने देता है।
  • इंटरफ़ेस वायरिंग (एक्शन): एक Generate बटन सभी इनपुट्स को generate_images() फ़ंक्शन (जो चुने हुए एडॉप्टर्स के साथ Qwen Edit चलाता है) और फिर create_zip() फ़ंक्शन (जो आउटपुट्स पैकेज करता है) से जोड़ता है, और इंटरफ़ेस को गैलरी व ZIP दोनों रिटर्न करता है।
  • ऐप लॉन्च: अंत में, demo.launch() वेब ऐप स्पिन-अप करता है और एक पब्लिक शेयर URL देता है—Colab सेशंस, त्वरित डेमो, या स्टेकहोल्डर्स को टूल आज़माने के लिए लिंक भेजने के लिए उत्तम।

अंत में, Generate दबाएँ और पूरा एंगल पैक रेंडर होते देखें। 

यहाँ इस मॉडल के साथ मेरे प्रयोगों के परिणाम हैं। सबसे पहले, आप देख सकते हैं कि अलग-अलग पैरामीटर्स सेट करने पर प्रोडक्ट्स कैसे दिखते हैं।

अगले वीडियो में, आप देखेंगे कि मैं इंटरफ़ेस, विभिन्न सेटिंग्स और हमारी मूल इमेज से जनरेट हुए परिणामों के साथ कैसे इंटरेक्ट कर सकता/सकती हूँ। 

अंतिम विचार

अब आपके पास एक Product Shot Booster Gradio एप्लिकेशन है जो एक सिंगल फोटो को Qwen-Image-Edit-2509 और LoRA “वर्चुअल कैमरा” कंट्रोल्स के ज़रिये मल्टी-एंगल रेंडर्स में बदल देता है। यह GPU-अवेयर है (A100 पर सर्वोत्तम, पर छोटे GPUs पर स्लाइसिंग का उपयोग करता है), पुनरुत्पादन योग्य है, और Fast प्रीव्यू से HQ एक्सपोर्ट तक का वर्कफ़्लो सपोर्ट करता है।

आगे आप यह आज़मा सकते हैं:

  • Ship it: ऑथ और कोटा जोड़ें, और Amazon/Etsy/PDP इमेज स्पेक्स के लिए वन-क्लिक प्रीसेट एक्सपोर्ट शामिल करें।
  • Scale it: एक /generate API एक्सपोज़ करें और बैच जॉब्स (SKUs के CSV/JSON) सपोर्ट करें ताकि टीमें बड़े पैमाने पर एंगल पैक्स रेंडर कर सकें।

यदि आप AI-समर्थित एप्लिकेशंस बनाने में और हाथ आजमाना चाहते हैं, तो मैं Developing AI Applications स्किल ट्रैक की सिफारिश करता/करती हूँ। 

=

विषय