こんにちは。エイチームライフデザイン技術開発室の鈴木です。普段はおもにPythonを使って機械学習や自然言語処理の開発をしています。
Pythonで開発した機械学習モデルや生成AIアプリケーションなどを他のメンバーに実際に利用してもらうために、できるだけ簡単にプロトタイプを提供したいというときが出てきます。手軽な方法のひとつとして、Jupyter Notebookを共有して「こことここのパラメータを入力して使ってみてください」といって提供することもありますが、開発者でない方にJupyter Notebookを利用してもらうには色々と厳しい面があると思います。一方で、データエンジニアや機械学習の開発者が簡単なプロトタイプを共有したいだけなのに、WebアプリケーションとしてHTMLやJavaScriptを記述したりするのはできるだけ避けたいこともあります。
そういう時に、手軽に利用できる便利なオープンソースPythonライブラリとしてStreamlit・Gradio・Dash・NiceGUIを紹介します。これらは、いずれもPythonで少量のコードを書くだけでインタラクティブなWebアプリケーションを構築できるツールです。弊社ではこういったライブラリを活用することでAI系のアプリケーションを手軽に使ってもらうという事も進めています。
本稿では、これら4つのライブラリでそれぞれOpenAIのChatGPT APIを実行するだけのプログラムを作って、比べてみました。通常のPythonスクリプトおよびColab等のNotebook環境では、以下のようなコードになるものです。
# `openai.api_key = "XXXXXXXX"`しておいて以下を実行 import openai input_text = "日本で一番高い山は?" completion = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": input_text}], max_tokens=100, ) print(completion["choices"][0]["message"]["content"])
この簡単な機能をWebアプリケーションとして共有したいという時に、4つのツールでそれぞれどのように記述すればいいかを見ていきます。
なおそれぞれのツールには独自のクラウドプラットフォーム上にデプロイするような機能などもありますが、本稿ではオープンソースライセンスで利用できるライブラリ部分に注目して紹介していきます。
コードの実行環境
本稿で紹介するコードについて、言語及びライブラリのバージョンは以下のものを用いました。
- Python 3.10
- OpenAI 0.27.8
- Streamlit 1.25.0
- Gradio 3.40.1
- Dash 2.12.1
- NiceGUI 1.3.11
また、以下の環境下でコードを実行しています
- 環境変数として
OPENAI_API_KEY
がセットされている - いずれもDockerコンテナ内でアプリを立ち上げ、デフォルトのポート番号を開放
各ライブラリの使用方法について、インストールや起動コマンドは省略しています。
各ライブラリの比較
Streamlit
Streamlitは、データアプリケーションを迅速に構築するためのフレームワークです。2022年にSnowflakeによって買収されました。
Streamlitは本稿で紹介する中で2023年9月時点でのGitHubのスター数が最も多く、Web上で解説の文献なども多く見つかるのではないかと思います。
import streamlit import openai input_text = streamlit.text_input('入力') if len(input_text) > 0: completion = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": input_text}], max_tokens=100, ) streamlit.write(completion["choices"][0]["message"]["content"])
StreamlitでChatGPTのAPIを実行するアプリケーションは上記のように記述できます。 Pythonスクリプトとして単体で実行したときと見比べると、ほとんど変わらないコードになっていることが分かると思います。たったこれだけのコードで、入力フォームを持つWebアプリケーションとして実行できます。
この手軽さがStreamlitの最大の特徴だと思います。
一方で、Streamlitはデフォルトでは入力値が変更されるたびにプログラム全体が実行されるようになっています。ChatGPTのAPIを意図しないタイミングで実行されないようにするには、必要に応じてボタンを押した時に処理を実行するなどに変更する必要があるでしょう。
Streamlitは公式サイトで「A faster way to build and share data apps」と謳われており、データを扱うアプリケーションに長けています。フォーム上で入力した値が自動で反映されてプログラムが何度も自動で再実行される仕組みになっているので、実際にはChatGPTのようなAPIを介した動作よりも、データに対して対話的なアプリケーションを組みたい時がより向いていると思います。とはいえ公式サイトでもChatGPTのような生成AIアプリケーション開発との親和性の高さがアピールされているので、本稿のようにChatGPTのアプリケーション開発に使うのもStreamlitの便利な用途のひとつといえます。
Gradio
Gradioは、機械学習モデルを利用したアプリの構築と共有のためのフレームワークです。Hugging Face上でも用いられており、機械学習をやっている方なら「Gradioという名前は聞いたことが無くても、そのUIデザインは見たことがある」という方もいるのではないかと思います。
import gradio import openai def generate(input_text: str) -> str: completion = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": input_text}], max_tokens=100, ) return completion["choices"][0]["message"]["content"] gradio.Interface( fn=generate, inputs="text", outputs="text" ).launch(server_name="0.0.0.0")
Streamlitのコードと比べてみると、テキストエリアの定義などインターフェースに関わる処理と、ChatGPTに指示を与えるモデルの処理とが分離するようになっています。これにより、ある程度複雑な処理を記述したときもコードの保守性を比較的担保しやすいと思います。
テキスト入力フォームの定義しかしていないのに「送信」「クリア」「フラグする(保存)」というボタンが自動で付属し、これらをクリックすると処理が動作するようになっています。入力したあとに(ボタンを押したりせず)暗黙的に処理が走ったりすることが無いので、実行にコストの掛かる機械学習アプリケーションにインターフェースを提供する際にも向いていると思います。
また、Gradioは共有関連の機能が強力です。GradioはPythonスクリプトからWebアプリケーションサーバとして起動する通常の方法だけでなく、Jupyter Notebookの中から直接起動したり、共有用の一意なURLを自動で払い出す機能などがあります。UIだけでなくWebAPIも同時に提供される機能もあります。共有までを手軽にできることが重視されています。
Google Colabolatory上でGradioを実行すると上記のようになります。
Dash
Dashはデータアプリケーションを構築するためのフレームワークです。データ可視化ツールで有名なPlotlyが開発しており、本稿で紹介するなかでは最も歴史が長いものになります。
from dash import Dash, html, dcc, callback, Output, Input, State import openai app = Dash(__name__) app.layout = html.Div([ html.Div(dcc.Input(id='input-text', type='text')), html.Button('Submit', id='submit-val', n_clicks=0), html.Div(id='result-text') ]) @callback( Output('result-text', 'children'), Input('submit-val', 'n_clicks'), State('input-text', 'value') ) def update_output(_n_clicks, input_text): if input_text is not None and len(input_text) > 0: completion = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": input_text}], max_tokens=100, ) return completion["choices"][0]["message"]["content"] return "" if __name__ == '__main__': app.run(host='0.0.0.0', debug=True)
他のものと比べてもコードの量が多く、HTMLのDOM要素やクリックイベントといったWeb開発の概念が表出しているのが特徴的です。またデフォルトでは見た目の飾り付けも暗黙的に行われることはなく、デザインを自前で用意する必要があります。
コードを書く必要が多いぶん、フレームワークの裏側で暗黙的に行われる処理も比較的薄くなっているため、細かい要望に沿った柔軟なアプリケーションを構築しやすくなると思います。 DashはStreamlitと同様にデータアプリケーションに向いていますが、より柔軟なアプリケーションを自前で構築したい場合に向いていると思います。
NiceGUI
NiceGUIは、PythonのWebアプリケーションフレームワークです。今回紹介するものの中では最も登場が新しいものです。GitHubのスター数も短期間で大きく伸びており、個人的に期待しているライブラリです。
NiceGUIは機械学習やデータダッシュボードといった用途に特化したものではなく、Webアプリケーション全般の開発を対象にしていますが、その使い勝手は本稿で紹介した他のライブラリによく似ています。実際にNiceGUIの開発者はStreamlitを好んでいると公式サイトに記載されており、影響を受けているようです。
import nicegui import openai def generate(e): input_text = e.sender.value completion = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": input_text}], max_tokens=100, ) result.text = completion["choices"][0]["message"]["content"] input_text = nicegui.ui.input().on('keydown.enter', generate) result = nicegui.ui.label() nicegui.ui.run()
ソースコードはGradioと似ていますが、JavaScriptのキーボード入力イベントやUIへの値セットなど、Gradioでは隠蔽されていたWebフロントエンドの要素が垣間見えます。実際に、NiceGUIの公式ドキュメントを読んでいくとVue.jsフレームワークのQuasarやTailwind CSSのドキュメントへ誘導されることがあり、Webフロントエンドの抽象度が比較的低くなっていると感じます。
見た目は以下のようになります。
NiceGUIは一見GradioやStreamlitと似ているものの、UI要素自体を動的に増減させるなど凝ったアプリケーションを構築したい時に向いています。機械学習やデータダッシュボードの形式にとらわれることなく、よりアプリケーションらしいアプリケーションを手軽に構築したい時に向いています。
まとめ
- Streamlitは、データダッシュボードを少ないコードで手早く構築したい時向け
- Gradioは、機械学習モデルを可視化するインターフェースを手早く作って共有したい時向け
- Dashは、データダッシュボードを多様な要望に応じて柔軟に構築したい時向け
- NiceGUIは、対話的なWebアプリケーションを少ないコードで手早く構築したい時向け
このように、これらのライブラリは「PythonのみでWebアプリが簡単に構築できる」という点で似ている所もあり、実際に同じような機能を持つアプリケーションを構築できます。ですが、コンセプトがそれぞれ異なっているため適した場面も異なります。弊社でもこういったツールを場面によって使い分けることで、機械学習や生成AIアプリケーションによるデモを手軽に触ってもらえるような工夫を進めています。