1// This app uses the fal.ai API to generate images based on user prompts.
2// It features a clean UI with an input field for the prompt and a button to generate the image.
3// The generated image is displayed below the input field.
4// React is used for the UI and the fal.ai serverless client for image generation.
5// The app measures and displays the latency for each image generation.
6// The background features randomly placed pixelart lightning bolts in neon yellow.
7
17const BOLT_SIZE = 40; // Width and height of each bolt
18const DEFAULT_PROMPT = "green grass landscape with text \"val.town\" is engraved, a townhouse in the background";
19const PLACEHOLDER_IMAGE = "https://fal.media/files/penguin/PysYf1-_ddhM7JKiLrkcF.png";
20const RATE_LIMIT = 15; // requests per hour
21const RATE_LIMIT_WINDOW = 5 * 60 * 1000; // 5 minutes in milliseconds
72function App() {
73 const [prompt, setPrompt] = useState(DEFAULT_PROMPT);
74 const [imageUrl, setImageUrl] = useState(PLACEHOLDER_IMAGE);
75 const [latency, setLatency] = useState<number | null>(null);
76 const [loading, setLoading] = useState(false);
77 const [error, setError] = useState("");
78
79 const generateImage = async () => {
80 setLoading(true);
81 setError("");
87 });
88 const data = await response.json();
89 if (!response.ok) throw new Error(data.error || "Failed to generate image");
90 setLatency(data.latency);
91 setImageUrl(data.imageUrl);
92 setError(""); // Clear any previous errors
93 } catch (err) {
103 <Background />
104 <div className="container">
105 <h1 className="title">AI Image Generator</h1>
106 <div className="input-container">
107 <input
113 />
114 </div>
115 <button onClick={generateImage} disabled={loading || !prompt} className="generate-btn">
116 {loading ? "Generating..." : "Generate Image"}
117 </button>
118 {error && <p className="error">{error}</p>}
119 <div className="image-container">
120 {latency !== null && (
121 <p className="latency">Inference time (doesn't include network): {latency.toFixed(2)} ms</p>
123 {loading
124 ? <LoadingSpinner />
125 : <img src={imageUrl} alt="Generated image" className="generated-image" />}
126 </div>
127 <div className="footer">
193 input: {
194 prompt,
195 image_size: "landscape_4_3",
196 num_inference_steps: 4,
197 num_images: 1,
198 enable_safety_checker: true,
199 sync_mode: true,
201 });
202 return new Response(
203 JSON.stringify({ imageUrl: result.images[0].url, latency: result.timings.inference * 1000 }),
204 {
205 headers: { "Content-Type": "application/json" },
207 );
208 } catch (error) {
209 return new Response(JSON.stringify({ error: "Failed to generate image" }), {
210 status: 500,
211 headers: { "Content-Type": "application/json" },
221 <meta charset="UTF-8">
222 <meta name="viewport" content="width=device-width, initial-scale=1.0">
223 <title>AI Image Generator</title>
224 <style>${css}</style>
225 </head>
315 text-align: center;
316 }
317 .image-container {
318 margin-top: 20px;
319 text-align: center;
322 border-radius: 10px;
323 }
324 .generated-image {
325 max-width: 100%;
326 height: auto;