Spaces:
Configuration error
Configuration error
Download free_image_gen.py from Brettapps/Trifecta-Lab: direct link, hf CLI and curl.
- Browser
- Download file 8.17 kB
-
https://huggingface.co/spaces/Brettapps/Trifecta-Lab/resolve/main/free_image_gen.py
- Command line
-
hf download hf://spaces/Brettapps/Trifecta-Lab/free_image_gen.py
-
curl -L -o free_image_gen.py https://huggingface.co/spaces/Brettapps/Trifecta-Lab/resolve/main/free_image_gen.py
8.17 kB
| #!/usr/bin/env python3 | |
| """ | |
| Free Image Generation Tool | |
| Uses Hugging Face Free Inference API (no auth required for public models) | |
| to generate images via CLI. Falls back to Pollinations.ai if HF fails. | |
| """ | |
| import argparse | |
| import hashlib | |
| import json | |
| import os | |
| import sys | |
| import urllib.request | |
| import urllib.parse | |
| import urllib.error | |
| from pathlib import Path | |
| # Hugging Face free inference endpoint (public models, no auth needed) | |
| HF_INFERENCE_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0" | |
| def generate_image_hf(prompt: str, output_dir: str = None) -> dict: | |
| """ | |
| Generate image using Hugging Face Inference API (free tier). | |
| Uses stabilityai/stable-diffusion-xl-base-1.0 model. | |
| """ | |
| if output_dir is None: | |
| output_dir = os.getcwd() | |
| output_path = Path(output_dir) | |
| output_path.mkdir(parents=True, exist_ok=True) | |
| prompt_hash = hashlib.md5(prompt.encode()).hexdigest()[:8] | |
| filename = f"hf_{prompt_hash}.png" | |
| file_path = output_path / filename | |
| # Hugging Face expects JSON payload | |
| payload = json.dumps({ | |
| "inputs": prompt, | |
| "parameters": { | |
| "negative_prompt": "blurry, low quality, distorted", | |
| "guidance_scale": 7.5, | |
| "num_inference_steps": 30 | |
| } | |
| }).encode('utf-8') | |
| req = urllib.request.Request( | |
| HF_INFERENCE_URL, | |
| data=payload, | |
| headers={ | |
| "Content-Type": "application/json", | |
| "Authorization": "Bearer hf_", # Empty token for public models | |
| "x-wait-for-model": "true" # Wait for model to load if cold | |
| } | |
| ) | |
| try: | |
| with urllib.request.urlopen(req, timeout=300) as response: | |
| if response.status != 200: | |
| raise Exception(f"API returned status {response.status}") | |
| # HF returns image binary data | |
| image_data = response.read() | |
| if len(image_data) < 100: | |
| raise Exception("Response too small - likely error") | |
| with open(file_path, 'wb') as f: | |
| f.write(image_data) | |
| file_size = file_path.stat().st_size | |
| return { | |
| "file_path": str(file_path.absolute()), | |
| "model": "stabilityai/stable-diffusion-xl-base-1.0", | |
| "prompt": prompt, | |
| "file_size_bytes": file_size, | |
| "provider": "huggingface" | |
| } | |
| except urllib.error.HTTPError as e: | |
| if e.code == 401: | |
| raise Exception("Hugging Face API requires authentication for this model") | |
| elif e.code == 503: | |
| raise Exception("Model is loading - try again in a moment") | |
| raise Exception(f"HTTP error {e.code}: {e.reason}") | |
| except urllib.error.URLError as e: | |
| raise Exception(f"Network error: {e.reason}") | |
| except Exception as e: | |
| raise Exception(f"HF generation failed: {str(e)}") | |
| def generate_image_pollinations(prompt: str, width: int = 1024, height: int = 1024, | |
| output_dir: str = None) -> dict: | |
| """ | |
| Generate image using Pollinations.ai free API. | |
| """ | |
| if output_dir is None: | |
| output_dir = os.getcwd() | |
| output_path = Path(output_dir) | |
| output_path.mkdir(parents=True, exist_ok=True) | |
| prompt_hash = hashlib.md5(prompt.encode()).hexdigest()[:8] | |
| filename = f"pollinations_{prompt_hash}.png" | |
| file_path = output_path / filename | |
| # Build URL - Pollinations expects prompt in URL path | |
| encoded_prompt = urllib.parse.quote(prompt) | |
| api_url = f"https://image.pollinations.ai/prompt/{encoded_prompt}" | |
| # Add query params | |
| params = urllib.parse.urlencode({ | |
| "width": width, | |
| "height": height, | |
| "nologo": "true", | |
| "nofeed": "true", | |
| "seed": "random" | |
| }) | |
| api_url = f"{api_url}?{params}" | |
| try: | |
| req = urllib.request.Request(api_url) | |
| req.add_header('User-Agent', 'FreeImageGen/1.0') | |
| with urllib.request.urlopen(req, timeout=60) as response: | |
| if response.status != 200: | |
| raise Exception(f"API returned status {response.status}") | |
| image_data = response.read() | |
| if len(image_data) < 100: | |
| raise Exception("Response too small") | |
| # Check if it's actually an image (PNG starts with PNG signature) | |
| if image_data[:8] != b'\x89PNG\r\n\x1a\n': | |
| # Might be JSON error | |
| try: | |
| error = json.loads(image_data.decode('utf-8')) | |
| raise Exception(f"API error: {error.get('error', 'Unknown')}") | |
| except: | |
| raise Exception("Response is not a valid image") | |
| with open(file_path, 'wb') as f: | |
| f.write(image_data) | |
| file_size = file_path.stat().st_size | |
| return { | |
| "file_path": str(file_path.absolute()), | |
| "model": "pollinations.ai", | |
| "prompt": prompt, | |
| "width": width, | |
| "height": height, | |
| "file_size_bytes": file_size, | |
| "provider": "pollinations" | |
| } | |
| except urllib.error.HTTPError as e: | |
| raise Exception(f"HTTP error {e.code}: {e.reason}") | |
| except urllib.error.URLError as e: | |
| raise Exception(f"Network error: {e.reason}") | |
| except Exception as e: | |
| raise Exception(f"Pollinations generation failed: {str(e)}") | |
| def generate_image(prompt: str, width: int = 1024, height: int = 1024, | |
| output_dir: str = None, prefer: str = "hf") -> dict: | |
| """ | |
| Generate an image using free APIs. | |
| Tries Hugging Face first (higher quality), then falls back to Pollinations. | |
| Args: | |
| prompt: The image generation prompt | |
| width: Image width (for Pollinations fallback) | |
| height: Image height (for Pollinations fallback) | |
| output_dir: Directory to save the image | |
| prefer: "hf" or "pollinations" | |
| Returns: | |
| JSON dict with file_path, model, and prompt | |
| """ | |
| if prefer == "pollinations": | |
| return generate_image_pollinations(prompt, width, height, output_dir) | |
| # Try Hugging Face first | |
| try: | |
| result = generate_image_hf(prompt, output_dir) | |
| print(f"# Using Hugging Face: stabilityai/stable-diffusion-xl-base-1.0", file=sys.stderr) | |
| return result | |
| except Exception as e: | |
| print(f"# HF failed: {e}. Falling back to Pollinations...", file=sys.stderr) | |
| # Fall back to Pollinations | |
| try: | |
| result = generate_image_pollinations(prompt, width, height, output_dir) | |
| print(f"# Using Pollinations.ai", file=sys.stderr) | |
| return result | |
| except Exception as e: | |
| raise Exception(f"All free APIs failed: {str(e)}") | |
| def main(): | |
| parser = argparse.ArgumentParser( | |
| description="Generate images using free APIs (Hugging Face or Pollinations.ai)" | |
| ) | |
| parser.add_argument("--prompt", type=str, required=True, help="Image generation prompt") | |
| parser.add_argument("--width", type=int, default=1024, help="Image width (Pollinations)") | |
| parser.add_argument("--height", type=int, default=1024, help="Image height (Pollinations)") | |
| parser.add_argument("--output_dir", type=str, default=None, help="Output directory") | |
| parser.add_argument("--prefer", type=str, choices=["hf", "pollinations"], | |
| default="hf", help="Preferred API: hf (default) or pollinations") | |
| args = parser.parse_args() | |
| try: | |
| result = generate_image( | |
| prompt=args.prompt, | |
| width=args.width, | |
| height=args.height, | |
| output_dir=args.output_dir, | |
| prefer=args.prefer | |
| ) | |
| print(json.dumps(result, indent=2)) | |
| except Exception as e: | |
| print(json.dumps({"error": str(e), "provider": "none"}, indent=2)) | |
| sys.exit(1) | |
| if __name__ == "__main__": | |
| main() |