from flask import Flask, render_template, request, jsonify, send_file from werkzeug.exceptions import RequestEntityTooLarge import os import json import datetime app = Flask(__name__) app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max upload # Data storage path DATA_DIR = os.path.join(os.path.dirname(__file__), 'data') os.makedirs(DATA_DIR, exist_ok=True) @app.errorhandler(RequestEntityTooLarge) def handle_file_too_large(e): return jsonify({"success": False, "message": "File too large. Maximum size is 16MB."}), 413 @app.errorhandler(404) def page_not_found(e): return render_template('index.html'), 404 @app.route('/') def index(): return render_template('index.html') @app.route('/health') def health_check(): return "OK", 200 @app.route('/api/save', methods=['POST']) def save_project(): try: data = request.json if not data: return jsonify({"success": False, "message": "No data provided"}), 400 project_name = data.get('projectName', 'untitled') # Sanitize filename safe_name = "".join([c for c in project_name if c.isalpha() or c.isdigit() or c in (' ', '-', '_')]).strip() if not safe_name: safe_name = 'untitled' filename = f"{safe_name}.json" filepath = os.path.join(DATA_DIR, filename) with open(filepath, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) return jsonify({"success": True, "message": "项目已保存", "filename": filename}) except Exception as e: return jsonify({"success": False, "message": str(e)}), 500 @app.route('/api/load', methods=['GET']) def load_projects(): try: if not os.path.exists(DATA_DIR): os.makedirs(DATA_DIR, exist_ok=True) files = [f for f in os.listdir(DATA_DIR) if f.endswith('.json')] projects = [] for f in files: filepath = os.path.join(DATA_DIR, f) try: with open(filepath, 'r', encoding='utf-8') as file: data = json.load(file) projects.append({ "filename": f, "projectName": data.get('projectName', f.replace('.json', '')), "updatedAt": datetime.datetime.fromtimestamp(os.path.getmtime(filepath)).strftime('%Y-%m-%d %H:%M:%S') }) except: continue # Sort by update time desc projects.sort(key=lambda x: x['updatedAt'], reverse=True) return jsonify({"success": True, "projects": projects}) except Exception as e: return jsonify({"success": False, "message": str(e)}), 500 @app.route('/api/load/', methods=['GET']) def load_project_detail(filename): try: # Security check if '..' in filename or not filename.endswith('.json'): return jsonify({"success": False, "message": "Invalid filename"}), 400 filepath = os.path.join(DATA_DIR, filename) if not os.path.exists(filepath): return jsonify({"success": False, "message": "File not found"}), 404 with open(filepath, 'r', encoding='utf-8') as f: data = json.load(f) return jsonify({"success": True, "data": data}) except Exception as e: return jsonify({"success": False, "message": str(e)}), 500 if __name__ == '__main__': # Use 7860 for Hugging Face Spaces default port = int(os.environ.get('PORT', 7860)) app.run(debug=True, host='0.0.0.0', port=port)