Alexey7878 commited on
Commit
2cd33b4
·
verified ·
1 Parent(s): f1bc99f

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +217 -246
index.html CHANGED
@@ -54,7 +54,6 @@
54
  font-weight: bold;
55
  cursor: pointer;
56
  font-size: 16px;
57
- transition: background 0.2s;
58
  }
59
 
60
  button:hover {
@@ -126,8 +125,8 @@
126
  <h2>Генерация изображений через Hugging Face</h2>
127
 
128
  <div class="info">
129
- Токен Hugging Face используется только для текущего запроса.
130
- Не публикуй этот HTML с токеном внутри кода.
131
  </div>
132
 
133
  <label for="hf-token">
@@ -181,396 +180,368 @@
181
 
182
  <script>
183
 
184
- const API_URL =
185
- "https://router.huggingface.co/v1/images/generations";
186
 
 
 
187
 
188
- const btn =
189
- document.getElementById("generateBtn");
190
 
191
- const tokenInput =
192
- document.getElementById("hf-token");
193
 
194
- const modelSelect =
195
- document.getElementById("modelSelect");
196
 
197
- const promptInput =
198
- document.getElementById("prompt");
199
 
200
- const statusText =
201
- document.getElementById("statusText");
202
 
203
- const errorContainer =
204
- document.getElementById("errorContainer");
205
 
206
- const outputImage =
207
- document.getElementById("outputImage");
208
 
209
 
210
- // Текущий URL изображения.
211
- // Нужен для освобождения памяти браузера.
212
- let currentImageUrl = null;
213
 
 
214
 
215
- function showError(title, details) {
216
 
217
- errorContainer.innerHTML = "";
 
218
 
219
- const block =
220
- document.createElement("div");
221
 
222
- block.className =
223
- "error-block";
224
 
 
 
225
 
226
- const heading =
227
- document.createElement("h3");
228
 
229
- heading.textContent =
230
- "⚠️ " + title;
231
 
 
 
232
 
233
- const code =
234
- document.createElement("div");
235
 
236
- code.className =
237
- "code";
238
 
239
- code.textContent =
240
- details;
241
 
 
242
 
243
- block.appendChild(heading);
244
 
245
- block.appendChild(code);
 
246
 
247
- errorContainer.appendChild(block);
248
- }
249
 
 
 
 
250
 
251
- function clearError() {
252
 
253
- errorContainer.innerHTML = "";
254
 
255
- }
256
 
257
 
258
- function clearImage() {
 
 
259
 
260
- outputImage.style.display =
261
- "none";
262
 
263
- outputImage.removeAttribute("src");
 
264
 
 
265
 
266
- if (currentImageUrl) {
267
 
268
- URL.revokeObjectURL(
269
- currentImageUrl
270
- );
271
 
272
- currentImageUrl = null;
273
- }
 
274
 
275
- }
276
 
 
277
 
278
- function setLoading(isLoading) {
279
 
280
- btn.disabled =
281
- isLoading;
282
 
283
- tokenInput.disabled =
284
- isLoading;
 
285
 
286
- modelSelect.disabled =
287
- isLoading;
288
 
289
- promptInput.disabled =
290
- isLoading;
291
 
292
- }
293
 
 
294
 
295
- async function parseErrorResponse(response) {
296
 
297
- const text =
298
- await response.text();
299
 
300
 
301
- if (!text) {
302
 
303
- return "Пустой ответ от сервера.";
 
304
 
305
- }
 
 
 
 
306
 
 
307
 
308
- try {
309
 
310
- const json =
311
- JSON.parse(text);
312
 
313
- return JSON.stringify(
314
- json,
315
- null,
316
- 2
317
- );
318
 
319
- } catch {
320
 
321
- return text;
 
 
322
 
323
- }
 
 
324
 
325
- }
 
326
 
 
 
327
 
328
- btn.addEventListener(
329
- "click",
330
- async () => {
331
 
332
- const token =
333
- tokenInput.value.trim();
334
 
335
- const model =
336
- modelSelect.value;
337
 
338
- const prompt =
339
- promptInput.value.trim();
340
 
341
 
342
- clearError();
343
 
344
- clearImage();
345
 
 
 
 
 
346
 
347
- // Валидация токена
348
 
349
- if (!token) {
350
 
351
- showError(
352
- "Ошибка валидации",
353
- "Введите Hugging Face Access Token."
354
- );
355
 
356
- return;
357
 
358
- }
359
 
 
 
 
 
360
 
361
- // Валидация промпта
362
 
363
- if (!prompt) {
364
 
365
- showError(
366
- "Ошибка валидации",
367
- "Введите описание изображения."
368
- );
369
 
370
- return;
 
371
 
372
- }
 
373
 
374
 
375
- setLoading(true);
376
 
 
 
 
 
 
 
 
 
 
377
 
378
- statusText.textContent =
379
- "Отправляем запрос в Hugging Face...";
380
 
381
 
382
- try {
 
 
 
 
383
 
384
- const response =
385
- await fetch(
386
- API_URL,
387
- {
388
- method: "POST",
389
 
390
- headers: {
 
391
 
392
- "Authorization":
393
- `Bearer ${token}`,
394
 
395
- "Content-Type":
396
- "application/json",
397
 
398
- "Accept":
399
- "application/json"
400
 
401
- },
 
402
 
403
- body:
404
- JSON.stringify({
405
 
406
- model:
407
- model,
408
 
409
- prompt:
410
- prompt
411
 
412
- })
413
 
414
- }
415
- );
416
 
 
 
417
 
418
- if (!response.ok) {
419
 
420
- const errorDetails =
421
- await parseErrorResponse(
422
- response
423
- );
424
 
 
425
 
426
- showError(
427
- `Ошибка API: ${response.status} ${response.statusText}`,
428
- `URL: ${API_URL}\n\nОтвет сервера:\n${errorDetails}`
429
  );
430
 
431
 
432
- statusText.textContent =
433
- "Генерация не удалась.";
434
-
435
- return;
436
-
437
- }
438
 
439
 
440
  statusText.textContent =
441
- "Получаем результат...";
442
-
443
-
444
- const data =
445
- await response.json();
446
-
447
-
448
- /*
449
- Ожидаемый формат:
450
-
451
- {
452
- "data": [
453
- {
454
- "url": "https://..."
455
- }
456
- ]
457
- }
458
 
459
- или:
460
 
461
- {
462
- "data": [
463
- {
464
- "b64_json": "..."
465
- }
466
- ]
467
- }
468
- */
469
-
470
-
471
- if (
472
- !data ||
473
- !Array.isArray(data.data) ||
474
- !data.data.length
475
- ) {
476
-
477
- showError(
478
- "Неожиданный ответ API",
479
- JSON.stringify(
480
- data,
481
- null,
482
- 2
483
- )
484
- );
485
 
486
- return;
487
 
488
- }
 
489
 
490
 
491
- const result =
492
- data.data[0];
 
493
 
 
 
494
 
495
- // Вариант 1:
496
- // API вернул URL изображения
497
 
498
- if (result.url) {
499
 
500
- outputImage.src =
501
- result.url;
 
 
502
 
503
- outputImage.style.display =
504
- "block";
505
 
506
- statusText.textContent =
507
- "✅ Изображение готово!";
508
 
509
- return;
 
 
 
510
 
511
- }
512
 
 
513
 
514
- // Вариант 2:
515
- // API вернул base64
516
 
517
- if (result.b64_json) {
 
 
518
 
519
- currentImageUrl =
520
- `data:image/png;base64,${result.b64_json}`;
 
 
521
 
522
- outputImage.src =
523
- currentImageUrl;
524
 
525
- outputImage.style.display =
526
- "block";
527
 
528
- statusText.textContent =
529
- "✅ Изображение готово!";
530
 
531
- return;
 
532
 
533
- }
534
 
 
 
535
 
536
- // Если формат неизвестен
537
 
538
- showError(
539
- "Неизвестный формат ответа",
540
- JSON.stringify(
541
- data,
542
- null,
543
- 2
544
- )
545
- );
546
 
 
547
 
548
- } catch (error) {
 
 
549
 
550
- console.error(
551
- "Generation error:",
552
- error
553
- );
554
 
 
 
 
 
 
555
 
556
- showError(
557
- "Ошибка соединения",
558
- error.message ||
559
- String(error)
560
- );
561
 
 
 
562
 
563
- statusText.textContent =
564
- "Не удалось выполнить запрос.";
565
 
566
- } finally {
567
 
568
- setLoading(false);
569
 
570
- }
 
571
 
572
  }
573
- );
 
 
574
 
575
  </script>
576
 
 
54
  font-weight: bold;
55
  cursor: pointer;
56
  font-size: 16px;
 
57
  }
58
 
59
  button:hover {
 
125
  <h2>Генерация изображений через Hugging Face</h2>
126
 
127
  <div class="info">
128
+ Для работы нужен Hugging Face Access Token
129
+ с разрешением Inference Providers.
130
  </div>
131
 
132
  <label for="hf-token">
 
180
 
181
  <script>
182
 
183
+ const btn =
184
+ document.getElementById("generateBtn");
185
 
186
+ const tokenInput =
187
+ document.getElementById("hf-token");
188
 
189
+ const modelSelect =
190
+ document.getElementById("modelSelect");
191
 
192
+ const promptInput =
193
+ document.getElementById("prompt");
194
 
195
+ const statusText =
196
+ document.getElementById("statusText");
197
 
198
+ const errorContainer =
199
+ document.getElementById("errorContainer");
200
 
201
+ const outputImage =
202
+ document.getElementById("outputImage");
203
 
 
 
204
 
205
+ let currentImageUrl = null;
 
206
 
207
 
208
+ // ----------------------------------------
209
+ // Показ ошибки
210
+ // ----------------------------------------
211
 
212
+ function showError(title, details) {
213
 
214
+ errorContainer.innerHTML = "";
215
 
216
+ const block =
217
+ document.createElement("div");
218
 
219
+ block.className =
220
+ "error-block";
221
 
 
 
222
 
223
+ const heading =
224
+ document.createElement("h3");
225
 
226
+ heading.textContent =
227
+ "⚠️ " + title;
228
 
 
 
229
 
230
+ const code =
231
+ document.createElement("div");
232
 
233
+ code.className =
234
+ "code";
235
 
236
+ code.textContent =
237
+ details;
238
 
 
 
239
 
240
+ block.appendChild(heading);
241
 
242
+ block.appendChild(code);
243
 
244
+ errorContainer.appendChild(block);
245
+ }
246
 
 
 
247
 
248
+ // ----------------------------------------
249
+ // Очистка ошибки
250
+ // ----------------------------------------
251
 
252
+ function clearError() {
253
 
254
+ errorContainer.innerHTML = "";
255
 
256
+ }
257
 
258
 
259
+ // ----------------------------------------
260
+ // Очистка предыдущего изображения
261
+ // ----------------------------------------
262
 
263
+ function clearImage() {
 
264
 
265
+ outputImage.style.display =
266
+ "none";
267
 
268
+ outputImage.removeAttribute("src");
269
 
 
270
 
271
+ if (currentImageUrl) {
 
 
272
 
273
+ URL.revokeObjectURL(
274
+ currentImageUrl
275
+ );
276
 
277
+ currentImageUrl = null;
278
 
279
+ }
280
 
281
+ }
282
 
 
 
283
 
284
+ // ----------------------------------------
285
+ // Разбор ошибки API
286
+ // ----------------------------------------
287
 
288
+ async function getErrorText(response) {
 
289
 
290
+ const text =
291
+ await response.text();
292
 
 
293
 
294
+ if (!text) {
295
 
296
+ return "Сервер вернул пустой ответ.";
297
 
298
+ }
 
299
 
300
 
301
+ try {
302
 
303
+ const json =
304
+ JSON.parse(text);
305
 
306
+ return JSON.stringify(
307
+ json,
308
+ null,
309
+ 2
310
+ );
311
 
312
+ } catch {
313
 
314
+ return text;
315
 
316
+ }
 
317
 
318
+ }
 
 
 
 
319
 
 
320
 
321
+ // ----------------------------------------
322
+ // Генерация изображения
323
+ // ----------------------------------------
324
 
325
+ btn.addEventListener(
326
+ "click",
327
+ async () => {
328
 
329
+ const token =
330
+ tokenInput.value.trim();
331
 
332
+ const model =
333
+ modelSelect.value;
334
 
335
+ const prompt =
336
+ promptInput.value.trim();
 
337
 
 
 
338
 
339
+ clearError();
 
340
 
341
+ clearImage();
 
342
 
343
 
344
+ // Проверка токена
345
 
346
+ if (!token) {
347
 
348
+ showError(
349
+ "Ошибка",
350
+ "Введите Hugging Face Access Token."
351
+ );
352
 
353
+ return;
354
 
355
+ }
356
 
 
 
 
 
357
 
358
+ // Проверка промпта
359
 
360
+ if (!prompt) {
361
 
362
+ showError(
363
+ "Ошибка",
364
+ "Введите промпт для генерации."
365
+ );
366
 
367
+ return;
368
 
369
+ }
370
 
 
 
 
 
371
 
372
+ btn.disabled =
373
+ true;
374
 
375
+ statusText.textContent =
376
+ "Генерируем изображение...";
377
 
378
 
379
+ try {
380
 
381
+ /*
382
+ * Hugging Face Inference Providers.
383
+ *
384
+ * fal-ai выбран явно.
385
+ *
386
+ * Важно:
387
+ * provider должен поддерживать
388
+ * выбранную модель.
389
+ */
390
 
391
+ const apiUrl =
392
+ `https://router.huggingface.co/fal-ai/models/${model}`;
393
 
394
 
395
+ const response =
396
+ await fetch(
397
+ apiUrl,
398
+ {
399
+ method: "POST",
400
 
401
+ headers: {
 
 
 
 
402
 
403
+ "Authorization":
404
+ `Bearer ${token}`,
405
 
406
+ "Content-Type":
407
+ "application/json",
408
 
409
+ "Accept":
410
+ "image/png"
411
 
412
+ },
 
413
 
414
+ body:
415
+ JSON.stringify({
416
 
417
+ inputs:
418
+ prompt,
419
 
420
+ parameters: {
 
421
 
422
+ num_inference_steps:
423
+ 4
424
 
425
+ }
426
 
427
+ })
 
428
 
429
+ }
430
+ );
431
 
 
432
 
433
+ // --------------------------------
434
+ // Обработка ошибки
435
+ // --------------------------------
 
436
 
437
+ if (!response.ok) {
438
 
439
+ const errorText =
440
+ await getErrorText(
441
+ response
442
  );
443
 
444
 
445
+ showError(
446
+ `Ошибка ${response.status} ${response.statusText}`,
447
+ `URL: ${apiUrl}\n\nОтвет сервера:\n${errorText}`
448
+ );
 
 
449
 
450
 
451
  statusText.textContent =
452
+ "Генерация не удалась.";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
453
 
454
+ return;
455
 
456
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
457
 
 
458
 
459
+ statusText.textContent =
460
+ "Изображение получено. Отображаем...";
461
 
462
 
463
+ // --------------------------------
464
+ // Получаем изображение как Blob
465
+ // --------------------------------
466
 
467
+ const blob =
468
+ await response.blob();
469
 
 
 
470
 
471
+ // Проверяем MIME-тип
472
 
473
+ if (
474
+ !blob.type ||
475
+ !blob.type.startsWith("image/")
476
+ ) {
477
 
478
+ const text =
479
+ await blob.text();
480
 
 
 
481
 
482
+ showError(
483
+ "API вернул не изображение",
484
+ text
485
+ );
486
 
487
+ return;
488
 
489
+ }
490
 
 
 
491
 
492
+ // --------------------------------
493
+ // Создаём URL изображения
494
+ // --------------------------------
495
 
496
+ currentImageUrl =
497
+ URL.createObjectURL(
498
+ blob
499
+ );
500
 
 
 
501
 
502
+ outputImage.src =
503
+ currentImageUrl;
504
 
 
 
505
 
506
+ outputImage.style.display =
507
+ "block";
508
 
 
509
 
510
+ statusText.textContent =
511
+ "✅ Изображение готово!";
512
 
513
+ }
514
 
 
 
 
 
 
 
 
 
515
 
516
+ catch (error) {
517
 
518
+ console.error(
519
+ error
520
+ );
521
 
 
 
 
 
522
 
523
+ showError(
524
+ "Ошибка соединения",
525
+ error.message ||
526
+ String(error)
527
+ );
528
 
 
 
 
 
 
529
 
530
+ statusText.textContent =
531
+ "Произошла ошибка.";
532
 
533
+ }
 
534
 
 
535
 
536
+ finally {
537
 
538
+ btn.disabled =
539
+ false;
540
 
541
  }
542
+
543
+ }
544
+ );
545
 
546
  </script>
547