diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -1,6 +1,5 @@ - -from flask import Flask, render_template_string, request, redirect, url_for, session, send_from_directory +from flask import Flask, render_template_string, request, redirect, url_for, session, send_file import json import os import logging @@ -12,97 +11,102 @@ from huggingface_hub.utils import RepositoryNotFoundError from werkzeug.utils import secure_filename app = Flask(__name__) -app.secret_key = 'your_unique_secret_key_12345' # Уникальный секретный ключ (Лучше сменить на более сложный) +app.secret_key = 'your_unique_secret_key_12345' # !!! CHANGE THIS TO A REAL SECRET KEY !!! DATA_FILE = 'data_soola.json' USERS_FILE = 'users_soola.json' -# Список файлов для синхронизации +# Список файлов для синхронизации (config.json убран) SYNC_FILES = [DATA_FILE, USERS_FILE] # Настройки Hugging Face -REPO_ID = "Kgshop/Soola" # Рекомендуется сменить на репозиторий для Soola Cosmetics +REPO_ID = "Kgshop/Soola" # Or change to your new repo ID like "YourUsername/SoolaCosmetics" HF_TOKEN_WRITE = os.getenv("HF_TOKEN") HF_TOKEN_READ = os.getenv("HF_TOKEN_READ") -# Адрес магазина +# Адрес магазина (теперь один) STORE_ADDRESS = "Рынок Дордой, Джунхай, терминал, 38" -# Валюта (только сом) -CURRENCY_SYMBOL = 'с' -CURRENCY_CODE = 'KGS' - # Настройка логирования -logging.basicConfig(level=logging.DEBUG) +logging.basicConfig(level=logging.INFO) # Changed to INFO for less noise, set to DEBUG if needed + +# --- Removed load_config, save_config, convert_price --- def load_data(): - """Загрузка данных о товарах и категориях.""" + """Загрузка данных товаров и категорий.""" try: - # Попытка скачать актуальные данные перед загрузкой + # Attempt to download first to get the latest version try: - download_db_from_hf() - except Exception as e: - logging.warning(f"Не удалось скачать данные с Hugging Face при запуске: {e}. Используется локальная копия.") + download_db_from_hf(DATA_FILE) + except Exception as download_error: + logging.warning(f"Не удалось скачать {DATA_FILE} с HF, используется локальная версия (если есть): {download_error}") + + if not os.path.exists(DATA_FILE): + logging.warning(f"Локальный файл {DATA_FILE} не найден. Создание пустой структуры.") + return {'products': [], 'categories': []} with open(DATA_FILE, 'r', encoding='utf-8') as file: data = json.load(file) - logging.info("Данные успешно загружены из JSON") - # Проверка структуры данных - if not isinstance(data, dict): - # Если старый формат (просто список продуктов), преобразуем - if isinstance(data, list): - return {'products': data, 'categories': []} - else: - return {'products': [], 'categories': []} - if 'products' not in data: + logging.info(f"Данные успешно загружены из {DATA_FILE}") + if not isinstance(data, dict) or 'products' not in data or 'categories' not in data: + logging.warning(f"Структура файла {DATA_FILE} некорректна. Сброс к пустой структуре.") + return {'products': [], 'categories': []} + # Ensure products and categories are lists + if not isinstance(data.get('products'), list): data['products'] = [] - if 'categories' not in data: + if not isinstance(data.get('categories'), list): data['categories'] = [] return data except FileNotFoundError: - logging.warning(f"{DATA_FILE} не найден. Создание пустой структуры данных.") + logging.warning(f"Локальный файл {DATA_FILE} не найден. Создание пустой структуры.") return {'products': [], 'categories': []} except json.JSONDecodeError: logging.error(f"Ошибка: Невозможно декодировать JSON файл {DATA_FILE}.") + # Consider backing up the corrupted file here if needed return {'products': [], 'categories': []} except Exception as e: - logging.error(f"Произошла непредвиденная ошибка при загрузке данных: {e}") + logging.error(f"Произошла ошибка при загрузке данных {DATA_FILE}: {e}") return {'products': [], 'categories': []} - def save_data(data): - """Сохранение данных о товарах и категориях.""" + """Сохранение данных товаров и категорий.""" try: with open(DATA_FILE, 'w', encoding='utf-8') as file: json.dump(data, file, ensure_ascii=False, indent=4) logging.info(f"Данные успешно сохранены в {DATA_FILE}") - # Загружаем на HF после сохранения - upload_db_to_hf(DATA_FILE) + upload_db_to_hf(DATA_FILE) # Upload specific file except Exception as e: logging.error(f"Ошибка при сохранении данных в {DATA_FILE}: {e}") - # Не прерываем работу приложения, но логируем ошибку - # raise # Можно раскомментировать, если критично прерывать работу при ошибке сохранения + # Optionally re-raise or handle more gracefully + # raise def load_users(): """Загрузка данных пользователей.""" try: - # Попытка скачать актуальные данные перед загрузкой + # Attempt to download first try: - download_db_from_hf() - except Exception as e: - logging.warning(f"Не удалось скачать данные пользователей с Hugging Face при запуске: {e}. Используется локальная копия.") + download_db_from_hf(USERS_FILE) + except Exception as download_error: + logging.warning(f"Не удалось скачать {USERS_FILE} с HF, используется локальная версия (если есть): {download_error}") + + if not os.path.exists(USERS_FILE): + logging.warning(f"Локальный файл {USERS_FILE} не найден. Создание пустого словаря.") + return {} with open(USERS_FILE, 'r', encoding='utf-8') as file: users = json.load(file) - logging.info("Данные пользователей успешно загружены") - return users if isinstance(users, dict) else {} + logging.info(f"Данные пользователей успешно загружены из {USERS_FILE}") + if not isinstance(users, dict): + logging.warning(f"Структура файла {USERS_FILE} некорректна. Сброс к пустому словарю.") + return {} + return users except FileNotFoundError: - logging.warning(f"{USERS_FILE} не найден. Возвращен пустой словарь пользователей.") + logging.warning(f"Локальный файл {USERS_FILE} не найден. Создание пустого словаря.") return {} except json.JSONDecodeError: logging.error(f"Ошибка: Невозможно декодировать JSON файл {USERS_FILE}.") return {} except Exception as e: - logging.error(f"Произошла непредвиденная ошибка при загрузке пользователей: {e}") + logging.error(f"Произошла ошибка при загрузке данных {USERS_FILE}: {e}") return {} def save_users(users): @@ -111,83 +115,80 @@ def save_users(users): with open(USERS_FILE, 'w', encoding='utf-8') as file: json.dump(users, file, ensure_ascii=False, indent=4) logging.info(f"Данные пользователей успешно сохранены в {USERS_FILE}") - # Загружаем на HF после сохранения - upload_db_to_hf(USERS_FILE) + upload_db_to_hf(USERS_FILE) # Upload specific file except Exception as e: - logging.error(f"Ошибка при сохранении данных пользователей в {USERS_FILE}: {e}") + logging.error(f"Ошибка при сохранении данных в {USERS_FILE}: {e}") + # Optionally re-raise or handle more gracefully + # raise -def upload_db_to_hf(filename_to_upload=None): - """Загрузка файлов на Hugging Face. Если filename_to_upload не указан, загружает все файлы из SYNC_FILES.""" +def upload_db_to_hf(file_to_upload=None): + """Загрузка указанного файла или всех SYNC_FILES на Hugging Face.""" if not HF_TOKEN_WRITE: - logging.warning("HF_TOKEN (токен для записи) не установлен. Загрузка на Hugging Face отключена.") + logging.warning("HF_TOKEN (write) не установлен. Загрузка на Hugging Face отключена.") return try: api = HfApi() - files_to_sync = [filename_to_upload] if filename_to_upload else SYNC_FILES + files_to_process = [file_to_upload] if file_to_upload else SYNC_FILES - for file_name in files_to_sync: + for file_name in files_to_process: if os.path.exists(file_name): - try: - api.upload_file( - path_or_fileobj=file_name, - path_in_repo=file_name, - repo_id=REPO_ID, - repo_type="dataset", - token=HF_TOKEN_WRITE, - commit_message=f"Автоматическое резервное копирование {file_name} {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" - ) - logging.info(f"Резервная копия {file_name} успешно загружена на Hugging Face.") - except Exception as e: - logging.error(f"Ошибка при загрузке файла {file_name} на Hugging Face: {e}") + logging.info(f"Попытка загрузки {file_name} на Hugging Face...") + api.upload_file( + path_or_fileobj=file_name, + path_in_repo=file_name, + repo_id=REPO_ID, + repo_type="dataset", + token=HF_TOKEN_WRITE, + commit_message=f"Автоматическое резервное копирование файла {file_name} {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" + ) + logging.info(f"Резервная копия {file_name} успешно загружена на Hugging Face.") else: - logging.warning(f"Файл {file_name} не найден для загрузки на Hugging Face.") + logging.warning(f"Файл {file_name} не найден для загрузки.") except Exception as e: - logging.error(f"Общая ошибка при инициализации или загрузке на Hugging Face: {e}") - -def download_db_from_hf(): - """Скачивание файлов с Hugging Face.""" - if not HF_TOKEN_READ and not HF_TOKEN_WRITE: - logging.warning("HF_TOKEN_READ и HF_TOKEN (токен для чтения/записи) не установлены. Скачивание с Hugging Face отключено.") - return + logging.error(f"Ошибка при загрузке резервной копии на Hugging Face: {e}") - # Используем токен для записи, если токен для чтения не задан - token_to_use = HF_TOKEN_READ if HF_TOKEN_READ else HF_TOKEN_WRITE +def download_db_from_hf(file_to_download=None): + """Скачивание указанного файла или всех SYNC_FILES с Hugging Face.""" + if not HF_TOKEN_READ: + logging.warning("HF_TOKEN_READ не установлен. Скачивание с Hugging Face может быть недоступно для приватных репозиториев.") + # Allow public repo download attempt even without read token + # return # Uncomment this line if read token is strictly required try: - api = HfApi() # Api() не используется для скачивания, но можно оставить для единообразия - for file_name in SYNC_FILES: - try: - hf_hub_download( - repo_id=REPO_ID, - filename=file_name, - repo_type="dataset", - token=token_to_use, - local_dir=".", - local_dir_use_symlinks=False, # Важно для корректной перезаписи - force_download=True # Принудительно скачивать, чтобы получить свежую версию - ) - logging.info(f"Файл {file_name} успешно скачан из Hugging Face.") - except RepositoryNotFoundError: - logging.error(f"Репозиторий {REPO_ID} не найден на Hugging Face. Скачивание {file_name} невозможно.") - # Не прерываем скачивание остальных файлов - except Exception as e: # Ловим более конкретные ошибки по файлам - # Проверяем, является ли ошибка 'Not Found' (файл не существует в репо) - if "404 Client Error" in str(e) or "EntryNotFoundError" in str(e): - logging.warning(f"Файл {file_name} не найден в репозитории {REPO_ID}. Пропускаем скачивание.") - else: - logging.error(f"Ошибка при скачивании файла {file_name} из Hugging Face: {e}") - - except Exception as e: # Общая ошибка на уровне всего процесса скачивания - logging.error(f"Общая ошибка при скачивании файлов с Hugging Face: {e}") - # Не прерываем работу приложения, но логируем - # raise # Можно раскомментировать, если критично прервать работу при ошибке скачивания + api = HfApi() # Not strictly needed for download, but hf_hub_download uses underlying logic + files_to_process = [file_to_download] if file_to_download else SYNC_FILES + + for file_name in files_to_process: + logging.info(f"Попытка скачивания {file_name} из Hugging Face...") + hf_hub_download( + repo_id=REPO_ID, + filename=file_name, + repo_type="dataset", + token=HF_TOKEN_READ, # Pass None if not set, might work for public repos + local_dir=".", + local_dir_use_symlinks=False, + force_download=True # Ensure we get the latest version over local cache + ) + logging.info(f"Файл {file_name} успешно скачан из Hugging Face.") + except RepositoryNotFoundError as e: + logging.error(f"Репозиторий {REPO_ID} не найден на Hugging Face: {e}") + # Don't raise here, allow using local files if repo not found + except Exception as e: + # Catch other potential download errors (network issues, file not found in repo, etc.) + logging.error(f"Ошибка при скачивании файла {file_name if file_name else 'files'} с Hugging Face: {e}") + # Don't raise, let the app try to use local files def periodic_backup(): """Периодическая загрузка всех файлов на Hugging Face.""" while True: - time.sleep(800) # 13 минут 20 секунд + time.sleep(800) # Wait first logging.info("Запуск периодического резервного копирования...") - upload_db_to_hf() # Загружаем все файлы + # Load current data before backup? Maybe not necessary, just upload existing files. + upload_db_to_hf() # Upload all sync files + +# Initial load on startup +load_data() +load_users() @app.route('/') def catalog(): @@ -202,26 +203,27 @@ def catalog():
-{{ product['description'][:100] }}{% if product['description']|length > 100 %}...{% endif %}
-{{ product['description'] }}
+Товары пока не добавлены.
- {% endif %} +