はじめに
前回の記事で、KaggleのHouse Sales in King County, USAのデータセットを使って、XGboost機械学習で学習モデルを生成して、その学習モデルをFlaskでAPIサーバーにするというのをやりました。今回は、そのAPIサーバー使って、HTMLからJSONでAjax通信するまでの手順を説明しています。機械学習で学習したモデルをAPIサーバーにするまでの手順は以下の記事を参考にしてみてください。
KaggleのHouse Sales in King County, USAのデータセットを使って、機械学習を行い、APIサーバーにするまでの手順
Ajax通信
ここでは、HTMLからjavascriptのAjaxで通信できるようにするために、Flaskで書いた、APIサーバーの起動ファイルを以下のように追記する必要があります。追記するのは、flask_corsというライブラリとそれに関連するコードです。flask_corsは事前にインストールしてある必要があります。
import json
from flask import Flask
from flask import request
from flask import abort
from flask_httpauth import HTTPBasicAuth
from flask_cors import CORS #追加する
import pandas as pd
from sklearn.externals import joblib
import xgboost as xgb
model = joblib.load("house_sales_model.pkl")
app = Flask(__name__)
# 追加
@app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
return response
# ↑ここまでを追加
# BasicAuth
auth = HTTPBasicAuth()
users = {
"username1": "password1",
"username2": "password2"
}
@auth.get_password
def get_pw(username):
if username in users:
return users.get(username)
return None
# Get headers for payload
headers = ['sqft_living','sqft_above','sqft_basement','lat','long','sqft_living15','grade_3','grade_4','grade_5','grade_6','grade_7','grade_8','grade_9','grade_10','grade_11','grade_12']
@app.route('/house_sails', methods=['POST'])
# BasicAuth
@auth.login_required
def housesails():
if not request.json:
abort(400)
payload = request.json['data']
values = [float(i) for i in payload.split(',')]
data1 = pd.DataFrame([values], columns=headers, dtype=float)
predict = model.predict(xgb.DMatrix(data1))
return json.dumps(str(predict[0]))
if __name__ == "__main__":
app.run(debug=True, port=5000)
HTMLからPOSTをしてJSONデータをAPIサーバーに送信する
HTMLファイルは、インターフェイスの部分はタグ内のinputタグなどで、データの入力フォームを作ります。その入力データをjavascriptで受け取って、整形し、JSON形式に変換して、Ajax通信でPOSTしています。通信が成功したら、APIサーバーからの予測値を受け取り、それをtextareaタグのエリア内に表示するという処理をしています。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HTMLファイルからPOSTでJSONデータを送信する</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>HTMLファイルからPOSTでJSONデータを送信する</h1>
<div class="alert alert-primary" role="alert">
<p>URL: <input type="text" id="url_post" name="url" class="form-control" size="100" value="http://localhost:5000/house_sails"></p>
</div>
<div class="d-flex bd-highlight">
<div class="flex-fill bd-highlight alert alert-primary mr-3" role="alert">
<p>sqft_living: <input type="number" id="value1" class="form-control" size="30" value=-1.026685></p>
</div>
<div class="flex-fill bd-highlight alert alert-primary mr-3" role="alert">
<p>sqft_above: <input type="number" id="value2" class="form-control" size="30" value=-0.725963></p>
</div>
<div class="flex-fill bd-highlight alert alert-primary" role="alert">
<p>sqft_basement: <input type="number" id="value3" class="form-control" size="30" value=-0.652987></p>
</div>
</div>
<div class="d-flex bd-highlight">
<div class="flex-fill bd-highlight alert alert-primary mr-3" role="alert">
<p>lat: <input type="number" id="value4" class="form-control" size="30" value=-0.323607></p>
</div>
<div class="flex-fill bd-highlight alert alert-primary mr-3" role="alert">
<p>long: <input type="number" id="value5" class="form-control" size="30" value=-0.307144></p>
</div>
<div class="flex-fill bd-highlight alert alert-primary" role="alert">
<p>sqft_living15: <input type="number" id="value6" class="form-control" size="30" value=-0.946801></p>
</div>
</div>
<div class="alert alert-primary" role="alert">
<p>gradeを選択:
<select name="grade" id="grade" class="form-control form-control-lg">
<option value="grade1">grade1</option>
<option value="grade2">grade2</option>
<option value="grade3">grade3</option>
<option value="grade4">grade4</option>
<option value="grade5">grade5</option>
<option value="grade6">grade6</option>
<option value="grade7">grade7</option>
<option value="grade8">grade8</option>
<option value="grade9">grade9</option>
<option value="grade10">grade10</option>
<option value="grade11">grade11</option>
<option value="grade12">grade12</option>
</select>
</p>
</div>
<p>usename: <input type="text" name="username" id="username" class="form-control" value="bitstudio"/></p>
<p>password: <input type="password" name="password" id="password" class="form-control" value="hirayama"/></p>
<p><button id="button" type="button" class="btn btn-primary">submit</button></p>
<textarea id="response" class="form-control" cols=120 rows=4 disabled></textarea>
<p><p>
</div>
</body>
<script type="text/javascript">
$(function(){
$("#response").html("Response Values");
$("#button").click( function(){
let value07 = 0;
let value08 = 0;
let value09 = 0;
let value10 = 0;
let value11 = 0;
let value12 = 0;
let value13 = 0;
let value14 = 0;
let value15 = 0;
let value16 = 0;
let element = document.getElementById("grade");
let grade01 = element.value;
if (grade01 == "grade1") {
value07 = 0;
}else if (grade01 == "grade2") {
value07 = 0;
}else if (grade01 == "grade3") {
value07 = 1;
}else if (grade01 == "grade4") {
value08 = 1;
}else if (grade01 == "grade5") {
value09 = 1;
}else if (grade01 == "grade6") {
value10 = 1;
}else if (grade01 == "grade7") {
value11 = 1;
}else if (grade01 == "grade8") {
value12 = 1;
}else if (grade01 == "grade9") {
value13 = 1;
}else if (grade01 == "grade10") {
value14 = 1;
}else if (grade01 == "grade11") {
value15 = 1;
}else{
value16 = 1;
}
var url = $("#url_post").val();
var feature1 =
$("#value1").val() + "," +
$("#value2").val() + "," +
$("#value3").val() + "," +
$("#value4").val() + "," +
$("#value5").val() + "," +
$("#value6").val() + "," +
value07 + "," +
value08 + "," +
value09 + "," +
value10 + "," +
value11 + "," +
value12 + "," +
value13 + "," +
value14 + "," +
value15 + "," +
value16;
var JSONdata = {
data: feature1
};
alert(JSON.stringify(JSONdata));
var username = $("input#username").val();
var password = $("input#password").val();
$.ajax({
type: 'POST',
url: url,
//basic認証送信
beforeSend: function(xhr){
xhr.setRequestHeader('Authorization', 'Basic ' + btoa(username+':'+password));},
data: JSON.stringify(JSONdata),
contentType: 'application/JSON',
dataType: 'JSON',
scriptCharset: 'utf-8',
success : function(data) {
// Success
alert("success");
alert(JSON.stringify(JSONdata));
$("#response").html(JSON.stringify(data));
},
error : function(data) {
// Error
alert("error");
alert(JSON.stringify(JSONdata));
$("#response").html(JSON.stringify(data));
}
});
})
})
</script>
</html>