こんにちは!@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 時点)となっており、今でも盛んに開発が行われています。
また、ChatBot の性能を比較することができる Web サイト、Chatbot Arena なんかも gradio で実装されていますね。
gradio の他の特徴としては、画像をアップロードして予測結果を返すモデル、テキストを入力して自然言語処理するツールなどを、たった数行のコードでWebアプリ化できます。公式にも似たような記載がありますが、下記のような特徴があると思います。
- 数行のコードでWebアプリが完成
- テキスト・画像・音声など豊富な入力/出力形式に対応
- Hugging Faceと連携してデプロイも簡単
- ローカルでも、インターネット経由でもすぐに使える
gradio vs Streamlit
同じようなライブラリとして、Streamlit などが有名でしょうか。筆者は 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)
を実装すると下記のようになります。
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)
実際の画面はこちらです。
名前を入力し、「挨拶する」ボタンを押すと…
こんな感じで「こんにちは、やまだたろうさん!」と出力されましたね。
コンポーネント
ここまでTextBox
とButton
を使った gradio の簡単なサンプルを見ました。ここからはTextBox
とButton
を含む、様々なコンポーネントを紹介していきます。
Textbox
名前の通り、文字列を表示することのできるボックスのことです。ここでは、よく利用する引数を紹介していきます。
テキストボックスの活性・非活性
interactive=False
にすることで、テキストボックスを入力不可にすることができます。
gr.Textbox(interactive=False)
テキストによる追加情報
placeholder
を設定することで、プレースホルダ(ユーザが入力するまでにボックス内に表示されているテキスト)を設定することができます。また、info
を設定することで、補助的な説明文を追加できます。更に、value
を設定することで、初期値を設定することができます。
gr.Textbox(placeholder="ここに名前を入力してください", info="姓名の間は空けないでください")
行の設定
lines
を設定することでテキストエリアの最低行数が設定でき、max_length
で文字数の最大数を入力することができます。
gr.Textbox(lines=3, max_length=10)
ちなみに改行も1文字使うので注意です。
ボタンの設定
テキストボックスには、いくつかのボタンが用意されています。submit_btn
, stop_btn
, show_copy_button
です。show_copy_button
はTrue/False
を設定するだけですが、submit_btn
, stop_btn
はstr
になっているので、ボタンを自由に作成できます。(画像は埋め込むことができませんが…。)
gr.Textbox(show_copy_button=True, stop_btn=True, submit_btn=True)
gr.Textbox(submit_btn="▶ Submit", stop_btn="⏸ Stop")
MultimodalTextbox
テキスト入力だけでなく、ファイル添付もしたい場合、MultimodalTextbox
を使うと便利です。ほとんどの設定はTextbox
と同じです。(max_length
以外は同じはず…。)その他、ファイル添付に関する引数が数多く用意されています。
ファイル添付の種類・数
引数file_types
, file_count
が用意されており、それぞれ添付できるファイルの種類、数を設定できます。file_types
は'image', '.json', '.mp4'
などが設定可能で、特定の拡張子のみ、または特定のメディアタイプのみなど、設定が可能です。"file"
を設定することで全てのファイルが添付可能…と思いきや、どんな拡張子のファイルを添付してもいいというわけではないようです。
file_count
は数字を設定するのではなく、'single', 'multiple', 'directory'
を設定します。字の通りですが、左から「添付できるファイルは1つのみ」「複数ファイル添付できる」「ディレクトリが可能」です。
また、sources
を指定すると、ファイル添付を表すボタンと録音ボタンを実装可能です。
gr.MultimodalTextbox(file_count="multiple", file_types=["text"], sources=["microphone","upload"])
クリップのボタンを押すと、エクスプローラーが開きます。
今はfile_types=["text"]
としているので、添付できるファイルは下記のようです。
Button
Gradio にはボタンも標準実装されています。
gr.Button(value="submit")
他にはsize
(ボタンの大きさを設定する)、icon
(ボタン内に画像を埋め込む)などが良く使われるでしょうか。
今のところ使用したことはありませんが、Button
の派生クラスとしてClearButton
, DownloadButton
, DuplicateButton
, LoginButton
, UploadButton
などがあるので、用途に合わせて使い分けてみてはいかがでしょうか?
Slider
スライダーも Gradio には用意されています。label
, info
は Textbox と同様に設定できます。maximum
, minimum
で最大最小、step
でスライダーの1あたりの変化幅を定義できます。
gr.Slider(minimum=1, maximum=10, step=1)
Number
スライダーと似たような用途として、Number
を紹介します。Slider
と同じくmaximum
, minimum
, step
が利用できます。label
, info
は ry)
gr.Number(minimum=1, maximum=10, step=1)
HTML, Markdown
gradio に文章を埋め込む際に、それぞれ HTML 形式、markdown 形式の文章を埋め込むことができます。
gr.Markdown("## 名前を入力して挨拶しよう!")
上記の場合、##
部分が markdown 形式として認識され、見出しとして表示されます。
File
ファイル添付をする領域を作成できます。MultimodalTextbox と同じように、file_types
やfile_count
を設定することができます。
gr.File()
Radio
ラジオボタンを実装できます。choices
で選択肢を設定します。
gr.Radio(choices=["hoge", "fuga"])
Audio, Video, Image
それぞれ、音声、動画、画像を表示することができます。画像はAnnotatedImage
, ImageEditor
のような派生クラスがあり、それぞれ「注釈付き画像」「画像の編集機能」が可能なようです。ImageMask
というものもあるようですが、それについては公式に記載がなく、あまりよく分かっていません。
gr.ImageEditor()
gr.ImageMask()
ここに貼り付けた例は上からImageEditor
, ImageMask
です。
これらのコンポーネントをまとめたいときは?
表形式、JSON形式を画面上に埋め込みたい場合など、紹介したいコンポーネントは色々あります。コンポーネントを全て紹介するときりが無いので、この辺りで割愛とさせていただきます。
では、これらのコンポーネントを並べたり、一つにまとめたい場合、どうすればいいでしょうか?その回答がRow
やColumn
, Accordion
などのブロックレイアウトです。
Accordion
アコーディオンメニューを実装したい場合はこれを使います。open
の引数を使うことで初期状態を設定できます。
with gr.Accordion(label="hoge"):
gr.Markdown("## 名前を入力して挨拶しよう!")
gr.Button("挨拶する")
上記のように実装することで、このようなアコーディオンメニューが簡単に作れますね!
右上の ▼ ボタンでアコーディオンを閉じたり開いたりできます。
Row
, Column
コンポーネントを横(縦)に並べて配置したい場合は、Row(Column)を使用します。Accordion
と同じように、with
句を使用します。それぞれの例を下記に記載しておきます。
with gr.Row():
gr.Markdown("## 名前を入力して挨拶しよう!")
name = gr.Textbox()
greet_btn = gr.Button("挨拶する")
with gr.Column():
gr.Markdown("## 名前を入力して挨拶しよう!")
name = gr.Textbox()
greet_btn = gr.Button("挨拶する")
これらのサンプルを見てお気づきかもしれませんが、デフォルトの設定では全ての幅が同じになっています。今回の例では、Markdown
, Textbox
, Button
は全て同じ幅になっていますね。これらの幅を設定するためにはscale
という引数を使用します。
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("挨拶する")
上記のように実装すれば、
画像のように、各コンポーネント幅がscale
に応じて設定されていることが分かります。
Group
先ほど、各コンポーネントの幅をwith gr.Column(scale=1):
のように指定しましたが、Group
を使うことも可能です。
Group
はコンポーネントを一つにまとめる効果があります。
with gr.Group():
gr.Markdown("## 名前を入力して挨拶しよう!")
name = gr.Textbox()
greet_btn = gr.Button("挨拶する")
上記のように設定すると、
Markdown
, Textbox
, Button
が一つのグループとして表示されます。
Tab
ブロックレイアウトで最後に紹介するのは、Tab
です。その名の通り、タブを設定できます。label
引数を使うことで、タブに表示する名称を記載することができます。
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("挨拶する")
ユーザ操作を保存するには…?
ここでブロックレイアウトからコンポーネントに話を戻します。Web アプリとして当たり前のことですが、ユーザの操作が他のユーザに漏れ出てしまうことがあってはいけません。
例えば、AさんがFile
で定義されたコンポーネントにaaa.txt
を添付したとして、それが別の利用者Bさんが同じWebサービスを開いたときに添付されていたら困りますよね?ダウンロードされてしまうと、簡単に情報が漏れ出てしまいます。
それを防ぐために gradio では State
, BrowserState
が用意されています。
State
公式では「フォームでよく使用されるコンポーネント(例:テキストボックス、ドロップダウン)の基本クラスです。」と記載されています。しかし、ただの基本クラスではなく、ユーザ操作の一時保存が可能です。「元に戻す」などを実装したい場合に利用できます。下記に簡単なサンプルを作ってみました。
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
というのが用意されていることが分かります。
画像の通り、state
は画面上にはどこにも表示されていません。
今、「挨拶する」ボタンを押したので、state
には「やまだたろう」が保存されています。
「たなかはなこ」を入力した上で「呼び戻す」ボタンを押すと…。
この通り、state
に保存されている「やまだたろう」さんが戻ってきました!
確かにState
は便利なのですが、リロードをするとState
の情報が消えてしまう という弱点があります。それを解決できるのがBrowserState
です。今回はこれ以上詳しく解説しませんが、一時的に保存したいのであればState
、リロードしても保存したいのであればBrowserState
で、基本的な使い方は同じです。筆者は前に設定した内容をリロードの度にいちいち設定し直すのが大変なときにBrowserState
を使うことがありましたので、合わせて紹介しておきました。
イベントリスナー
ここまでコンポーネントやブロックについて説明していきました。しかし、これだけでは Web 画面の構成を決めることしかできません。gradio では、ボタンを押すなどのイベントリスナーを実装することができます。ただし、gradio のイベントリスナーの実装は少し癖のあるものになっていますので、その実装方法について説明していきます。
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 のコンポーネントである必要がある という点です。
name = "やまだたろう"
(中略)
greet_btn.click(fn=greet, inputs=name, outputs=output)
これでは、inputs
に設定している値が文字列なので、エラーが出力されます。ちなみにfn
に渡す引数は関数であればいいので、functools
を用いて
name = "やまだたろう"
(中略)
greet_btn.click(
fn=functools.partial(greet, name=name),
inputs=None,
outputs=output
)
のようにしてあげれば、文字列であってもfn
に設定することが可能です。その他、簡単な処理であれば Lambda 式を使うことも可能です。
greet_btn.click(
fn=lambda x: f"こんにちは、{x}さん!",
inputs=name,
outputs=output
)
複数の引数を設定したい場合は、リスト形式で設定します。
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 を確認することができます。
False
に設定することで非表示にすることができます。
queue
キューを設定することができます。これによって、ボタン押下などのイベント処理がキューに保存され、順番に処理できるようになります。例えば、複数人が使う Web サービスでイベント処理に大きな負荷がかかる場合に使ったりします。
cancels
例えば少しずつ文字列を表示していくような Chat システムを作りたいとして、途中でイベント処理を止めたいということもあるかと思います。その場合、cancels
という引数が有効です。
cancels
には停止したいイベントリスナーを記載します。例えば下記のように、click イベントに変数名を付けて、リストに設定してあげます。なお、リストで設定できるように、複数のイベントをまとめて設定することが可能です。
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
を使うことで解決できます。
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()
が非表示になる例を考えてみます。
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
を使用します。
def display_btn_click(state):
return gr.update(visible=not state), not state
これまで紹介していませんでしたがコンポーネントの表示/非表示にはvisible
を使用します。そして、この引数をupdate
で渡すことによって、表示/非表示が切り替わります。
「表示を切り替える」ボタンを押すことで、Textbox が消えることが分かります。
その他、interactive
を用いると Textbox に入力不可にできたりもするので、活用してみてください。
イベント処理の色んな書き方
gradio では、デコレータを用いた書き方もサポートされています。
これまでの書き方
def greet(name):
return f"こんにちは、{name}さん!"
greet_btn.click(fn=greet, inputs=name, outputs=output)
デコレータを使った書き方
@greet_btn.click(inputs=name, outputs=output)
def greet(name):
return f"こんにちは、{name}さん!"
デコレータで書く場合も同じように引数を設定できるので、どちらを使うかはお好みで。
イベントそのものの種類について
次に、イベントの種類を紹介していきます。ここまでclick
を例に紹介していきましたが、その他にもいくつか用意されております。コンポーネントによっては用意されていないイベントもありますので、どのコンポーネントにどのイベントが用意されているのかは公式をご確認ください。
load
, unload
Web 画面を開いた(閉じた)ときに処理をしたい場合にこのイベントが役に立ちます。例えば画面遷移した瞬間に DB から必要な値を取得したい場合、load
が利用できます。
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
などでも用意されているので、よく使われます。が、筆者はあまり違いが分かっておらず、画像の通り(画像では分かりにくいかもしれませんが)同じようにイベント処理が実行されてしまいます…。
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)
(ご存じの方がおられましたらコメントいただければ幸いです…。)
イベント処理、ちょっとした応用編②
最後に紹介するのは、イベントリスナーのつなげ方です。Aという処理をしてからBという処理をしたいときはthen
, success
でつなげることによって実現できます。
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 関数を実行した後、更に何かしらの処理をしたい場合、下記のようにして実装します。
greet_btn.click(
fn=greet, inputs=name, outputs=output
).then(
fn=hoge, (略)
)
引数も他のイベントリスナーと同様、fn
, inputs
, outputs
等用意されておりますので、これまでのイベントリスナーと同じように利用できます。
なお、then
とsuccess
の使い分けですが、then
はイベント関数の成否に関わらず処理されますが、success
はイベント関数が成功した場合のみ呼び出されます。処理が失敗した時に後続のイベント処理をしたくない場合にはsuccess
を使用してください。
ただし、gradio のイベント処理の成否は Exception が raise されたかどうかで判定するため、success
の使いどころは少し難しいかもしれません。エラーハンドリングの難しさについてはこちらの記事をご参照ください。
まとめ
ここまで gradio の様々な機能について紹介していきました。始めのほうで述べた通り、サクッと Web アプリを作って試したいときに gradio は有効な手段の一つになるかと思います。公式を見ればわかる部分も多いかと思いますが、イベント処理の書き方に癖を感じる部分が多かったので、自分の知識習得を兼ねて今回記事にしてみました。gradio の書き方にお困りの方の一助になれば幸いです。
また、これ以外にも様々なコンポーネント、イベント処理が用意されているので興味があれば公式ホームページを参照ください。
gradio の今後
最近生成 AI 界隈で流行?を見せている MCP も gradio で用意されており、今も進化を見せております。リアルタイムな音声対話を実現できる FastRTC に gradio コンポーネントが用意されているので、これらの記事もいつか書いてみたいですね。
ここまでお読みいただきありがとうございます!よき gradio ライフを!