web4 / app.py
Yussifweb3's picture
Update app.py
eacc19f verified
<!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;
}
@keyframes spin {
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>