import React, { useState } from 'react';
const apiKey = ""; // API key is provided by the execution environment
const FLOWERS = [
'Iris',
'White Orchid',
'Lupine',
'Lotus',
'Peony',
'Sunflower',
'Bird of Paradise',
'Poppy',
'Lily',
'Cherry Blossom Branch',
'Pea Flowers',
'Custom...'
];
const GEOMETRIES = [
'Minimalist Sacred Geometry',
'Nordic Design Geometric Lines',
'Neo Trad Tattoo Style',
'Sparse Geometric Gold Leaf Accents',
'Abstract Minimalist Halos'
];
export default function App() {
const [flower, setFlower] = useState(FLOWERS[0]);
const [customFlower, setCustomFlower] = useState('');
const [geometry, setGeometry] = useState(GEOMETRIES[0]);
const [isGenerating, setIsGenerating] = useState(false);
const [generatedImage, setGeneratedImage] = useState(null);
const [error, setError] = useState(null);
const activeFlower = flower === 'Custom...' ? (customFlower || 'Exotic flower') : flower;
const generatePrompt = () => {
// Randomize layout to strictly avoid the center and force unique compositions
const layouts = [
"growing strictly along the bottom edge of the canvas, leaving the top completely empty",
"sprawling diagonally down from the top right corner, hugging the edge",
"sweeping along the extreme left side of the canvas, avoiding the middle",
"emerging dynamically from two opposite corners, framing the center space but not filling it",
"placed in an extreme off-centered, asymmetrical composition touching the very edges of the frame"
];
const randomLayout = layouts[Math.floor(Math.random() * layouts.length)];
// Randomize stem count (weighted heavily towards 1, but sometimes 3 or 5)
const stemCounts = [1, 1, 1, 1, 3, 5];
const randomStemCount = stemCounts[Math.floor(Math.random() * stemCounts.length)];
const stemText = randomStemCount === 1 ? "1 single cut stem" : `${randomStemCount} cut stems arranged randomly`;
// Randomize background coverage
const bgCoverageOptions = [
"only as a small, minimal decorative accent placed just behind the floral elements",
"only as a small, minimal decorative accent placed just behind the floral elements",
"covering a specific portion of the negative space as an abstract backdrop"
];
const randomBgCoverage = bgCoverageOptions[Math.floor(Math.random() * bgCoverageOptions.length)];
// Apply specific flower aesthetic tweaks
let flowerDescription = activeFlower;
if (activeFlower === 'Peony') {
flowerDescription = "light, airy, abstract, and fluffy peony, avoiding heavy flat or perfectly round shapes";
} else if (activeFlower === 'White Orchid') {
flowerDescription = "elegant white orchid with delicate, abstract petals";
} else if (activeFlower === 'Cherry Blossom Branch') {
flowerDescription = "sprawling, delicate cherry blossom branch reaching elegantly across the frame, highly reminiscent of traditional Japanese wall art and screen paintings, with intricate dark branches and soft blooms executed with thick impressionist oil paint";
} else if (activeFlower === 'Pea Flowers') {
flowerDescription = "cascading sweet pea flowers with ruffled, delicate petals and curly tendrils";
}
return `A tall, vertical modern abstract painting of ${stemText} of a ${flowerDescription}. The floral elements are heavily impressionistic and not realistic; they are painted with extremely thick, rough palette knife swipes of wide oil paint. They feature rough, jagged edges and organic, natural, expressive shapes. Crucially, DO NOT place the flowers in the middle: they MUST be ${randomLayout}. There are absolutely no pots, vases, or containers.
BACKGROUND: The background is mostly clean, empty negative space to maintain a highly minimalist aesthetic. It features ${geometry}, rendered specifically in bright metallic gold leaf paint, and used ${randomBgCoverage}. The metallic gold details are just extra accents, not a cluttered full background. High quality, emphasis on the extreme asymmetric layout and the strong contrast between the rough floral knife swipes and the precise metallic gold background accents. Aspect ratio 3:4.`;
};
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
const fetchWithRetry = async (url, options, maxRetries = 5) => {
let retries = 0;
while (retries < maxRetries) {
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (err) {
retries++;
if (retries >= maxRetries) throw err;
await delay(Math.pow(2, retries) * 1000); // 2s, 4s, 8s, 16s...
}
}
};
const handleGenerate = async () => {
if (isGenerating) return;
setIsGenerating(true);
setError(null);
setGeneratedImage(null);
const promptText = generatePrompt();
try {
const url = `https://generativelanguage.googleapis.com/v1beta/models/imagen-4.0-generate-001:predict?key=${apiKey}`;
const payload = {
instances: [{ prompt: promptText }],
parameters: {
sampleCount: 1,
aspectRatio: "3:4"
}
};
const result = await fetchWithRetry(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload)
});
if (result.predictions && result.predictions[0] && result.predictions[0].bytesBase64Encoded) {
const base64Img = `data:image/png;base64,${result.predictions[0].bytesBase64Encoded}`;
setGeneratedImage(base64Img);
} else {
throw new Error("Invalid response format from API");
}
} catch (err) {
console.error("Generation failed:", err);
setError("Failed to generate image. Please try again in a moment.");
} finally {
setIsGenerating(false);
}
};
const handleDownload = () => {
if (!generatedImage) return;
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
const jpgUrl = canvas.toDataURL('image/jpeg', 1.0);
const link = document.createElement('a');
link.href = jpgUrl;
link.download = `Abstract-Flora-${activeFlower.replace(/\s+/g, '-')}-${Date.now()}.jpg`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
img.src = generatedImage;
};
return (
{/* Header */}
{/* Palette SVG */}
Abstract Flora Studio
Generate off-centered, impressionist botanical paintings with palette knife textures and metallic gold geometric accents.
"A rough, impressionist palette knife painting of {activeFlower.toLowerCase()}, styled asymmetrically on the edges of the canvas with sparse, minimal {geometry.toLowerCase()} accents in metallic gold leaf..."
{/* Generate Button */}
{error && (
{/* AlertCircle SVG */}
{error}
)}
{/* Display Section */}
{/* Loading Overlay */}
{isGenerating && (
Applying heavy palette knife textures...
)}
{/* Image Display */}
{generatedImage ? (
) : (
{/* Image/Placeholder SVG */}
Your canvas awaits.
Select your botanical subject and geometric accents to begin generating your custom piece.
)}
{/* Action Area below the image */}
{generatedImage && (