Gradioでセッションの概念を導入する
Posted On 2023-01-24
Gradioでユーザー名などセッションごとに変数を記録したいときはよくあります。gr.Stateで簡単にできるので、アンチパターンとセットで紹介していきます。
目次
アンチパターン:グローバル変数で状態を記録する
例えば、以下のようにログインした人の名前を記録して、挨拶するようなアプリを考えてみましょう。以下はアンチパターンです。
import gradio as gr
_USERNAME = None
def login(username):
global _USERNAME
_USERNAME = username
return f"{username}さんがログインしました!"
def greet():
global _USERNAME
return f"{_USERNAME}さん、こんにちは!"
with gr.Blocks() as demo:
with gr.Row():
with gr.Column():
tb_username = gr.Textbox(label="Input your name")
button_login = gr.Button(value="Login")
with gr.Column():
message = gr.Markdown()
button_greet = gr.Button(value="Greet")
button_login.click(login, tb_username, message)
button_greet.click(greet, None, message)
if __name__ == "__main__":
demo.launch()
どの点がよくないのか見てみましょう。ブラウザを2つ使います。プログラムを実行したあとず最初のブラウザで開き、名前を「Joe Biden」にしてLogin→Greetしてみます。
これでうまくいっているように思えます。別ブラウザで同じURLを開き、名前を「Kim Jong-un」にしてLoginしてみます。
もとのブラウザに戻り、「Greet」を押してみましょう。
「Joe Biden」としてログインしたはずなのに、「Kim Jong-unさん、こんにちは!」と表示されてしまいました。これはユーザー名をセッションごとに記録していないので、Loginのたびにグローバル変数が上書きされてしまうからです。
解決策:gr.Stateを使う
このようなときのために、セッションごとのステートを記録できるオブジェクトgr.Stateが用意されています。Block以下でこのように使います。
import gradio as gr
def login(username, state):
state["username"] = username
return f"{username}さんがログインしました!", state
def greet(state):
return f"{state['username']}さん、こんにちは!", state
with gr.Blocks() as demo:
state = gr.State({
"username": None
})
with gr.Row():
with gr.Column():
tb_username = gr.Textbox(label="Input your name")
button_login = gr.Button(value="Login")
with gr.Column():
message = gr.Markdown()
button_greet = gr.Button(value="Greet")
button_login.click(login, [tb_username, state], [message, state])
button_greet.click(greet, state, [message, state])
if __name__ == "__main__":
demo.launch()
変更点は以下の通りです。
- セッションの状態を記録するstateを追加
- login, greet関数内の引数と返り値にstateを追加
これでユーザー名がセッションごとに記録されるので、Joe Bidenのセッションで「Kim Jong-unさん、こんにちは!」と表示されなくなります。
Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内
技術書コーナー
北海道の駅巡りコーナー
One Comment