
どーも!某 (@7254bou)です!
Gradioを使うと簡単にwebアプリが作成できて便利ですよね。Gradioについて知らない方は下記の記事をご確認ください。

今回はGradioのレイアウトを改善できるBlocksについて紹介します。
GradioのBlocksとは
BlocksはGradioの低レベルAPIで、Webアプリケーションやデモを作成することができます。
GradioでWebアプリを作成する際には、基本的にはInterfaceを使っていると思いますが、Blocksを使うとより多機能なレイアウトが使えます。
Blocksでできること
(1) コンポーネントのレイアウト
(2) 関数の実行を引き起こすイベント
(3) データの流れ(例えば、入力が出力を引き起こし、それが次のレベルの出力を引き起こすことができる)。
また、Blocksでは、関連するデモをタブなどでグループ化することができます。
Blocksの基本的な使い方は、Blocksオブジェクトを作成し、それをコンテキストとして(with構文で)使用し、Blocksコンテキスト内でレイアウト、コンポーネント、イベントなどを定義します。最後に、launch()メソッドを呼び出すと、アプリが起動します。
今回は基本的なBlocksの使い方と、Blocksで使用できるレイアウトを紹介します。
InterfaceとBlocksの違い
基本的には簡易的に使用する場合は、Interfaceを使い、より複雑なレイアウトを作る場合はBlocksを使うと考えればわかりやすいです。
Interfaceのメリット
例えばInterfaceではショートカット文字列の使用が可能ですが、Blocksでは使えません。また、Interfaceでは基本的なボタンも自動で作成してくれます。したがって爆速でデモアプリを作る場合はInterfaceの方が楽です。
Blocksのメリット
一方でいくつかのレイアウトはBlocksでしか使えないですし、Blocksの方がレイアウトが複雑になった場合でもwith文で可読性の高いコードが書けます。したがってある程度UIを調整したい場合はBlocksを使うのがいいです。
個人的にはデフォルト設定で十分な場合はInterfaceを使い、それ以外はBlocksを使うのがベターだと思います。
Blocksの使い方
アプリケーションを定義するのにInterfaceの代わりにBlocksを使います。
Blocksはwith構文を使って定義します。
import gradio as gr
def greet(name): return "Hello " + name + "!"
# Blocksでappを定義
with gr.Blocks() as app: inputs = gr.Textbox(placeholder="名前を入力してね!", label="名前") outputs = gr.Textbox(label="挨拶") btn = gr.Button("クリックしてね!") # イベントを定義 btn.click(fn=greet, inputs=inputs, outputs=outputs)
# launch()メソッドでWebアプリを起動
app.launch()
上記のコードを実行すると、名前を入力して「クリックしてね!」と書かれたボタンを押すと出力欄(挨拶)にHello ○○!と名前を書いてくれるアプリができます。

Blocksのレイアウト
先ほどのBlocksの例では、コンポーネントがデフォルトのレイアウトで表示されました。
今のところInterfaceを使った時と同じようなレイアウトでしかありません。
BlocksではInterfaceでは使えないいくつかのレイアウトを使うことができます。
今回はBlocksで使えるレイアウトを一つずつ紹介します。
Row
Rowはその名の通り、コンポーネントを横に並べることができます。
RowはBlockの中のレイアウト要素で、すべての子要素を水平にレンダリングします。
Blocksと同様に、with構文を使って定義します。
import gradio as gr
def greet(name): return "Hello " + name + "!"
with gr.Blocks() as app: # Row()関数でレイアウトを定義 with gr.Row(): inputs = gr.Textbox(placeholder="名前を入力してね!", label="名前") outputs = gr.Textbox(label="挨拶") btn = gr.Button("クリックしてね!") # btnにクリックイベントを追加 btn.click(fn=greet, inputs=inputs, outputs=outputs)
app.launch()
上で作ったアプリと違って入力コンポーネントと出力コンポーネントが水平に並んでいるのが分かります。

Column
ColumnもBlocks のレイアウト要素のひとつで、すべての子要素を縦方向にレンダリングします。元々コンポーネントは縦に並んでいますが、Columnを使うと幅などを制御できます。
カラムの幅は scale
と min_width
パラメータで設定することができます。scaleにはintを指定し、同じレイアウト内にあるカラムの幅の倍率を調整できます(例: カラムAのscale=2、カラムBのscale=1のとき、カラムAはBの二倍の横幅になる)。min_widthはそのままですが、幅をpxで指定します。ちなみにscaleが min_width よりも狭いカラムになる場合はmin_width パラメータが優先されます。
import gradio as gr
def greet(name): return "Hello " + name + "!"
# Blocksでappを定義
with gr.Blocks() as app: # Column()関数でレイアウトを定義 with gr.Row(): with gr.Column(scale=2): inputs = gr.Textbox(placeholder="名前を入力してね!", label="名前") outputs = gr.Textbox(label="挨拶") with gr.Column(scale=1): btn = gr.Button("クリックしてね!") # btnにクリックイベントを追加 btn.click(fn=greet, inputs=inputs, outputs=outputs)
app.launch()
上記のコードを実行したのが下記の画像ですが、ボタンの横幅が入出力のテキストボックスより短くなっていることがわかります(半分になっているはず)。

Tab
タブを使うと、複数のコンポーネントをグループ化し、タブで分けることができます。Tab()の場合は、labelパラメータの指定が必須です。
import gradio as gr
def greet(name): return "Hello " + name + "!"
with gr.Blocks() as app: # 入力タブを定義 with gr.Tab("入力タブ"): inputs = gr.Textbox(placeholder="名前を入力してね!", label="名前") btn = gr.Button("クリックしてね!") # 出力タブを定義 with gr.Tab("出力タブ"): outputs = gr.Textbox(label="挨拶") btn.click(fn=greet, inputs=inputs, outputs=outputs)
app.launch()

出力タブをクリックすると下記のようになります。

Box
Box はレイアウト要素の一つで、角が丸く、周囲にパディングがあるボックス内に子要素を配置します。
import gradio as gr
def greet(name): return "Hello " + name + "!"
with gr.Blocks() as app: # Box()関数でレイアウトを定義 with gr.Box(): inputs = gr.Textbox(placeholder="名前を入力してね!", label="名前") outputs = gr.Textbox(label="挨拶") btn = gr.Button("クリックしてね!") # イベントを定義 btn.click(fn=greet, inputs=inputs, outputs=outputs)
app.launch()
上記のコードを実行したのが下記の画像です。見にくいかも知れませんが周りにボックスが追加されています。ボタンは小さくなってレイアウトが崩れるので、Boxではまとめない方が良いかもしれません。

Accordion
Accordion はレイアウト要素の一つで、子要素を折りたたみ可能なセクションに配置します。
アコーディオンはwebページによく出てくるクリックすると下に情報が表示されるやつです。例として下にアコーディオンを表示しておきます。
こいつです!
ちなみにAccordion()の場合もTab()と同様に、labelパラメータの指定が必須です。openパラメータもデフォルトで開いた状態になっているのでFalseがオススメ(というよりデフォルトでFalseにしてほしい)。
import gradio as gr
def greet(name): return "Hello " + name + "!"
with gr.Blocks() as app: # Accordion()関数でレイアウトを定義 with gr.Accordion(label="アプリを見る", open=False): inputs = gr.Textbox(placeholder="名前を入力してね!", label="名前") outputs = gr.Textbox(label="挨拶") btn = gr.Button("クリックしてね!") # イベントを定義 btn.click(fn=greet, inputs=inputs, outputs=outputs)
app.launch()
上記のコードを実行したのが下記の画像です。

アコーディオンをクリックすると下記の画像のようになります。

色々やるならInterfaceよりもBlocksがオススメ
GradioのBlocksでレイアウトを定義するとwebアプリケーションをより綺麗なレイアウトで作成することができます。
個人的にはBlocksを使うといろいろレイアウトできるので、よほど簡単なアプリを作る場合以外はInterfaceではなく基本Blocksを使うつもりです。

Blocksで簡単かつ綺麗なwebアプリを作ろう!