Spaces:
Running
Running
File size: 3,688 Bytes
c6b874d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | """Pollinations.ai image generation backend — free, no API key required.
Generates images via https://image.pollinations.ai/prompt/{prompt}.
Downloads the result and saves to $HERMES_HOME/cache/images/.
Supports landscape/square/portrait aspect ratios.
"""
from __future__ import annotations
import logging
import os
import urllib.parse
import urllib.request
from typing import Any, Dict, List
from agent.image_gen_provider import (
DEFAULT_ASPECT_RATIO,
ImageGenProvider,
error_response,
resolve_aspect_ratio,
success_response,
)
logger = logging.getLogger(__name__)
_API_BASE = "https://image.pollinations.ai/prompt"
_SIZES = {
"landscape": "1344x768",
"square": "1024x1024",
"portrait": "768x1344",
}
DEFAULT_MODEL = "flux"
class PollinationsImageGenProvider(ImageGenProvider):
"""Pollinations.ai free image generation backend."""
@property
def name(self) -> str:
return "pollinations"
@property
def display_name(self) -> str:
return "Pollinations (Free)"
def is_available(self) -> bool:
return True # no API key needed
def list_models(self) -> List[Dict[str, Any]]:
return [
{
"id": "flux",
"display": "Flux (Free)",
"speed": "~10-20s",
"strengths": "Free, no API key, good quality",
"price": "Free",
}
]
def get_setup_schema(self) -> Dict[str, Any]:
return {
"name": "Pollinations.ai",
"badge": "free",
"tag": "Free image generation — no API key required",
"env_vars": [],
}
def default_model(self) -> str:
return DEFAULT_MODEL
def generate(
self,
prompt: str,
aspect_ratio: str = DEFAULT_ASPECT_RATIO,
**kwargs: Any,
) -> Dict[str, Any]:
prompt = (prompt or "").strip()
aspect = resolve_aspect_ratio(aspect_ratio)
if not prompt:
return error_response(
error="Prompt is required",
error_type="invalid_argument",
provider="pollinations",
aspect_ratio=aspect,
)
width, height = _SIZES.get(aspect, _SIZES["square"]).split("x")
seed = os.urandom(4).hex()
url = f"{_API_BASE}/{urllib.parse.quote(prompt)}?width={width}&height={height}&seed={seed}&nologo=true&model=flux"
# Download image to cache
try:
from hermes_constants import get_hermes_home
import datetime
import uuid
cache_dir = get_hermes_home() / "cache" / "images"
cache_dir.mkdir(parents=True, exist_ok=True)
ts = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
short = uuid.uuid4().hex[:8]
save_path = cache_dir / f"pollinations_{ts}_{short}.png"
req = urllib.request.Request(url, headers={"User-Agent": "Hermes/1.0"})
with urllib.request.urlopen(req, timeout=60) as resp:
data = resp.read()
save_path.write_bytes(data)
image_ref = str(save_path)
except Exception as exc:
logger.warning("Pollinations image download failed: %s", exc)
# Fallback: return URL directly
image_ref = url
return success_response(
image=image_ref,
model=DEFAULT_MODEL,
prompt=prompt,
aspect_ratio=aspect,
provider="pollinations",
extra={"url": url},
)
def register(ctx) -> None:
ctx.register_image_gen_provider(PollinationsImageGenProvider())
|