<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Generador de Imágenes Purépecha</title>
<!-- Carga de Tailwind CSS desde CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Carga de React y ReactDOM desde CDN -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!-- Carga de Babel para transformar JSX en el navegador -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- Fuente Inter para una mejor estética -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Inter', sans-serif;
}
</style>
</head>
<body class="bg-gradient-to-br from-purple-100 to-indigo-200 min-h-screen flex items-center justify-center p-4">
<div id="root" class="w-full max-w-xl"></div>
<script type="text/babel">
// Main App component
function App() {
const [prompt, setPrompt] = React.useState('');
const [imageUrl, setImageUrl] = React.useState('');
const [loading, setLoading] = React.useState(false);
const [error, setError] = React.useState('');
// Function to generate the image
const generateImage = async () => {
setLoading(true);
setImageUrl('');
setError('');
// Construct the payload for the image generation API
const payload = {
instances: { prompt: prompt },
parameters: { "sampleCount": 1 }
};
// API key for the image generation model (will be provided at runtime)
// DO NOT EDIT THIS LINE: The API key is automatically provided by the environment.
const apiKey = "";
// API URL for imagen-3.0-generate-002
const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/imagen-3.0-generate-002:predict?key=${apiKey}`;
try {
// Make the API call
const response = await fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
// Parse the response
const result = await response.json();
// Check if image generation was successful
if (result.predictions && result.predictions.length > 0 && result.predictions[0].bytesBase64Encoded) {
// Set the generated image URL
setImageUrl(`data:image/png;base64,${result.predictions[0].bytesBase64Encoded}`);
} else {
setError('No se pudo generar la imagen. Intenta de nuevo.');
console.error('Error in API response:', result);
}
} catch (e) {
console.error('Error al generar la imagen:', e);
setError('Ocurrió un error al conectar con el servicio. Por favor, intenta de nuevo.');
} finally {
setLoading(false);
}
};
return (
<div className="flex flex-col items-center justify-center p-4 text-gray-800">
<header className="mb-8 text-center">
<h1 className="text-5xl font-extrabold text-indigo-800 mb-4 tracking-tight leading-tight">
Generador de Imágenes
</h1>
<p className="text-xl text-indigo-600 max-w-2xl mx-auto">
Crea imágenes impresionantes con solo una descripción.
</p>
</header>
<main className="w-full bg-white rounded-3xl shadow-2xl p-8 flex flex-col items-center border border-indigo-200">
<div className="w-full mb-6">
<label htmlFor="prompt-input" className="block text-lg font-semibold text-gray-700 mb-2">
Describe la imagen que deseas:
</label>
<textarea
id="prompt-input"
className="w-full p-4 border border-gray-300 rounded-xl focus:ring-4 focus:ring-indigo-300 focus:border-indigo-500 transition-all duration-300 ease-in-out resize-none text-lg"
rows="4"
placeholder="Una persona purépecha tomándose una selfie en el palacio, ubicado en La Crucita en Zacapu, Michoacán"
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
></textarea>
</div>
<button
onClick={generateImage}
disabled={loading || !prompt.trim()}
className={`w-full py-4 px-6 rounded-xl text-xl font-bold transition-all duration-300 ease-in-out transform
${loading || !prompt.trim()
? 'bg-indigo-300 text-indigo-100 cursor-not-allowed'
: 'bg-indigo-600 hover:bg-indigo-700 text-white shadow-lg hover:shadow-xl hover:scale-105 active:scale-95'
}`}
>
{loading ? (
<div className="flex items-center justify-center">
<svg className="animate-spin -ml-1 mr-3 h-6 w-6 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Generando...
</div>
) : (
'Generar Imagen'
)}
</button>
{error && (
<p className="mt-6 text-red-600 bg-red-100 p-3 rounded-lg border border-red-300 text-center w-full">
{error}
</p>
)}
{imageUrl && (
<div className="mt-8 w-full">
<h2 className="text-2xl font-bold text-gray-800 mb-4 text-center">Tu Imagen Generada:</h2>
<div className="bg-gray-50 p-2 rounded-2xl shadow-inner border border-gray-200">
<img
src={imageUrl}
alt="Imagen generada"
className="w-full h-auto rounded-xl object-cover shadow-md"
onError={(e) => { e.target.onerror = null; e.target.src = 'https://placehold.co/600x400/CCCCCC/333333?text=Error+al+cargar+imagen'; }}
/>
</div>
</div>
)}
</main>
<footer className="mt-12 text-center text-gray-600">
<p className="text-sm">
Impulsado por el modelo de generación de imágenes de Google.
</p>
</footer>
</div>
);
}
// Render the React application
const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(<App />);
</script>
</body>
</html>
¡Síguenos en Tik Tok!
Noticias Relacionadas