データアナリティクス事業本部のueharaです。
突然ですが、ChatGPT流行ってますよね。
特に、Pythonを使ってChatGPT (OpenAI)のAPIを叩くサンプルが多いので、Pythonを使って遊んでいる方も多いのではないでしょうか。
中でもPythonで記載した処理ロジックはそのままに、「ちょっと画面が欲しいな...」というケースがあると思うので、今回はPythonのWebアプリケーションフレームワークであるFlaskを用いて、画面側(HTML/JS)と非同期にやり取りする骨子部分を作ってみたいと思います。
Flaskのインストール方法
特に難しい手順はなく、以下のようにpipでインストールすることができます。
pip install flask
まずはFlaskを使ってみる
今回は簡単ですが、以下のファイル構成を作成します。
.
├ main.py
└ templates/
└ index.html
main.py
で、いわゆるサーバサイドの処理を行い、index.html
を画面として使うことを想定しています。
index.htmlの表示
Flaskにおいて、「トップページにアクセスされるとindex.htmlを返す」という処理は以下のように書くことができます。
main.py
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
@app.route("/")
def index():
html = render_template("index.html")
return html
if __name__ == "__main__":
app.run(debug=True)
index.html
は、簡単ですが以下のようにしました。
index.html
<html lang="ja">
<header>
<meta charset="utf-8" />
<title>Flask Test</title>
</header>
<body>
<h1>Flask Test</h1>
</body>
</html>
ここまで準備できたら、Flaskを起動します。
$ python main.py
起動すると、デフォルトでは http://127.0.0.1:5000 でListenしている旨が表示されると思うので、ブラウザでアクセスしてみます。
上記のように表示されていれば成功です。
XMLHttpRequestによる非同期通信
まず、Python (Flask)側での処理を記載します。
今回は /endpoint
にPOSTされたメッセージをAPIで処理する、といったケースを考え、以下のように書いてみました。
main.py
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
@app.route("/")
def index():
html = render_template("index.html")
return html
def process_by_gpt(message):
"""
ChatGPT APIを利用して何かしらの処理をする
"""
return "ChatGPTで処理した {} に対するレスポンス".format(message)
@app.route("/endpoint", methods=["POST"])
def endpoint():
# エンドポイントにPOSTされたリクエストボディからメッセージを取得
message = request.json["message"]
print("user_message: {}".format(message))
# ChatGPTで処理した結果のメッセージ
gpt_res_message = process_by_gpt(message)
# 画面側に渡すレスポンスを作成
response_data = {"gpt_res_message": gpt_res_message}
# レスポンスをJSON形式で返す
return jsonify(response_data)
if __name__ == "__main__":
app.run(debug=True)
ここでは、ChatGPTでの処理は敢えて書かずに(スクリプトがごちゃごちゃしてしまうので)、ChatGPTで処理した {message} に対するレスポンス
という形で何かしらの処理をした体で返すようにしました。
次に、先程のindex.html
を少し編集します。
具体的には入力フォームを用意し、XMLHttpRequestでフォームに入力されたメッセージを /endpoint
にPOSTする処理をJavascriptで書いてみます。
※[注] 今回は簡単化のため1つのファイルにまとめるべくhtml上に直接Javascriptの処理を記載していますが、本来であればファイルを分ける方が適切です。
<html lang="ja">
<header>
<meta charset="utf-8" />
<title>Flask Test</title>
</header>
<body>
<form class="msg-form">
<input type="text" class="msg-input" placeholder="input text">
<button type="submit" class="msg-send-btn">送信</button>
</form>
<div class="msg-res"></div>
<script>
const msgForm = document.querySelector(".msg-form");
const msgInput = document.querySelector(".msg-input");
const msgRes = document.querySelector(".msg-res");
msgForm.addEventListener("submit", event => {
event.preventDefault();
const msgText = msgInput.value;
console.log(msgText);
if (!msgText) return;
const xhr = new XMLHttpRequest();
// エンドポイントを指定
xhr.open('POST', '/endpoint');
xhr.setRequestHeader('Content-Type', 'application/json');
// レスポンス処理を記述
xhr.onload = function () {
const response = JSON.parse(xhr.responseText);
const gptResMessage = response.gpt_res_message;
appendResponce(gptResMessage);
};
// メッセージをJSON形式に変換して送信
xhr.send(JSON.stringify({ message: msgText }));
msgInput.value = "";
});
// レスポンスのメッセージを追加していく
function appendResponce(msg) {
const msgHTML = `<div class="msg-res">${msg}</div>`;
msgRes.insertAdjacentHTML("beforeend", msgHTML);
}
</script>
</body>
</html>
今回、Python (Flask)側から返ってきたレスポンスはフォームの下に追記していくようにしてみました。
早速、実行してみます。まず、アクセスすると以下のような画面になっていると思います。
入力フォームに適当に文字列を入力して送信すると、レスポンスが下に追記されていきます。
最後に
今回はPythonのWebアプリケーションフレームワークであるFlask用いて、画面側(HTML/JS)と非同期にやり取りする骨子部分を作ってみました。
他にも画面を作る方法としてネイティブアプリであればtkinterや、同じくWebでもより簡単に作成できるStreamlit等様々な方法があるのですが、画面側はHTML/CSS/JSで作れた方がより汎用的な開発ができるので今回このような形で紹介させて頂きました。
上記は非常にシンプルな例となっていますが、作り込めばよりリッチなUIも作成可能ですので(それこそ、本家ChatGPTのようなチャット形式のアプリケーションなど)、参考になりましたら幸いです。