Module 4: Image Generation
4. Comparison: DALL-E 3 vs Stable Diffusion
Description
Choosing between DALL-E 3 and Stable Diffusion is not a question of "which is better" — it's an engineering decision based on context: budget, volume, level of control needed, iteration speed, and reproducibility requirements. This capsule gives you the tools to make that decision with data: a detailed comparison table, benchmark code that sends the same prompt to both, cost analysis by scenario, and a programmatic decision tree.
Why it matters: In production, it's common to use both models in a single system: DALL-E 3 as the main generator (quality) and Stable Diffusion as a fallback (cost, availability). Understanding their differences lets you design resilient architectures and optimize costs without sacrificing quality.
Detailed Comparison Table
Technical criteria
| Criterion | DALL-E 3 (OpenAI) | Stable Diffusion (SDXL via Replicate) |
|---|---|---|
| Cost per image | $0.04-0.12 | $0.002-0.02 |
| Base quality | Excellent, consistent | Good, variable depending on parameters |
| Prompt understanding | Superior (rewrites + interprets) | Literal (what you write is what it generates) |
| Negative prompts | Not supported | Yes, highly effective |
| Parameter control | Limited (size, quality, style) | Extensive (steps, cfg, seed, scheduler, etc.) |
| Reproducibility | Low (no exposed seed) | High (seed = deterministic) |
| Speed | 10-25 seconds | 5-40 seconds (depends on model/steps) |
| Resolutions | 3 fixed (1024², 1792x1024, 1024x1792) | Flexible (multiples of 64) |
| Text in images | Acceptable | Poor |
| Consistency across generations | High | Medium (requires seed) |
| API | OpenAI official, stable | Replicate, Stability AI, multiple |
| Available models | dall-e-3, dall-e-2 | SDXL, SD3, Flux, hundreds of variants |
| Native inpainting | Only with dall-e-2 | Yes, specialized models |
| Open source | No | Yes |
| Works offline/local | No | Yes (with GPU) |
| Rate limits | Strict (per OpenAI tier) | Based on credits/balance |
| Content policy | Strict, rejects sensitive prompts | More permissive (depends on hosting) |
| Prompt rewriting | Yes (revised prompt) | No |
Business criteria
| Criterion | DALL-E 3 | Stable Diffusion |
|---|---|---|
| Initial setup | Minimal (OpenAI API key) | Low (Replicate API key) |
| Learning curve | Low (few parameters) | Medium (many parameters to optimize) |
| Cost scalability | Linear, predictable | Linear, much lower |
| Vendor lock-in | High (OpenAI only) | Low (multiple APIs, local execution) |
| Enterprise support | Yes (OpenAI Enterprise) | Limited (Stability AI, or self-hosted) |
| SLA / uptime | 99.9% (OpenAI) | Variable (depends on the provider) |
| Compliance | SOC 2, data not used for training | Depends on hosting (Replicate, self-hosted) |
Benchmark: Same Prompt on Both Models
Benchmark setup
This code sends the same prompt to DALL-E 3 and Stable Diffusion, measures time and saves results for visual comparison:
import time
import json
import requests
from pathlib import Path
from openai import OpenAI
import replicate
client = OpenAI()
SDXL_MODEL = "stability-ai/sdxl:39ed52f2a40e4be0e682a3e7d0645ef75e93dd3bd23a9c5fe73e589d1a3adc3b"
def benchmark_dalle3(prompt: str, save_path: str) -> dict:
start = time.time()
response = client.images.generate(
model="dall-e-3",
prompt=prompt,
size="1024x1024",
quality="standard",
style="vivid",
n=1
)
elapsed = time.time() - start
url = response.data[0].url
img_data = requests.get(url, timeout=30).content
Path(save_path).parent.mkdir(parents=True, exist_ok=True)
Path(save_path).write_bytes(img_data)
return {
"model": "dall-e-3",
"time_seconds": round(elapsed, 2),
"cost_usd": 0.04,
"revised_prompt": response.data[0].revised_prompt,
"saved_to": save_path,
}
def benchmark_sd(prompt: str, save_path: str) -> dict:
start = time.time()
output = replicate.run(
SDXL_MODEL,
input={
"prompt": prompt,
"negative_prompt": "blurry, low quality, distorted, deformed, ugly, watermark",
"width": 1024,
"height": 1024,
"num_inference_steps": 25,
"guidance_scale": 7.5,
}
)
elapsed = time.time() - start
url = output[0] if isinstance(output, list) else str(output)
img_data = requests.get(url, timeout=30).content
Path(save_path).parent.mkdir(parents=True, exist_ok=True)
Path(save_path).write_bytes(img_data)
return {
"model": "sdxl",
"time_seconds": round(elapsed, 2),
"cost_usd": 0.005,
"saved_to": save_path,
}
Run the benchmark
def run_benchmark(prompts: list[str], output_dir: str = "generated/benchmark") -> list[dict]:
Path(output_dir).mkdir(parents=True, exist_ok=True)
results = []
for i, prompt in enumerate(prompts):
print(f"\n--- Prompt {i+1}/{len(prompts)} ---")
print(f"'{prompt[:80]}...'")
dalle_result = benchmark_dalle3(prompt, f"{output_dir}/dalle_{i:02d}.png")
print(f" DALL-E 3: {dalle_result['time_seconds']}s, ${dalle_result['cost_usd']}")
sd_result = benchmark_sd(prompt, f"{output_dir}/sd_{i:02d}.png")
print(f" SDXL: {sd_result['time_seconds']}s, ${sd_result['cost_usd']}")
results.append({
"prompt": prompt,
"dalle": dalle_result,
"sd": sd_result,
"time_ratio": round(dalle_result["time_seconds"] / max(sd_result["time_seconds"], 0.1), 2),
"cost_ratio": round(dalle_result["cost_usd"] / max(sd_result["cost_usd"], 0.001), 1),
})
report_path = f"{output_dir}/benchmark_report.json"
Path(report_path).write_text(json.dumps(results, indent=2, ensure_ascii=False))
print(f"\nReport saved to: {report_path}")
return results
benchmark_prompts = [
"A professional headshot portrait with studio lighting, neutral background",
"A colorful abstract painting with geometric shapes and bold colors",
"A technical architecture diagram showing microservices with arrows",
"A photorealistic landscape of mountains reflected in a lake at sunset",
"A cute cartoon robot holding a book, children's illustration style",
]
results = run_benchmark(benchmark_prompts)
Cost Analysis by Scenario
Real scenarios
def cost_analysis(scenario: str, images_per_month: int, dalle_config: str = "standard") -> dict:
dalle_prices = {
"standard": 0.04,
"hd": 0.08,
"landscape_standard": 0.08,
"landscape_hd": 0.12,
}
sd_price = 0.005
dalle_cost = images_per_month * dalle_prices.get(dalle_config, 0.04)
sd_cost = images_per_month * sd_price
savings = dalle_cost - sd_cost
savings_pct = (savings / dalle_cost) * 100 if dalle_cost > 0 else 0
return {
"scenario": scenario,
"images_per_month": images_per_month,
"dalle_monthly": round(dalle_cost, 2),
"sd_monthly": round(sd_cost, 2),
"monthly_savings": round(savings, 2),
"savings_pct": round(savings_pct, 1),
"annual_savings": round(savings * 12, 2),
}
scenarios = [
cost_analysis("Startup - Blog thumbnails", 100),
cost_analysis("E-commerce - Product photos", 500, "hd"),
cost_analysis("Marketing - Campaign creatives", 1000, "landscape_standard"),
cost_analysis("Enterprise - Document diagrams", 5000),
cost_analysis("Platform - User-generated content", 50000),
]
print(f"{'Scenario':<40} {'Imgs/mo':>10} {'DALL-E':>10} {'SD':>10} {'Savings':>10} {'Savings %':>10}")
print("-" * 90)
for s in scenarios:
print(
f"{s['scenario']:<40} {s['images_per_month']:>10,} "
f"${s['dalle_monthly']:>8,.2f} ${s['sd_monthly']:>8,.2f} "
f"${s['monthly_savings']:>8,.2f} {s['savings_pct']:>9.1f}%"
)
print(f"{'':>40} {'Annual savings:':<20} ${s['annual_savings']:>8,.2f}")
Break-even point: when is DALL-E's quality worth it?
| Factor | Choose DALL-E 3 | Choose Stable Diffusion |
|---|---|---|
| Volume | < 1,000 imgs/mo | > 1,000 imgs/mo |
| Use | Brand/enterprise/marketing | Batch, prototype, experimental |
| Team | No expertise in SD tuning | Can optimize parameters |
| Control | Doesn't need negative prompts | Needs reproducibility, seeds |
| Vendor | Already uses OpenAI, a single API | Prefers provider independence |
| Editing | Doesn't need advanced inpainting | Needs ControlNet, inpainting |
Programmatic Decision Tree
Simple version
def choose_generator(
budget_per_image: float = 0.05,
need_negative_prompt: bool = False,
need_reproducibility: bool = False,
images_per_month: int = 100,
use_case: str = "general",
) -> str:
if need_negative_prompt:
return "sd"
if need_reproducibility:
return "sd"
if budget_per_image < 0.02:
return "sd"
if images_per_month > 5000:
return "sd"
if use_case in ["brand", "product", "enterprise", "marketing"]:
return "dalle"
return "dalle"
Version with scoring
def choose_generator_scored(
budget_per_image: float = 0.05,
need_negative_prompt: bool = False,
need_reproducibility: bool = False,
need_inpainting: bool = False,
images_per_month: int = 100,
quality_priority: str = "high",
use_case: str = "general",
) -> dict:
dalle_score = 0
sd_score = 0
if budget_per_image >= 0.04:
dalle_score += 2
elif budget_per_image >= 0.02:
dalle_score += 1
sd_score += 1
else:
sd_score += 3
if need_negative_prompt:
sd_score += 3
if need_reproducibility:
sd_score += 2
if need_inpainting:
sd_score += 3
if images_per_month > 5000:
sd_score += 2
elif images_per_month > 1000:
sd_score += 1
quality_scores = {"high": 2, "medium": 0, "low": -1}
dalle_score += quality_scores.get(quality_priority, 0)
use_case_dalle = {"brand", "product", "enterprise", "marketing", "editorial"}
use_case_sd = {"prototype", "batch", "experimental", "inpainting", "gaming"}
if use_case in use_case_dalle:
dalle_score += 2
elif use_case in use_case_sd:
sd_score += 2
recommendation = "dalle" if dalle_score > sd_score else "sd"
confidence = abs(dalle_score - sd_score) / max(dalle_score + sd_score, 1)
return {
"recommendation": recommendation,
"dalle_score": dalle_score,
"sd_score": sd_score,
"confidence": round(confidence, 2),
"reasoning": (
f"DALL-E: {dalle_score} pts, SD: {sd_score} pts. "
f"{'High' if confidence > 0.3 else 'Low'} confidence."
),
}
print(choose_generator_scored(
budget_per_image=0.10,
images_per_month=200,
quality_priority="high",
use_case="brand",
))
print(choose_generator_scored(
budget_per_image=0.01,
images_per_month=10000,
need_negative_prompt=True,
need_reproducibility=True,
quality_priority="medium",
use_case="batch",
))
Fallback System: DALL-E + Stable Diffusion
The most useful pattern in production: try DALL-E 3 first (better quality), and if it fails, fall back to Stable Diffusion automatically.
import time
from openai import BadRequestError, RateLimitError, APIError
def generate_image_with_fallback(
prompt: str,
save_path: str | None = None,
prefer: str = "dalle",
) -> dict:
generators = {
"dalle": _try_dalle,
"sd": _try_sd,
}
order = ["dalle", "sd"] if prefer == "dalle" else ["sd", "dalle"]
for gen_name in order:
result = generators[gen_name](prompt, save_path)
if result["status"] == "success":
result["generator_used"] = gen_name
result["was_fallback"] = gen_name != order[0]
return result
print(f" {gen_name} failed: {result.get('error', 'unknown')}")
return {"status": "error", "error": "All generators failed", "prompt": prompt}
def _try_dalle(prompt: str, save_path: str | None) -> dict:
try:
response = client.images.generate(
model="dall-e-3",
prompt=prompt,
size="1024x1024",
quality="standard",
n=1,
)
url = response.data[0].url
result = {
"status": "success",
"url": url,
"revised_prompt": response.data[0].revised_prompt,
}
if save_path:
img_data = requests.get(url, timeout=30).content
Path(save_path).parent.mkdir(parents=True, exist_ok=True)
Path(save_path).write_bytes(img_data)
result["saved_to"] = save_path
return result
except (BadRequestError, RateLimitError, APIError) as e:
return {"status": "error", "error": str(e)}
def _try_sd(prompt: str, save_path: str | None) -> dict:
try:
output = replicate.run(
SDXL_MODEL,
input={
"prompt": prompt,
"negative_prompt": "blurry, low quality, distorted, deformed",
"width": 1024,
"height": 1024,
"num_inference_steps": 25,
"guidance_scale": 7.5,
}
)
url = output[0] if isinstance(output, list) else str(output)
result = {"status": "success", "url": url}
if save_path:
img_data = requests.get(url, timeout=60).content
Path(save_path).parent.mkdir(parents=True, exist_ok=True)
Path(save_path).write_bytes(img_data)
result["saved_to"] = save_path
return result
except Exception as e:
return {"status": "error", "error": str(e)}
result = generate_image_with_fallback(
"A modern office space with natural lighting and green plants",
save_path="generated/fallback_test.png"
)
print(f"Status: {result['status']}")
print(f"Generator: {result.get('generator_used')}")
print(f"Was fallback: {result.get('was_fallback')}")
Quality vs Cost: Visualization
def quality_cost_matrix() -> list[dict]:
configs = [
{"name": "DALL-E 3 HD Landscape", "cost": 0.120, "quality": 9.5, "generator": "dalle"},
{"name": "DALL-E 3 HD Square", "cost": 0.080, "quality": 9.0, "generator": "dalle"},
{"name": "DALL-E 3 Std Square", "cost": 0.040, "quality": 8.5, "generator": "dalle"},
{"name": "SD3 (Stability)", "cost": 0.030, "quality": 8.0, "generator": "sd"},
{"name": "SDXL (Replicate)", "cost": 0.005, "quality": 7.5, "generator": "sd"},
{"name": "Flux Dev", "cost": 0.015, "quality": 8.5, "generator": "sd"},
{"name": "Flux Schnell", "cost": 0.003, "quality": 7.0, "generator": "sd"},
{"name": "DALL-E 2", "cost": 0.020, "quality": 6.0, "generator": "dalle"},
]
configs.sort(key=lambda x: x["quality"] / max(x["cost"], 0.001), reverse=True)
print(f"{'Configuration':<25} {'Cost':>8} {'Quality':>8} {'Quality/$':>10}")
print("-" * 55)
for c in configs:
ratio = c["quality"] / c["cost"]
bar = "█" * int(ratio / 50)
print(f"{c['name']:<25} ${c['cost']:>6.3f} {c['quality']:>7.1f} {ratio:>9.0f} {bar}")
return configs
quality_cost_matrix()
The quality/price ratio massively favors the SD/Flux models. DALL-E 3 wins on absolute quality, but with diminishing returns per dollar.
When to Use Each: Quick Guide
Choose DALL-E 3 when:
- Visual quality directly impacts revenue (brand, premium e-commerce)
- You don't have time to iterate on parameters (you need "generate and done")
- You already use OpenAI and want a single bill/API
- Volume is low-to-medium (< 1,000/mo) and the absolute cost is acceptable
- You need the best semantic understanding of complex prompts
Choose Stable Diffusion when:
- Volume is high (> 1,000/mo) and the savings justify the complexity
- You need fine control (negative prompts, seeds, schedulers)
- You need reproducibility (same seed = same image)
- You have inpainting or advanced editing capabilities
- You don't want vendor lock-in with OpenAI
- You're experimenting and need to iterate fast without worrying about costs
Use both (fallback) when:
- You're building a product where availability is critical
- You want DALL-E quality for the normal flow, SD as a backup
- Different features require different generators (brand → DALL-E, batch → SD)
Troubleshooting
| Problem | With DALL-E 3 | With Stable Diffusion |
|---|---|---|
| Blurry image | Change quality="hd" | Raise steps to 30+, guidance to 8 |
| Doesn't resemble the prompt | Review revised_prompt; be more explicit | Raise guidance_scale; improve prompt |
| Deformed hands | Add "with correct hands" to the prompt | Add "bad hands, extra fingers" to the negative |
| Illegible text in image | DALL-E 3 is limited with typography | SD is worse; avoid text in images |
| Content policy rejection | Rephrase; see capsule 2 (reprompting) | Switch to SD, which is more permissive |
| Too slow | No speed control in DALL-E | Reduce steps; use Flux Schnell |
| Too expensive | Reduce resolution; use standard | Already cheap; reduce steps if necessary |
| Inconsistent results | Expected (no seed in DALL-E 3) | Set a seed for reproducibility |
| Fallback doesn't work | Check error handling in _try_dalle | Check REPLICATE_API_TOKEN |
Exercises
Exercise 1: Visual benchmark with automatic analysis
Implement a benchmark that sends 3 prompts to both generators, downloads the images, and generates a JSON report with times, costs and image paths for manual comparison.
See solution
import json
import time
from datetime import datetime
from pathlib import Path
def full_benchmark(prompts: list[str], output_dir: str = "generated/full_benchmark") -> dict:
Path(output_dir).mkdir(parents=True, exist_ok=True)
results = []
for i, prompt in enumerate(prompts):
print(f"\n[{i+1}/{len(prompts)}] {prompt[:60]}...")
entry = {"prompt": prompt, "index": i}
start = time.time()
try:
dalle_response = client.images.generate(
model="dall-e-3", prompt=prompt, size="1024x1024", quality="standard", n=1
)
dalle_time = time.time() - start
dalle_url = dalle_response.data[0].url
dalle_path = f"{output_dir}/dalle_{i:02d}.png"
Path(dalle_path).write_bytes(requests.get(dalle_url, timeout=30).content)
entry["dalle"] = {
"time": round(dalle_time, 2),
"cost": 0.04,
"path": dalle_path,
"revised_prompt": dalle_response.data[0].revised_prompt[:100],
}
print(f" DALL-E 3: {dalle_time:.1f}s")
except Exception as e:
entry["dalle"] = {"error": str(e)}
print(f" DALL-E 3: ERROR - {e}")
start = time.time()
try:
sd_output = replicate.run(
SDXL_MODEL,
input={
"prompt": prompt,
"negative_prompt": "blurry, low quality, distorted",
"width": 1024, "height": 1024,
"num_inference_steps": 25, "guidance_scale": 7.5,
}
)
sd_time = time.time() - start
sd_url = sd_output[0] if isinstance(sd_output, list) else str(sd_output)
sd_path = f"{output_dir}/sd_{i:02d}.png"
Path(sd_path).write_bytes(requests.get(sd_url, timeout=60).content)
entry["sd"] = {"time": round(sd_time, 2), "cost": 0.005, "path": sd_path}
print(f" SDXL: {sd_time:.1f}s")
except Exception as e:
entry["sd"] = {"error": str(e)}
print(f" SDXL: ERROR - {e}")
results.append(entry)
report = {
"timestamp": datetime.now().isoformat(),
"total_prompts": len(prompts),
"results": results,
"totals": {
"dalle_cost": sum(r["dalle"].get("cost", 0) for r in results),
"sd_cost": sum(r["sd"].get("cost", 0) for r in results),
"dalle_avg_time": round(
sum(r["dalle"].get("time", 0) for r in results) / len(results), 2
),
"sd_avg_time": round(
sum(r["sd"].get("time", 0) for r in results) / len(results), 2
),
},
}
report_path = f"{output_dir}/report.json"
Path(report_path).write_text(json.dumps(report, indent=2, ensure_ascii=False))
print(f"\nReport: {report_path}")
return report
full_benchmark([
"A minimalist logo for a coffee shop, flat design, warm colors",
"An aerial photograph of a coastal city at golden hour",
"A watercolor illustration of a cat reading a book in a library",
])
Exercise 2: Interactive cost calculator
Create a function that takes a usage scenario (monthly volume, preferred configuration, percentage of HD images) and returns a cost comparison between DALL-E 3 and SD, including annual projection and recommendation.
See solution
def cost_calculator(
monthly_volume: int,
hd_percentage: float = 0.2,
landscape_percentage: float = 0.3,
dalle_config: str = "mixed",
) -> dict:
standard_square = monthly_volume * (1 - hd_percentage) * (1 - landscape_percentage)
hd_square = monthly_volume * hd_percentage * (1 - landscape_percentage)
standard_landscape = monthly_volume * (1 - hd_percentage) * landscape_percentage
hd_landscape = monthly_volume * hd_percentage * landscape_percentage
dalle_monthly = (
standard_square * 0.04 +
hd_square * 0.08 +
standard_landscape * 0.08 +
hd_landscape * 0.12
)
sd_monthly = monthly_volume * 0.005
recommendation = "sd" if monthly_volume > 500 and dalle_monthly > 30 else "dalle"
if dalle_monthly < 10:
recommendation = "dalle"
result = {
"monthly_volume": monthly_volume,
"dalle": {
"monthly": round(dalle_monthly, 2),
"annual": round(dalle_monthly * 12, 2),
"per_image_avg": round(dalle_monthly / max(monthly_volume, 1), 4),
},
"sd": {
"monthly": round(sd_monthly, 2),
"annual": round(sd_monthly * 12, 2),
"per_image_avg": 0.005,
},
"savings_monthly": round(dalle_monthly - sd_monthly, 2),
"savings_annual": round((dalle_monthly - sd_monthly) * 12, 2),
"savings_pct": round((1 - sd_monthly / max(dalle_monthly, 0.01)) * 100, 1),
"recommendation": recommendation,
}
print(f"=== Cost Analysis ({monthly_volume:,} imgs/mo) ===")
print(f"\nDALL-E 3: ${result['dalle']['monthly']:,.2f}/mo (${result['dalle']['annual']:,.2f}/yr)")
print(f"SD (SDXL): ${result['sd']['monthly']:,.2f}/mo (${result['sd']['annual']:,.2f}/yr)")
print(f"\nSavings with SD: ${result['savings_monthly']:,.2f}/mo ({result['savings_pct']}%)")
print(f"Annual savings: ${result['savings_annual']:,.2f}")
print(f"\nRecommendation: {'DALL-E 3' if recommendation == 'dalle' else 'Stable Diffusion'}")
return result
cost_calculator(100, hd_percentage=0.5)
cost_calculator(5000, hd_percentage=0.1, landscape_percentage=0.5)
Exercise 3: Fallback system with metrics
Extend the fallback system to record metrics: how many times each generator was used, how many fallbacks occurred, average time, and accumulated cost.
See solution
from dataclasses import dataclass, field
@dataclass
class GeneratorMetrics:
dalle_calls: int = 0
dalle_successes: int = 0
dalle_failures: int = 0
sd_calls: int = 0
sd_successes: int = 0
sd_failures: int = 0
fallback_count: int = 0
total_cost: float = 0.0
dalle_times: list = field(default_factory=list)
sd_times: list = field(default_factory=list)
def record(self, generator: str, success: bool, time_s: float, cost: float, was_fallback: bool):
if generator == "dalle":
self.dalle_calls += 1
if success:
self.dalle_successes += 1
self.dalle_times.append(time_s)
else:
self.dalle_failures += 1
else:
self.sd_calls += 1
if success:
self.sd_successes += 1
self.sd_times.append(time_s)
else:
self.sd_failures += 1
if was_fallback:
self.fallback_count += 1
if success:
self.total_cost += cost
def summary(self) -> dict:
return {
"dalle": {
"calls": self.dalle_calls,
"success_rate": round(self.dalle_successes / max(self.dalle_calls, 1) * 100, 1),
"avg_time": round(sum(self.dalle_times) / max(len(self.dalle_times), 1), 2),
},
"sd": {
"calls": self.sd_calls,
"success_rate": round(self.sd_successes / max(self.sd_calls, 1) * 100, 1),
"avg_time": round(sum(self.sd_times) / max(len(self.sd_times), 1), 2),
},
"fallback_rate": round(self.fallback_count / max(self.dalle_calls + self.sd_calls, 1) * 100, 1),
"total_cost": round(self.total_cost, 4),
}
metrics = GeneratorMetrics()
def generate_with_metrics(prompt: str, save_path: str | None = None) -> dict:
start = time.time()
try:
response = client.images.generate(
model="dall-e-3", prompt=prompt, size="1024x1024", quality="standard", n=1
)
elapsed = time.time() - start
url = response.data[0].url
if save_path:
Path(save_path).parent.mkdir(parents=True, exist_ok=True)
Path(save_path).write_bytes(requests.get(url, timeout=30).content)
metrics.record("dalle", True, elapsed, 0.04, False)
return {"status": "success", "generator": "dalle", "url": url, "time": round(elapsed, 2)}
except Exception as e:
elapsed = time.time() - start
metrics.record("dalle", False, elapsed, 0, False)
start = time.time()
try:
output = replicate.run(SDXL_MODEL, input={
"prompt": prompt, "negative_prompt": "blurry, low quality",
"width": 1024, "height": 1024, "num_inference_steps": 25,
})
elapsed = time.time() - start
url = output[0] if isinstance(output, list) else str(output)
if save_path:
Path(save_path).parent.mkdir(parents=True, exist_ok=True)
Path(save_path).write_bytes(requests.get(url, timeout=60).content)
metrics.record("sd", True, elapsed, 0.005, True)
return {"status": "success", "generator": "sd", "url": url, "time": round(elapsed, 2), "was_fallback": True}
except Exception as e:
elapsed = time.time() - start
metrics.record("sd", False, elapsed, 0, True)
return {"status": "error", "error": str(e)}
test_prompts = [
"A futuristic car design concept, metallic blue",
"A cozy winter cabin in the mountains with snow",
"Abstract digital art with flowing neon colors",
]
for i, prompt in enumerate(test_prompts):
result = generate_with_metrics(prompt, save_path=f"generated/metrics_{i}.png")
print(f"[{i+1}] {result.get('generator', 'none')}: {result['status']}")
print("\n=== Metrics ===")
print(json.dumps(metrics.summary(), indent=2))
Additional Resources
- OpenAI Pricing — Up-to-date DALL-E prices
- Replicate Pricing — Pay-per-second-of-GPU model
- Stability AI Pricing — Prices for the official SD API
- OpenAI Rate Limits — Limits per tier
- Replicate SDXL — Model documentation on Replicate