Shveiauto commited on
Commit
74e09f6
·
verified ·
1 Parent(s): 97229a9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -42
app.py CHANGED
@@ -26,7 +26,7 @@ app = Flask(__name__)
26
 
27
  DATA_FILE = 'datatestoboto.json'
28
 
29
- REPO_ID = "Kgshop/bottest"
30
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
31
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
32
 
@@ -51,7 +51,32 @@ def load_data():
51
  return loaded_data
52
  except Exception as e:
53
  logger.error(f"Ошибка при загрузке данных: {e}")
54
- return {'products': [], 'orders': [], 'categories': [], 'users': []}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  def save_data(data):
57
  try:
@@ -65,6 +90,10 @@ def upload_db_to_hf():
65
  if not HF_TOKEN_WRITE:
66
  logger.warning("HF_TOKEN_WRITE не установлен. Пропуск загрузки на Hugging Face.")
67
  return
 
 
 
 
68
  api = HfApi()
69
  api.upload_file(
70
  path_or_fileobj=DATA_FILE,
@@ -95,10 +124,7 @@ def download_db_from_hf():
95
  logger.info("База скачана из Hugging Face")
96
  except Exception as e:
97
  logger.error(f"Ошибка при скачивании: {e}")
98
- if not os.path.exists(DATA_FILE):
99
- raise
100
- else:
101
- logger.warning(f"Продолжение работы с локальной базой ({DATA_FILE}) из-за ошибки скачивания.")
102
 
103
  def start_periodic_backup():
104
  def backup_loop():
@@ -132,9 +158,10 @@ def get_product_keyboard(product_id):
132
  @dp.message(Command("start"))
133
  async def cmd_start(message: types.Message):
134
  user_id = message.from_user.id
135
- if user_id not in data['users']:
136
  data['users'].append(user_id)
137
  save_data(data)
 
138
  logger.info(f"Новый пользователь добавлен: {user_id}")
139
  await message.answer("Здравствуйте ! это магазин Routine!. Выберите действие:", reply_markup=get_main_keyboard())
140
 
@@ -151,9 +178,10 @@ async def show_products_in_category(callback_query: types.CallbackQuery):
151
  cat_id = int(callback_query.data.split('_')[1])
152
  products_in_cat = [p for p in data['products'] if p.get('category_id') == cat_id]
153
 
 
 
154
  if not products_in_cat:
155
  await bot.send_message(callback_query.from_user.id, "В этой категории нет товаров.")
156
- await bot.answer_callback_query(callback_query.id)
157
  return
158
 
159
  async def send_product_batch(products_batch):
@@ -169,36 +197,39 @@ async def show_products_in_category(callback_query: types.CallbackQuery):
169
  media_group.append(InputMediaPhoto(media=photo_url, caption=caption))
170
  else:
171
  media_group.append(InputMediaPhoto(media=photo_url))
172
- await bot.send_media_group(chat_id=callback_query.from_user.id, media=media_group)
 
 
173
  await bot.send_message(callback_query.from_user.id, "Выберите действие:", reply_markup=get_product_keyboard(product['id']))
174
  else:
175
  await bot.send_message(callback_query.from_user.id, caption, reply_markup=get_product_keyboard(product['id']))
176
  except Exception as e:
177
- logger.error(f"Ошибка при отправке медиа или сообщения: {e}")
 
178
  await bot.send_message(callback_query.from_user.id, caption, reply_markup=get_product_keyboard(product['id']))
179
 
180
- batch_size = 5
181
  for i in range(0, len(products_in_cat), batch_size):
182
  batch = products_in_cat[i:i + batch_size]
183
  await send_product_batch(batch)
184
- await asyncio.sleep(0.1)
185
 
186
- await bot.answer_callback_query(callback_query.id)
187
  except Exception as e:
188
  logger.error(f"Ошибка в show_products_in_category: {e}")
189
- await bot.answer_callback_query(callback_query.id, "Ошибка при загрузке товаров")
 
190
 
191
  @dp.message(F.text == "🛒 Корзина")
192
  async def show_cart(message: types.Message):
193
  user_id = message.from_user.id
194
- cart = next((o for o in data['orders'] if o['user_id'] == user_id and not o.get('completed')), None)
195
  if not cart or not cart['items']:
196
  await message.answer("Ваша корзина пуста.")
197
  return
198
  total = 0
199
  response = "Ваша корзина:\n"
200
  for item in cart['items']:
201
- product = next((p for p in data['products'] if p['id'] == item['product_id']), None)
202
  if product:
203
  response += f"🏷 {product['name']} - {product['price']} сом x {item['quantity']}\n"
204
  total += product['price'] * item['quantity']
@@ -229,15 +260,16 @@ async def confirm_add_to_cart(callback_query: types.CallbackQuery):
229
  parts = callback_query.data.split('_')
230
  product_id = int(parts[1])
231
  quantity = int(parts[2])
232
- product = next((p for p in data['products'] if p['id'] == product_id), None)
233
  if product:
234
  user_id = callback_query.from_user.id
235
- cart = next((o for o in data['orders'] if o['user_id'] == user_id and not o.get('completed')), None)
236
  if not cart:
237
  cart = {'user_id': user_id, 'items': [], 'date': datetime.now().isoformat(), 'completed': False}
238
  data['orders'].append(cart)
239
  cart['items'].append({'product_id': product_id, 'quantity': quantity})
240
  save_data(data)
 
241
  await bot.answer_callback_query(callback_query.id, "Товар добавлен в корзину!")
242
  else:
243
  await bot.answer_callback_query(callback_query.id, "Товар не найден")
@@ -249,12 +281,12 @@ async def confirm_add_to_cart(callback_query: types.CallbackQuery):
249
  async def complete_order(callback_query: types.CallbackQuery):
250
  try:
251
  user_id = int(callback_query.data.split('_')[1])
252
- cart = next((o for o in data['orders'] if o['user_id'] == user_id and not o.get('completed')), None)
253
  if cart and cart['items']:
254
  total = 0
255
  cart_text = "Привет, я хочу сделать заказ:\n"
256
  for item in cart['items']:
257
- product = next((p for p in data['products'] if p['id'] == item['product_id']), None)
258
  if product:
259
  cart_text += f"{product['name']} - {product['price']} сом x {item['quantity']}\n"
260
  total += product['price'] * item['quantity']
@@ -265,6 +297,8 @@ async def complete_order(callback_query: types.CallbackQuery):
265
  cart['completed'] = True
266
  cart['date'] = datetime.now().isoformat()
267
  save_data(data)
 
 
268
 
269
  await bot.send_message(user_id, f"Ваш заказ принят! Для завершения оформите его через WhatsApp:\n{whatsapp_link}")
270
  await bot.answer_callback_query(callback_query.id)
@@ -277,16 +311,24 @@ async def complete_order(callback_query: types.CallbackQuery):
277
  @dp.message(F.text == "📦 Заказы")
278
  async def show_orders(message: types.Message):
279
  user_id = message.from_user.id
280
- user_orders = [o for o in data['orders'] if o.get('completed') and o['user_id'] == user_id]
281
  if not user_orders:
282
  await message.answer("У вас нет оформленных заказов.")
283
  return
284
  response_list = ["Ваши оформленные заказы:\n"]
285
  for order in user_orders:
286
- order_text = f"--- Заказ от {datetime.fromisoformat(order['date']).strftime('%Y-%m-%d %H:%M')} ---\n"
 
 
 
 
 
 
 
 
287
  total = 0
288
  for item in order['items']:
289
- product = next((p for p in data['products'] if p['id'] == item['product_id']), None)
290
  if product:
291
  order_text += f"🏷 {product['name']} - {product['price']} сом x {item['quantity']}\n"
292
  total += product['price'] * item['quantity']
@@ -472,7 +514,7 @@ admin_html = """
472
  {% for order in completed_orders %}
473
  <div class="item">
474
  Пользователь: {{ order.user_id }}<br>
475
- Дата: {{ order.date }}<br>
476
  Товары:
477
  {% for item in order['items'] %}
478
  {% set product = products | selectattr('id', 'equalto', item.product_id) | first %}
@@ -499,7 +541,7 @@ admin_html = """
499
  {% for order in pending_orders %}
500
  <div class="item">
501
  Пользователь: {{ order.user_id }}<br>
502
- Дата создания: {{ order.date }}<br>
503
  Товары в корзине:
504
  {% for item in order['items'] %}
505
  {% set product = products | selectattr('id', 'equalto', item.product_id) | first %}
@@ -577,7 +619,7 @@ def add_product():
577
  description = request.form['description']
578
  category_id = int(request.form['category_id'])
579
  photos = request.files.getlist('photo')
580
- product_id = max((p['id'] for p in data['products']), default=0) + 1
581
 
582
  photos_filenames = []
583
  if HF_TOKEN_WRITE:
@@ -621,12 +663,13 @@ def add_product():
621
  return redirect("/")
622
  except Exception as e:
623
  logger.error(f"Ошибка при добавлении товара: {e}")
624
- return jsonify({'status': 'error', 'message': str(e)}), 500
 
625
 
626
  @app.route('/delete_product/<int:product_id>', methods=['POST'])
627
  def delete_product(product_id):
628
  try:
629
- data['products'] = [p for p in data['products'] if p['id'] != product_id]
630
  save_data(data)
631
  upload_db_to_hf()
632
  update_event.set()
@@ -639,7 +682,7 @@ def delete_product(product_id):
639
  def add_category():
640
  try:
641
  name = request.form['name']
642
- category_id = max((c['id'] for c in data['categories']), default=0) + 1
643
  data['categories'].append({'id': category_id, 'name': name})
644
  save_data(data)
645
  upload_db_to_hf()
@@ -647,12 +690,12 @@ def add_category():
647
  return redirect("/")
648
  except Exception as e:
649
  logger.error(f"Ошибка при добавлении категории: {e}")
650
- return jsonify({'status': 'error', 'message': str(e)}), 500
651
 
652
  @app.route('/delete_category/<int:category_id>', methods=['POST'])
653
  def delete_category(category_id):
654
  try:
655
- data['categories'] = [c for c in data['categories'] if c['id'] != category_id]
656
  save_data(data)
657
  upload_db_to_hf()
658
  update_event.set()
@@ -675,10 +718,12 @@ async def async_send_broadcast(bot: Bot, user_ids: list[int], text: str, media_u
675
  await asyncio.sleep(0.1)
676
  except Exception as e:
677
  failed_count += 1
 
678
  logger.error(f"Не удалось отправить объявление пользователю {user_id}: {e}")
679
  await asyncio.sleep(0.1)
680
  logger.info(f"Рассылка завершена. Успешно отправлено: {sent_count}, Ошибок: {failed_count}")
681
 
 
682
  @app.route('/send_announcement', methods=['POST'])
683
  def send_announcement():
684
  try:
@@ -689,14 +734,14 @@ def send_announcement():
689
  if not text:
690
  return jsonify({'status': 'error', 'message': 'Текст объявления обязателен'}), 400
691
 
692
- # Wait briefly for the bot to be ready
693
- if not bot_is_ready.wait(timeout=10): # Wait up to 10 seconds
694
- logger.error("Бот не стал готов в течение 10 секунд.")
695
- return jsonify({'status': 'error', 'message': 'Бот еще не готов. Попробуйте позже.'}), 503
 
 
 
696
 
697
- if asyncio_loop is None:
698
- logger.error("asyncio_loop не инициализирован после ожидания bot_is_ready.")
699
- return jsonify({'status': 'error', 'message': 'Внутренняя ошибка сервера: петля событий бота не инициализирована.'}), 500
700
 
701
  if media_file and media_file.filename:
702
  if HF_TOKEN_WRITE:
@@ -729,22 +774,21 @@ def send_announcement():
729
 
730
  user_ids_to_send = list(data.get('users', []))
731
  if user_ids_to_send:
732
- # Use call_soon_threadsafe to schedule the async function on the bot's event loop
733
  asyncio_loop.call_soon_threadsafe(
734
- asyncio_loop.create_task, # Use create_task to run the coroutine
735
  async_send_broadcast(bot, user_ids_to_send, text, media_url)
736
  )
737
  logger.info(f"Задача рассылки поставлена в очередь для {len(user_ids_to_send)} пользователей.")
738
  else:
739
  logger.warning("Нет пользователей для отправки объявления.")
740
 
741
- # Always redirect back to the admin page after processing
742
  return redirect("/")
743
 
744
  except Exception as e:
745
  logger.error(f"Ошибка при обработке запроса отправки объявления: {e}")
746
  # Redirect on unexpected errors as well
747
- return redirect("/")
 
748
 
749
  @app.route('/updates')
750
  def sse_updates():
@@ -770,6 +814,9 @@ def run_flask():
770
  app.run(host='0.0.0.0', port=7860, debug=True, use_reloader=False)
771
 
772
  if __name__ == '__main__':
 
 
 
773
  flask_thread = threading.Thread(target=run_flask, daemon=True)
774
  flask_thread.start()
775
  logger.info("Flask запущен")
 
26
 
27
  DATA_FILE = 'datatestoboto.json'
28
 
29
+ REPO_ID = "Kgshop/bottest" # Changed repository ID
30
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
31
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
32
 
 
51
  return loaded_data
52
  except Exception as e:
53
  logger.error(f"Ошибка при загрузке данных: {e}")
54
+ # If download fails AND local file doesn't exist or is corrupted, return empty structure
55
+ if not os.path.exists(DATA_FILE) or not isinstance(load_data_from_local(), dict):
56
+ return {'products': [], 'orders': [], 'categories': [], 'users': []}
57
+ else:
58
+ # If download fails but local data is usable, load local data
59
+ logger.warning("Загрузка с HF не удалась, использую локальные данные.")
60
+ return load_data_from_local()
61
+
62
+ def load_data_from_local():
63
+ try:
64
+ with open(DATA_FILE, 'r', encoding='utf-8') as f:
65
+ loaded_data = json.load(f)
66
+ if not (isinstance(loaded_data, dict) and 'products' in loaded_data and 'orders' in loaded_data):
67
+ return {'products': [], 'orders': [], 'categories': [], 'users': []}
68
+ if "categories" not in loaded_data:
69
+ loaded_data["categories"] = []
70
+ if "users" not in loaded_data:
71
+ loaded_data["users"] = []
72
+ for order in loaded_data['orders']:
73
+ if 'completed' not in order:
74
+ order['completed'] = False
75
+ return loaded_data
76
+ except Exception as e:
77
+ logger.error(f"Ошибка при загрузке локальных данных: {e}")
78
+ return {'products': [], 'orders': [], 'categories': [], 'users': []}
79
+
80
 
81
  def save_data(data):
82
  try:
 
90
  if not HF_TOKEN_WRITE:
91
  logger.warning("HF_TOKEN_WRITE не установлен. Пропуск загрузки на Hugging Face.")
92
  return
93
+ if not os.path.exists(DATA_FILE):
94
+ logger.warning(f"Файл данных {DATA_FILE} не найден. Пропуск загрузки на Hugging Face.")
95
+ return
96
+
97
  api = HfApi()
98
  api.upload_file(
99
  path_or_fileobj=DATA_FILE,
 
124
  logger.info("База скачана из Hugging Face")
125
  except Exception as e:
126
  logger.error(f"Ошибка при скачивании: {e}")
127
+ raise
 
 
 
128
 
129
  def start_periodic_backup():
130
  def backup_loop():
 
158
  @dp.message(Command("start"))
159
  async def cmd_start(message: types.Message):
160
  user_id = message.from_user.id
161
+ if user_id not in data.get('users', []):
162
  data['users'].append(user_id)
163
  save_data(data)
164
+ upload_db_to_hf() # Upload after adding a new user
165
  logger.info(f"Новый пользователь добавлен: {user_id}")
166
  await message.answer("Здравствуйте ! это магазин Routine!. Выберите действие:", reply_markup=get_main_keyboard())
167
 
 
178
  cat_id = int(callback_query.data.split('_')[1])
179
  products_in_cat = [p for p in data['products'] if p.get('category_id') == cat_id]
180
 
181
+ await bot.answer_callback_query(callback_query.id) # Answer immediately
182
+
183
  if not products_in_cat:
184
  await bot.send_message(callback_query.from_user.id, "В этой категории нет товаров.")
 
185
  return
186
 
187
  async def send_product_batch(products_batch):
 
197
  media_group.append(InputMediaPhoto(media=photo_url, caption=caption))
198
  else:
199
  media_group.append(InputMediaPhoto(media=photo_url))
200
+ if media_group: # Send media group only if there are photos
201
+ await bot.send_media_group(chat_id=callback_query.from_user.id, media=media_group)
202
+ # Always send the keyboard separately for reliability, especially with media groups
203
  await bot.send_message(callback_query.from_user.id, "Выберите действие:", reply_markup=get_product_keyboard(product['id']))
204
  else:
205
  await bot.send_message(callback_query.from_user.id, caption, reply_markup=get_product_keyboard(product['id']))
206
  except Exception as e:
207
+ logger.error(f"Ошибка при отправке медиа или сообщения для товара {product.get('id')}: {e}")
208
+ # Fallback to sending text if media fails
209
  await bot.send_message(callback_query.from_user.id, caption, reply_markup=get_product_keyboard(product['id']))
210
 
211
+ batch_size = 3 # Adjusted batch size for potentially faster sending
212
  for i in range(0, len(products_in_cat), batch_size):
213
  batch = products_in_cat[i:i + batch_size]
214
  await send_product_batch(batch)
215
+ await asyncio.sleep(0.5) # Increase sleep slightly
216
 
 
217
  except Exception as e:
218
  logger.error(f"Ошибка в show_products_in_category: {e}")
219
+ await bot.send_message(callback_query.from_user.id, "Произошла ошибка при загрузке товаров.")
220
+
221
 
222
  @dp.message(F.text == "🛒 Корзина")
223
  async def show_cart(message: types.Message):
224
  user_id = message.from_user.id
225
+ cart = next((o for o in data.get('orders', []) if o['user_id'] == user_id and not o.get('completed')), None)
226
  if not cart or not cart['items']:
227
  await message.answer("Ваша корзина пуста.")
228
  return
229
  total = 0
230
  response = "Ваша корзина:\n"
231
  for item in cart['items']:
232
+ product = next((p for p in data.get('products', []) if p['id'] == item['product_id']), None)
233
  if product:
234
  response += f"🏷 {product['name']} - {product['price']} сом x {item['quantity']}\n"
235
  total += product['price'] * item['quantity']
 
260
  parts = callback_query.data.split('_')
261
  product_id = int(parts[1])
262
  quantity = int(parts[2])
263
+ product = next((p for p in data.get('products', []) if p['id'] == product_id), None)
264
  if product:
265
  user_id = callback_query.from_user.id
266
+ cart = next((o for o in data.get('orders', []) if o['user_id'] == user_id and not o.get('completed')), None)
267
  if not cart:
268
  cart = {'user_id': user_id, 'items': [], 'date': datetime.now().isoformat(), 'completed': False}
269
  data['orders'].append(cart)
270
  cart['items'].append({'product_id': product_id, 'quantity': quantity})
271
  save_data(data)
272
+ upload_db_to_hf()
273
  await bot.answer_callback_query(callback_query.id, "Товар добавлен в корзину!")
274
  else:
275
  await bot.answer_callback_query(callback_query.id, "Товар не найден")
 
281
  async def complete_order(callback_query: types.CallbackQuery):
282
  try:
283
  user_id = int(callback_query.data.split('_')[1])
284
+ cart = next((o for o in data.get('orders', []) if o['user_id'] == user_id and not o.get('completed')), None)
285
  if cart and cart['items']:
286
  total = 0
287
  cart_text = "Привет, я хочу сделать заказ:\n"
288
  for item in cart['items']:
289
+ product = next((p for p in data.get('products', []) if p['id'] == item['product_id']), None)
290
  if product:
291
  cart_text += f"{product['name']} - {product['price']} сом x {item['quantity']}\n"
292
  total += product['price'] * item['quantity']
 
297
  cart['completed'] = True
298
  cart['date'] = datetime.now().isoformat()
299
  save_data(data)
300
+ upload_db_to_hf()
301
+
302
 
303
  await bot.send_message(user_id, f"Ваш заказ принят! Для завершения оформите его через WhatsApp:\n{whatsapp_link}")
304
  await bot.answer_callback_query(callback_query.id)
 
311
  @dp.message(F.text == "📦 Заказы")
312
  async def show_orders(message: types.Message):
313
  user_id = message.from_user.id
314
+ user_orders = [o for o in data.get('orders', []) if o.get('completed') and o['user_id'] == user_id]
315
  if not user_orders:
316
  await message.answer("У вас нет оформленных заказов.")
317
  return
318
  response_list = ["Ваши оформленные заказы:\n"]
319
  for order in user_orders:
320
+ # Safely handle potential missing 'date' key or invalid format
321
+ date_str = order.get('date', 'Неизвестная дата')
322
+ try:
323
+ date_obj = datetime.fromisoformat(date_str)
324
+ formatted_date = date_obj.strftime('%Y-%m-%d %H:%M')
325
+ except ValueError:
326
+ formatted_date = date_str
327
+
328
+ order_text = f"--- Заказ от {formatted_date} ---\n"
329
  total = 0
330
  for item in order['items']:
331
+ product = next((p for p in data.get('products', []) if p['id'] == item['product_id']), None)
332
  if product:
333
  order_text += f"🏷 {product['name']} - {product['price']} сом x {item['quantity']}\n"
334
  total += product['price'] * item['quantity']
 
514
  {% for order in completed_orders %}
515
  <div class="item">
516
  Пользователь: {{ order.user_id }}<br>
517
+ Дата: {{ order.date | default('Неизвестная дата') }}<br>
518
  Товары:
519
  {% for item in order['items'] %}
520
  {% set product = products | selectattr('id', 'equalto', item.product_id) | first %}
 
541
  {% for order in pending_orders %}
542
  <div class="item">
543
  Пользователь: {{ order.user_id }}<br>
544
+ Дата создания: {{ order.date | default('Неизвестная дата') }}<br>
545
  Товары в корзине:
546
  {% for item in order['items'] %}
547
  {% set product = products | selectattr('id', 'equalto', item.product_id) | first %}
 
619
  description = request.form['description']
620
  category_id = int(request.form['category_id'])
621
  photos = request.files.getlist('photo')
622
+ product_id = max((p['id'] for p in data.get('products', [])), default=0) + 1
623
 
624
  photos_filenames = []
625
  if HF_TOKEN_WRITE:
 
663
  return redirect("/")
664
  except Exception as e:
665
  logger.error(f"Ошибка при добавлении товара: {e}")
666
+ # Redirect on error instead of jsonify for better admin panel flow
667
+ return redirect("/")
668
 
669
  @app.route('/delete_product/<int:product_id>', methods=['POST'])
670
  def delete_product(product_id):
671
  try:
672
+ data['products'] = [p for p in data.get('products', []) if p['id'] != product_id]
673
  save_data(data)
674
  upload_db_to_hf()
675
  update_event.set()
 
682
  def add_category():
683
  try:
684
  name = request.form['name']
685
+ category_id = max((c['id'] for c in data.get('categories', [])), default=0) + 1
686
  data['categories'].append({'id': category_id, 'name': name})
687
  save_data(data)
688
  upload_db_to_hf()
 
690
  return redirect("/")
691
  except Exception as e:
692
  logger.error(f"Ошибка при добавлении категории: {e}")
693
+ return redirect("/")
694
 
695
  @app.route('/delete_category/<int:category_id>', methods=['POST'])
696
  def delete_category(category_id):
697
  try:
698
+ data['categories'] = [c for c in data.get('categories', []) if c['id'] != category_id]
699
  save_data(data)
700
  upload_db_to_hf()
701
  update_event.set()
 
718
  await asyncio.sleep(0.1)
719
  except Exception as e:
720
  failed_count += 1
721
+ # Log specific error for the user
722
  logger.error(f"Не удалось отправить объявление пользователю {user_id}: {e}")
723
  await asyncio.sleep(0.1)
724
  logger.info(f"Рассылка завершена. Успешно отправлено: {sent_count}, Ошибок: {failed_count}")
725
 
726
+
727
  @app.route('/send_announcement', methods=['POST'])
728
  def send_announcement():
729
  try:
 
734
  if not text:
735
  return jsonify({'status': 'error', 'message': 'Текст объявления обязателен'}), 400
736
 
737
+ # Check if the bot's asyncio loop is available and the bot is ready
738
+ # Increased timeout to 20 seconds as startup might take longer
739
+ if not bot_is_ready.wait(timeout=20) or asyncio_loop is None:
740
+ logger.error("Бот не стал готов в течение 20 секунд или asyncio_loop не установлен.")
741
+ # Redirect instead of jsonify for better admin panel UX on this specific error
742
+ # return jsonify({'status': 'error', 'message': 'Бот еще не готов. Попробуйте позже.'}), 503
743
+ return redirect("/?error=bot_not_ready") # Redirect and indicate error
744
 
 
 
 
745
 
746
  if media_file and media_file.filename:
747
  if HF_TOKEN_WRITE:
 
774
 
775
  user_ids_to_send = list(data.get('users', []))
776
  if user_ids_to_send:
 
777
  asyncio_loop.call_soon_threadsafe(
778
+ asyncio_loop.create_task,
779
  async_send_broadcast(bot, user_ids_to_send, text, media_url)
780
  )
781
  logger.info(f"Задача рассылки поставлена в очередь для {len(user_ids_to_send)} пользователей.")
782
  else:
783
  logger.warning("Нет пользователей для отправки объявления.")
784
 
 
785
  return redirect("/")
786
 
787
  except Exception as e:
788
  logger.error(f"Ошибка при обработке запроса отправки объявления: {e}")
789
  # Redirect on unexpected errors as well
790
+ return redirect("/?error=send_failed") # Redirect and indicate error
791
+
792
 
793
  @app.route('/updates')
794
  def sse_updates():
 
814
  app.run(host='0.0.0.0', port=7860, debug=True, use_reloader=False)
815
 
816
  if __name__ == '__main__':
817
+ # Load data initially
818
+ data = load_data() # Ensure data is loaded before starting Flask/bot
819
+
820
  flask_thread = threading.Thread(target=run_flask, daemon=True)
821
  flask_thread.start()
822
  logger.info("Flask запущен")