CoolFace
Apppublic

gup/FLUX.1-dev

sourceHugging Facemitupdated 2mo agoView on Hugging Face
0likes
index.html257 linesDownload Raw Back to root
1<!DOCTYPE html>2<html lang="en">3<head>4<meta charset="UTF-8">5<meta name="viewport" content="width=device-width, initial-scale=1.0">6<title>FLUX.1 [dev] — text-to-image</title>7<style>8  :root {9    --bg: #0b0f19; --panel: #121a2b; --line: #22304a; --text: #e8edf6;10    --muted: #93a0b6; --accent: #ffb347; --accent2: #5aa7ff;11  }12  * { box-sizing: border-box; margin: 0; padding: 0; }13  body {14    background: radial-gradient(900px 500px at 80% -10%, rgba(90,167,255,.08), transparent 60%), var(--bg);15    color: var(--text); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, sans-serif;16    min-height: 100vh; padding: 32px 16px;17  }18  .wrap { max-width: 720px; margin: 0 auto; }19  h1 { font-size: 30px; letter-spacing: -.01em; }20  h1 small { font-size: 15px; color: var(--muted); font-weight: 400; display: block; margin-top: 4px; }21  .topbar { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 20px; }22  button {23    font: inherit; border: none; border-radius: 8px; cursor: pointer;24    padding: 10px 18px; font-weight: 600;25  }26  #login-btn { background: var(--accent); color: #1a1205; white-space: nowrap; }27  #logout-btn { background: transparent; color: var(--muted); border: 1px solid var(--line); padding: 6px 12px; font-size: 12.5px; }28  .userchip { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); }29  .row { display: flex; gap: 10px; margin-bottom: 12px; }30  textarea {31    flex: 1; background: var(--panel); border: 1px solid var(--line); border-radius: 10px;32    color: var(--text); font: inherit; padding: 12px 14px; resize: vertical; min-height: 52px;33  }34  textarea:focus { outline: none; border-color: var(--accent2); }35  #generate {36    background: var(--accent2); color: #06101f; min-width: 110px;37  }38  #generate:disabled { opacity: .45; cursor: not-allowed; }39  .examples { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }40  .chip {41    background: var(--panel); border: 1px solid var(--line); color: var(--muted);42    border-radius: 20px; padding: 5px 12px; font-size: 12.5px; cursor: pointer;43  }44  .chip:hover { border-color: var(--accent2); color: var(--text); }45  details {46    background: var(--panel); border: 1px solid var(--line); border-radius: 10px;47    padding: 12px 16px; margin-bottom: 16px; font-size: 13.5px;48  }49  summary { cursor: pointer; color: var(--muted); font-weight: 600; }50  .controls { display: grid; grid-template-columns: 1fr 1fr; gap: 14px 24px; margin-top: 14px; }51  .ctl label { display: flex; justify-content: space-between; font-size: 12.5px; color: var(--muted); margin-bottom: 5px; }52  .ctl label output { color: var(--text); font-variant-numeric: tabular-nums; }53  input[type=range] { width: 100%; accent-color: var(--accent2); }54  input[type=number] {55    width: 100%; background: #0d1524; border: 1px solid var(--line); border-radius: 6px;56    color: var(--text); font: inherit; padding: 6px 8px;57  }58  .check { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); margin-top: 18px; }59  #status { min-height: 22px; font-size: 13.5px; color: var(--muted); margin-bottom: 10px; }60  #status.err { color: #ef8a84; }61  #result-box {62    background: var(--panel); border: 1px solid var(--line); border-radius: 12px;63    min-height: 200px; display: flex; align-items: center; justify-content: center;64    overflow: hidden; position: relative;65  }66  #result-box img { max-width: 100%; height: auto; display: block; }67  #placeholder { color: #3d4962; font-size: 14px; padding: 60px 20px; text-align: center; }68  #dl { display: none; position: absolute; right: 10px; bottom: 10px; background: rgba(10,15,25,.8);69       color: var(--text); font-size: 12.5px; padding: 6px 12px; border-radius: 6px; text-decoration: none; }70  .footnote { font-size: 11.5px; color: #5b6780; margin-top: 16px; line-height: 1.5; }71  .footnote a { color: var(--accent2); text-decoration: none; }72  .spinner { width: 26px; height: 26px; border: 3px solid var(--line); border-top-color: var(--accent2);73             border-radius: 50%; animation: spin .8s linear infinite; }74  @keyframes spin { to { transform: rotate(360deg); } }75</style>76</head>77<body>78<div class="wrap">79  <div class="topbar">80    <h1>FLUX.1 [dev]<small>12B rectified-flow transformer by Black Forest Labs — via HF Inference Providers</small></h1>81    <div id="auth-area"><button id="login-btn">Sign in with 🤗</button></div>82  </div>83 84  <div class="row">85    <textarea id="prompt" placeholder="Describe the image you want…" spellcheck="false"></textarea>86    <button id="generate" disabled>Generate</button>87  </div>88 89  <div class="examples" id="examples"></div>90 91  <details>92    <summary>Advanced settings</summary>93    <div class="controls">94      <div class="ctl"><label>Width <output id="width-out">1024</output></label>95        <input type="range" id="width" min="256" max="1440" step="32" value="1024"></div>96      <div class="ctl"><label>Height <output id="height-out">1024</output></label>97        <input type="range" id="height" min="256" max="1440" step="32" value="1024"></div>98      <div class="ctl"><label>Inference steps <output id="steps-out">28</output></label>99        <input type="range" id="steps" min="1" max="50" step="1" value="28"></div>100      <div class="ctl"><label>Guidance scale <output id="guidance-out">3.5</output></label>101        <input type="range" id="guidance" min="1" max="10" step="0.1" value="3.5"></div>102      <div class="ctl"><label>Seed</label><input type="number" id="seed" min="0" step="1" value="42"></div>103      <div class="ctl"><div class="check"><input type="checkbox" id="rand-seed" checked><label for="rand-seed">Randomize seed</label></div></div>104    </div>105  </details>106 107  <div id="status"></div>108 109  <div id="result-box">110    <div id="placeholder">Sign in, enter a prompt, and hit Generate.<br>Inference is billed to your Hugging Face account's provider quota.</div>111    <a id="dl" download="flux1-dev.png">Download</a>112  </div>113 114  <p class="footnote">115    Model: <a href="https://huggingface.co/black-forest-labs/FLUX.1-dev" target="_blank">black-forest-labs/FLUX.1-dev</a>116    (<a href="https://huggingface.co/black-forest-labs/FLUX.1-dev/blob/main/LICENSE.md" target="_blank">non-commercial license</a>).117    Serving: <a href="https://huggingface.co/docs/inference-providers" target="_blank">HF Inference Providers</a> (fal / Replicate / Wavespeed, routed automatically).118    This static Space hosts no model and stores nothing; your token stays in your browser.119  </p>120</div>121 122<script type="module">123import { oauthLoginUrl, oauthHandleRedirectIfPresent } from "https://esm.sh/@huggingface/hub@2";124import { InferenceClient } from "https://esm.sh/@huggingface/inference@4";125 126const $ = (id) => document.getElementById(id);127const statusEl = $("status");128const genBtn = $("generate");129const OAUTH_KEY = "flux_oauth";130 131const EXAMPLES = [132  "a tiny astronaut hatching from an egg on the moon",133  "a cat holding a sign that says hello world",134  "an anime illustration of a wiener schnitzel",135];136 137let oauth = null;138 139// wire sliders to their value labels140for (const id of ["width", "height", "steps", "guidance"]) {141  $(id).addEventListener("input", () => { $(id + "-out").textContent = $(id).value; });142}143 144// example chips145for (const ex of EXAMPLES) {146  const chip = document.createElement("button");147  chip.className = "chip";148  chip.textContent = ex;149  chip.addEventListener("click", () => { $("prompt").value = ex; });150  $("examples").appendChild(chip);151}152 153function setStatus(msg, isErr = false) {154  statusEl.textContent = msg;155  statusEl.className = isErr ? "err" : "";156}157 158function setSignedIn() {159  const name = oauth?.userInfo?.preferred_username || oauth?.userInfo?.name || "signed in";160  $("auth-area").innerHTML =161    `<div class="userchip"><span>🤗 ${name}</span><button id="logout-btn">Sign out</button></div>`;162  $("logout-btn").addEventListener("click", () => {163    localStorage.removeItem(OAUTH_KEY);164    location.href = location.pathname;165  });166  genBtn.disabled = false;167  setStatus("Ready.");168}169 170async function initAuth() {171  const fresh = await oauthHandleRedirectIfPresent();172  if (fresh) {173    localStorage.setItem(OAUTH_KEY, JSON.stringify(fresh));174    history.replaceState(null, "", location.pathname);   // clean token fragments from URL175    oauth = fresh;176    return setSignedIn();177  }178  const stored = localStorage.getItem(OAUTH_KEY);179  if (stored) {180    const parsed = JSON.parse(stored);181    if (new Date(parsed.accessTokenExpiresAt) > new Date(Date.now() + 60_000)) {182      oauth = parsed;183      return setSignedIn();184    }185    localStorage.removeItem(OAUTH_KEY);186  }187  $("login-btn").addEventListener("click", async () => {188    location.href = await oauthLoginUrl();   // clientId/scopes auto-detected from the Space189  });190}191 192async function generate() {193  const prompt = $("prompt").value.trim();194  if (!prompt) return setStatus("Enter a prompt first.", true);195  if (!oauth) return setStatus("Sign in first.", true);196 197  if ($("rand-seed").checked) $("seed").value = Math.floor(Math.random() * 2 ** 31);198  const seed = parseInt($("seed").value, 10);199 200  genBtn.disabled = true;201  $("placeholder").innerHTML = "";202  $("placeholder").appendChild(Object.assign(document.createElement("div"), { className: "spinner" }));203  $("dl").style.display = "none";204  const existing = document.querySelector("#result-box img");205  if (existing) existing.remove();206  setStatus(`Generating… (${$("steps").value} steps, seed ${seed})`);207  const t0 = performance.now();208 209  try {210    const client = new InferenceClient(oauth.accessToken);211    const blob = await client.textToImage(212      {213        model: "black-forest-labs/FLUX.1-dev",214        provider: "auto",215        inputs: prompt,216        parameters: {217          width: parseInt($("width").value, 10),218          height: parseInt($("height").value, 10),219          num_inference_steps: parseInt($("steps").value, 10),220          guidance_scale: parseFloat($("guidance").value),221          seed,222        },223      },224      { outputType: "blob" },225    );226    const url = URL.createObjectURL(blob);227    const img = document.createElement("img");228    img.src = url;229    img.alt = prompt;230    $("placeholder").innerHTML = "";231    $("result-box").prepend(img);232    $("dl").href = url;233    $("dl").style.display = "block";234    setStatus(`Done in ${((performance.now() - t0) / 1000).toFixed(1)}s · seed ${seed}`);235  } catch (e) {236    console.error(e);237    $("placeholder").textContent = "Generation failed.";238    let msg = e?.message || String(e);239    if (/quota|payment|402|credit/i.test(msg)) {240      msg += " — your HF inference-provider quota may be exhausted (free tier is limited; PRO includes monthly credits).";241    }242    setStatus(msg, true);243  } finally {244    genBtn.disabled = false;245  }246}247 248genBtn.addEventListener("click", generate);249$("prompt").addEventListener("keydown", (e) => {250  if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); generate(); }251});252 253initAuth();254</script>255</body>256</html>257