今更ながら、gradioの使い方解説してみた！#Python

こんにちは！@2626です。

久しぶりの投稿となりましたが、今回は gradio という **python だけでフロントエンドを作成できるライブラリ**を~~今更~~見つけましたので、その使い方について紹介していきます！！！


# 背景

弊社では生成 AI の利活用を積極的に推進しており、「どうやって業務に使えるかな…。」と試行錯誤しているところでございます。しかし、業務に使う方法を考えるほど、「**Web の生成 AI サービスでは痒いところに手が届かないな…。**」という気持ちになることがあります。

例えば、生成 AI 界隈で人気を継続している RAG などの新しい技術を試したいときに、どうしても自分で作らないといけない場合があったりします。一方で、生成 AI 界隈の進化に対応するためには、自分で作るのにそれほど時間を掛けたくありません。作っている最中に「新しい仕組みが出てきた！」「新しいサービスが出てきた！」というのは珍しくありません。

特に、新しい生成 AI の仕組みやアーキテクチャを試したいときに、「Webフロントエンドにそれほど時間を掛けたくないな…。」と正直思っていました。これは筆者がバックエンド専門だったからというのも背景にあるかもしれません。そういった背景もあり、サクッと Web フロントエンドを作成できるツールがないかなと探っておりました。


# gradio とは？

## 概要

**Gradio（グラディオ）** は、Pythonで機械学習モデルや関数のインターフェース（UI）を超簡単に作れるライブラリです。

Hugging Face などでも採用されており、Github の Issue でも、38.1k（2025/5/18 時点）となっており、今でも盛んに開発が行われています。

https://github.com/gradio-app/gradio

また、ChatBot の性能を比較することができる Web サイト、[Chatbot Arena](https://lmarena.ai/) なんかも gradio で実装されていますね。

gradio の他の特徴としては、画像をアップロードして予測結果を返すモデル、テキストを入力して自然言語処理するツールなどを、たった数行のコードでWebアプリ化できます。[公式](https://www.gradio.app/)にも似たような記載がありますが、下記のような特徴があると思います。

- 数行のコードでWebアプリが完成
- テキスト・画像・音声など豊富な入力/出力形式に対応
- Hugging Faceと連携してデプロイも簡単
- ローカルでも、インターネット経由でもすぐに使える

## gradio vs Streamlit

同じようなライブラリとして、[Streamlit](https://streamlit.io/) などが有名でしょうか。筆者は Streamlit については詳しくないので、詳しい比較は他の方にお任せしますが、

- シンプルに作って、簡単に動かしたいなら gradio
- ある程度柔軟にUIを構築して使いやすくしたいなら Streamlit

という印象です。「gradio vs streamlit」なんかで検索すると記事が出てきますので、ご参照ください。

## 備考

なお、今回の説明に使用した gradio のバージョンは 5.25.2 です。執筆時点でバージョンの変更により、実装方法が変化している可能性がある点、予めご了承ください。


# 使い方

ではここから、実際のコーディングを見ながら解説していましょう。


## `Blocks`

公式には、「Blocks is Gradio's low-level API that allows you to create more custom web applications and demos than Interfaces (yet still entirely in Python).」と書かれていますね。大まかには一画面の構成全体を作るものって言うイメージでしょうか。

もう一つ `interface` というものもありますが、

- `Interface`：シンプルなUIを作る方法
- `Blocks`：複数の入力・出力、細かいレイアウトやカスタマイズが可能な上級向けの方法

という認識です。使い方としては with 句で囲うことによって、一つのブロックを表現します。例えば

- 名前の入力欄（Textbox）
- 実行するボタン（Button）
- ボタンを押すとメッセージを返す出力欄（Textbox）

を実装すると下記のようになります。

```python
import gradio as gr

with gr.Blocks() as demo:
    gr.Markdown("## 名前を入力して挨拶しよう！")

    with gr.Row():
        name = gr.Textbox(label="お名前")
        greet_btn = gr.Button("挨拶する")

    output = gr.Textbox(label="メッセージ")

    def greet(name):
        return f"こんにちは、{name}さん！"

    greet_btn.click(fn=greet, inputs=name, outputs=output)
```

実際の画面はこちらです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/20c929dc-15fe-4234-81ef-03ddfa3ff310.png)

名前を入力し、「挨拶する」ボタンを押すと…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/2dba3575-8003-4d58-a988-3fd89164fb90.png)

こんな感じで「こんにちは、やまだたろうさん！」と出力されましたね。


## コンポーネント

ここまで`TextBox`と`Button`を使った gradio の簡単なサンプルを見ました。ここからは`TextBox`と`Button`を含む、様々なコンポーネントを紹介していきます。

### `Textbox`

名前の通り、文字列を表示することのできるボックスのことです。ここでは、よく利用する引数を紹介していきます。

#### テキストボックスの活性・非活性

`interactive=False`にすることで、テキストボックスを入力不可にすることができます。
```python
gr.Textbox(interactive=False)
```

#### テキストによる追加情報

`placeholder`を設定することで、プレースホルダ（ユーザが入力するまでにボックス内に表示されているテキスト）を設定することができます。また、`info`を設定することで、補助的な説明文を追加できます。更に、`value`を設定することで、初期値を設定することができます。

```python
gr.Textbox(placeholder="ここに名前を入力してください", info="姓名の間は空けないでください")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/119c42b7-2af4-48d1-bb51-77d08f8a5297.png)

#### 行の設定

`lines`を設定することでテキストエリアの最低行数が設定でき、`max_length`で文字数の最大数を入力することができます。

```python
gr.Textbox(lines=3, max_length=10)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/752730a8-7db1-4ea2-b784-dafe11ae382c.png)

ちなみに改行も1文字使うので注意です。

#### ボタンの設定

テキストボックスには、いくつかのボタンが用意されています。`submit_btn`, `stop_btn`, `show_copy_button`です。`show_copy_button`は`True/False`を設定するだけですが、`submit_btn`, `stop_btn`は`str`になっているので、ボタンを自由に作成できます。（画像は埋め込むことができませんが…。）

```python
gr.Textbox(show_copy_button=True, stop_btn=True, submit_btn=True)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/fc0fb02f-daf8-4056-88bf-4f6f2f1fd698.png)

```python
gr.Textbox(submit_btn="▶ Submit", stop_btn="⏸ Stop")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/07f1946b-5ade-40f6-a7c9-cea357342b21.png)


### `MultimodalTextbox`

テキスト入力だけでなく、ファイル添付もしたい場合、`MultimodalTextbox`を使うと便利です。ほとんどの設定は`Textbox`と同じです。（`max_length`以外は同じはず…。）その他、ファイル添付に関する引数が数多く用意されています。

#### ファイル添付の種類・数

引数`file_types`, `file_count`が用意されており、それぞれ添付できるファイルの種類、数を設定できます。`file_types`は`'image', '.json', '.mp4'`などが設定可能で、特定の拡張子のみ、または特定のメディアタイプのみなど、設定が可能です。`"file"`を設定することで全てのファイルが添付可能…と思いきや、どんな拡張子のファイルを添付してもいいというわけではないようです。

`file_count`は数字を設定するのではなく、`'single', 'multiple', 'directory'`を設定します。字の通りですが、左から「添付できるファイルは１つのみ」「複数ファイル添付できる」「ディレクトリが可能」です。

また、`sources`を指定すると、ファイル添付を表すボタンと録音ボタンを実装可能です。

```python
gr.MultimodalTextbox(file_count="multiple", file_types=["text"], sources=["microphone","upload"])
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/f3e59e5c-6e32-4932-bf02-3912b7ceb87e.png)

クリップのボタンを押すと、エクスプローラーが開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/c9421111-8e4c-4960-aa3d-42126a05700f.png)

今は`file_types=["text"]`としているので、添付できるファイルは下記のようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/3911da1c-94d7-47ff-946c-37212ad5e783.png)


### `Button`

Gradio にはボタンも標準実装されています。

```python
gr.Button(value="submit")
```

他には`size`（ボタンの大きさを設定する）、`icon`（ボタン内に画像を埋め込む）などが良く使われるでしょうか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/030e5755-36c3-48f3-a8bf-578306f1f736.png)

今のところ使用したことはありませんが、`Button`の派生クラスとして`ClearButton`, `DownloadButton`, `DuplicateButton`, `LoginButton`, `UploadButton`などがあるので、用途に合わせて使い分けてみてはいかがでしょうか？


### `Slider`

スライダーも Gradio には用意されています。`label`, `info`は Textbox と同様に設定できます。`maximum`, `minimum`で最大最小、`step`でスライダーの１あたりの変化幅を定義できます。

```python
gr.Slider(minimum=1, maximum=10, step=1)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/c2f2c9ce-8787-4860-b213-987e99f93021.png)


### `Number`

スライダーと似たような用途として、`Number`を紹介します。`Slider`と同じく`maximum`, `minimum`, `step`が利用できます。`label`, `info`は ry)

```python
gr.Number(minimum=1, maximum=10, step=1)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/6d4beacf-0f77-438d-9be1-ded752c467ea.png)


### HTML, Markdown

gradio に文章を埋め込む際に、それぞれ HTML 形式、markdown 形式の文章を埋め込むことができます。

```python
gr.Markdown("## 名前を入力して挨拶しよう！")
```

上記の場合、`##` 部分が markdown 形式として認識され、見出しとして表示されます。


### File

ファイル添付をする領域を作成できます。MultimodalTextbox と同じように、`file_types`や`file_count`を設定することができます。

```python
gr.File()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/bcbb4851-49fc-4a92-98ae-42d21f94907e.png)


### Radio

ラジオボタンを実装できます。`choices`で選択肢を設定します。

```python
gr.Radio(choices=["hoge", "fuga"])
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/db15d253-eab6-481e-8116-0491171c91bc.png)


### Audio, Video, Image

それぞれ、音声、動画、画像を表示することができます。画像は`AnnotatedImage`, `ImageEditor`のような派生クラスがあり、それぞれ「注釈付き画像」「画像の編集機能」が可能なようです。`ImageMask`というものもあるようですが、それについては公式に記載がなく、あまりよく分かっていません。

```python
gr.ImageEditor()
```

```python
gr.ImageMask()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/7b2603ca-83e1-4b99-99f1-61074747d375.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/42fe89cc-b102-4443-80bd-6dc2b36203e5.png)

ここに貼り付けた例は上から`ImageEditor`, `ImageMask` です。


## これらのコンポーネントをまとめたいときは？

表形式、JSON形式を画面上に埋め込みたい場合など、紹介したいコンポーネントは色々あります。コンポーネントを全て紹介するときりが無いので、この辺りで割愛とさせていただきます。

では、これらのコンポーネントを並べたり、一つにまとめたい場合、どうすればいいでしょうか？その回答が`Row`や`Column`, `Accordion`などのブロックレイアウトです。


### `Accordion`

アコーディオンメニューを実装したい場合はこれを使います。`open`の引数を使うことで初期状態を設定できます。

```python
with gr.Accordion(label="hoge"):
    gr.Markdown("## 名前を入力して挨拶しよう！")
    gr.Button("挨拶する")
```

上記のように実装することで、このようなアコーディオンメニューが簡単に作れますね！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/f1857cd0-19f3-4f34-a70b-821076b5d33d.png)

右上の ▼ ボタンでアコーディオンを閉じたり開いたりできます。


### `Row`, `Column`

コンポーネントを横（縦）に並べて配置したい場合は、Row（Column）を使用します。`Accordion`と同じように、`with`句を使用します。それぞれの例を下記に記載しておきます。

```python
with gr.Row():
    gr.Markdown("## 名前を入力して挨拶しよう！")
    name = gr.Textbox()
    greet_btn = gr.Button("挨拶する")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/9f145464-01d6-475a-9d55-8941026abba4.png)

```python
with gr.Column():
    gr.Markdown("## 名前を入力して挨拶しよう！")
    name = gr.Textbox()
    greet_btn = gr.Button("挨拶する")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/4b213409-ce67-4076-aa88-5d6c18babb7e.png)

これらのサンプルを見てお気づきかもしれませんが、デフォルトの設定では全ての幅が同じになっています。今回の例では、`Markdown`, `Textbox`, `Button`は全て同じ幅になっていますね。これらの幅を設定するためには`scale`という引数を使用します。

```python
with gr.Row():
    with gr.Column(scale=1):
        gr.Markdown("## 名前を入力して挨拶しよう！")
    with gr.Column(scale=3):
        name = gr.Textbox()
    with gr.Column(scale=2):
        greet_btn = gr.Button("挨拶する")
```

上記のように実装すれば、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/20a32f31-7d9b-4d57-92d1-3d9931bef19a.png)

画像のように、各コンポーネント幅が`scale`に応じて設定されていることが分かります。


### `Group`

先ほど、各コンポーネントの幅を`with gr.Column(scale=1):`のように指定しましたが、`Group`を使うことも可能です。

`Group`はコンポーネントを一つにまとめる効果があります。

```python
with gr.Group():
    gr.Markdown("## 名前を入力して挨拶しよう！")
    name = gr.Textbox()
    greet_btn = gr.Button("挨拶する")
```

上記のように設定すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/0e2d96d2-eecb-456b-89cd-39ad77cac8dc.png)

`Markdown`, `Textbox`, `Button`が一つのグループとして表示されます。


### `Tab`

ブロックレイアウトで最後に紹介するのは、`Tab`です。その名の通り、タブを設定できます。`label`引数を使うことで、タブに表示する名称を記載することができます。

```python
with gr.Tab(label="出会いの挨拶"):
    gr.Markdown("## 名前を入力して挨拶しよう！")
    name = gr.Textbox()
    greet_btn = gr.Button("挨拶する")
with gr.Tab(label="別れの挨拶"):
    gr.Markdown("## 名前を入力して挨拶しよう！")
    name = gr.Textbox()
    greet_btn = gr.Button("挨拶する")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/fa919d1d-9e90-4edc-9ff6-edb8463fcbc2.png)


## ユーザ操作を保存するには…？

ここでブロックレイアウトからコンポーネントに話を戻します。Web アプリとして当たり前のことですが、ユーザの操作が他のユーザに漏れ出てしまうことがあってはいけません。

例えば、Aさんが`File`で定義されたコンポーネントに`aaa.txt`を添付したとして、それが別の利用者Bさんが同じWebサービスを開いたときに添付されていたら困りますよね？ダウンロードされてしまうと、簡単に情報が漏れ出てしまいます。

それを防ぐために gradio では `State`, `BrowserState`が用意されています。


### `State`

公式では「**フォームでよく使用されるコンポーネント（例：テキストボックス、ドロップダウン）の基本クラスです。**」と記載されています。しかし、ただの基本クラスではなく、ユーザ操作の一時保存が可能です。「元に戻す」などを実装したい場合に利用できます。下記に簡単なサンプルを作ってみました。

```python
state = gr.State("")
gr.Markdown("## 名前を入力して挨拶しよう！")
name = gr.Textbox()
greet_btn = gr.Button("挨拶する")
reset_btn = gr.Button("呼び戻す")
output = gr.Textbox(label="メッセージ")

def greet(name):
    return f"こんにちは、{name}さん！", name

greet_btn.click(fn=greet, inputs=name, outputs=[output,state])
reset_btn.click(fn=lambda x: x, inputs=state, outputs=name)
```

細かい実装は省略して、`state`というのが用意されていることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/f01701fa-6343-4ee4-a1bb-2e7acded0c41.png)

画像の通り、`state`は画面上にはどこにも表示されていません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/3662f1ce-2ee4-46ff-b81d-b9c1973dfdde.png)

今、「挨拶する」ボタンを押したので、`state`には「やまだたろう」が保存されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/d0f16473-e6ca-4aa4-9eb4-a00f47fe0213.png)

「たなかはなこ」を入力した上で「呼び戻す」ボタンを押すと…。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/73470cb2-f20c-4be8-b92e-f547fb6a41a6.png)

この通り、`state`に保存されている「やまだたろう」さんが戻ってきました！

確かに`State`は便利なのですが、**リロードをすると`State`の情報が消えてしまう** という弱点があります。それを解決できるのが`BrowserState`です。今回はこれ以上詳しく解説しませんが、一時的に保存したいのであれば`State`、リロードしても保存したいのであれば`BrowserState`で、基本的な使い方は同じです。筆者は前に設定した内容をリロードの度にいちいち設定し直すのが大変なときに`BrowserState`を使うことがありましたので、合わせて紹介しておきました。


## イベントリスナー

ここまでコンポーネントやブロックについて説明していきました。しかし、これだけでは Web 画面の構成を決めることしかできません。gradio では、ボタンを押すなどのイベントリスナーを実装することができます。ただし、gradio のイベントリスナーの実装は少し癖のあるものになっていますので、その実装方法について説明していきます。

```python
name = gr.Textbox()
greet_btn = gr.Button("挨拶する")
output = gr.Textbox(label="メッセージ")

def greet(name):
    return f"こんにちは、{name}さん！"

greet_btn.click(fn=greet, inputs=name, outputs=output)
```

上記の例では、`greet_btn`のボタンを押したときのイベントリスナーを`greet`関数で定義しています。


### `fn`

イベント処理時に呼び出される関数を表しています。

### `inputs`

イベント処理に渡す関数の引数を表します。複数渡す場合は list にする必要があります。次に説明する`output`と合わせて注意しないといけないのは、**ここで設定する値は gradio のコンポーネントである必要がある** という点です。

```python
name = "やまだたろう"
(中略)
greet_btn.click(fn=greet, inputs=name, outputs=output)
```

これでは、`inputs`に設定している値が文字列なので、エラーが出力されます。ちなみに`fn`に渡す引数は関数であればいいので、`functools`を用いて

```python
name = "やまだたろう"
(中略)
greet_btn.click(
    fn=functools.partial(greet, name=name),
    inputs=None,
    outputs=output
)
```

のようにしてあげれば、文字列であっても`fn`に設定することが可能です。その他、簡単な処理であれば Lambda 式を使うことも可能です。

```python
greet_btn.click(
    fn=lambda x: f"こんにちは、{x}さん！",
    inputs=name,
    outputs=output
)
```

複数の引数を設定したい場合は、リスト形式で設定します。

```python
a = gr.Number()
b = gr.Number()
(中略)
btn.click(
    fn=lambda x, y: x+y,
    inputs=[a, b],
    outputs=output
)
```

### `show_api`

API の公開/非公開を設定することができます。gradio では、「APIを介して使用」というボタンが用意されており、これをクリックすることで API を確認することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/2d30f391-3346-4842-bfec-62601873111c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/7a6bce84-c060-4ef6-8198-67cec4c22c16.png)

`False` に設定することで非表示にすることができます。


### `queue`

キューを設定することができます。これによって、ボタン押下などのイベント処理がキューに保存され、順番に処理できるようになります。例えば、複数人が使う Web サービスでイベント処理に大きな負荷がかかる場合に使ったりします。


### `cancels`

例えば少しずつ文字列を表示していくような Chat システムを作りたいとして、途中でイベント処理を止めたいということもあるかと思います。その場合、`cancels`という引数が有効です。

`cancels`には停止したいイベントリスナーを記載します。例えば下記のように、click イベントに変数名を付けて、リストに設定してあげます。なお、リストで設定できるように、複数のイベントをまとめて設定することが可能です。

```python
submit_btn = gr.Button("処理実行")
stop_btn = gr.Button("処理停止")
msg_box = gr.Textbox("結果を表示")

def hoge():
    # (時間のかかる処理)
    yield message

event = submit_btn.click(fn=hoge, inputs=None, outputs=msg_box)
stop_btn.click(fn=None, calcels=[event])
```


## イベントリスナー、ちょっとした応用編

これまで、ボタン押下で`Textbox`の文字列を更新する例を見てきましたが、「**選択する値によって非表示にしたい**」など、文字列を入れること以外のイベント処理を行いたい場合があると思います。その場合は`gr.update`を使うことで解決できます。

```python
name = gr.Textbox()
greet_btn = gr.Button("挨拶する")
output = gr.Textbox(label="メッセージ")

def greet(name):
    return f"こんにちは、{name}さん！"

greet_btn.click(fn=greet, inputs=name, outputs=output)
```

今回は`display_btn`を押すと`name = gr.Textbox()`が非表示になる例を考えてみます。

```python
state = gr.State(True)
name = gr.Textbox()
display_btn = gr.Button("表示を切り替える")
(中略)
display_btn.click(fn=display_btn_click, inputs=[state], outputs=[name, state])
```

まずは同じように`click`イベントを定義します。`state`が引数、戻り値に入っていますが、これは今の`Textbox`の表示状態を表しています。そして、関数`display_btn_click`の戻り値で`update`を使用します。

```python
def display_btn_click(state):
    return gr.update(visible=not state), not state
```

これまで紹介していませんでしたがコンポーネントの表示/非表示には`visible`を使用します。そして、この引数を`update`で渡すことによって、表示/非表示が切り替わります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/fc55ef6c-fc48-4e21-995f-a515808b4339.png)

「表示を切り替える」ボタンを押すことで、Textbox が消えることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/9c512728-886c-4b59-91db-613be6962bd7.png)

その他、`interactive`を用いると Textbox に入力不可にできたりもするので、活用してみてください。


## イベント処理の色んな書き方

gradio では、デコレータを用いた書き方もサポートされています。


### これまでの書き方

```python
def greet(name):
    return f"こんにちは、{name}さん！"

greet_btn.click(fn=greet, inputs=name, outputs=output)
```

### デコレータを使った書き方
```python
@greet_btn.click(inputs=name, outputs=output)
def greet(name):
    return f"こんにちは、{name}さん！"
```

デコレータで書く場合も同じように引数を設定できるので、どちらを使うかはお好みで。


## イベントそのものの種類について

次に、イベントの種類を紹介していきます。ここまで`click`を例に紹介していきましたが、その他にもいくつか用意されております。コンポーネントによっては用意されていないイベントもありますので、どのコンポーネントにどのイベントが用意されているのかは公式をご確認ください。


### `load`, `unload`

Web 画面を開いた（閉じた）ときに処理をしたい場合にこのイベントが役に立ちます。例えば画面遷移した瞬間に DB から必要な値を取得したい場合、`load`が利用できます。

```python
with gr.Blocks() as demo:
    output = gr.Textbox()

    def get_hoge():
        # (DBから値を取ってくるような処理)
        return result

    demo.load(fn=get_hoge, inputs=None, outputs=output)
```

### `focus`, `blur`

Textbox などで、フォーカスされた（フォーカスが外れた）ときにイベントを実行したい場合、`focus`や`blur`が便利です。


### `change`, `input`

Textbox などで、値が変更されたときにイベントを実行したい場合、`change`, `input`が便利です。これらは`Slider`や`Radio`, `Dropdown`などでも用意されているので、よく使われます。が、筆者はあまり違いが分かっておらず、画像の通り（画像では分かりにくいかもしれませんが）同じようにイベント処理が実行されてしまいます…。

```python
def on_input(text):
    return f"inputイベント: {text}"

def on_change(text):
    return f"changeイベント: {text}"

textbox = gr.Textbox(label="ここに入力してみてね")
out1 = gr.Textbox(label="リアルタイム反応")
out2 = gr.Textbox(label="確定後反応")

textbox.input(on_input, inputs=textbox, outputs=out1)
textbox.change(on_change, inputs=textbox, outputs=out2)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904801/9ddc0958-4c3c-477c-87ec-5ada36b371f8.png)

（ご存じの方がおられましたらコメントいただければ幸いです…。）


## イベント処理、ちょっとした応用編②

最後に紹介するのは、イベントリスナーのつなげ方です。Aという処理をしてからBという処理をしたいときは`then`, `success`でつなげることによって実現できます。

```python
name = gr.Textbox()
greet_btn = gr.Button("挨拶する")
output = gr.Textbox(label="メッセージ")

def greet(name):
    return f"こんにちは、{name}さん！"

greet_btn.click(fn=greet, inputs=name, outputs=output)
```

例えば、greet 関数を実行した後、更に何かしらの処理をしたい場合、下記のようにして実装します。

```python
greet_btn.click(
    fn=greet, inputs=name, outputs=output
).then(
    fn=hoge, (略)  
)
```

引数も他のイベントリスナーと同様、`fn`, `inputs`, `outputs`等用意されておりますので、これまでのイベントリスナーと同じように利用できます。

なお、`then`と`success`の使い分けですが、`then`はイベント関数の成否に関わらず処理されますが、`success`はイベント関数が成功した場合のみ呼び出されます。処理が失敗した時に後続のイベント処理をしたくない場合には`success`を使用してください。

ただし、gradio のイベント処理の成否は Exception が raise されたかどうかで判定するため、`success`の使いどころは少し難しいかもしれません。エラーハンドリングの難しさについてはこちらの記事をご参照ください。

https://qiita.com/nekoniii3/items/5acf764af65212d9f04f


# まとめ

ここまで gradio の様々な機能について紹介していきました。始めのほうで述べた通り、サクッと Web アプリを作って試したいときに gradio は有効な手段の一つになるかと思います。公式を見ればわかる部分も多いかと思いますが、イベント処理の書き方に癖を感じる部分が多かったので、自分の知識習得を兼ねて今回記事にしてみました。gradio の書き方にお困りの方の一助になれば幸いです。

また、これ以外にも様々なコンポーネント、イベント処理が用意されているので興味があれば公式ホームページを参照ください。

https://www.gradio.app/


# gradio の今後

最近生成 AI 界隈で流行？を見せている [MCP](https://modelcontextprotocol.io/introduction) も [gradio で用意](https://www.gradio.app/guides/building-mcp-server-with-gradio)されており、今も進化を見せております。リアルタイムな音声対話を実現できる [FastRTC](https://fastrtc.org/userguide/gradio/) に gradio コンポーネントが用意されているので、これらの記事もいつか書いてみたいですね。

ここまでお読みいただきありがとうございます！よき gradio ライフを！