Recreating Lensa AI: Building an Open-Source Batch Avatar Generator
How to bypass subscription paywalls by building an automated Python pipeline for batch Img2Img avatar generation using modern AI APIs.
The Problem: The Consumer Avatar Paywall Trap
Consumer AI avatar applications surged into viral ubiquity by packaging image-to-image (Img2Img) neural diffusion models into consumer mobile wrappers. Behind sleek onboarding screens and recurring subscriptions ($30 to $50 annually, or micro-transactions of $5 to $10 per batch), these commercial apps are fundamentally basic wrappers around foundational diffusion endpoints.
For technical builders, paying ongoing subscription fees for basic batch API calls introduces several severe friction points:
- Opaque Pricing Models: Commercial mobile apps markup underlying GPU inference by upwards of 2,000%, locking users into recurring subscriptions for tasks requiring seconds of compute.
- Zero Parameter Control: Prompts, seeds, denoising weights, guidance scales, and reference conditioning are black-boxed. If an avatar exhibits structural facial distortions or mismatched eye geometry, the user has no tuning controls other than paying for another blind generation run.
- Data Privacy Risks: Uploading raw, high-resolution personal facial biometric data to unverified third-party consumer apps introduces indefinite data retention risks and questionable terms of service.
The solution is straightforward: build an open-source, automated batch orchestrator that connects directly to modern generative AI APIs at pure compute cost.
The Solution & System Architecture
The pipeline engineered in img2img-batch-avitar-generator decouples image acquisition, pre-processing, inference submission, and artifact recovery into three resilient stages:
[Local Raw Photos]
│
▼
┌──────────────────────────────────────────────┐
│ 1. Pillow Pre-Processing & Normalization │
│ - EXIF orientation transposition │
│ - Aspect ratio standardization (1:1) │
│ - Dimension clamping & compression │
└──────────────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ 2. Ephemeral Ingestion Bridge │
│ - Secure public URL generation │
│ - Short-lived TTL reference delivery │
└──────────────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ 3. REST Dispatch & Async Status Polling │
│ - Payload dispatch (IMAGETOIAMGE mode) │
│ - Stylistic prompt weight injection │
│ - Polling 'record-info' via backoff loop │
│ - High-fidelity artifact streaming │
└──────────────────────┬───────────────────────┘
│
▼
[Curated Avatar Repository]
1. Local Directory Scanning & Pillow EXIF Normalization
Smartphones embed camera orientation metadata directly in EXIF headers rather than rotating physical pixel buffers. When uploaded directly to neural diffusion pipelines, photos taken in portrait orientation frequently trigger distorted 90-degree rotated outputs.
Our Python ingestion engine utilizes Pillow's ImageOps.exif_transpose to rotate image buffers into their canonical orientation before inference:
- Automatically scans directories for
.jpg,.jpeg,.png, and.webpinputs. - Strips personal location / GPS metadata.
- Applies centered aspect ratio cropping to standardize images to a clean 1:1 square canvas.
- Clamps max dimensions to 1024×1024 or 512×512 to minimize network latency while preserving facial fidelity.
2. Ephemeral Public Hosting Bridge
High-performance cloud inference APIs require reference images via accessible HTTP(S) URLs rather than multi-megabyte multipart form payloads. The pipeline implements a lightweight ephemeral staging bridge (via pre-signed S3/Cloudflare R2 buckets or temporary secure tunneling) that provides short-lived, authenticated ingestion URLs for the exact duration of the inference job.
3. REST API Integration: IMAGETOIAMGE & Async Polling
Generative image synthesis is compute-intensive and inherently asynchronous. Submitting a request returns a task_id rather than waiting for completion on an open HTTP socket.
The client pipeline:
- Dispatches a structured payload specifying
IMAGETOIAMGEtask type, prompt weighting (e.g., stylized anime, cyber neon, oil painting, grandmaster portrait, 8k octane render), negative prompts, and 1:1 aspect ratio. - Enters an asynchronous polling loop querying the
record-infotask status endpoint with exponential backoff and jitter. - Automatically streams output image URLs into local organized directories upon
SUCCESS.
Code Highlight: Request Dispatch & Polling Loop
Below is the production-ready Python snippet implementing the request dispatch and status polling architecture:
import time
import requests
from typing import Optional, Dict, Any
class BatchAvatarGenerator:
"""
Automated batch orchestrator for Img2Img AI avatar generation.
Connects to modern generative endpoints, handles prompt weighting,
and polls asynchronous task states.
"""
def __init__(self, api_key: str, base_url: str):
self.api_key = api_key
self.base_url = base_url.rstrip("/")
self.headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
}
def dispatch_img2img_task(
self,
image_url: str,
prompt: str,
negative_prompt: str = "blurry, low quality, distorted, extra limbs, bad eyes",
denoising_strength: float = 0.55,
aspect_ratio: str = "1:1"
) -> str:
"""
Dispatches an asynchronous Img2Img generation job.
Returns the unique task ID for tracking.
"""
endpoint = f"{self.base_url}/v1/tasks/dispatch"
payload = {
"task_type": "IMAGETOIAMGE",
"input_image_url": image_url,
"prompt": prompt,
"negative_prompt": negative_prompt,
"strength": denoising_strength,
"aspect_ratio": aspect_ratio,
"sampler": "Euler a",
"steps": 30,
"guidance_scale": 7.5
}
response = requests.post(endpoint, json=payload, headers=self.headers, timeout=30)
response.raise_for_status()
data = response.json()
task_id = data.get("task_id") or data.get("id")
if not task_id:
raise ValueError(f"Failed to obtain task_id from response: {data}")
print(f"[DISPATCHED] Task ID: {task_id} for reference: {image_url}")
return task_id
def poll_task_status(
self,
task_id: str,
max_attempts: int = 60,
delay_seconds: float = 3.0
) -> Dict[str, Any]:
"""
Polls the 'record-info' endpoint until the generation task reaches terminal state.
"""
endpoint = f"{self.base_url}/v1/tasks/record-info/{task_id}"
for attempt in range(1, max_attempts + 1):
response = requests.get(endpoint, headers=self.headers, timeout=15)
response.raise_for_status()
record = response.json()
status = record.get("status", "").upper()
if status == "SUCCESS":
output_urls = record.get("output_images", [])
print(f"[COMPLETED] Task {task_id} generated {len(output_urls)} artifacts.")
return record
elif status in ("FAILED", "ERROR"):
error_msg = record.get("error_message", "Unknown inference error")
raise RuntimeError(f"Task {task_id} failed: {error_msg}")
# Exponential backoff with ceiling
sleep_duration = min(delay_seconds * (1.1 ** (attempt // 5)), 10.0)
print(f"[POLLING] Task {task_id} status: {status}... Waiting {sleep_duration:.1f}s (attempt {attempt}/{max_attempts})")
time.sleep(sleep_duration)
raise TimeoutError(f"Task {task_id} timed out after {max_attempts} polling attempts.")
Gallery Showcase: Generated Artifacts
Using this pipeline, a single input photo can be transformed across dozens of distinct artistic directions in seconds. Here are three sample generated outputs produced by the system:
Variant 01
Cyber Neon & Ambient Glow
High-contrast hair highlights and soft amber fill lighting.
Variant 02
Graphic Novel Noir & Tailored Suit
Inked linework, deep chiaroscuro shadows, and executive pose.
Variant 03
Warm Studio Portrait
Ochre studio backdrop, crisp collar, and natural facial geometry.
Upcoming Interactive Feature
An upcoming update to the media gallery will introduce an interactive side-by-side comparison collage, enabling real-time visual inspection of the original input photograph alongside its generated avatar counterparts with adjustable alpha blend sliders.
Open Source Repository & Community Access
The complete Python script, prompt weighting configs, and directory batching logic are open-source and publicly hosted on GitHub:
- Repository: https://github.com/tidypy/img2img-batch-avitar-generator
- Author & Maintainer: Christopher Lazok (@tidypy)
- Primary Domain: https://christopherlazok.com
- LinkedIn: https://www.linkedin.com/in/christopher-lazok
- License: MIT