shell / index.html
Alexey7878's picture
Update index.html
4da8013 verified
Raw History Blame Contribute Delete
9.77 kB
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Генерация изображений — Hugging Face SDK</title>
<style>
* { box-sizing: border-box; }
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
max-width: 700px;
margin: 0 auto;
padding: 30px 20px;
background: #f9fafb;
color: #111827;
}
h1 { margin-top: 0; margin-bottom: 8px; }
.subtitle { color: #6b7280; margin-bottom: 20px; }
label { display: block; margin: 15px 0 6px; font-weight: 600; font-size: 14px; }
input, textarea, select, button {
width: 100%;
padding: 12px;
border-radius: 8px;
border: 1px solid #d1d5db;
font: inherit;
background: #fff;
}
textarea { min-height: 100px; resize: vertical; }
.accordion {
border: 1px solid #e5e7eb;
border-radius: 8px;
margin: 20px 0;
background: #ffffff;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
.accordion summary {
padding: 12px 16px;
font-weight: 600;
cursor: pointer;
user-select: none;
background: #f3f4f6;
border-radius: 8px;
outline: none;
}
.accordion[open] summary {
border-bottom: 1px solid #e5e7eb;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.accordion-content { padding: 15px; }
.row { display: flex; gap: 15px; }
.row > div { flex: 1; }
button {
margin-top: 10px;
border: none;
background: #10b981;
color: white;
font-weight: 700;
cursor: pointer;
}
button:hover { background: #059669; }
button:disabled { background: #9ca3af; cursor: wait; }
#status { margin-top: 15px; min-height: 24px; color: #4b5563; font-weight: 500; }
#result {
display: none;
width: 100%;
margin-top: 20px;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.12);
}
#download {
display: none;
margin-top: 15px;
text-align: center;
text-decoration: none;
background: #374151;
color: white;
padding: 12px;
border-radius: 8px;
font-weight: 600;
}
#error {
display: none;
margin-top: 15px;
padding: 15px;
background: #fef2f2;
border: 1px solid #fca5a5;
border-radius: 8px;
color: #991b1b;
white-space: pre-wrap;
word-break: break-word;
}
.warning {
padding: 12px;
margin-bottom: 20px;
background: #fff7ed;
border: 1px solid #fed7aa;
border-radius: 8px;
color: #9a3412;
font-size: 14px;
}
</style>
</head>
<body>
<h1>🎨 Генерация изображений</h1>
<div class="subtitle">Интерфейс с расширенным выбором моделей и настройками Gradio-style</div>
<div class="warning">
⚠️ Токен используется в браузере. Убедитесь, что используете Read-токен.
</div>
<label for="token">Hugging Face Access Token</label>
<input id="token" type="password" placeholder="hf_..." autocomplete="off">
<label for="model">Модель</label>
<select id="model">
<option value="black-forest-labs/FLUX.1-schnell">FLUX.1-schnell (Сверхбыстрая)</option>
<option value="black-forest-labs/FLUX.1-dev">FLUX.1-dev (Высокое качество)</option>
<option value="stabilityai/stable-diffusion-3.5-large">Stable Diffusion 3.5 Large</option>
<option value="stabilityai/stable-diffusion-xl-base-1.0">Stable Diffusion XL (SDXL)</option>
<option value="stabilityai/stable-diffusion-2-1">Stable Diffusion 2.1</option>
</select>
<details class="accordion">
<summary>⚙️ Дополнительные параметры (Настройки генерации)</summary>
<div class="accordion-content">
<div class="row">
<div>
<label for="steps">Количество шагов (Steps)</label>
<input id="steps" type="number" value="4" min="1" max="50">
</div>
<div>
<label for="guidance">Сила промпта (Guidance Scale)</label>
<input id="guidance" type="number" value="3.5" step="0.5" min="1" max="20">
</div>
</div>
<div class="row">
<div>
<label for="width">Ширина (Width)</label>
<input id="width" type="number" value="1024" step="64" min="256" max="1440">
</div>
<div>
<label for="height">Высота (Height)</label>
<input id="height" type="number" value="1024" step="64" min="256" max="1440">
</div>
</div>
</div>
</details>
<label for="prompt">Промпт</label>
<textarea id="prompt" placeholder="A cinematic photo of a futuristic city at night, neon lights, rain, ultra detailed..."></textarea>
<button id="generate">Сгенерировать</button>
<div id="status"></div>
<div id="error"></div>
<img id="result" alt="Generated image">
<a id="download" download="generated-image.png">Скачать изображение</a>
<script type="module">
import { InferenceClient } from "https://esm.sh/@huggingface/inference";
const tokenInput = document.getElementById("token");
const modelInput = document.getElementById("model");
const promptInput = document.getElementById("prompt");
const stepsInput = document.getElementById("steps");
const guidanceInput = document.getElementById("guidance");
const widthInput = document.getElementById("width");
const heightInput = document.getElementById("height");
const generateButton = document.getElementById("generate");
const status = document.getElementById("status");
const errorBox = document.getElementById("error");
const resultImage = document.getElementById("result");
const downloadLink = document.getElementById("download");
let currentImageUrl = null;
function showError(message) {
errorBox.textContent = message;
errorBox.style.display = "block";
}
function clearError() {
errorBox.textContent = "";
errorBox.style.display = "none";
}
function clearResult() {
resultImage.style.display = "none";
downloadLink.style.display = "none";
if (currentImageUrl) {
URL.revokeObjectURL(currentImageUrl);
currentImageUrl = null;
}
}
generateButton.addEventListener("click", async () => {
clearError();
clearResult();
const token = tokenInput.value.trim();
const prompt = promptInput.value.trim();
const model = modelInput.value;
const steps = parseInt(stepsInput.value) || 4;
const guidance = parseFloat(guidanceInput.value) || 3.5;
const width = parseInt(widthInput.value) || 1024;
const height = parseInt(heightInput.value) || 1024;
if (!token) {
showError("Введите Hugging Face Access Token.");
return;
}
if (!prompt) {
showError("Введите промпт.");
return;
}
generateButton.disabled = true;
status.textContent = "⏳ Генерация изображения...";
try {
const client = new InferenceClient(token);
const imageBlob = await client.textToImage({
model: model,
inputs: prompt,
parameters: {
num_inference_steps: steps,
guidance_scale: guidance,
width: width,
height: height
}
});
currentImageUrl = URL.createObjectURL(imageBlob);
resultImage.src = currentImageUrl;
resultImage.style.display = "block";
downloadLink.href = currentImageUrl;
downloadLink.style.display = "block";
status.textContent = "✅ Изображение готово!";
} catch (error) {
console.error(error);
let message = "Не удалось сгенерировать изображение.";
if (error) {
message += "\n\n" + (error.message || String(error));
}
showError(message);
status.textContent = "❌ Ошибка генерации.";
} finally {
generateButton.disabled = false;
}
});
</script>
</body>
</html>