flpolprojects commited on
Commit
da22402
·
verified ·
1 Parent(s): 8172b9d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +278 -270
app.py CHANGED
@@ -111,12 +111,12 @@ def catalog():
111
  }
112
  h1 {
113
  color: #333;
114
- text-align: center;
115
  margin-bottom: 20px;
116
  }
117
- .container {
118
  display: grid;
119
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); /* Адаптивная сетка */
120
  gap: 20px;
121
  }
122
  .product {
@@ -124,19 +124,23 @@ def catalog():
124
  border: 1px solid #ddd;
125
  padding: 15px;
126
  border-radius: 5px;
127
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
 
 
 
 
128
  }
129
  .product h2 {
130
  margin-top: 0;
131
  color: #555;
132
- font-size: 1.5em;
133
  }
134
  .product p {
135
  color: #777;
136
- font-size: 1em;
137
  }
138
  .product img {
139
- max-width: 100%;
140
  height: auto;
141
  margin-top: 10px;
142
  border: 1px solid #ccc;
@@ -146,26 +150,30 @@ def catalog():
146
  margin-right: auto;
147
  }
148
 
149
- /* Адаптивные стили для экранов меньше 600px */
 
 
 
 
 
 
 
150
  @media (max-width: 600px) {
151
- .container {
152
- grid-template-columns: 1fr; /* Одна колонка на мобильных устройствах */
153
  }
154
  .product {
155
  padding: 10px;
156
  }
157
- .product h2 {
158
- font-size: 1.2em;
159
- }
160
- .product p {
161
- font-size: 0.9em;
162
  }
163
  }
164
  </style>
165
  </head>
166
  <body>
167
  <h1>Каталог товаров</h1>
168
- <div class="container">
169
  {% for product in products %}
170
  <div class="product">
171
  <h2>{{ product['name'] }}</h2>
@@ -188,254 +196,254 @@ def admin():
188
  if request.method == 'POST':
189
  action = request.form.get('action')
190
 
191
- if action == 'add':
192
- name = request.form.get('name')
193
- price = request.form.get('price')
194
- description = request.form.get('description')
195
- photo = request.files.get('photo')
196
-
197
- logging.debug(f"Полученные данные из формы: name={name}, price={price}, description={description}")
198
-
199
- photo_filename = None
200
- if photo and photo.filename:
201
- photo_filename = secure_filename(photo.filename)
202
- # Сохраняем файл временно в папку uploads
203
- uploads_dir = 'uploads'
204
- os.makedirs(uploads_dir, exist_ok=True)
205
- temp_path = os.path.join(uploads_dir, photo_filename)
206
- photo.save(temp_path)
207
-
208
- # Загружаем фото в репозиторий в папку "photos"
209
- try:
210
- api = HfApi()
211
- api.upload_file(
212
- path_or_fileobj=temp_path,
213
- path_in_repo=f"photos/{photo_filename}",
214
- repo_id=REPO_ID,
215
- repo_type="dataset",
216
- token=HF_TOKEN_WRITE,
217
- commit_message=f"Добавлено фото для товара {name} {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
218
- )
219
- logging.info("Фото успешно загружено в репозиторий.")
220
- except Exception as e:
221
- logging.error(f"Ошибка при загрузке фото: {e}")
222
- return f"Ошибка при загрузке фото: {e}", 500
223
- finally:
224
- # Удаляем временный файл
225
- os.remove(temp_path)
226
-
227
- if name and price and description:
228
- try:
229
- price = float(price.replace(',', '.'))
230
- except ValueError:
231
- logging.error("Ошибка: Цена должна быть числом.")
232
- return "Ошибка: Цена должна быть числом.", 400
233
-
234
- product_entry = {
235
- 'name': name,
236
- 'price': price,
237
- 'description': description
238
- }
239
- if photo_filename:
240
- product_entry['photo'] = photo_filename
241
-
242
- products.append(product_entry)
243
- save_data(products)
244
- return redirect(url_for('admin'))
245
-
246
- elif action == 'edit':
247
- index = int(request.form.get('index'))
248
- name = request.form.get('name')
249
- price = request.form.get('price')
250
- description = request.form.get('description')
251
- photo = request.files.get('photo')
252
-
253
- # Логика обновления фотографии
254
- if photo:
255
- photo_filename = secure_filename(photo.filename)
256
- uploads_dir = 'uploads'
257
- os.makedirs(uploads_dir, exist_ok=True)
258
- temp_path = os.path.join(uploads_dir, photo_filename)
259
- photo.save(temp_path)
260
-
261
- try:
262
- api = HfApi()
263
- api.upload_file(
264
- path_or_fileobj=temp_path,
265
- path_in_repo=f"photos/{photo_filename}",
266
- repo_id=REPO_ID,
267
- repo_type="dataset",
268
- token=HF_TOKEN_WRITE,
269
- commit_message=f"Обновлено фото для товара {name} {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
270
- )
271
- logging.info("Фото успешно обновлено в репозитории.")
272
- products[index]['photo'] = photo_filename # Обновляем имя файла
273
- except Exception as e:
274
- logging.error(f"Ошибка при загрузке фото: {e}")
275
- return f"Ошибка при загрузке фото: {e}", 500
276
- finally:
277
- os.remove(temp_path)
278
 
279
- # Обновление остальных полей
280
- products[index]['name'] = name
281
- try:
282
- price = float(price.replace(',', '.'))
283
- except ValueError:
284
- logging.error("Ошибка: Цена должна быть числом.")
285
- return "Ошибка: Цена должна быть числом.", 400
286
- products[index]['price'] = price
287
- products[index]['description'] = description
288
-
289
- save_data(products)
290
- return redirect(url_for('admin'))
291
-
292
- elif action == 'delete':
293
- index = int(request.form.get('index'))
294
- del products[index]
295
- save_data(products)
296
- return redirect(url_for('admin'))
297
-
298
- admin_html = '''
299
- <!DOCTYPE html>
300
- <html lang="ru">
301
- <head>
302
- <meta charset="UTF-8">
303
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
304
- <title>Админ-панель</title>
305
- <style>
306
- body {
307
- font-family: Arial, sans-serif;
308
- margin: 20px;
309
- background-color: #f9f9f9;
310
- }
311
- h1 {
312
- color: #333;
313
- }
314
- form {
315
- background-color: #fff;
316
- padding: 20px;
317
- border: 1px solid #ddd;
318
- border-radius: 5px;
319
- max-width: 400px;
320
- margin-bottom: 20px;
321
- }
322
- label {
323
- display: block;
324
- margin-top: 10px;
325
- color: #555;
326
- }
327
- input, textarea {
328
- width: 100%;
329
- padding: 8px;
330
- margin-top: 5px;
331
- border: 1px solid #ddd;
332
- border-radius: 4px;
333
- }
334
- button {
335
- margin-top: 15px;
336
- padding: 10px 15px;
337
- background-color: #28a745;
338
- color: white;
339
- border: none;
340
- border-radius: 4px;
341
- cursor: pointer;
342
- }
343
- button:hover {
344
- background-color: #218838;
345
- }
346
- .product-list {
347
- margin-top: 20px;
348
- }
349
- .product-item {
350
- background-color: #fff;
351
- border: 1px solid #ddd;
352
- padding: 15px;
353
- margin-bottom: 10px;
354
- border-radius: 5px;
355
- }
356
- .edit-form {
357
- margin-top: 10px;
358
- padding: 10px;
359
- border: 1px solid #ddd;
360
- border-radius: 5px;
361
- background-color: #f9f9f9;
362
- }
363
- </style>
364
- </head>
365
- <body>
366
- <h1>Добавление товара</h1>
367
- <form method="POST" enctype="multipart/form-data">
368
- <input type="hidden" name="action" value="add">
369
- <label for="name">Название товара:</label>
370
- <input type="text" id="name" name="name" required>
371
-
372
- <label for="price">Цена:</label>
373
- <input type="number" id="price" name="price" step="0.01" required>
374
-
375
- <label for="description">Описание:</label>
376
- <textarea id="description" name="description" rows="4" required></textarea>
377
-
378
- <label for="photo">Фотография товара (необязательно):</label>
379
- <input type="file" id="photo" name="photo" accept="image/*">
380
-
381
- <button type="submit">Добавить товар</button>
382
- </form>
383
-
384
- <h2>Управление базой данных</h2>
385
-
386
- <!-- Кнопки для резервной копии и скачивания -->
387
- <form method="POST" action="{{ url_for('backup') }}">
388
- <button type="submit">Создать резервную копию</button>
389
- </form>
390
-
391
- <form method="GET" action="{{ url_for('download') }}">
392
- <button type="submit">Скачать базу данных</button>
393
- </form>
394
-
395
- <h2>Список товаров</h2>
396
- <div class="product-list">
397
- {% for product in products %}
398
- <div class="product-item">
399
- <h3>{{ product['name'] }}</h3>
400
- <p><strong>Цена:</strong> {{ product['price'] }} руб.</p>
401
- <p><strong>Описание:</strong> {{ product['description'] }}</p>
402
- {% if product.get('photo') %}
403
- <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ product['photo'] }}" alt="{{ product['name'] }}" style="max-width: 100px;">
404
- {% endif %}
405
-
406
- <details>
407
- <summary>Редактировать</summary>
408
- <form method="POST" enctype="multipart/form-data" class="edit-form">
409
- <input type="hidden" name="action" value="edit">
410
- <input type="hidden" name="index" value="{{ loop.index0 }}">
411
- <label for="name">Название товара:</label>
412
- <input type="text" id="name" name="name" value="{{ product['name'] }}" required>
413
-
414
- <label for="price">Цена:</label>
415
- <input type="number" id="price" name="price" step="0.01" value="{{ product['price'] }}" required>
416
-
417
- <label for="description">Описание:</label>
418
- <textarea id="description" name="description" rows="4" required>{{ product['description'] }}</textarea>
419
-
420
- <label for="photo">Фотография товара (необязательно):</label>
421
- <input type="file" id="photo" name="photo" accept="image/*">
422
-
423
- <button type="submit">Сохранить изменения</button>
424
- </form>
425
- </details>
426
-
427
- <form method="POST">
428
- <input type="hidden" name="action" value="delete">
429
- <input type="hidden" name="index" value="{{ loop.index0 }}">
430
- <button type="submit">Удалить</button>
431
- </form>
432
- </div>
433
- {% endfor %}
434
- </div>
435
-
436
- </body>
437
- </html>
438
- '''
439
  return render_template_string(admin_html, products=products, repo_id=REPO_ID)
440
 
441
  @app.route('/backup', methods=['POST'])
@@ -455,12 +463,12 @@ if __name__ == '__main__':
455
  backup_thread = threading.Thread(target=periodic_backup, daemon=True)
456
  backup_thread.start()
457
 
458
- # Попытка загрузить базу данных из репозитория перед запуском приложения
459
- try:
460
- load_data()
461
- except Exception as e:
462
- logging.error(f"Не удалось загрузить базу данных при запуске: {e}")
463
- # Здесь можно добавить логику для создания пустой базы данных, если это необходимо
464
- # Например: save_data([])
465
 
466
  app.run(debug=True, host='0.0.0.0', port=7860)
 
111
  }
112
  h1 {
113
  color: #333;
114
+ text-align: center; /* Added for centering */
115
  margin-bottom: 20px;
116
  }
117
+ .product-grid {
118
  display: grid;
119
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); /* Responsive columns */
120
  gap: 20px;
121
  }
122
  .product {
 
124
  border: 1px solid #ddd;
125
  padding: 15px;
126
  border-radius: 5px;
127
+ transition: transform 0.2s;
128
+ }
129
+ .product:hover {
130
+ transform: translateY(-5px);
131
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
132
  }
133
  .product h2 {
134
  margin-top: 0;
135
  color: #555;
136
+ font-size: 1.5em; /* Increased font size */
137
  }
138
  .product p {
139
  color: #777;
140
+ font-size: 1em; /* Increased font size */
141
  }
142
  .product img {
143
+ max-width: 100%; /* Make images responsive */
144
  height: auto;
145
  margin-top: 10px;
146
  border: 1px solid #ccc;
 
150
  margin-right: auto;
151
  }
152
 
153
+ /* Media query for larger screens */
154
+ @media (min-width: 768px) {
155
+ .product-grid {
156
+ grid-template-columns: repeat(3, 1fr); /* 3 columns on larger screens */
157
+ }
158
+ }
159
+
160
+ /* Basic mobile optimization */
161
  @media (max-width: 600px) {
162
+ body {
163
+ margin: 10px;
164
  }
165
  .product {
166
  padding: 10px;
167
  }
168
+ h1 {
169
+ font-size: 1.8em;
 
 
 
170
  }
171
  }
172
  </style>
173
  </head>
174
  <body>
175
  <h1>Каталог товаров</h1>
176
+ <div class="product-grid">
177
  {% for product in products %}
178
  <div class="product">
179
  <h2>{{ product['name'] }}</h2>
 
196
  if request.method == 'POST':
197
  action = request.form.get('action')
198
 
199
+ if action == 'add':
200
+ name = request.form.get('name')
201
+ price = request.form.get('price')
202
+ description = request.form.get('description')
203
+ photo = request.files.get('photo')
204
+
205
+ logging.debug(f"Полученные данные из формы: name={name}, price={price}, description={description}")
206
+
207
+ photo_filename = None
208
+ if photo and photo.filename:
209
+ photo_filename = secure_filename(photo.filename)
210
+ # Сохраняем файл временно в папку uploads
211
+ uploads_dir = 'uploads'
212
+ os.makedirs(uploads_dir, exist_ok=True)
213
+ temp_path = os.path.join(uploads_dir, photo_filename)
214
+ photo.save(temp_path)
215
+
216
+ # Загружаем фото в репозиторий в папку "photos"
217
+ try:
218
+ api = HfApi()
219
+ api.upload_file(
220
+ path_or_fileobj=temp_path,
221
+ path_in_repo=f"photos/{photo_filename}",
222
+ repo_id=REPO_ID,
223
+ repo_type="dataset",
224
+ token=HF_TOKEN_WRITE,
225
+ commit_message=f"Добавлено фото для товара {name} {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
226
+ )
227
+ logging.info("Фото успешно загружено в репозиторий.")
228
+ except Exception as e:
229
+ logging.error(f"Ошибка при загрузке фото: {e}")
230
+ return f"Ошибка при загрузке фото: {e}", 500
231
+ finally:
232
+ # Удаляем временный файл
233
+ os.remove(temp_path)
234
+
235
+ if name and price and description:
236
+ try:
237
+ price = float(price.replace(',', '.'))
238
+ except ValueError:
239
+ logging.error("Ошибка: Цена должна быть числом.")
240
+ return "Ошибка: Цена должна быть числом.", 400
241
+
242
+ product_entry = {
243
+ 'name': name,
244
+ 'price': price,
245
+ 'description': description
246
+ }
247
+ if photo_filename:
248
+ product_entry['photo'] = photo_filename
249
+
250
+ products.append(product_entry)
251
+ save_data(products)
252
+ return redirect(url_for('admin'))
253
+
254
+ elif action == 'edit':
255
+ index = int(request.form.get('index'))
256
+ name = request.form.get('name')
257
+ price = request.form.get('price')
258
+ description = request.form.get('description')
259
+ photo = request.files.get('photo')
260
+
261
+ # Логика обновления фотограф��и
262
+ if photo:
263
+ photo_filename = secure_filename(photo.filename)
264
+ uploads_dir = 'uploads'
265
+ os.makedirs(uploads_dir, exist_ok=True)
266
+ temp_path = os.path.join(uploads_dir, photo_filename)
267
+ photo.save(temp_path)
268
+
269
+ try:
270
+ api = HfApi()
271
+ api.upload_file(
272
+ path_or_fileobj=temp_path,
273
+ path_in_repo=f"photos/{photo_filename}",
274
+ repo_id=REPO_ID,
275
+ repo_type="dataset",
276
+ token=HF_TOKEN_WRITE,
277
+ commit_message=f"Обновлено фото для товара {name} {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
278
+ )
279
+ logging.info("Фото успешно обновлено в репозитории.")
280
+ products[index]['photo'] = photo_filename # Обновляем имя файла
281
+ except Exception as e:
282
+ logging.error(f"Ошибка при загрузке фото: {e}")
283
+ return f"Ошибка при загрузке фото: {e}", 500
284
+ finally:
285
+ os.remove(temp_path)
286
 
287
+ # Обновление остальных полей
288
+ products[index]['name'] = name
289
+ try:
290
+ price = float(price.replace(',', '.'))
291
+ except ValueError:
292
+ logging.error("Ошибка: Цена должна быть числом.")
293
+ return "Ошибка: Цена должна быть числом.", 400
294
+ products[index]['price'] = price
295
+ products[index]['description'] = description
296
+
297
+ save_data(products)
298
+ return redirect(url_for('admin'))
299
+
300
+ elif action == 'delete':
301
+ index = int(request.form.get('index'))
302
+ del products[index]
303
+ save_data(products)
304
+ return redirect(url_for('admin'))
305
+
306
+ admin_html = '''
307
+ <!DOCTYPE html>
308
+ <html lang="ru">
309
+ <head>
310
+ <meta charset="UTF-8">
311
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
312
+ <title>Админ-панель</title>
313
+ <style>
314
+ body {
315
+ font-family: Arial, sans-serif;
316
+ margin: 20px;
317
+ background-color: #f9f9f9;
318
+ }
319
+ h1 {
320
+ color: #333;
321
+ }
322
+ form {
323
+ background-color: #fff;
324
+ padding: 20px;
325
+ border: 1px solid #ddd;
326
+ border-radius: 5px;
327
+ max-width: 400px;
328
+ margin-bottom: 20px;
329
+ }
330
+ label {
331
+ display: block;
332
+ margin-top: 10px;
333
+ color: #555;
334
+ }
335
+ input, textarea {
336
+ width: 100%;
337
+ padding: 8px;
338
+ margin-top: 5px;
339
+ border: 1px solid #ddd;
340
+ border-radius: 4px;
341
+ }
342
+ button {
343
+ margin-top: 15px;
344
+ padding: 10px 15px;
345
+ background-color: #28a745;
346
+ color: white;
347
+ border: none;
348
+ border-radius: 4px;
349
+ cursor: pointer;
350
+ }
351
+ button:hover {
352
+ background-color: #218838;
353
+ }
354
+ .product-list {
355
+ margin-top: 20px;
356
+ }
357
+ .product-item {
358
+ background-color: #fff;
359
+ border: 1px solid #ddd;
360
+ padding: 15px;
361
+ margin-bottom: 10px;
362
+ border-radius: 5px;
363
+ }
364
+ .edit-form {
365
+ margin-top: 10px;
366
+ padding: 10px;
367
+ border: 1px solid #ddd;
368
+ border-radius: 5px;
369
+ background-color: #f9f9f9;
370
+ }
371
+ </style>
372
+ </head>
373
+ <body>
374
+ <h1>Добавление товара</h1>
375
+ <form method="POST" enctype="multipart/form-data">
376
+ <input type="hidden" name="action" value="add">
377
+ <label for="name">Название товара:</label>
378
+ <input type="text" id="name" name="name" required>
379
+
380
+ <label for="price">Цена:</label>
381
+ <input type="number" id="price" name="price" step="0.01" required>
382
+
383
+ <label for="description">Описание:</label>
384
+ <textarea id="description" name="description" rows="4" required></textarea>
385
+
386
+ <label for="photo">Фотография товара (необязательно):</label>
387
+ <input type="file" id="photo" name="photo" accept="image/*">
388
+
389
+ <button type="submit">Добавить товар</button>
390
+ </form>
391
+
392
+ <h2>Управление базой данных</h2>
393
+
394
+ <!-- Кнопки для резервной копии и скачивания -->
395
+ <form method="POST" action="{{ url_for('backup') }}">
396
+ <button type="submit">Создать резервную копию</button>
397
+ </form>
398
+
399
+ <form method="GET" action="{{ url_for('download') }}">
400
+ <button type="submit">Скачать базу данных</button>
401
+ </form>
402
+
403
+ <h2>Список товаров</h2>
404
+ <div class="product-list">
405
+ {% for product in products %}
406
+ <div class="product-item">
407
+ <h3>{{ product['name'] }}</h3>
408
+ <p><strong>Цена:</strong> {{ product['price'] }} руб.</p>
409
+ <p><strong>Описание:</strong> {{ product['description'] }}</p>
410
+ {% if product.get('photo') %}
411
+ <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ product['photo'] }}" alt="{{ product['name'] }}" style="max-width: 100px;">
412
+ {% endif %}
413
+
414
+ <details>
415
+ <summary>Редактировать</summary>
416
+ <form method="POST" enctype="multipart/form-data" class="edit-form">
417
+ <input type="hidden" name="action" value="edit">
418
+ <input type="hidden" name="index" value="{{ loop.index0 }}">
419
+ <label for="name">Название товара:</label>
420
+ <input type="text" id="name" name="name" value="{{ product['name'] }}" required>
421
+
422
+ <label for="price">Цена:</label>
423
+ <input type="number" id="price" name="price" step="0.01" value="{{ product['price'] }}" required>
424
+
425
+ <label for="description">Описание:</label>
426
+ <textarea id="description" name="description" rows="4" required>{{ product['description'] }}</textarea>
427
+
428
+ <label for="photo">Фотография товара (необязательно):</label>
429
+ <input type="file" id="photo" name="photo" accept="image/*">
430
+
431
+ <button type="submit">Сохранить изменения</button>
432
+ </form>
433
+ </details>
434
+
435
+ <form method="POST">
436
+ <input type="hidden" name="action" value="delete">
437
+ <input type="hidden" name="index" value="{{ loop.index0 }}">
438
+ <button type="submit">Удалить</button>
439
+ </form>
440
+ </div>
441
+ {% endfor %}
442
+ </div>
443
+
444
+ </body>
445
+ </html>
446
+ '''
447
  return render_template_string(admin_html, products=products, repo_id=REPO_ID)
448
 
449
  @app.route('/backup', methods=['POST'])
 
463
  backup_thread = threading.Thread(target=periodic_backup, daemon=True)
464
  backup_thread.start()
465
 
466
+ # Попытка загрузить базу данных из репозитория перед запуском приложения
467
+ try:
468
+ load_data()
469
+ except Exception as e:
470
+ logging.error(f"Не удалось загрузить базу данных при запуске: {e}")
471
+ # Здесь можно добавить логику для создания пустой базы данных, если это необходимо
472
+ # Например: save_data([])
473
 
474
  app.run(debug=True, host='0.0.0.0', port=7860)