Spaces:
Runtime error
Runtime error
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>AI Image Generator</title> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/gradio-client/1.0.0/index.js"></script> | |
<style> | |
:root { | |
--primary-color: #6366f1; | |
--secondary-color: #4338ca; | |
--background-color: #f9fafb; | |
--text-color: #1f2937; | |
} | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
font-family: system-ui, -apple-system, sans-serif; | |
} | |
body { | |
background-color: var(--background-color); | |
color: var(--text-color); | |
min-height: 100vh; | |
padding: 2rem; | |
line-height: 1.5; | |
} | |
.container { | |
max-width: 800px; | |
margin: 0 auto; | |
} | |
header { | |
text-align: center; | |
margin-bottom: 3rem; | |
} | |
h1 { | |
font-size: 2.5rem; | |
margin-bottom: 1rem; | |
color: var(--primary-color); | |
} | |
.description { | |
color: #6b7280; | |
font-size: 1.1rem; | |
margin-bottom: 0.5rem; | |
} | |
.generator-form { | |
background: white; | |
padding: 2rem; | |
border-radius: 1rem; | |
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1); | |
margin-bottom: 2rem; | |
} | |
.form-group { | |
margin-bottom: 1.5rem; | |
} | |
label { | |
display: block; | |
margin-bottom: 0.5rem; | |
font-weight: 500; | |
} | |
textarea, input[type="number"] { | |
width: 100%; | |
padding: 0.75rem; | |
border: 1px solid #e5e7eb; | |
border-radius: 0.5rem; | |
font-size: 1rem; | |
} | |
textarea { | |
min-height: 100px; | |
resize: vertical; | |
} | |
.controls { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); | |
gap: 1rem; | |
margin-top: 1rem; | |
} | |
.advanced-options { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
gap: 1rem; | |
margin-top: 1rem; | |
padding-top: 1rem; | |
border-top: 1px solid #e5e7eb; | |
} | |
button { | |
background-color: var(--primary-color); | |
color: white; | |
padding: 0.75rem 1.5rem; | |
border: none; | |
border-radius: 0.5rem; | |
font-size: 1rem; | |
font-weight: 500; | |
cursor: pointer; | |
transition: all 0.2s; | |
} | |
button:hover { | |
background-color: var(--secondary-color); | |
transform: translateY(-1px); | |
} | |
button:disabled { | |
background-color: #9ca3af; | |
cursor: not-allowed; | |
} | |
#clearBtn { | |
background-color: #ef4444; | |
} | |
#clearBtn:hover { | |
background-color: #dc2626; | |
} | |
.loading { | |
display: none; | |
text-align: center; | |
margin: 2rem 0; | |
padding: 2rem; | |
background: white; | |
border-radius: 1rem; | |
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1); | |
} | |
.loading-spinner { | |
border: 4px solid #f3f3f3; | |
border-top: 4px solid var(--primary-color); | |
border-radius: 50%; | |
width: 40px; | |
height: 40px; | |
animation: spin 1s linear infinite; | |
margin: 0 auto 1rem; | |
} | |
0% { transform: rotate(0deg); } | |
100% { transform: rotate(360deg); } | |
} | |
.result { | |
display: none; | |
text-align: center; | |
background: white; | |
padding: 2rem; | |
border-radius: 1rem; | |
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1); | |
} | |
.result img { | |
max-width: 100%; | |
border-radius: 0.5rem; | |
margin-bottom: 1rem; | |
} | |
.download-btn { | |
background-color: #059669; | |
} | |
.download-btn:hover { | |
background-color: #047857; | |
} | |
.error { | |
display: none; | |
background-color: #fee2e2; | |
color: #991b1b; | |
padding: 1rem; | |
border-radius: 0.5rem; | |
margin-top: 1rem; | |
text-align: center; | |
} | |
#examples { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); | |
gap: 1rem; | |
margin-top: 2rem; | |
} | |
.example-prompt { | |
background: white; | |
padding: 1rem; | |
border-radius: 0.5rem; | |
cursor: pointer; | |
transition: all 0.2s; | |
} | |
.example-prompt:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1); | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<header> | |
<h1>AI Image Generator</h1> | |
<p class="description">Create unique images using FLUX.1-dev model</p> | |
<p class="description">Powered by Black Forest Labs</p> | |
</header> | |
<main> | |
<form class="generator-form" id="generatorForm"> | |
<div class="form-group"> | |
<label for="prompt">Describe your image:</label> | |
<textarea | |
id="prompt" | |
placeholder="A serene landscape with mountains and a lake at sunset..." | |
required | |
></textarea> | |
</div> | |
<div class="advanced-options"> | |
<div class="form-group"> | |
<label for="width">Width:</label> | |
<input type="number" id="width" value="256" min="64" max="1024" step="64"> | |
</div> | |
<div class="form-group"> | |
<label for="height">Height:</label> | |
<input type="number" id="height" value="256" min="64" max="1024" step="64"> | |
</div> | |
<div class="form-group"> | |
<label for="guidance">Guidance Scale:</label> | |
<input type="number" id="guidance" value="1" min="1" max="20" step="0.1"> | |
</div> | |
<div class="form-group"> | |
<label for="steps">Inference Steps:</label> | |
<input type="number" id="steps" value="1" min="1" max="50"> | |
</div> | |
</div> | |
<div class="controls"> | |
<button type="submit" id="generateBtn">Generate Image</button> | |
<button type="button" id="clearBtn">Clear</button> | |
</div> | |
</form> | |
<div id="examples"> | |
<div class="example-prompt"> | |
"A magical forest at twilight with glowing mushrooms" | |
</div> | |
<div class="example-prompt"> | |
"A futuristic cityscape with flying cars" | |
</div> | |
<div class="example-prompt"> | |
"A cozy cafe interior with steam rising from coffee cups" | |
</div> | |
</div> | |
<div class="loading" id="loading"> | |
<div class="loading-spinner"></div> | |
<p>Creating your masterpiece... This may take a few moments.</p> | |
</div> | |
<div class="error" id="error"> | |
<p>An error occurred while generating the image. Please try again.</p> | |
<p id="errorDetails"></p> | |
</div> | |
<div class="result" id="result"> | |
<img id="generatedImage" alt="Generated image"> | |
<button class="download-btn" id="downloadBtn">Download Image</button> | |
</div> | |
</main> | |
</div> | |
<script> | |
let client = null; | |
async function initClient() { | |
try { | |
client = await gradioClient.Client.connect("black-forest-labs/FLUX.1-dev"); | |
console.log('FLUX.1-dev client initialized successfully'); | |
} catch (err) { | |
console.error('Error initializing client:', err); | |
showError('Failed to initialize the image generator. Please refresh the page.'); | |
} | |
} | |
// Initialize when the page loads | |
window.addEventListener('DOMContentLoaded', initClient); | |
const form = document.getElementById('generatorForm'); | |
const generateBtn = document.getElementById('generateBtn'); | |
const clearBtn = document.getElementById('clearBtn'); | |
const loading = document.getElementById('loading'); | |
const result = document.getElementById('result'); | |
const error = document.getElementById('error'); | |
const errorDetails = document.getElementById('errorDetails'); | |
const generatedImage = document.getElementById('generatedImage'); | |
const downloadBtn = document.getElementById('downloadBtn'); | |
const promptInput = document.getElementById('prompt'); | |
const examples = document.querySelectorAll('.example-prompt'); | |
// Get advanced options inputs | |
const widthInput = document.getElementById('width'); | |
const heightInput = document.getElementById('height'); | |
const guidanceInput = document.getElementById('guidance'); | |
const stepsInput = document.getElementById('steps'); | |
function showError(message) { | |
error.style.display = 'block'; | |
errorDetails.textContent = message; | |
loading.style.display = 'none'; | |
generateBtn.disabled = false; | |
} | |
function clearAll() { | |
promptInput.value = ''; | |
result.style.display = 'none'; | |
error.style.display = 'none'; | |
loading.style.display = 'none'; | |
generateBtn.disabled = false; | |
// Reset advanced options to defaults | |
widthInput.value = '256'; | |
heightInput.value = '256'; | |
guidanceInput.value = '1'; | |
stepsInput.value = '1'; | |
} | |
examples.forEach(example => { | |
example.addEventListener('click', () => { | |
promptInput.value = example.textContent.trim().replace(/"/g, ''); | |
promptInput.focus(); | |
}); | |
}); | |
clearBtn.addEventListener('click', clearAll); | |
downloadBtn.addEventListener('click', () => { | |
const link = document.createElement('a'); | |
link.download = 'generated-image.png'; | |
link.href = generatedImage.src; | |
link.click(); | |
}); | |
form.addEventListener('submit', async (e) => { | |
e.preventDefault(); | |
const prompt = promptInput.value.trim(); | |
if (!prompt) { | |
showError('Please enter a description for your image.'); | |
return; | |
} | |
if (!client) { | |
showError('Image generator is not properly initialized. Please refresh the page.'); | |
return; | |
} | |
// Hide any previous results or errors | |
result.style.display = 'none'; | |
error.style.display = 'none'; | |
// Show loading state | |
loading.style.display = 'block'; | |
generateBtn.disabled = true; | |
try { | |
const params = { | |
prompt: prompt, | |
seed: 0, | |
randomize_seed: true, | |
width: parseInt(widthInput.value), | |
height: parseInt(heightInput.value), | |
guidance_scale: parseFloat(guidanceInput.value), | |
num_inference_steps: parseInt(stepsInput.value) | |
}; | |
const output = await client.predict("/infer", params); | |
if (output && output.data) { | |
generatedImage.src = output.data; | |
result.style.display = 'block'; | |
} else { | |
throw new Error('Invalid response from image generator'); | |
} | |
} catch (err) { | |
console.error('Error:', err); | |
showError('Failed to generate image. Please try again.' + | |
(err.message ? ` Error: ${err.message}` : '')); | |
} finally { | |
loading.style.display = 'none'; | |
generateBtn.disabled = false; | |
} | |
}); | |
</script> | |
</body> | |
</html> |