diff --git "a/app.py" "b/app.py"
--- "a/app.py"
+++ "b/app.py"
@@ -1,60 +1,528 @@
+# --- START OF FILE app (1) (9).py (MODIFIED) ---
-from flask import Flask, render_template_string, request, redirect, url_for, send_file, flash, jsonify
-import json
import os
+import uuid
+from flask import Flask, request, jsonify, Response, send_from_directory
+import google.generativeai as genai
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 uuid
+import json # Added for load_app_data/save_app_data in generated app
-load_dotenv()
+# Configure logging for the main generator app
+logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
app = Flask(__name__)
-app.secret_key = 'your_unique_secret_key_soola_cosmetics_67890_no_login'
-DATA_FILE = 'data.json'
+# INTERNAL API KEY FOR THE GENERATOR ITSELF (FOR GOOGLE GEMINI)
+API_KEY_INTERNAL = "AIzaSyArKidc4o0MwbaCFKStlb2q2AwNg6Pnqns"
-SYNC_FILES = [DATA_FILE]
+# DIRECTORY FOR STORING GENERATED PYTHON FLASK APPLICATIONS
+GENERATED_APPS_DIR = 'generated_apps'
-REPO_ID = "Kgshop/balluu"
-HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
-HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
+# REPOSITORY ID FOR DATA SYNCHRONIZATION OF THE *GENERATED* FLASK APPS
+GENERATED_APP_REPO_ID = "Kgshop/testsynk"
-STORE_ADDRESS = "Рынок дордой , восток кишка , 235 контейнер "
+if not os.path.exists(GENERATED_APPS_DIR):
+ os.makedirs(GENERATED_APPS_DIR)
-CURRENCY_CODE = 'KGS'
-CURRENCY_NAME = 'Кыргызский сом'
+# HTML TEMPLATE FOR THE GENERATOR'S FRONTEND
+html_template = """
+
+
+
+
+
+ EVA - Генератор Сайтов
+
+
+
+
+
EVA
+
Генератор Python приложений на базе ИИ
-DOWNLOAD_RETRIES = 3
-DOWNLOAD_DELAY = 5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+"""
+
+# INJECTED HUGGING FACE SYNC CODE FOR THE *GENERATED* FLASK APPLICATIONS
+_GENERATED_APP_HF_SYNC_SNIPPET = """
+# --- Hugging Face Sync System for this Generated App ---
+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 dotenv import load_dotenv
+import requests
+
+# Load environment variables for this generated app instance
+load_dotenv()
+
+APP_REPO_ID = "{generated_app_repo_id}"
+APP_DATA_FILE = 'app_data.json' # Data file specific to this generated app
+APP_HF_TOKEN_WRITE = os.getenv("HF_TOKEN") # Expect HF_TOKEN to be set in environment for this app
+APP_HF_TOKEN_READ = os.getenv("HF_TOKEN_READ") # Or use APP_HF_TOKEN_WRITE if READ isn't set
+
+APP_DOWNLOAD_RETRIES = 3
+APP_DOWNLOAD_DELAY = 5
+
+# Configure logging for the generated app
+app_logger = logging.getLogger(__name__)
+app_logger.setLevel(logging.INFO)
+# Prevent adding multiple handlers if this code is reloaded/executed multiple times (e.g. in dev)
+if not app_logger.handlers:
+ handler = logging.StreamHandler()
+ formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
+ handler.setFormatter(formatter)
+ app_logger.addHandler(handler)
+
+def _app_download_db_from_hf(specific_file=None, retries=APP_DOWNLOAD_RETRIES, delay=APP_DOWNLOAD_DELAY):
+ # Ensure tokens are available
+ token_to_use = APP_HF_TOKEN_READ if APP_HF_TOKEN_READ else APP_HF_TOKEN_WRITE
+ if not token_to_use:
+ app_logger.warning("HF_TOKEN_READ/HF_TOKEN not set for generated app. Download might fail for private repos.")
+
+ files_to_download = [specific_file] if specific_file else [APP_DATA_FILE]
+ app_logger.info(f"Generated app: Attempting download for {files_to_download} from {{APP_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})...")
+ app_logger.info(f"Generated app: Downloading {{file_name}} (Attempt {{attempt + 1}}/{{retries + 1}})...")
local_path = hf_hub_download(
- repo_id=REPO_ID,
+ repo_id=APP_REPO_ID,
filename=file_name,
repo_type="dataset",
token=token_to_use,
@@ -63,50 +531,51 @@ def download_db_from_hf(specific_file=None, retries=DOWNLOAD_RETRIES, delay=DOWN
force_download=True,
resume_download=False
)
- logging.info(f"Successfully downloaded {file_name} to {local_path}.")
+ app_logger.info(f"Generated app: Successfully downloaded {{file_name}} to {{local_path}}.")
success = True
break
except RepositoryNotFoundError:
- logging.error(f"Repository {REPO_ID} not found. Download cancelled for all files.")
+ app_logger.error(f"Generated app: Repository {{APP_REPO_ID}} not found. Download cancelled for all files.")
return False
except HfHubHTTPError as e:
if e.response.status_code == 404:
- logging.warning(f"File {file_name} not found in repo {REPO_ID} (404). Skipping this file.")
+ app_logger.warning(f"Generated app: File {{file_name}} not found in repo {{APP_REPO_ID}} (404). Skipping this file.")
if attempt == 0 and not os.path.exists(file_name):
try:
- if file_name == DATA_FILE:
+ # Create an empty default JSON file if it's the data file and not found on HF
+ if file_name == APP_DATA_FILE:
with open(file_name, 'w', encoding='utf-8') as f:
- json.dump({'products': [], 'categories': [], 'orders': {}}, f)
- logging.info(f"Created empty local file {file_name} because it was not found on HF.")
+ json.dump({{}}, f) # Empty dictionary as default for app data
+ app_logger.info(f"Generated app: Created empty local file {{file_name}} because it was not found on HF.")
except Exception as create_e:
- logging.error(f"Failed to create empty local file {file_name}: {create_e}")
+ app_logger.error(f"Generated app: Failed to create empty local file {{file_name}}: {{create_e}}")
success = False
- break
+ break # Don't retry 404s for the specific file
else:
- logging.error(f"HTTP error downloading {file_name} (Attempt {attempt + 1}): {e}. Retrying in {delay}s...")
+ app_logger.error(f"Generated app: HTTP error downloading {{file_name}} (Attempt {{attempt + 1}}): {{e}}. Retrying in {{delay}}s...")
except requests.exceptions.RequestException as e:
- logging.error(f"Network error downloading {file_name} (Attempt {attempt + 1}): {e}. Retrying in {delay}s...")
+ app_logger.error(f"Generated app: Network error downloading {{file_name}} (Attempt {{attempt + 1}}): {{e}}. Retrying in {{delay}}s...")
except Exception as e:
- logging.error(f"Unexpected error downloading {file_name} (Attempt {attempt + 1}): {e}. Retrying in {delay}s...", exc_info=True)
+ app_logger.error(f"Generated app: Unexpected error downloading {{file_name}} (Attempt {{attempt + 1}}): {{e}}. Retrying in {{delay}}s...", exc_info=True)
if attempt < retries:
time.sleep(delay)
if not success:
- logging.error(f"Failed to download {file_name} after {retries + 1} attempts.")
+ app_logger.error(f"Generated app: Failed to download {{file_name}} after {{retries + 1}} attempts.")
all_successful = False
- logging.info(f"Download process finished. Overall success: {all_successful}")
+ app_logger.info(f"Generated app: Download process finished. Overall success: {{all_successful}}")
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 to Hugging Face.")
+def _app_upload_db_to_hf(specific_file=None):
+ if not APP_HF_TOKEN_WRITE:
+ app_logger.warning("Generated app: HF_TOKEN (for writing) not set. Skipping upload to Hugging Face.")
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 HF repo {REPO_ID}...")
+ files_to_upload = [specific_file] if specific_file else [APP_DATA_FILE]
+ app_logger.info(f"Generated app: Starting upload of {{files_to_upload}} to HF repo {{APP_REPO_ID}}...")
for file_name in files_to_upload:
if os.path.exists(file_name):
@@ -114,1679 +583,238 @@ def upload_db_to_hf(specific_file=None):
api.upload_file(
path_or_fileobj=file_name,
path_in_repo=file_name,
- repo_id=REPO_ID,
+ repo_id=APP_REPO_ID,
repo_type="dataset",
- token=HF_TOKEN_WRITE,
- commit_message=f"Sync {file_name} {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
+ token=APP_HF_TOKEN_WRITE,
+ commit_message=f"Sync {{file_name}} from generated app {{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}}"
)
- logging.info(f"File {file_name} successfully uploaded to Hugging Face.")
+ app_logger.info(f"Generated app: File {{file_name}} successfully uploaded to Hugging Face.")
except Exception as e:
- logging.error(f"Error uploading file {file_name} to Hugging Face: {e}")
+ app_logger.error(f"Generated app: Error uploading file {{file_name}} to Hugging Face: {{e}}")
else:
- logging.warning(f"File {file_name} not found locally, skipping upload.")
- logging.info("Finished uploading files to HF.")
+ app_logger.warning(f"Generated app: File {{file_name}} not found locally, skipping upload.")
+ app_logger.info("Generated app: Finished uploading files to HF.")
except Exception as e:
- logging.error(f"General error during Hugging Face upload initialization or process: {e}", exc_info=True)
+ app_logger.error(f"Generated app: General error during Hugging Face upload initialization or process: {{e}}", exc_info=True)
-def periodic_backup():
- backup_interval = 1800
- logging.info(f"Setting up periodic backup every {backup_interval} seconds.")
- 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 = {'products': [], 'categories': [], 'orders': {}}
+def load_app_data():
+ default_data = {{}} # AI will assume this is an empty dictionary to start with
try:
- with open(DATA_FILE, 'r', encoding='utf-8') as file:
+ with open(APP_DATA_FILE, 'r', encoding='utf-8') as file:
data = json.load(file)
- logging.info(f"Local data loaded successfully from {DATA_FILE}")
+ app_logger.info(f"Generated app: Local app data loaded successfully from {{APP_DATA_FILE}}")
if not isinstance(data, dict):
- logging.warning(f"Local {DATA_FILE} is not a dictionary. Attempting download.")
- raise FileNotFoundError
- if 'products' not in data: data['products'] = []
- if 'categories' not in data: data['categories'] = []
- if 'orders' not in data: data['orders'] = {}
+ app_logger.warning(f"Generated app: Local {{APP_DATA_FILE}} is not a dictionary. Using default empty data.")
+ return default_data
return data
- except FileNotFoundError:
- logging.warning(f"Local file {DATA_FILE} not found. Attempting download from HF.")
- except json.JSONDecodeError:
- logging.error(f"Error decoding JSON in local {DATA_FILE}. File might be corrupt. Attempting download.")
-
- if download_db_from_hf(specific_file=DATA_FILE):
+ except (FileNotFoundError, json.JSONDecodeError):
+ app_logger.warning(f"Generated app: Local file {{APP_DATA_FILE}} not found or corrupted. Using default empty data.")
+ # If file not found or corrupted, create an empty one locally
try:
- with open(DATA_FILE, 'r', encoding='utf-8') as file:
- data = json.load(file)
- logging.info(f"Data loaded successfully from {DATA_FILE} after download.")
- if not isinstance(data, dict):
- logging.error(f"Downloaded {DATA_FILE} is not a dictionary. Using default.")
- return default_data
- if 'products' not in data: data['products'] = []
- if 'categories' not in data: data['categories'] = []
- if 'orders' not in data: data['orders'] = {}
- return data
- except FileNotFoundError:
- logging.error(f"File {DATA_FILE} still not found even after download reported success. Using default.")
- return default_data
- except json.JSONDecodeError:
- logging.error(f"Error decoding JSON in downloaded {DATA_FILE}. Using default.")
- return default_data
- except Exception as e:
- logging.error(f"Unknown error loading downloaded {DATA_FILE}: {e}. Using default.", exc_info=True)
- return default_data
- else:
- logging.error(f"Failed to download {DATA_FILE} from HF after retries. Using empty default data structure.")
- if not os.path.exists(DATA_FILE):
- try:
- with open(DATA_FILE, 'w', encoding='utf-8') as f:
- json.dump(default_data, f)
- logging.info(f"Created empty local file {DATA_FILE} after failed download.")
- except Exception as create_e:
- logging.error(f"Failed to create empty local file {DATA_FILE}: {create_e}")
+ with open(APP_DATA_FILE, 'w', encoding='utf-8') as f:
+ json.dump(default_data, f)
+ app_logger.info(f"Generated app: Created empty local file {{APP_DATA_FILE}} for corrupted/missing file.")
+ except Exception as create_e:
+ app_logger.error(f"Generated app: Failed to create empty local file {{APP_DATA_FILE}}: {{create_e}}")
return default_data
-def save_data(data):
+def save_app_data(data):
try:
if not isinstance(data, dict):
- logging.error("Attempted to save invalid data structure (not a dict). Aborting save.")
+ app_logger.error("Generated app: Attempted to save invalid data structure (not a dict). Aborting save.")
return
- if 'products' not in data: data['products'] = []
- if 'categories' not in data: data['categories'] = []
- if 'orders' not in data: data['orders'] = {}
-
- with open(DATA_FILE, 'w', encoding='utf-8') as file:
+ with open(APP_DATA_FILE, 'w', encoding='utf-8') as file:
json.dump(data, file, ensure_ascii=False, indent=4)
- logging.info(f"Data successfully saved to {DATA_FILE}")
- upload_db_to_hf(specific_file=DATA_FILE)
+ app_logger.info(f"Generated app: App data successfully saved to {{APP_DATA_FILE}}")
+ _app_upload_db_to_hf(specific_file=APP_DATA_FILE)
except Exception as e:
- logging.error(f"Error saving data to {DATA_FILE}: {e}", exc_info=True)
-
-
-
-CATALOG_TEMPLATE = '''
-
-
-
-
-
- Brand_Baaluu - Каталог
-
-
-
-
-
-
-
-
-
-
-
Brand_Baaluu
-
-
-
-
-
Наш адрес: {{ store_address }}
-
-
-
- {% for category in categories %}
-
- {% endfor %}
-
-
-
-
-
-
-
- {% for product in products %}
-
- {% if product.get('is_top', False) %}
- Топ
- {% endif %}
-
- {% if product.get('photos') and product['photos']|length > 0 %}
-
- {% else %}
-
- {% endif %}
-
-
-
- {% with messages = get_flashed_messages(with_categories=true) %}
- {% if messages %}
- {% for category, message in messages %}
-
{{ message }}
- {% endfor %}
- {% endif %}
- {% endwith %}
-
-
-
Синхронизация с Датацентром
-
-
-
-
-
Резервное копирование происходит автоматически каждые 30 минут, а также после каждого сохранения данных. Используйте эти кнопки для немедленной синхронизации.
-
-
-
-
-
-
Управление категориями
-
- Добавить новую категорию
-
-
-
-
-
-
Существующие категории:
- {% if categories %}
-
- {% for category in categories %}
-
- {{ category }}
-
-
- {% endfor %}
-
- {% else %}
-
Категорий пока нет.
- {% endif %}
-
-
-
-
-
-
Информация
-
Управление пользователями отключено, так как сайт не требует входа.
-
Заказы создаются анонимно и должны быть подтверждены через WhatsApp.
- {{ product['name'] }}
- {% if product.get('in_stock', True) %}
- В наличии
- {% else %}
- Нет в наличии
- {% endif %}
- {% if product.get('is_top', False) %}
- Топ
- {% endif %}
-
- {% if product.get('photos') and product['photos']|length > 1 %}
-
(Всего фото: {{ product['photos']|length }})
- {% endif %}
-
-
-
-
-
-
-
-
-
-
Редактирование: {{ product['name'] }}
-
-
-
- {% endfor %}
-
- {% else %}
-
Товаров пока нет.
- {% endif %}
-
-
-
-
-
-
-
-'''
-
-
-
-@app.route('/')
-def catalog():
- data = load_data()
- all_products = data.get('products', [])
- categories = sorted(data.get('categories', []))
-
- products_in_stock = [p for p in all_products if p.get('in_stock', True)]
- products_sorted = sorted(products_in_stock, key=lambda p: (not p.get('is_top', False), p.get('name', '').lower()))
-
- return render_template_string(
- CATALOG_TEMPLATE,
- products=products_sorted,
- categories=categories,
- repo_id=REPO_ID,
- store_address=STORE_ADDRESS,
- currency_code=CURRENCY_CODE
- )
+def app_periodic_backup():
+ backup_interval = 1800 # 30 minutes
+ app_logger.info(f"Generated app: Setting up periodic backup every {{backup_interval}} seconds.")
+ while True:
+ time.sleep(backup_interval)
+ app_logger.info("Generated app: Starting periodic backup...")
+ _app_upload_db_to_hf(specific_file=APP_DATA_FILE)
+ app_logger.info("Generated app: Periodic backup finished.")
+# --- END Hugging Face Sync System ---
+""".format(generated_app_repo_id=GENERATED_APP_REPO_ID)
-@app.route('/product/')
-def product_detail(index):
- data = load_data()
- all_products = data.get('products', [])
- products_in_stock = [p for p in all_products if p.get('in_stock', True)]
- products_sorted = sorted(products_in_stock, key=lambda p: (not p.get('is_top', False), p.get('name', '').lower()))
+def generate_flask_app_code(user_prompt):
try:
- product = products_sorted[index]
- except IndexError:
- logging.warning(f"Attempted access to non-existent or out-of-stock product with index {index}")
- return "Товар не найден или отсутствует в наличии.", 404
-
- return render_template_string(
- PRODUCT_DETAIL_TEMPLATE,
- product=product,
- repo_id=REPO_ID,
- currency_code=CURRENCY_CODE
+ genai.configure(api_key=API_KEY_INTERNAL)
+ except Exception as e:
+ logging.error(f"Error configuring GenAI: {e}")
+ raise ValueError(f"Не удалось настроить Google AI. Проблема с конфигурацией. Ошибка: {e}")
+
+ if not user_prompt or not user_prompt.strip():
+ raise ValueError("Текстовый запрос (промпт) не может быть пустым.")
+
+ system_instruction = (
+ "You are an expert Python Flask developer. Your task is to generate the core logic "
+ "for a single-file Python Flask application based on the user's request. "
+ "The application should strictly adhere to the following:\n"
+ "1. Define a Flask application instance: `app = Flask(__name__)`.\n"
+ "2. Implement basic routes (e.g., `/`, `/add`, `/delete/`) as needed by the user's request.\n"
+ "3. Manage all application data using two provided functions: `load_app_data()` to read data "
+ " from `app_data.json`, and `save_app_data(data)` to write data back to `app_data.json`. "
+ " Assume `load_app_data()` returns an empty dictionary `{}` if the file is new or empty. "
+ " Your code should define the structure of this dictionary (e.g., `{'items': []}`).\n"
+ "4. All HTML, CSS, and JavaScript must be embedded directly within Python strings "
+ " and rendered using `render_template_string()`. Do NOT use `render_template()` with external files, "
+ " or external CSS/JS links. All visual styles should be in `