flpolprojects commited on
Commit
afad0a7
·
verified ·
1 Parent(s): 75f90e3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +105 -18
app.py CHANGED
@@ -8,13 +8,16 @@ from aiogram.utils.keyboard import ReplyKeyboardBuilder, InlineKeyboardBuilder
8
  from flask import Flask, request, jsonify, render_template_string
9
  import logging
10
  import threading
 
 
 
11
 
12
  # Настройка логирования
13
  logging.basicConfig(level=logging.INFO)
14
  logger = logging.getLogger(__name__)
15
 
16
  # Инициализация бота и Flask
17
- BOT_TOKEN = '7734802681:AAGKHGG8O9uNk64JWTHH5yqXzvSxCcoLUdA'
18
  bot = Bot(token=BOT_TOKEN)
19
  dp = Dispatcher()
20
  app = Flask(__name__)
@@ -22,24 +25,75 @@ app = Flask(__name__)
22
  # Путь для хранения данных (товары и заказы)
23
  DATA_FILE = 'data.json'
24
 
25
- # Загрузка или создание данных
 
 
 
 
 
26
  def load_data():
27
  try:
28
- if os.path.exists(DATA_FILE):
29
- with open(DATA_FILE, 'r', encoding='utf-8') as f:
30
- return json.load(f)
 
 
 
 
 
 
 
 
31
  return {'products': [], 'orders': []}
32
  except Exception as e:
33
  logger.error(f"Ошибка при загрузке данных: {e}")
34
  return {'products': [], 'orders': []}
35
 
 
36
  def save_data(data):
37
  try:
38
  with open(DATA_FILE, 'w', encoding='utf-8') as f:
39
  json.dump(data, f, ensure_ascii=False, indent=4)
 
40
  except Exception as e:
41
  logger.error(f"Ошибка при сохранении данных: {e}")
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  data = load_data()
44
 
45
  # Клавиатуры
@@ -67,8 +121,17 @@ async def show_products(message: types.Message):
67
  await message.answer("Нет доступных товаров.")
68
  return
69
  for product in data['products']:
70
- await message.answer(f"🏷 {product['name']} - {product['price']} руб.\nОписание: {product['description']}\n/id: {product['id']}",
71
- reply_markup=get_product_keyboard(product['id']))
 
 
 
 
 
 
 
 
 
72
 
73
  @dp.message(F.text == "🛒 Корзина")
74
  async def show_cart(message: types.Message):
@@ -147,15 +210,17 @@ admin_html = """
147
  input, textarea { width: 100%; margin: 5px 0; padding: 8px; }
148
  button { background-color: #4CAF50; color: white; padding: 10px 15px; border: none; border-radius: 5px; cursor: pointer; }
149
  button:hover { background-color: #45a049; }
 
150
  </style>
151
  </head>
152
  <body>
153
  <div class="container">
154
  <h1>Управление товарами</h1>
155
- <form id="addProductForm">
156
  <input type="text" name="name" placeholder="Название" required><br>
157
  <input type="number" name="price" placeholder="Цена" step="0.01" required><br>
158
  <textarea name="description" placeholder="Описание" required></textarea><br>
 
159
  <button type="submit">Добавить товар</button>
160
  </form>
161
  <h2>Существующие товары</h2>
@@ -164,6 +229,9 @@ admin_html = """
164
  <div class="product">
165
  {{ product.name }} - {{ product.price }} руб.<br>
166
  {{ product.description }}<br>
 
 
 
167
  <button onclick="deleteProduct({{ product.id }})">Удалить</button>
168
  </div>
169
  {% endfor %}
@@ -191,12 +259,6 @@ admin_html = """
191
  {% endif %}
192
  </div>
193
  <script>
194
- document.getElementById('addProductForm').onsubmit = async (e) => {
195
- e.preventDefault();
196
- const formData = new FormData(e.target);
197
- const response = await fetch('/add_product', { method: 'POST', body: formData });
198
- if (response.ok) window.location.reload();
199
- };
200
  async function deleteProduct(productId) {
201
  const response = await fetch(`/delete_product/${productId}`, { method: 'POST' });
202
  if (response.ok) window.location.reload();
@@ -210,7 +272,7 @@ admin_html = """
210
  def admin_panel():
211
  try:
212
  logger.info("Rendering admin panel with products and orders")
213
- return render_template_string(admin_html, products=data['products'], orders=data['orders'])
214
  except Exception as e:
215
  logger.error(f"Ошибка в шаблоне: {e}")
216
  return "Ошибка сервера. Проверь логи.", 500
@@ -223,8 +285,33 @@ def add_product():
223
  name = request.form['name']
224
  price = float(request.form['price'])
225
  description = request.form['description']
 
226
  product_id = max((p['id'] for p in data['products']), default=0) + 1
227
- data['products'].append({'id': product_id, 'name': name, 'price': price, 'description': description})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  save_data(data)
229
  return jsonify({'status': 'success'})
230
  except Exception as e:
@@ -249,7 +336,7 @@ async def on_startup(_):
249
  def run_flask():
250
  try:
251
  logger.info("Starting Flask server on port 7860")
252
- app.run(host='0.0.0.0', port=7860)
253
  except Exception as e:
254
  logger.error(f"Ошибка в Flask: {e}")
255
 
@@ -265,4 +352,4 @@ if __name__ == '__main__':
265
  except KeyboardInterrupt:
266
  logger.info("Stopping bot and Flask")
267
  finally:
268
- flask_thread.join() # Ждём завершения потока Flask при завершении программы
 
8
  from flask import Flask, request, jsonify, render_template_string
9
  import logging
10
  import threading
11
+ from huggingface_hub import HfApi, hf_hub_download
12
+ from huggingface_hub.utils import RepositoryNotFoundError
13
+ from werkzeug.utils import secure_filename
14
 
15
  # Настройка логирования
16
  logging.basicConfig(level=logging.INFO)
17
  logger = logging.getLogger(__name__)
18
 
19
  # Инициализация бота и Flask
20
+ BOT_TOKEN = '7734802681:AAGKHGG8O9uNk64JWTHH5yqXzvSxCcoLUdA' # Замените на токен вашего бота
21
  bot = Bot(token=BOT_TOKEN)
22
  dp = Dispatcher()
23
  app = Flask(__name__)
 
25
  # Путь для хранения данных (товары и заказы)
26
  DATA_FILE = 'data.json'
27
 
28
+ # Настройки Hugging Face
29
+ REPO_ID = "flpolprojects/Clients" # Замените на ваш репозиторий
30
+ HF_TOKEN_WRITE = os.getenv("HF_TOKEN") # Установите переменную окружения HF_TOKEN
31
+ HF_TOKEN_READ = os.getenv("HF_TOKEN_READ") # Установите переменную окружения HF_TOKEN_READ
32
+
33
+ # Функция для загрузки данных из Hugging Face Hub
34
  def load_data():
35
  try:
36
+ download_db_from_hf()
37
+ with open(DATA_FILE, 'r', encoding='utf-8') as f:
38
+ return json.load(f)
39
+ except FileNotFoundError:
40
+ logger.warning("Локальный файл базы данных не найден после скачивания.")
41
+ return {'products': [], 'orders': []}
42
+ except json.JSONDecodeError:
43
+ logger.error("Ошибка при загрузке данных: Невозможно декодировать JSON файл.")
44
+ return {'products': [], 'orders': []}
45
+ except RepositoryNotFoundError:
46
+ logger.error("Репозиторий не найден. Создание локальной базы данных.")
47
  return {'products': [], 'orders': []}
48
  except Exception as e:
49
  logger.error(f"Ошибка при загрузке данных: {e}")
50
  return {'products': [], 'orders': []}
51
 
52
+ # Функция для сохранения данных в Hugging Face Hub
53
  def save_data(data):
54
  try:
55
  with open(DATA_FILE, 'w', encoding='utf-8') as f:
56
  json.dump(data, f, ensure_ascii=False, indent=4)
57
+ upload_db_to_hf()
58
  except Exception as e:
59
  logger.error(f"Ошибка при сохранении данных: {e}")
60
 
61
+ # Функция для загрузки базы данных из Hugging Face Hub
62
+ def upload_db_to_hf():
63
+ try:
64
+ api = HfApi()
65
+ api.upload_file(
66
+ path_or_fileobj=DATA_FILE,
67
+ path_in_repo=DATA_FILE,
68
+ repo_id=REPO_ID,
69
+ repo_type="dataset",
70
+ token=HF_TOKEN_WRITE,
71
+ commit_message=f"Автоматическое резервное копирование базы данных {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
72
+ )
73
+ logger.info("Резервная копия JSON базы успешно загружена на Hugging Face.")
74
+ except Exception as e:
75
+ logger.error(f"Ошибка при загрузке резервной копии: {e}")
76
+
77
+ # Функция для скачивания базы данных из Hugging Face Hub
78
+ def download_db_from_hf():
79
+ try:
80
+ hf_hub_download(
81
+ repo_id=REPO_ID,
82
+ filename=DATA_FILE,
83
+ repo_type="dataset",
84
+ token=HF_TOKEN_READ,
85
+ local_dir=".",
86
+ local_dir_use_symlinks=False
87
+ )
88
+ logger.info("JSON база успешно скачана из Hugging Face.")
89
+ except RepositoryNotFoundError as e:
90
+ logger.error(f"Репозиторий не найден: {e}")
91
+ raise
92
+ except Exception as e:
93
+ logger.error(f"Ошибка при скачивании JSON базы: {e}")
94
+ raise
95
+
96
+ # Загрузка данных
97
  data = load_data()
98
 
99
  # Клавиатуры
 
121
  await message.answer("Нет доступных товаров.")
122
  return
123
  for product in data['products']:
124
+ photo_url = f"https://huggingface.co/datasets/{REPO_ID}/resolve/main/photos/{product['photo']}" if 'photo' in product else None
125
+ caption = f"🏷 {product['name']} - {product['price']} руб.\nОписание: {product['description']}\n/id: {product['id']}"
126
+
127
+ if photo_url:
128
+ try:
129
+ await bot.send_photo(chat_id=message.chat.id, photo=photo_url, caption=caption, reply_markup=get_product_keyboard(product['id']))
130
+ except Exception as e:
131
+ logger.error(f"Ошибка при отправке фото: {e}")
132
+ await message.answer(caption, reply_markup=get_product_keyboard(product['id']))
133
+ else:
134
+ await message.answer(caption, reply_markup=get_product_keyboard(product['id']))
135
 
136
  @dp.message(F.text == "🛒 Корзина")
137
  async def show_cart(message: types.Message):
 
210
  input, textarea { width: 100%; margin: 5px 0; padding: 8px; }
211
  button { background-color: #4CAF50; color: white; padding: 10px 15px; border: none; border-radius: 5px; cursor: pointer; }
212
  button:hover { background-color: #45a049; }
213
+ img { max-width: 100px; max-height: 100px; }
214
  </style>
215
  </head>
216
  <body>
217
  <div class="container">
218
  <h1>Управление товарами</h1>
219
+ <form id="addProductForm" method="POST" enctype="multipart/form-data" action="/add_product">
220
  <input type="text" name="name" placeholder="Название" required><br>
221
  <input type="number" name="price" placeholder="Цена" step="0.01" required><br>
222
  <textarea name="description" placeholder="Описание" required></textarea><br>
223
+ <input type="file" name="photo" accept="image/*"><br>
224
  <button type="submit">Добавить товар</button>
225
  </form>
226
  <h2>Существующие товары</h2>
 
229
  <div class="product">
230
  {{ product.name }} - {{ product.price }} руб.<br>
231
  {{ product.description }}<br>
232
+ {% if product.photo %}
233
+ <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ product.photo }}" alt="{{ product.name }}">
234
+ {% endif %}
235
  <button onclick="deleteProduct({{ product.id }})">Удалить</button>
236
  </div>
237
  {% endfor %}
 
259
  {% endif %}
260
  </div>
261
  <script>
 
 
 
 
 
 
262
  async function deleteProduct(productId) {
263
  const response = await fetch(`/delete_product/${productId}`, { method: 'POST' });
264
  if (response.ok) window.location.reload();
 
272
  def admin_panel():
273
  try:
274
  logger.info("Rendering admin panel with products and orders")
275
+ return render_template_string(admin_html, products=data['products'], orders=data['orders'], repo_id=REPO_ID)
276
  except Exception as e:
277
  logger.error(f"Ошибка в шаблоне: {e}")
278
  return "Ошибка сервера. Проверь логи.", 500
 
285
  name = request.form['name']
286
  price = float(request.form['price'])
287
  description = request.form['description']
288
+ photo = request.files['photo'] # Получаем файл фотографии
289
  product_id = max((p['id'] for p in data['products']), default=0) + 1
290
+
291
+ photo_filename = None
292
+ if photo:
293
+ photo_filename = secure_filename(photo.filename)
294
+ temp_path = os.path.join(".", photo_filename) # Сохраняем временно локально
295
+ photo.save(temp_path)
296
+
297
+ try:
298
+ api = HfApi()
299
+ api.upload_file(
300
+ path_or_fileobj=temp_path,
301
+ path_in_repo=f"photos/{photo_filename}",
302
+ repo_id=REPO_ID,
303
+ repo_type="dataset",
304
+ token=HF_TOKEN_WRITE,
305
+ commit_message=f"Добавлено фото для товара {name}"
306
+ )
307
+ logger.info(f"Фото успешно загружено: {photo_filename}")
308
+ except Exception as e:
309
+ logger.error(f"Ошибка при загрузке фото: {e}")
310
+ return jsonify({'status': 'error', 'message': f'Ошибка при загрузке фото: {str(e)}'}), 500
311
+ finally:
312
+ os.remove(temp_path) # Удаляем временный файл
313
+
314
+ data['products'].append({'id': product_id, 'name': name, 'price': price, 'description': description, 'photo': photo_filename}) # Сохраняем имя файла фотографии
315
  save_data(data)
316
  return jsonify({'status': 'success'})
317
  except Exception as e:
 
336
  def run_flask():
337
  try:
338
  logger.info("Starting Flask server on port 7860")
339
+ app.run(host='0.0.0.0', port=7860, debug=True)
340
  except Exception as e:
341
  logger.error(f"Ошибка в Flask: {e}")
342
 
 
352
  except KeyboardInterrupt:
353
  logger.info("Stopping bot and Flask")
354
  finally:
355
+ flask_thread.join() # Ждём завершения потока Flask при завершении программы