「Mesop」を使ってPythonでWebアプリを作成してみる
ちょろっと触った感触からして、こいつは普段 Flask とかで Python ウェブアプリを作っている開発者の人に向いてそうな雰囲気 (/・ω・)/
Gradio は ML エンジニアとか Data Scientists とかが使いそう
Streamlit は Data Scientists とかアナリストが使いそう
な使い分けになりそうな予感 (/・ω・)/
公式
とりあえずサラッと触ってみる。
Getting Startedにしたがって進める
とりあえずnotebook通りに動かしてみる。
パッケージインストール
!pip install mesop
ここはおそらくColaboratory用の実行なんだと思う。
import mesop as me
import mesop.labs as mel
me.colab_run()
ローカルでサーバが立ち上がる。
Running server on: http://localhost:32123
* Serving Flask app 'mesop.server.server'
* Debug mode: off
INFO:werkzeug:WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (::)
* Running on http://[::1]:32123
* Running on http://[::1]:32123
INFO:werkzeug:Press CTRL+C to quit
"Hello World"を表示する。
@me.page(path="/hello_world")
def app():
me.text("Hello World!")
- すべての Mesop アプリは、
import mesop as me
で始まる。これがmesopをインポートする唯一の推奨方法で、そうしないと内部実装の詳細に依存することになるため、将来アプリが壊れる可能性がある。@me.page
は関数デコレーターで、関数を特定のパスのルートコンポーネントにする。path
パラメータを省略すると、@me.page(path="/")
と同じになる。app
はPythonの関数で、body内にMesopコンポーネントを作成するため、コンポーネントと呼ぶことにする。
では実行。これによりColaboratoryの場合はセル内に出力が表示される。
me.colab_show(path="/hello_world", height=100)
Componentはブロックであり、ブロックを使ってコンポーネントのツリーを作るとMesopアプリとなる。
- Mesopにはネイティブでコンポーネントが組み込まれている。これらはAngular/Javascriptを使って実装されたコンポーネントであり、これらのコンポーネントの多くは Angular Material コンポーネントをラップしている。
- ユーザー定義コンポーネントと呼ばれる独自のコンポーネントを作成することもできる。これらは基本的に、前の例のappのようなPython関数である。
ビルトインのコンポーネントは以下にある。
ざっと見た限り、ハイレベルな抽象化コンポーネントはimport mesop.labs as mel
、通常のコンポーネントimport mesop as me
でインポートされるように見える。
notebookにあるハイレベルなChatコンポーネントの例。
@me.page(path="/chat")
def chat():
mel.chat(transform)
def transform(prompt: str, history: list[mel.ChatMessage]) -> str:
return "Hello " + prompt
me.colab_show(path="/chat")
ローレベルなコンポーネントを使用したカウンターアプリの例
import mesop as me
@me.stateclass
class State:
clicks: int
def button_click(event: me.ClickEvent):
state = me.state(State)
state.clicks += 1
@me.page(path="/counter")
def main():
state = me.state(State)
me.text(f"Clicks: {state.clicks}")
me.button("Increment", on_click=button_click)
me.colab_show(path="/counter")
"Increment"をクリックすると、カウンターが増えていく。
この例ではComponent以外に以下が使用されている
- State
- Event handler
State
クラスはブラウザセッションにおけるアプリケーションの状態を保持する。つまり、全てのユーザーセッションはそれぞれがState
インスタンスを持つ。
State
は@me.StateClass
で定義する。
@me.stateclass
class State:
clicks: int
そしてbutton_click
がイベントハンドラとなる。イベントハンドラは値が含まれたevent
を受けて、これを元にステートを更新するなどのアクションを行う。上記の例では、onClickイベントでbutton_click
を呼び出してステートのclicks
をインクリメントしている。
def button_click(event: me.ClickEvent):
state = me.state(State)
state.clicks += 1
@me.page(path="/counter")
def main():
state = me.state(State)
me.text(f"Clicks: {state.clicks}")
me.button("Increment", on_click=button_click)
また、with
を使うとコンポーネントのネストができる。例示されているwith me.button...
はエラーになってしまうので、me.box
で囲んでみた。
import mesop as me
@me.stateclass
class State:
clicks: int
def button_click(event: me.ClickEvent):
state = me.state(State)
state.clicks += 1
@me.page(path="/counter")
def main():
state = me.state(State)
with me.box(
style=me.Style(
background="black",
margin=me.Margin.symmetric(vertical=24, horizontal=12),
padding=me.Padding.symmetric(vertical=24, horizontal=12),
border=me.Border.symmetric(
horizontal=me.BorderSide(width=2, color="red", style="solid"),
vertical=me.BorderSide(width=2, color="red", style="solid"),
),
)
):
me.text(f"Clicks: {state.clicks}", style=me.Style(color="limegreen"))
me.button("Increment", on_click=button_click, color="primary", type="raised")
me.colab_show(path="/counter")
以下にコード付きのデモがある。
自分のユースケースとしては、StreamlitやGradioよりもちょっとレイアウトとか色々凝りたい、みたいな場合のものをイメージしているのだけど、そのユースケースなら自分はReflexを選びそう。デプロイ周りも含めて用意された流れに乗っかってできそうな気がするので。