#!/bin/bash # Generate a texture via Cloudflare Workers AI FLUX (flux-1-schnell). # Usage: flux_texture.sh "" [size_px] [target_luma] # # target_luma (0-255) scales the result down to that mean brightness. FLUX # returns a near-white sheet for anything described as pale -- "off white metal # panel" came back at 240/255 however it was worded -- and a blown-out albedo # renders as a featureless void in game. Only ever darkens. # Credentials: sourced from known .env files; accepts CLOUDFLARE_API_TOKEN/CF_API_TOKEN # + CLOUDFLARE_ACCOUNT_ID/CF_ACCOUNT_ID. Values never printed. set -euo pipefail for f in ~/Documents/fluxgod-work/.env ~/Documents/backnforth/.env ~/Documents/wardrobegod/.env; do [ -f "$f" ] && set -a && source "$f" 2>/dev/null && set +a done TOKEN="${CLOUDFLARE_API_TOKEN:-${CF_API_TOKEN:-${CLOUDFLARE_TOKEN:-}}}" ACCT="${CLOUDFLARE_ACCOUNT_ID:-${CF_ACCOUNT_ID:-${CLOUDFLARE_ACCOUNT:-}}}" if [ -z "$TOKEN" ] || [ -z "$ACCT" ]; then echo "MISSING_CREDS token_present=$([ -n "$TOKEN" ] && echo yes || echo no) acct_present=$([ -n "$ACCT" ] && echo yes || echo no)" exit 1 fi PROMPT="$1" OUT="$2" SIZE="${3:-512}" LUMA="${4:-0}" RESP=$(mktemp) HTTP=$(curl -s -w '%{http_code}' -o "$RESP" --max-time 120 \ "https://api.cloudflare.com/client/v4/accounts/$ACCT/ai/run/@cf/black-forest-labs/flux-1-schnell" \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ -d "$(python3 -c 'import json,sys; print(json.dumps({"prompt": sys.argv[1], "steps": 6}))' "$PROMPT")") if [ "$HTTP" != "200" ]; then ERR="$(python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); print(d.get("errors"))' "$RESP" 2>/dev/null | head -c 200)" rm -f "$RESP" # Cloudflare's free tier is 10,000 neurons/day and a full set regen eats it. # Fall back to the local MODELBEAST farm rather than failing the texture. echo "cloudflare HTTP $HTTP ($ERR) -- falling back to local FLUX" >&2 exec python3 "$(dirname "$0")/flux_local.py" "$PROMPT" "$OUT" "$SIZE" "$LUMA" fi python3 - "$RESP" "$OUT" <<'EOF' import base64, json, sys d = json.load(open(sys.argv[1])) open(sys.argv[2] + ".png", "wb").write(base64.b64decode(d["result"]["image"])) EOF sips -Z "$SIZE" -s format jpeg -s formatOptions 80 "$OUT.png" --out "$OUT" > /dev/null 2>&1 rm -f "$RESP" "$OUT.png" if [ "$LUMA" != "0" ]; then python3 - "$OUT" "$LUMA" <<'EOF' import sys from PIL import Image, ImageStat im = Image.open(sys.argv[1]).convert("RGB") mean = ImageStat.Stat(im.convert("L")).mean[0] target = float(sys.argv[2]) if mean > target: im = im.point(lambda v, k=target / mean: int(v * k)) im.save(sys.argv[1], quality=88) EOF fi echo "OK $OUT ($(du -h "$OUT" | cut -f1))"