AIで手軽にアプリが作れる世界になったので、プログラマーでなくても、ちょっとしたツールを作成する機会が増えた。とは言え、コマンドラインツールの作成は意外に面倒だ。そこで、関数を定義しただけで手軽にコマンドラインツールに仕立てることができる便利ライブラリTyperを使ってみよう。例として、画像を生成するコマンドラインツールを作ってみよう

  • Typerで画像生成するコマンドラインツールを作ろう

    Typerで画像生成するコマンドラインツールを作ろう

Typerとは

「Typer」とは、Pythonでコマンドラインツール(CLIツール)を簡単に作成するためのライブラリだ。PythonでWeb APIを開発するフレームワークとして有名な「FastAPI」の作者が開発している。Typerを使うと、関数を定義するだけで、Pythonの関数定義を解析して、自動的に引数解析・ヘルプメッセージ生成・シェルのタブ補完まで実現できるので便利だ。

Typerのインストールは、ほかのPythonライブラリと同じで、ターミナル(WindowsならPowerShell、macOS/LinuxならTerminal)を起動して、下記のコマンドを実行しよう。

pip install typer openai
# あるいは
python -m pip install typer openai    

なお、今回、画像生成のOpenAIを使うので、Typerに加えてopenaiパッケージも指定している。

Typerを使った一番簡単なプログラム

まずは、Typerを使って一番簡単なプログラムを作ってみよう。以下のプログラムを、hoge.pyというファイル名で保存しよう。

import typer  # Typerを使うことを宣言 --- (*1)

def main(name: str):
    """自己紹介を表示するプログラム"""  # 適当な関数を定義 --- (*2)
    print(f"こんにちは! {name}さん。")

if __name__ == "__main__":
    typer.run(main)  # Typerでmain関数を有効にする --- (*3)

上記のプログラムは、(*1)のように、Typerを使うことを宣言し、(*2)で適当な関数を定義し、(*3)でTyperにmain関数を与えて実行する。Typerの使い方はこれだけだ。

このように書くことで、コマンドライン引数を、関数mainの引数にマッピングして実行してくれる。それでは、ターミナルで、コマンドを実行してみよう。

python hoge.py クジラ

すると、次のように「こんにちは! くじらさん。」とコマンドラインに指定した引数を、関数mainの引数に自動的にマッピングして実行してくれる。

  • コマンドライン引数を自動的に関数mainに指定して実行してくれる

    コマンドライン引数を自動的に関数mainに指定して実行してくれる

Typerを使わない場合、わざわざコマンドライン引数を解析して、関数を呼び出すコードを書かないといけない。しかし、Typerを使えば、とても手軽にコマンドラインで動くツールを作ることができる。

また、「--help」オプションを付けて実行すると、プログラムの使い方を分かりやすく表示してくれるという便利機能も持っている。試しに、先ほどのプログラムの使い方を表示させてみよう。

python hoge.py --help

すると、下記のように、プログラムの使い方を表示してくれる。なんと、引数nameを指定する必要がある点、「--help」というオプションが使えることを表示してくれた。

  • 「--help」オプションを付けて実行すると、使い方が表示される

    「--help」オプションを付けて実行すると、使い方が表示される

OpenAIのAPIキーを取得して環境変数に登録しよう

それでは、これから今回の本題となる、画像生成コマンドを作ってみよう。なお、画像生成には、OpenAIのAPIを使おう。

OpenAIのAPIを使うのが初めての人は、OpenAIの開発者プラットフォームにアクセスして、OpenAI/ChatGPTのアカウントでログインしよう。そして、APIキーを作成しよう。詳しい手順は、こちらの姉妹連載で詳しく紹介しているので参考にしよう。

なお、上記の記事では、プログラムにAPIキーを埋め込んで、書き換えて実行する方式だが、最近は、環境変数にAPIキーを登録しておくのがトレンドだ。そうすれば、プログラムを公開した時に、APIキーが流出するのを防ぐことができる。

【Windowsで環境変数を設定する方法】

Windowsで、環境変数にAPIキーを登録するには、次の手順で作業しよう。まず、スタートメニューを開いて「環境変数」と入力して、「環境変数を編集」をクリックしよう。そして、上部の「ユーザー環境変数」で「新規」をクリックして、下記の項目を入力しよう。

- 変数名: OPENAI_API_KEY
- 変数値: (取得したOpenAIのAPIキー)
  • WindowsでAPIキーを登録する方法

    WindowsでAPIキーを登録する方法

【macOSで環境変数を設定する方法】

macOSの場合、シェルの設定ファイル「~/.zshrc」に以下のようなテキストを追加しよう。そして、コマンド「source ~/.zshrc」を実行して設定を反映しよう。

export OPENAI_API_KEY="(ここに取得したAPIキーを指定)"

画像生成コマンドを作ってみよう

次に、画像生成を行うプログラムを作ってみよう。Typerを組み込んで、OpenAIのDALL-Eを使って画像生成をするプログラムは、次の通りだ。プログラムは「image-gen.py」というファイル名で保存しよう。以下のプログラムをこちらにもアップロードしている。

import base64
from openai import OpenAI
import typer

# 画像生成用のプロンプトテンプレート --- (*1)
PROMPT_TEMPLATE = """\
指示: {prompt}
画風: {style}
"""

# Typerアプリケーションの作成 --- (*2)
app = typer.Typer()

@app.command()  # 関数の引数を指定 --- (*3)
def generate(
    prompt: str = typer.Argument(..., help="画像生成のためのプロンプト"),
    style: str = typer.Option("浮世絵風", "--style", "-S", help="画風の指定"),
    output: str = typer.Option("image.png", "--output", "-o", help="出力ファイル"),
    size: str = typer.Option("1024x1024", "--size", "-s", help="画像サイズ"),
    model: str = typer.Option("gpt-image-1-mini", "--model", "-m", help="使用モデル"),
    input: str = typer.Option(None, "--input", "-i", help="入力画像ファイル"),
):
    """OpenAI APIを使って画像を生成・再編集するプログラム"""  # --- (*4)
    client = OpenAI()  # OpenAIクライアントの初期化 - 環境変数から自動取得
    typer.echo(f"画像を生成中: {prompt}")
    typer.echo(f"サイズ: {size}, モデル: {model}")
    try:
        if input is None:
            # 画像生成 --- (*5)
            response = client.images.generate(
                  model=model,
                prompt=PROMPT_TEMPLATE.format(
                    prompt=prompt, style=style),
                size=size,
            )
        else:
            # 画像を再編集 --- (*6)
            response = client.images.edit(
                model=model,
                image=open(input, "rb"),
                prompt=prompt,
                size=size,
            )
        # 生成された画像を取得して保存 --- (*7)
        image_base64 = response.data[0].b64_json
        image_bytes = base64.b64decode(image_base64)
        with open(output, "wb") as f:
            f.write(image_bytes)
        typer.echo(f"画像を保存しました: {output}")
    except Exception as e:
        typer.echo(f"エラー: {e}", err=True)
        raise typer.Exit(code=1)

if __name__ == "__main__":
    app()

上記のプログラムを確認しよう。(*1)では、画像生成用のプロンプト(指示書)のひな形を定義している。(*2)では、Typerを利用するための初期化処理を記述した。(*3)では、Typerのデコレーターを利用して関数generateをコマンドラインツールのエントリーポイントとして指定している。また、引数を指定する際、引数のデフォルト値や説明を「typer.Argument(...)」や「typer.Option(...)」を使って付加情報としてTyperに与えることができる。

(*4)ではOpenAIのAPIを使って、画像生成を行うプログラムを記述した。(*5)では画像生成APIを呼び出し、(*6)では、画像を再編集するAPIを呼び出す。引数inputの有無で、生成か変換かを選べるようにしている。(*7)では生成された画像を取得して保存する。

プログラムを実行しよう - その前に認証が必要

なお、画像生成のプログラムを実行する前に、OpenAIの組織認証を有効にする必要がある。こちらの設定を開いて、「Verifications > Verify Organization」のボタンをクリックしよう。

ここで、スマートフォンなどを利用して、身分証明書のスキャンや顔写真の撮影が必要となる。非常に面倒だが、これは、画像生成などの高度なモデルを悪用するケースが増えたため、政府規制やAPIの不正使用を防ぐための措置とのことだ。組織認証をパスするためには、登録してから15分ほどの時間が必要だ。

APIが有効になったら、ターミナルで下記のコマンドを実行しよう。

python image-gen.py 富士山をバックに踊る猫

すると、下記のような画像が生成される。

  • コマンドを実行して画像生成したところ

    コマンドを実行して画像生成したところ

もし、組織認証が完了していない場合、下記のエラーが表示されるので、先ほど紹介した方法で認証を完了させよう。

  • 組織認証が完了しない場合のエラー

    組織認証が完了しない場合のエラー

また、プログラムの使い方を表示するには、「--help」オプションを指定しよう。

  • --help」オプションを指定したところ

    「--help」オプションを指定したところ

画像を再編集したいとき

今回のプログラムでは、既存画像に対して、プロンプトを指定して再編集する機能をつけてみた。「--input (画像ファイルパス)」のように入力画像を指定すると、画像の再編集が可能になる。

先ほど生成した猫の画像を犬の画像に変更してみよう。

python image-gen.py --input=image.png --output="dog.png" "猫を犬に変更して"
  • 画像の猫を犬に変更したところ

    画像の猫を犬に変更したところ

もちろん、ChatGPTを開けば、同じことができるのだが、プログラムの(*1)の部分を工夫することで、いつものお気に入りのスタイルを指定したり、特定のプロンプトを指定することができる。いろいろと工夫してみよう。

まとめ

以上、今回は、コマンドライン引数を関数の引数として与えることができるTyperを使って、画像生成コマンドを作ってみた。コマンドライン引数の解析は意外にも面倒なので、関数の引数として直接与えることができるTyperを使うと面倒がなくて楽ができる。いろいろなコマンドラインツール作成に活用しよう。

自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2004年度未踏ユース スーパークリエータ認定、2010年 OSS貢献者章受賞。これまで50冊以上の技術書を執筆した。直近では、「大規模言語モデルを使いこなすためのプロンプトエンジニアリングの教科書(マイナビ出版)」「Pythonでつくるデスクトップアプリ(ソシム)」「実践力を身につける Pythonの教科書 第2版」「シゴトがはかどる Python自動処理の教科書(マイナビ出版)」など。