Spaces:
Running
Running
| import os | |
| import time | |
| from fastapi import FastAPI, Request, HTTPException | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import Response | |
| import httpx | |
| from bs4 import BeautifulSoup | |
| from typing import List, Dict | |
| app = FastAPI() | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["GET"], | |
| allow_headers=["*"], | |
| ) | |
| OLLAMA_LIBRARY_URL = "https://ollama.com/library" | |
| # ----------------------------- | |
| # RATE LIMITING (25 req/day/IP) | |
| # ----------------------------- | |
| RATE_LIMIT = 25 | |
| WINDOW_SECONDS = 60 * 60 * 24 # 24 hours | |
| ip_store = {} # { ip: { "count": int, "reset": timestamp } } | |
| def check_rate_limit(ip: str): | |
| now = time.time() | |
| if ip not in ip_store: | |
| ip_store[ip] = {"count": 0, "reset": now + WINDOW_SECONDS} | |
| entry = ip_store[ip] | |
| if now > entry["reset"]: | |
| entry["count"] = 0 | |
| entry["reset"] = now + WINDOW_SECONDS | |
| if entry["count"] >= RATE_LIMIT: | |
| raise HTTPException( | |
| status_code=429, | |
| detail="Daily limit reached: 25 images per IP" | |
| ) | |
| entry["count"] += 1 | |
| # ----------------------------- | |
| # IMAGE GENERATION ENDPOINT | |
| # ----------------------------- | |
| PKEY = os.getenv("POLLINATIONS_KEY", "") # ensure this is set in your environment | |
| async def generate_image(prompt: str, request: Request): | |
| client_ip = request.client.host | |
| check_rate_limit(client_ip) | |
| url = f"https://gen.pollinations.ai/image/{prompt}?model=zimage&key={PKEY}" | |
| async with httpx.AsyncClient() as client: | |
| response = await client.get(url) | |
| if response.status_code != 200: | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"Pollinations error: {response.status_code}" | |
| ) | |
| # Pollinations always returns JPEG | |
| return Response( | |
| content=response.content, | |
| media_type="image/jpeg" | |
| ) | |
| # ----------------------------- | |
| # EXISTING MODELS SCRAPER | |
| # ----------------------------- | |
| async def get_models() -> List[Dict]: | |
| async with httpx.AsyncClient() as client: | |
| response = await client.get(OLLAMA_LIBRARY_URL) | |
| html = response.text | |
| soup = BeautifulSoup(html, "html.parser") | |
| items = soup.select("li[x-test-model]") | |
| models = [] | |
| for item in items: | |
| name = item.select_one("[x-test-model-title] span") | |
| description = item.select_one("p.max-w-lg") | |
| sizes = [el.get_text(strip=True) for el in item.select("[x-test-size]")] | |
| pulls = item.select_one("[x-test-pull-count]") | |
| tags = [t.get_text(strip=True) for t in item.select('span[class*="text-blue-600"]')] | |
| updated = item.select_one("[x-test-updated]") | |
| link = item.select_one("a") | |
| models.append({ | |
| "name": name.get_text(strip=True) if name else "", | |
| "description": description.get_text(strip=True) if description else "No description", | |
| "sizes": sizes, | |
| "pulls": pulls.get_text(strip=True) if pulls else "Unknown", | |
| "tags": tags, | |
| "updated": updated.get_text(strip=True) if updated else "Unknown", | |
| "link": link.get("href") if link else None, | |
| }) | |
| return models | |