| """
|
| Standalone Flask MCP Server
|
| Extracted from streamlit.py to run as separate service
|
| """
|
| import sys
|
| import os
|
| sys.path.insert(0, '/app')
|
|
|
| from flask import Flask, request, jsonify
|
| from flask_cors import CORS
|
| import numpy as np
|
| import warnings
|
|
|
| warnings.filterwarnings('ignore')
|
|
|
|
|
| def clean_for_json(obj):
|
| """Convert numpy arrays and other non-serializable objects to JSON-safe format"""
|
| if isinstance(obj, dict):
|
| return {k: clean_for_json(v) for k, v in obj.items()}
|
| elif isinstance(obj, list):
|
| return [clean_for_json(item) for item in obj]
|
| elif isinstance(obj, np.ndarray):
|
| return obj.tolist()
|
| elif isinstance(obj, (np.integer, np.int64, np.int32)):
|
| return int(obj)
|
| elif isinstance(obj, (np.floating, np.float64, np.float32)):
|
| if np.isnan(obj) or np.isinf(obj):
|
| return 0.0
|
| return float(obj)
|
| else:
|
| return obj
|
|
|
|
|
| try:
|
| import importlib.util
|
| spec = importlib.util.spec_from_file_location("streamlit_module", "/app/streamlit.py")
|
| streamlit_module = importlib.util.module_from_spec(spec)
|
| spec.loader.exec_module(streamlit_module)
|
| TSNEExplorer = streamlit_module.TSNEExplorer
|
| except Exception as e:
|
| print(f"Error importing TSNEExplorer: {e}")
|
| TSNEExplorer = None
|
|
|
| app = Flask(__name__)
|
| CORS(app)
|
| backend = None
|
|
|
| def get_backend():
|
| global backend
|
| if backend is None and TSNEExplorer is not None:
|
| backend = TSNEExplorer()
|
| return backend
|
|
|
| @app.route('/mcp/health', methods=['GET'])
|
| def health():
|
| return jsonify({
|
| 'status': 'ok',
|
| 'service': 'mcp-server',
|
| 'message': 'MCP server running on HF Spaces'
|
| })
|
|
|
| @app.route('/mcp/generate_simplex_points', methods=['POST'])
|
| def generate_simplex_points():
|
| try:
|
| data = request.json
|
| backend = get_backend()
|
| result = backend.generate_simplex_points(
|
| int(data['n']),
|
| int(data['d']),
|
| int(data['k']),
|
| int(data.get('seed', 42))
|
| )
|
| return jsonify(clean_for_json(result))
|
| except Exception as e:
|
| return jsonify({'success': False, 'error': str(e)}), 500
|
|
|
| @app.route('/mcp/load_mnist', methods=['POST'])
|
| def load_mnist():
|
| try:
|
| data = request.json
|
| backend = get_backend()
|
| result = backend.load_mnist(
|
| int(data.get('max_samples', 1000)),
|
| data.get('subset', 'train')
|
| )
|
| return jsonify(clean_for_json(result))
|
| except Exception as e:
|
| return jsonify({'success': False, 'error': str(e)}), 500
|
|
|
| @app.route('/mcp/run_tsne', methods=['POST'])
|
| def run_tsne():
|
| try:
|
| data = request.json
|
| backend = get_backend()
|
| X = np.array(data['X'])
|
| result = backend.run_tsne(
|
| X,
|
| int(data.get('perplexity', 30)),
|
| int(data.get('learning_rate', 200)),
|
| int(data.get('n_iter', 1000)),
|
| int(data.get('early_exaggeration', 12)),
|
| float(data.get('momentum', 0.8)),
|
| int(data.get('seed', 42))
|
| )
|
| return jsonify(clean_for_json(result))
|
| except Exception as e:
|
| return jsonify({'success': False, 'error': str(e)}), 500
|
|
|
| @app.route('/mcp/run_clustering', methods=['POST'])
|
| def run_clustering():
|
| try:
|
| data = request.json
|
| backend = get_backend()
|
| Y = np.array(data['Y'])
|
| result = backend.run_clustering(
|
| Y,
|
| data.get('method', 'kmeans'),
|
| int(data.get('k', 3)),
|
| float(data.get('eps', 0.5)),
|
| int(data.get('min_samples', 5))
|
| )
|
| return jsonify(clean_for_json(result))
|
| except Exception as e:
|
| return jsonify({'success': False, 'error': str(e)}), 500
|
|
|
| if __name__ == '__main__':
|
| print('Starting Flask MCP Server on port 5000...')
|
| app.run(host='0.0.0.0', port=5000, debug=False, threaded=True)
|
|
|