from flask import Flask, render_template_string, request, redirect, url_for, flash import json import os import logging import threading import time from datetime import datetime from huggingface_hub import HfApi, hf_hub_download from huggingface_hub.utils import RepositoryNotFoundError, HfHubHTTPError from werkzeug.utils import secure_filename from dotenv import load_dotenv import requests import io load_dotenv() app = Flask(__name__) app.secret_key = 'raina_hvac_secret_key_v2_projects_dynamic' DATA_FILE = 'data.json' SYNC_FILES = [DATA_FILE] REPO_ID = "Kgshop/raina" HF_TOKEN_WRITE = os.getenv("HF_TOKEN") HF_TOKEN_READ = os.getenv("HF_TOKEN_READ") CONTACT_PHONE = "+996 773 901 313" WHATSAPP_PHONE = "996773901313" DOWNLOAD_RETRIES = 3 DOWNLOAD_DELAY = 5 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') def download_db_from_hf(specific_file=None, retries=DOWNLOAD_RETRIES, delay=DOWNLOAD_DELAY): if not HF_TOKEN_READ and not HF_TOKEN_WRITE: logging.warning("HF_TOKEN_READ/HF_TOKEN_WRITE not set. Download might fail for private repos.") token_to_use = HF_TOKEN_READ if HF_TOKEN_READ else HF_TOKEN_WRITE files_to_download = [specific_file] if specific_file else SYNC_FILES logging.info(f"Attempting download for {files_to_download} from {REPO_ID}...") all_successful = True for file_name in files_to_download: success = False for attempt in range(retries + 1): try: logging.info(f"Downloading {file_name} (Attempt {attempt + 1}/{retries + 1})...") 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, resume_download=False ) logging.info(f"Successfully downloaded {file_name}.") success = True break except RepositoryNotFoundError: logging.error(f"Repository {REPO_ID} not found. Download cancelled.") return False except HfHubHTTPError as e: if e.response.status_code == 404: logging.warning(f"File {file_name} not found in repo {REPO_ID}. Creating empty local file.") if not os.path.exists(file_name): try: with open(file_name, 'w', encoding='utf-8') as f: json.dump({'equipment': [], 'categories': [], 'services': [], 'projects': [], 'settings': {'prices_enabled': True}}, f) except Exception as create_e: logging.error(f"Failed to create empty local file {file_name}: {create_e}") success = True break else: logging.error(f"HTTP error downloading {file_name}: {e}. Retrying...") except Exception as e: logging.error(f"Unexpected error downloading {file_name}: {e}. Retrying...", exc_info=True) if attempt < retries: time.sleep(delay) if not success: logging.error(f"Failed to download {file_name} after {retries + 1} attempts.") all_successful = False return all_successful def upload_db_to_hf(specific_file=None): if not HF_TOKEN_WRITE: logging.warning("HF_TOKEN (for writing) not set. Skipping upload.") return try: api = HfApi() files_to_upload = [specific_file] if specific_file else SYNC_FILES logging.info(f"Starting upload of {files_to_upload} to {REPO_ID}...") for file_name in files_to_upload: if os.path.exists(file_name): 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"Sync {file_name} {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" ) logging.info(f"File {file_name} successfully uploaded.") else: logging.warning(f"File {file_name} not found locally, skipping upload.") except Exception as e: logging.error(f"Error during Hugging Face upload: {e}", exc_info=True) def periodic_backup(): backup_interval = 1800 while True: time.sleep(backup_interval) logging.info("Starting periodic backup...") upload_db_to_hf() logging.info("Periodic backup finished.") def load_data(): default_data = {'equipment': [], 'categories': [], 'services': [], 'projects': [], 'settings': {'prices_enabled': True}} try: with open(DATA_FILE, 'r', encoding='utf-8') as file: data = json.load(file) if not isinstance(data, dict): raise ValueError("Data is not a dictionary") if 'equipment' not in data: data['equipment'] = [] if 'categories' not in data: data['categories'] = [] if 'services' not in data: data['services'] = [] if 'projects' not in data: data['projects'] = [] if 'settings' not in data: data['settings'] = {'prices_enabled': True} if 'prices_enabled' not in data['settings']: data['settings']['prices_enabled'] = True return data except (FileNotFoundError, json.JSONDecodeError, ValueError): logging.warning(f"Local file {DATA_FILE} not found or corrupt. Attempting download.") if download_db_from_hf(specific_file=DATA_FILE): return load_data() return default_data def save_data(data): try: if not isinstance(data, dict): logging.error("Attempted to save invalid data structure. Aborting.") return with open(DATA_FILE, 'w', encoding='utf-8') as file: json.dump(data, file, ensure_ascii=False, indent=4) logging.info(f"Data saved to {DATA_FILE}") upload_db_to_hf(specific_file=DATA_FILE) except Exception as e: logging.error(f"Error saving data: {e}", exc_info=True) LANDING_TEMPLATE = '''
Мы предлагаем комплексный подход к созданию идеального микроклимата в ваших помещениях, обеспечивая высочайшее качество услуг и продукции.
Получить консультациюНаша команда состоит из высококвалифицированных инженеров и техников, обладающих глубокими знаниями и опытом в области HVAC. Мы постоянно совершенствуем свои навыки и внедряем передовые технологии.
Мы стремимся создавать оптимальный микроклимат для каждого клиента, обеспечивая комфорт, здоровье и высокую производительность через надежные и энергоэффективные климатические системы.
Точные расчеты, 3D-модели и вся необходимая проектная документация для ваших систем.
Профессиональная установка всех типов систем вентиляции и кондиционирования, от бытовых до промышленных.
Плановое техническое обслуживание и оперативный аварийный ремонт для бесперебойной работы ваших систем.
Повышение энергоэффективности и снижение эксплуатационных расходов за счет оптимизации существующих систем.
{{ service.description }}
Информация об услугах "под ключ" скоро появится на сайте.
{% endif %}
{% endif %}
{{ "%.2f"|format(item.price) }} KGS
Запросить {% else %}Уточнить цену
Уточнить цену {% endif %}Каталог оборудования скоро будет доступен.
{% endif %}Свяжитесь с нами для профессиональной консультации и подбора оптимального климатического решения для вашего объекта.
Телефон: {{ contact_phone }}
Написать в WhatsAppРеквизиты: ОсОО «Раина Климат Систем», ИНН: 00812202110194, ОКПО: 31290279
{{ project.title }}: {{ project.description }}
{% if project.photo %}{{ service.title }}: {{ service.description }}
{% if service.photo %}{{ item.name }} ({{ item.category }}) - {{ "%.2f"|format(item.price) }} KGS
{% if item.photo %}