diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -1,3 +1,4 @@ + import os import io import base64 @@ -17,7 +18,7 @@ import requests load_dotenv() -app = Flask(name) +app = Flask(__name__) app.secret_key = 'your_unique_secret_key_gippo_312_shop_54321_no_login_synkris' DATA_FILE = 'data.json' DATA_FILE_TEMP = 'data.json.tmp' @@ -34,451 +35,428 @@ 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: -return False -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 -all_successful = True -for file_name in files_to_download: -success = False -for attempt in range(retries + 1): -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, -resume_download=False -) -success = True -break -except RepositoryNotFoundError: -all_successful = False -break -except HfHubHTTPError as e: -if e.response.status_code == 404: -if attempt == 0 and not os.path.exists(file_name): -try: -if file_name == DATA_FILE: -with open(file_name, 'w', encoding='utf-8') as f: -json.dump({}, f) -except Exception: -pass -success = True -break -else: -pass -except Exception: -pass -if attempt < retries: -time.sleep(delay) -if not success: -all_successful = False -return all_successful + if not HF_TOKEN_READ and not HF_TOKEN_WRITE: + return False + 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 + all_successful = True + for file_name in files_to_download: + success = False + for attempt in range(retries + 1): + 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, + resume_download=False + ) + success = True + break + except RepositoryNotFoundError: + all_successful = False + break + except HfHubHTTPError as e: + if e.response.status_code == 404: + if attempt == 0 and not os.path.exists(file_name): + try: + if file_name == DATA_FILE: + with open(file_name, 'w', encoding='utf-8') as f: + json.dump({}, f) + except Exception: + pass + success = True + break + else: + pass + except Exception: + pass + if attempt < retries: + time.sleep(delay) + if not success: + all_successful = False + return all_successful def upload_db_to_hf(specific_file=None): -if not HF_TOKEN_WRITE: -return -try: -api = HfApi() -files_to_upload = [specific_file] if specific_file else SYNC_FILES -for file_name in files_to_upload: -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"Sync {file_name} {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" -) -except Exception: -pass -except Exception: -pass + if not HF_TOKEN_WRITE: + return + try: + api = HfApi() + files_to_upload = [specific_file] if specific_file else SYNC_FILES + for file_name in files_to_upload: + 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"Sync {file_name} {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" + ) + except Exception: + pass + except Exception: + pass def periodic_backup(): -backup_interval = 1800 -while True: -time.sleep(backup_interval) -upload_db_to_hf() + backup_interval = 1800 + while True: + time.sleep(backup_interval) + upload_db_to_hf() def load_data(): -data = {} -if os.path.exists(DATA_FILE): -try: -with open(DATA_FILE, 'r', encoding='utf-8') as f: -data = json.load(f) -except json.JSONDecodeError: -if download_db_from_hf(specific_file=DATA_FILE): -try: -with open(DATA_FILE, 'r', encoding='utf-8') as f: -data = json.load(f) -except (FileNotFoundError, json.JSONDecodeError): -data = {} -elif download_db_from_hf(specific_file=DATA_FILE): -try: -with open(DATA_FILE, 'r', encoding='utf-8') as f: -data = json.load(f) -except (FileNotFoundError, json.JSONDecodeError): -data = {} - -code -Code -download -content_copy -expand_less -if not isinstance(data, dict): data = {} -return data + if os.path.exists(DATA_FILE): + try: + with open(DATA_FILE, 'r', encoding='utf-8') as f: + data = json.load(f) + except json.JSONDecodeError: + if download_db_from_hf(specific_file=DATA_FILE): + try: + with open(DATA_FILE, 'r', encoding='utf-8') as f: + data = json.load(f) + except (FileNotFoundError, json.JSONDecodeError): + data = {} + elif download_db_from_hf(specific_file=DATA_FILE): + try: + with open(DATA_FILE, 'r', encoding='utf-8') as f: + data = json.load(f) + except (FileNotFoundError, json.JSONDecodeError): + data = {} + + if not isinstance(data, dict): + data = {} + return data def save_data(data): -try: -with open(DATA_FILE_TEMP, 'w', encoding='utf-8') as file: -json.dump(data, file, ensure_ascii=False, indent=4) -os.replace(DATA_FILE_TEMP, DATA_FILE) -upload_db_to_hf(specific_file=DATA_FILE) -except Exception: -if os.path.exists(DATA_FILE_TEMP): -os.remove(DATA_FILE_TEMP) + try: + with open(DATA_FILE_TEMP, 'w', encoding='utf-8') as file: + json.dump(data, file, ensure_ascii=False, indent=4) + os.replace(DATA_FILE_TEMP, DATA_FILE) + upload_db_to_hf(specific_file=DATA_FILE) + except Exception: + if os.path.exists(DATA_FILE_TEMP): + os.remove(DATA_FILE_TEMP) LANDING_PAGE_TEMPLATE = ''' - - - - - MetaStore - AI система для Вашего Бизнеса - + + + MetaStore - AI система для Вашего Бизнеса + - + ''' - ADMHOSTO_TEMPLATE = ''' - - - - -Админ-панель - - - + .env-type-badge { font-size: 0.75rem; padding: 3px 8px; border-radius: 20px; font-weight: bold; text-transform: uppercase; white-space: nowrap; } + .type-open { background-color: #d4edda; color: #155724; } + .type-closed { background-color: #f8d7da; color: #721c24; } + + .env-actions { display: flex; flex-wrap: wrap; gap: 8px; } + + .message { padding: 12px; border-radius: 8px; margin-bottom: 20px; text-align: center; font-size: 0.95rem; } + .message.success { background-color: #d4edda; color: #155724; } + .message.error { background-color: #f8d7da; color: #721c24; } + + .modal { display: none; position: fixed; z-index: 2000; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.6); backdrop-filter: blur(2px); } + .modal-content { background-color: #fff; margin: 15% auto; padding: 25px; width: 90%; max-width: 600px; border-radius: 12px; position: relative; box-shadow: 0 5px 20px rgba(0,0,0,0.2); } + .close-modal { color: #888; position: absolute; right: 15px; top: 10px; font-size: 30px; font-weight: bold; cursor: pointer; padding: 5px; } + .stats-table { width: 100%; border-collapse: collapse; margin-top: 15px; font-size: 0.85rem; } + .stats-table th, .stats-table td { border: 1px solid #eee; padding: 10px 8px; text-align: left; } + .stats-table th { background-color: var(--bg-medium); color: white; } + .stats-table tr:nth-child(even) { background-color: #f9f9f9; } + + .empty-list-placeholder { text-align:center; padding: 20px; color: #888; } + .no-margin { margin-bottom: 0; } + + @media (max-width: 768px) { + .env-item { grid-template-columns: 1fr; gap: 12px; } + .env-actions { justify-content: flex-start; } + .modal-content { margin: 10% auto; width: 95%; padding: 20px 15px; } + } + + @media (max-width: 600px) { + body { padding: 10px; } + .container { padding: 15px; } + h1 { font-size: 1.3rem; margin-bottom: 20px; } + + .controls-row { flex-direction: column; align-items: stretch; } + .radio-group { justify-content: space-between; background: #fff; padding: 10px; border-radius: 8px; border: 1px solid #ddd; } + .add-env-form .button { width: 100%; padding: 14px; } + + .stats-table th, .stats-table td { font-size: 0.75rem; padding: 6px 4px; } + } + -
-

Управление Средами

-{% with messages = get_flashed_messages(with_categories=true) %} -{% if messages %} -{% for category, message in messages %} -
{{ message }}
-{% endfor %} -{% endif %} -{% endwith %} - -code -Code -download -content_copy -expand_less -
-
- -
-
- - -
- -
-
-
- -
- -
- -
- {% if active_environments %} - - {% else %} -
Список активных сред пуст
- {% endif %} -
+ +
+ +
+ +
+ +
+ {% if active_environments %} + + {% else %} +
Список активных сред пуст
+ {% endif %} +
-
-

Архив

- {% if archived_environments %} - - {% else %} -
Архив пуст
- {% endif %} +
+
+ +
+
+ + {% endfor %} + + {% else %} +
Архив пуст
+ {% endif %} +
- -