flpolprojects commited on
Commit
da6d436
·
verified ·
1 Parent(s): 88b7393

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +202 -66
app.py CHANGED
@@ -1,4 +1,4 @@
1
- from flask import Flask, render_template_string, request, redirect, url_for
2
  import json
3
  import os
4
  import logging
@@ -11,6 +11,7 @@ from werkzeug.utils import secure_filename
11
 
12
  app = Flask(__name__)
13
  DATA_FILE = 'products.json'
 
14
 
15
  # Настройки Hugging Face
16
  REPO_ID = "flpolprojects/Clients"
@@ -282,9 +283,9 @@ def catalog():
282
  <div class="products-grid">
283
  {% for product in products %}
284
  <div class="product">
285
- {% if product.get('photo') %}
286
  <div class="product-image">
287
- <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ product['photo'] }}"
288
  alt="{{ product['name'] }}"
289
  loading="lazy">
290
  </div>
@@ -292,7 +293,7 @@ def catalog():
292
  <h2>{{ product['name'] }}</h2>
293
  <div class="product-price">{{ product['price'] }} ₽</div>
294
  <p class="product-description">{{ product['description'] }}</p>
295
- <a href="#" class="product-button">Подробнее</a>
296
  </div>
297
  {% endfor %}
298
  </div>
@@ -302,6 +303,120 @@ def catalog():
302
  '''
303
  return render_template_string(catalog_html, products=products, repo_id=REPO_ID)
304
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  @app.route('/admin', methods=['GET', 'POST'])
306
  def admin():
307
  products = load_data()
@@ -312,31 +427,33 @@ def admin():
312
  name = request.form.get('name')
313
  price = request.form.get('price')
314
  description = request.form.get('description')
315
- photo = request.files.get('photo')
316
-
317
- photo_filename = None
318
- if photo and photo.filename:
319
- photo_filename = secure_filename(photo.filename)
320
- uploads_dir = 'uploads'
321
- os.makedirs(uploads_dir, exist_ok=True)
322
- temp_path = os.path.join(uploads_dir, photo_filename)
323
- photo.save(temp_path)
324
-
325
- try:
326
- api = HfApi()
327
- api.upload_file(
328
- path_or_fileobj=temp_path,
329
- path_in_repo=f"photos/{photo_filename}",
330
- repo_id=REPO_ID,
331
- repo_type="dataset",
332
- token=HF_TOKEN_WRITE,
333
- commit_message=f"Добавлено фото для товара {name}"
334
- )
335
- except Exception as e:
336
- logging.error(f"Ошибка при загрузке фото: {e}")
337
- return f"Ошибка при загрузке фото: {e}", 500
338
- finally:
339
- os.remove(temp_path)
 
 
340
 
341
  if name and price and description:
342
  try:
@@ -347,10 +464,9 @@ def admin():
347
  product = {
348
  'name': name,
349
  'price': price,
350
- 'description': description
 
351
  }
352
- if photo_filename:
353
- product['photo'] = photo_filename
354
 
355
  products.append(product)
356
  save_data(products)
@@ -361,31 +477,34 @@ def admin():
361
  name = request.form.get('name')
362
  price = request.form.get('price')
363
  description = request.form.get('description')
364
- photo = request.files.get('photo')
365
-
366
- if photo:
367
- photo_filename = secure_filename(photo.filename)
368
- uploads_dir = 'uploads'
369
- os.makedirs(uploads_dir, exist_ok=True)
370
- temp_path = os.path.join(uploads_dir, photo_filename)
371
- photo.save(temp_path)
372
-
373
- try:
374
- api = HfApi()
375
- api.upload_file(
376
- path_or_fileobj=temp_path,
377
- path_in_repo=f"photos/{photo_filename}",
378
- repo_id=REPO_ID,
379
- repo_type="dataset",
380
- token=HF_TOKEN_WRITE,
381
- commit_message=f"Обновлено фото для товара {name}"
382
- )
383
- products[index]['photo'] = photo_filename
384
- except Exception as e:
385
- logging.error(f"Ошибка при загрузке фото: {e}")
386
- return f"Ошибка при загрузке фото: {e}", 500
387
- finally:
388
- os.remove(temp_path)
 
 
 
389
 
390
  products[index]['name'] = name
391
  try:
@@ -394,6 +513,7 @@ def admin():
394
  return "Ошибка: Цена должна быть числом.", 400
395
  products[index]['price'] = price
396
  products[index]['description'] = description
 
397
 
398
  save_data(products)
399
  return redirect(url_for('admin'))
@@ -489,6 +609,20 @@ def admin():
489
  margin-bottom: 10px;
490
  }
491
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
492
  </style>
493
  </head>
494
  <body>
@@ -504,8 +638,8 @@ def admin():
504
  <label for="description">Описание:</label>
505
  <textarea id="description" name="description" rows="4" required></textarea>
506
 
507
- <label for="photo">Фотография товара (необязательно):</label>
508
- <input type="file" id="photo" name="photo" accept="image/*">
509
 
510
  <button type="submit">Добавить товар</button>
511
  </form>
@@ -526,11 +660,13 @@ def admin():
526
  <h3>{{ product['name'] }}</h3>
527
  <p><strong>Цена:</strong> {{ product['price'] }} руб.</p>
528
  <p><strong>Описание:</strong> {{ product['description'] }}</p>
529
- {% if product.get('photo') %}
530
- <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ product['photo'] }}"
531
- alt="{{ product['name'] }}"
532
- style="max-width: 100px;">
533
- {% endif %}
 
 
534
 
535
  <details>
536
  <summary>Редактировать</summary>
@@ -546,8 +682,8 @@ def admin():
546
  <label for="description">Описание:</label>
547
  <textarea id="description" name="description" rows="4" required>{{ product['description'] }}</textarea>
548
 
549
- <label for="photo">Фотография товара (необязательно):</label>
550
- <input type="file" id="photo" name="photo" accept="image/*">
551
 
552
  <button type="submit">Сохранить изменения</button>
553
  </form>
 
1
+ from flask import Flask, render_template_string, request, redirect, url_for, abort
2
  import json
3
  import os
4
  import logging
 
11
 
12
  app = Flask(__name__)
13
  DATA_FILE = 'products.json'
14
+ MAX_PHOTOS = 5 # Максимальное количество фото на товар
15
 
16
  # Настройки Hugging Face
17
  REPO_ID = "flpolprojects/Clients"
 
283
  <div class="products-grid">
284
  {% for product in products %}
285
  <div class="product">
286
+ {% if product.get('photos') and product['photos'] %}
287
  <div class="product-image">
288
+ <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ product['photos'][0] }}"
289
  alt="{{ product['name'] }}"
290
  loading="lazy">
291
  </div>
 
293
  <h2>{{ product['name'] }}</h2>
294
  <div class="product-price">{{ product['price'] }} ₽</div>
295
  <p class="product-description">{{ product['description'] }}</p>
296
+ <a href="{{ url_for('product', product_id=loop.index0) }}" class="product-button">Подробнее</a>
297
  </div>
298
  {% endfor %}
299
  </div>
 
303
  '''
304
  return render_template_string(catalog_html, products=products, repo_id=REPO_ID)
305
 
306
+ @app.route('/product/<int:product_id>')
307
+ def product(product_id):
308
+ products = load_data()
309
+ try:
310
+ product = products[product_id]
311
+ except IndexError:
312
+ abort(404)
313
+
314
+ product_html = '''
315
+ <!DOCTYPE html>
316
+ <html lang="ru">
317
+ <head>
318
+ <meta charset="UTF-8">
319
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
320
+ <title>{{ product['name'] }}</title>
321
+ <style>
322
+ * {
323
+ margin: 0;
324
+ padding: 0;
325
+ box-sizing: border-box;
326
+ }
327
+
328
+ body {
329
+ font-family: Arial, sans-serif;
330
+ line-height: 1.6;
331
+ background-color: #f4f4f4;
332
+ color: #333;
333
+ padding: 20px;
334
+ }
335
+
336
+ .container {
337
+ max-width: 900px;
338
+ margin: 0 auto;
339
+ }
340
+
341
+ h1 {
342
+ text-align: center;
343
+ margin-bottom: 30px;
344
+ color: #3498db;
345
+ }
346
+
347
+ .product-gallery {
348
+ display: flex;
349
+ flex-wrap: wrap;
350
+ justify-content: center;
351
+ margin-bottom: 20px;
352
+ }
353
+
354
+ .product-gallery img {
355
+ width: 200px;
356
+ height: 200px;
357
+ object-fit: cover;
358
+ margin: 10px;
359
+ border-radius: 8px;
360
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
361
+ }
362
+
363
+ .product-description {
364
+ background-color: #fff;
365
+ padding: 20px;
366
+ border-radius: 8px;
367
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
368
+ }
369
+
370
+ .product-description h2 {
371
+ color: #3498db;
372
+ margin-bottom: 15px;
373
+ }
374
+
375
+ .product-description p {
376
+ font-size: 1.1em;
377
+ line-height: 1.7;
378
+ }
379
+
380
+ .back-button {
381
+ display: inline-block;
382
+ padding: 10px 20px;
383
+ background-color: #3498db;
384
+ color: white;
385
+ text-decoration: none;
386
+ border-radius: 5px;
387
+ transition: background-color 0.3s;
388
+ margin-top: 20px;
389
+ }
390
+
391
+ .back-button:hover {
392
+ background-color: #2980b9;
393
+ }
394
+ </style>
395
+ </head>
396
+ <body>
397
+ <div class="container">
398
+ <h1>{{ product['name'] }}</h1>
399
+ <div class="product-gallery">
400
+ {% if product.get('photos') and product['photos'] %}
401
+ {% for photo in product['photos'] %}
402
+ <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ photo }}" alt="{{ product['name'] }}">
403
+ {% endfor %}
404
+ {% else %}
405
+ <p>Нет доступных фотографий.</p>
406
+ {% endif %}
407
+ </div>
408
+ <div class="product-description">
409
+ <h2>Описание товара</h2>
410
+ <p>{{ product['description'] }}</p>
411
+ <p><strong>Цена:</strong> {{ product['price'] }} ₽</p>
412
+ </div>
413
+ <a href="{{ url_for('catalog') }}" class="back-button">Вернуться в каталог</a>
414
+ </div>
415
+ </body>
416
+ </html>
417
+ '''
418
+ return render_template_string(product_html, product=product, repo_id=REPO_ID)
419
+
420
  @app.route('/admin', methods=['GET', 'POST'])
421
  def admin():
422
  products = load_data()
 
427
  name = request.form.get('name')
428
  price = request.form.get('price')
429
  description = request.form.get('description')
430
+ photos = request.files.getlist('photos')
431
+
432
+ photo_filenames = []
433
+ if photos:
434
+ for photo in photos[:MAX_PHOTOS]:
435
+ if photo.filename:
436
+ photo_filename = secure_filename(photo.filename)
437
+ uploads_dir = 'uploads'
438
+ os.makedirs(uploads_dir, exist_ok=True)
439
+ temp_path = os.path.join(uploads_dir, photo_filename)
440
+ photo.save(temp_path)
441
+
442
+ try:
443
+ api = HfApi()
444
+ api.upload_file(
445
+ path_or_fileobj=temp_path,
446
+ path_in_repo=f"photos/{photo_filename}",
447
+ repo_id=REPO_ID,
448
+ repo_type="dataset",
449
+ token=HF_TOKEN_WRITE,
450
+ commit_message=f"Добавлено фото для товара {name}"
451
+ )
452
+ photo_filenames.append(photo_filename)
453
+ except Exception as e:
454
+ logging.error(f"Ошибка при загрузке фото: {e}")
455
+ finally:
456
+ os.remove(temp_path)
457
 
458
  if name and price and description:
459
  try:
 
464
  product = {
465
  'name': name,
466
  'price': price,
467
+ 'description': description,
468
+ 'photos': photo_filenames
469
  }
 
 
470
 
471
  products.append(product)
472
  save_data(products)
 
477
  name = request.form.get('name')
478
  price = request.form.get('price')
479
  description = request.form.get('description')
480
+ photos = request.files.getlist('photos')
481
+
482
+ photo_filenames = products[index].get('photos', []) # Сохраняем текущие фото
483
+
484
+ if photos:
485
+ for photo in photos[:MAX_PHOTOS]:
486
+ if photo.filename:
487
+ photo_filename = secure_filename(photo.filename)
488
+ uploads_dir = 'uploads'
489
+ os.makedirs(uploads_dir, exist_ok=True)
490
+ temp_path = os.path.join(uploads_dir, photo_filename)
491
+ photo.save(temp_path)
492
+
493
+ try:
494
+ api = HfApi()
495
+ api.upload_file(
496
+ path_or_fileobj=temp_path,
497
+ path_in_repo=f"photos/{photo_filename}",
498
+ repo_id=REPO_ID,
499
+ repo_type="dataset",
500
+ token=HF_TOKEN_WRITE,
501
+ commit_message=f"Обновлено фото для товара {name}"
502
+ )
503
+ photo_filenames.append(photo_filename)
504
+ except Exception as e:
505
+ logging.error(f"Ошибка при загрузке фото: {e}")
506
+ finally:
507
+ os.remove(temp_path)
508
 
509
  products[index]['name'] = name
510
  try:
 
513
  return "Ошибка: Цена должна быть числом.", 400
514
  products[index]['price'] = price
515
  products[index]['description'] = description
516
+ products[index]['photos'] = photo_filenames[:MAX_PHOTOS] # Обновляем список фото, ограничивая MAX_PHOTOS
517
 
518
  save_data(products)
519
  return redirect(url_for('admin'))
 
609
  margin-bottom: 10px;
610
  }
611
  }
612
+
613
+ .product-photos {
614
+ display: flex;
615
+ flex-wrap: wrap;
616
+ margin-top: 10px;
617
+ }
618
+
619
+ .product-photos img {
620
+ max-width: 50px;
621
+ max-height: 50px;
622
+ margin-right: 5px;
623
+ border: 1px solid #ddd;
624
+ padding: 2px;
625
+ }
626
  </style>
627
  </head>
628
  <body>
 
638
  <label for="description">Описание:</label>
639
  <textarea id="description" name="description" rows="4" required></textarea>
640
 
641
+ <label for="photos">Фотографии товара (до 5):</label>
642
+ <input type="file" id="photos" name="photos" accept="image/*" multiple>
643
 
644
  <button type="submit">Добавить товар</button>
645
  </form>
 
660
  <h3>{{ product['name'] }}</h3>
661
  <p><strong>Цена:</strong> {{ product['price'] }} руб.</p>
662
  <p><strong>Описание:</strong> {{ product['description'] }}</p>
663
+ <div class="product-photos">
664
+ {% if product.get('photos') and product['photos'] %}
665
+ {% for photo in product['photos'] %}
666
+ <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ photo }}" alt="{{ product['name'] }}">
667
+ {% endfor %}
668
+ {% endif %}
669
+ </div>
670
 
671
  <details>
672
  <summary>Редактировать</summary>
 
682
  <label for="description">Описание:</label>
683
  <textarea id="description" name="description" rows="4" required>{{ product['description'] }}</textarea>
684
 
685
+ <label for="photos">Фотографии товара (до 5):</label>
686
+ <input type="file" id="photos" name="photos" accept="image/*" multiple>
687
 
688
  <button type="submit">Сохранить изменения</button>
689
  </form>