如何通过JavaScript发送Ajax请求调用Python机器学习脚本并获取返回结果
实现方案说明
你目前直接向.py脚本发HTTP请求的方式不可行,普通Python脚本没有处理HTTP请求的能力,Web服务器默认也不会直接执行Python脚本返回运行结果,需要给Python侧加一个轻量的Web服务层来接收请求、调用模型、返回结果,我们用最适合新手的Flask框架实现。
步骤1:安装依赖
执行以下命令安装需要的包:
pip install flask flask-cors
flask用来搭建web服务,flask-cors用来解决跨域请求问题。
步骤2:改造Python侧代码
首先优化ml.py(避免每次请求都重新训练模型)
把模型训练逻辑移到函数外,服务启动时只训练一次,后续请求直接调用,大幅提升响应速度:
import numpy as np import pandas as pd from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier # 服务启动时就加载数据、训练模型,全局只执行一次 data = pd.read_csv('/Users/Mariwa/.bitnami/stackman/machines/xampp/volumes/root/htdocs/HomeExchange/tier match/home_tier_dataset.csv') X = data.iloc[:,:-1].values Y = data.iloc[:, 18].values X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = 0.9) scaler = StandardScaler() scaler.fit(X_train) X_train = scaler.transform(X_train) classifier = KNeighborsClassifier(n_neighbors=5) classifier.fit(X_train,Y_train) def knn_prediction(features): check_value = np.array(features) # 输入特征要和训练数据一样做归一化 check_value = scaler.transform([check_value]) tier_prediction = classifier.predict(check_value) return tier_prediction[0]
改造run.py为Flask Web服务
from flask import Flask, request, jsonify from flask_cors import CORS import ml app = Flask(__name__) # 允许跨域请求 CORS(app) # 预测接口,仅接收POST请求 @app.route('/predict', methods=['POST']) def predict(): # 接收前端传的JSON数据 data = request.get_json() # 按模型要求的特征顺序把JSON值转成列表,*注意顺序要和训练用的特征完全一致* house_features = [ data['home_type'], data['residence_type'], data['bedrooms'], data['bathrooms'], data['occupancy'], data['swimming'], data['wifi'], data['tv'], data['workers'], data['wheelchair'], data['parking'], data['gym'], data['kids'], data['security'], data['garden'], data['ac'], data['pets'], data['smokers'] ] # 调用模型预测 tier = ml.knn_prediction(house_features) # 返回JSON格式结果 return jsonify({"tier": int(tier)}) if __name__ == '__main__': # 启动服务,默认端口5000 app.run(host='0.0.0.0', port=5000, debug=False)
步骤3:修改前端JS请求代码
你之前的请求头配置错误,发送JSON数据需要把Content-Type改成application/json,请求地址改成Flask服务的接口地址:
$(document).on('submit', '#form', function(e) { e.preventDefault(); e.stopPropagation(); var form_data = new FormData(this); form_data.append('subcounty', $('#subcounty_search').val()); form_data.append('area', $('#area').val()); $.ajax({ url: 'add.php', type: 'post', data: form_data, contentType: false, processData: false, cache: false, success: function(data) { var xml = new XMLHttpRequest(); // 改成你的Flask服务接口地址,本地测试就是下面这个 xml.open("POST", "http://127.0.0.1:5000/predict", true); // 这里修改请求头为JSON类型 xml.setRequestHeader("Content-type", "application/json"); xml.onload = function() { var dataReply = JSON.parse(this.responseText) // 预测结果存在dataReply.tier里 alert("预测房屋等级:" + dataReply.tier) } var dataSend = JSON.stringify({ 'home_type': $('input[name="home_type"]:checked').val(), 'residence_type': $('input[name="residence_type"]:checked').val(), 'bedrooms': $('#bedrooms').text(), 'bathrooms': $('#bathrooms').text(), 'occupancy': $('#occupancy').text(), 'swimming': encodeHomeFeatures($('input[name="swimming"]:checked').val()), 'wifi': encodeHomeFeatures($('input[name="wifi"]:checked').val()), 'tv': encodeHomeFeatures($('input[name="tv"]:checked').val()), 'workers': encodeHomeFeatures($('input[name="workers"]:checked').val()), 'wheelchair': encodeHomeFeatures($('input[name="wheelchair"]:checked').val()), 'parking': encodeHomeFeatures($('input[name="parking"]:checked').val()), 'gym': encodeHomeFeatures($('input[name="gym"]:checked').val()), 'kids': encodeHomeFeatures($('input[name="kids"]:checked').val()), 'security': encodeHomeFeatures($('input[name="security"]:checked').val()), 'garden': encodeHomeFeatures($('input[name="garden"]:checked').val()), 'ac': encodeHomeFeatures($('input[name="ac"]:checked').val()), 'pets': encodeHomeFeatures($('input[name="pets"]:checked').val()), 'smokers': encodeHomeFeatures($('input[name="smokers"]:checked').val()) }); xml.send(dataSend) } }); });
步骤4:运行测试
- 运行改造后的
run.py,启动Flask服务 - 打开前端页面提交表单,即可收到Python侧返回的预测结果
注意:部署到线上时需要把Flask改成生产模式运行,不要直接用内置的开发服务器。
内容的提问来源于stack exchange,提问作者Mariwa
相关产品推荐
相关产品推荐

