gradio
gradioというPythonモジュールがあります。
これを利用すると、AI Webアプリを簡単に実装でき、WebブラウザをフロントエンドにするローカルAIアプリも容易に実装できます。実際、Stable Diffusion Web UI AUTOMATIC1111などさまざまなAIアプリで活用されています。
gradioを利用する場合、Webアプリなら開発者がHugging Face spaces等のサイトでアプリを構築すればユーザは簡単に利用できます。
ですが、Pythonアプリを配布して、ローカルでPythonアプリを実行させたい場合、ユーザーにPython本体をインストールさせた上でアプリを実行させる必要があります。コマンドラインに慣れている多くのLinuxユーザは別ですが、一般的なWindowsユーザやmacOSユーザにとっては使いやすくはないでしょう。
Pythonにはスクリプトを実行ファイルにするアプリやモジュールがいくつかあります。その一つPyinstallerを使うと1ファイルの実行ファイルにまとめることができます。
ただ、gradioを利用したPythonスクリプトは単にコマンドを実行するだけでは実行ファイル化できなかったので、こちらやこちらを参考に、1ファイル化する具体的な手順を解説します。また、macOSではPyinstaller(またはgradio)にバグがあり、うまく動かない場合があるので、代替手法も説明します。
Pyinstallerでの1ファイル化
サンプルアプリ作成
Python公式サイトのなどを参照し、Pythonをインストールして実行できるようにしておいてください。
適当な作業用フォルダに移動しvenvで仮想環境を構築します(pythonではなくpython3の場合もあります)。
python -m venv venv
仮想環境を有効にします。
Windowsの場合
.\venv\Scripts\Activate.ps1
macOSやLinuxの場合
. venv/bin/activate
gradioをpip
でインストールします(pip
ではなくpip3
の場合もあります)。
pip install gradio
gradioのサイトのトップの例を自動でブラウザが立ち上がるよう修正したスクリプトを作成します。次の内容のtest.py
を適当なエディタで作成してください。
import gradio as gr
def greet(name):
return "Hello " + name + "!"
demo = gr.Interface(fn=greet, inputs="text", outputs="text")
demo.launch(inbrowser=True)
動作確認します。
python test.py
自動的にブラウザが起動します。
name欄に名前を入れて送信ボタンを押せば、outputにメッセージが表示されます。
一旦終了してください。
Pyinstallerによる実行ファイル化
Pyinstallerをpip
でインストールします。
pip install pyinstaller
pyinstaller
で1ファイルとして実行ファイル化してみます。
pyinstaller --onefile test.py
distフォルダ以下にtest.exe
(Windowsの場合)またはtest
(macOSやLinux場合)が生成されるので、一見正しく動作しているように見えるのですが、実行してみるとうまく動きません。
Windowsの場合
dist\test.exe
...
File "gradio_client\serializing.py", line 16, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\asfdwe\\AppData\\Local\\Temp\\_MEI127082\\gradio_client\\types.json'
[PYI-5196:ERROR] Failed to execute script 'test' due to unhandled exception!
macOSの場合
dist/test
...
File "gradio_client/serializing.py", line 16, in <module>
FileNotFoundError: [Errno 2] No such file or directory: '/var/folders/lc/q4l6040s4n709pxrsg3jx7d40000gp/T/_MEI0cSdr3/gradio_client/types.json'
[PYI-14006:ERROR] Failed to execute script 'test' due to unhandled exception!
Linuxの場合
dist/test
...
File "gradio_client/serializing.py", line 16, in <module>
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/_MEIrMnl9c/gradio_client/types.json'
[PYI-358283:ERROR] Failed to execute script 'test' due to unhandled exception!
エラーの原因はgradio_client
モジュールのファイル不足のようです。
--collect-data
でgradio_client
を指定します。もう一度pyinstaller
を実行します。
pyinstaller --onefile --collect-data gradio_client test.py
dist\test.exe
...
File "safehttpx\__init__.py", line 12, in get_version
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\asfdrwe\\AppData\\Local\\Temp\\_MEI74442\\safehttpx\\version.txt'
[PYI-3580:ERROR] Failed to execute script 'test' due to unhandled exception!
safehttpx
モジュールのファイルが足らないので追加してもう一度pyinstaller
を実行します。
pyinstaller --onefile --collect-data gradio_client --collect-data safehttpx test.py
dist\test.exe
...
File "groovy\__init__.py", line 5, in <module>
File "pathlib.py", line 1134, in read_text
File "pathlib.py", line 1119, in open
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\asfdrwe\\AppData\\Local\\Temp\\_MEI146082\\groovy\\version.txt'
[PYI-6776:ERROR] Failed to execute script 'test' due to unhandled exception!
groovy
モジュールを追加します。
pyinstaller --onefile --collect-data gradio_client --collect-data safehttpx --collect-data groovy test.py
dist\test.exe
...
File "gradio\component_meta.py", line 111, in create_or_modify_pyi
File "pathlib.py", line 1134, in read_text
File "pathlib.py", line 1119, in open
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\asfdrwe\\AppData\\Local\\Temp\\_MEI81842\\gradio\\blocks_events.pyc'
[PYI-3820:ERROR] Failed to execute script 'test' due to unhandled exception!
まだダメです。gradio
モジュールを追加します。
pyinstaller --onefile --collect-data gradio_client --collect-data safehttpx --collect-data groovy --collect-data gradio test.py
dist\test.exe
...
File "gradio\blocks_events.py", line 20, in __new__
File "gradio\component_meta.py", line 111, in create_or_modify_pyi
File "pathlib.py", line 1134, in read_text
File "pathlib.py", line 1119, in open
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\asfdrwe\\AppData\\Local\\Temp\\_MEI38162\\gradio\\blocks_events.pyc'
[PYI-11504:ERROR] Failed to execute script 'test' due to unhandled exception!
blocks_events.pyc
の扱いが問題のようです。specファイルを編集してgradio内のファイルの扱いを変更します。
pyinstaller
はpythonスクリプトを解析し、specファイルを出力し、specファイル内容に基づいて実行ファイル化します。pyi-makespec
コマンドで一旦specファイルを出力させたあと、specファイルを修正した上で、specファイルに基づいて実行ファイル化するようにします。
pyi-makespec
コマンドをpyinstaller
を同じ引数で実行します。
pyi-makespec --onefile --collect-data gradio_client --collect-data safehttpx --collect-data groovy --collect-data gradio test.py
生成されたtest.spec
をテキストエディタで開いてください。
# -*- mode: python ; coding: utf-8 -*-
from PyInstaller.utils.hooks import collect_data_files
datas = []
datas += collect_data_files('gradio_client')
datas += collect_data_files('safehttpx')
datas += collect_data_files('groovy')
datas += collect_data_files('gradio')
a = Analysis(
['test.py'],
pathex=[],
binaries=[],
datas=datas,
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='test',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
上の方に--collection-data
で追加した内容が書かれています。gradioに対するmodule_collection_modeを変更するために、中央付近のoptimize=0
あたりを次のように修正して保存します。
# -*- mode: python ; coding: utf-8 -*-
from PyInstaller.utils.hooks import collect_data_files
datas = []
datas += collect_data_files('gradio_client')
datas += collect_data_files('safehttpx')
datas += collect_data_files('groovy')
datas += collect_data_files('gradio')
a = Analysis(
['test.py'],
pathex=[],
binaries=[],
datas=datas,
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
module_collection_mode={
'gradio': 'py', # Collect gradio package as source .py files
},
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='test',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
pyinstaller
をspecファイルに対して実行します。
pyinstaller test.spec
これでWindowsやLinuxでは正常に実行できるようになります。
Windowsの場合
dist\test.exe
test.exe
ファイルをどこかに移動させて、エクスプローラーでダブルクリックしても自動的にターミナルとブラウザが起動して正常に動作するはずです。
Linuxの場合
dist/test
同様にうまく動くはずです。
macOSの場合
dist/test
とすると、python3.9(コマンドライン版xcodeでインストールされるものやbrew python@3.9でインストールされるもの両方)は正常に動くはずです。
python3.10~3.13の場合、
* Running on local URL: http://127.0.0.1:7860
* To create a public link, set `share=True` in `launch()`.
* Running on local URL: http://127.0.0.1:7863
* To create a public link, set `share=True` in `launch()`.
* Running on local URL: http://127.0.0.1:7864
* To create a public link, set `share=True` in `launch()`.
* Running on local URL: http://127.0.0.1:7865
* To create a public link, set `share=True` in `launch()`.
* Running on local URL: http://127.0.0.1:7866
* To create a public link, set `share=True` in `launch()`.
* Running on local URL: http://127.0.0.1:7867
* To create a public link, set `share=True` in `launch()`.
* Running on local URL: http://127.0.0.1:7868
...
と、ブラウザを何度の起動するバグにぶつかります。
python3.9で問題ないならばpython3.9で実行ファイル化してください。
macOSでのPyinstaller以外の手段
他にもやり方はあるのかもしれませんが、python実行環境をどのフォルダに移動させても実行できるポータブルアプリ化した上でアプリに組み込み、その実行環境を使用するようにしたcommandファイルを作成すれば、ユーザにpythonを意識させずにpythonアプリを利用させることができます。
通常のmacOS用のPython実行環境はそのままでは移動できないので、この記事が参考にpython 3.12.10をrelocateable-pythonツールを使ってポータブル化してみましょう。
今までのPython仮想環境に入っている場合抜けてください。
deactivate
test.pyのあるフォルダで作業を続けます。git
でrelocatable-pythonをインストールします。
git clone https://github.com/gregneagle/relocatable-python
cd relocatable-python
./make_relocatable_python_framework.py --python-version 3.12.10 --os-version 11 --upgrade-pip
Python.framework
フォルダがポータブル実行環境です。このフォルダはどこに移動させても動作します。python3
やpip3
などの実行ファイルはPython.framework/Versions/Current/bin
以下に存在します。
test.pyのあるフォルダに戻り、Python.framework
フォルダ移動させます。
mv Python.framework ..
cd ..
relocatable-pythonはもういらないので削除します。
rm -rf relocatable-python
ポータブルPython環境にパスを通します。
export PATH=Python.framework/Versions/Current/bin:$PATH
hash -r
gradioモジュールをインストールしてtest.pyを動かせるようにします。
pip3 install gradio
test.pyがこの環境で動くか確認します。
python3 test.py
次の内容でtest.commandを作成してください。
#!/bin/sh
cd "$(dirname "$0")"
exec ./Python.framework/Versions/Current/bin/python3 test.py
test.commandに実行属性をつけます。
chmod +x test.command
こうすれば、test.pyのあるフォルダをどこに移動させてもFinderでtest.commandをダブルクリックすることで問題なく実行することができます。
あとは、この記事などを参考に、一般的なmacOSアプリ形式にすれば、gradioを使用したmacOSアプリを一般ユーザでも扱いやすい形で配布できると思います。