from flask import Flask, render_template, send_from_directory, jsonify, request import os import json app = Flask(__name__, static_folder='static', template_folder='templates') # Configuration for file uploads app.config['MAX_CONTENT_LENGTH'] = 2 * 1024 * 1024 # Limit upload to 2MB (JSON files shouldn't be large) # Jinja2 configuration to avoid conflict with Vue.js # Using default Jinja2 delimiters {{ }}. Vue.js will be configured to use ['${', '}'] # Project Metadata PROJECT_INFO = { "name": "Stakeholder Map Studio", "title_cn": "利益相关者地图工坊", "short_description": "可视化的利益相关者分析工具,通过权力-利益矩阵(Power-Interest Matrix)帮助团队识别关键人物并制定沟通策略。", "version": "1.1.0" } @app.route('/') def index(): return render_template('index.html', project=PROJECT_INFO) @app.route('/health') def health(): return "OK", 200 @app.route('/static/') def send_static(path): return send_from_directory('static', path) # API for importing JSON data (server-side validation example) @app.route('/api/import', methods=['POST']) def import_data(): if 'file' not in request.files: return jsonify({'error': 'No file part'}), 400 file = request.files['file'] if file.filename == '': return jsonify({'error': 'No selected file'}), 400 if file and file.filename.endswith('.json'): try: data = json.load(file) # Basic validation if not isinstance(data, list): return jsonify({'error': 'Invalid format: Root must be a list'}), 400 return jsonify({'success': True, 'data': data}) except json.JSONDecodeError: return jsonify({'error': 'Invalid JSON file'}), 400 except Exception as e: return jsonify({'error': str(e)}), 500 return jsonify({'error': 'Invalid file type'}), 400 @app.errorhandler(413) def request_entity_too_large(error): return jsonify({'error': 'File too large (Max 2MB)'}), 413 @app.errorhandler(404) def page_not_found(e): return render_template('index.html', project=PROJECT_INFO), 404 @app.errorhandler(500) def internal_server_error(e): return jsonify(error=str(e), message="Internal Server Error"), 500 if __name__ == '__main__': app.run(host='0.0.0.0', port=7860, debug=True)