
ブラウザを開かなくても簡単に画像生成ができるんだね。

Alexaアプリから実行できるよ。



↓↓
自身のメールアドレスにURLが届く
↓↓

↓↓
URLから画像が確認できる
↓↓

本記事では、Alexaのカスタムスキル実装方法と実際の動作についてご紹介します。
Contents
構成と処理の流れ
主な構成要素は、以下のとおりです。
- Alexa
- Lambda
- EC2(Lambdaのレイヤー作成用)
- OpenAIのAPI(gptとDALL-E 3)
- Amazon SNS

- アレクサスキルでLambda処理を呼び出す
- Alexaからの入力(日本語)をgptのAPIで英訳
- DALL-E 3のAPIの実行(プロンプトは2の処理で英訳したもの)
- 生成画像のURLをAmazon SNSで自身のメールアドレスに送信
Alexaのカスタムスキル作成

- カスタムスキルを作成
- カスタムスキルとLambdaの紐付け
カスタムスキルを作成
Alexaのカスタムスキルとは、自身で実装した処理に従ってアレクサが応答するというものです。
Alexa Developer Consoleから、カスタムスキルを作成することができます。


カスタムスキル作成のさらに具体的な作成手順は、以下の記事をご確認ください。
Skill Invocation Nameの設定
作成したカスタムスキルのdeveloper consoleから、「Skill Invocation Name」を選択します。

カスタムスキルを呼び出すためのトリガーワードを設定します。
今回は「イラスト作成して」というトリガーワードでカスタムスキルが起動するようにしてみました。

Intentsの作成
developer consoleからIntentsも作成しておきます。
ユーザーからの応答は、このIntentsに設定内容に応じて処理されます。


questionという名前でAMAZON.Languageというスロットを設定します。

ざっくりというと、日本語を検知したら「この処理が走るよ。」という意味のスロットです。
Lambda関数では、以下の箇所が該当します。
ユーザーからの応答が日本語として、questionに格納されます。
class ChatGPTImageGeneIntentHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
return ask_utils.is_intent_name("ChatGPTImageGeneIntent")(handler_input)
def handle(self, handler_input):
slots = handler_input.request_envelope.request.intent.slots
question = slots["question"].value
prompt = question
詳しくは以下のドキュメントを参照してみてください。
Alexa developer console スロットタイプリファレンス
アレクサスキルとLambdaの紐付け
developer consoleのEndpointで「Default Region」を設定します。
この値は、Lambda関数のARNを入力してください。


‖


これでAlexaカスタムスキルの設定は完了です。
Lambda設定

Lambda関数では、実際の処理を実装します。
今回はアレクサで読み取った音声を入力として、ChatGPT、VOICEVOXで出力ファイルを作成し、最後にアレクサから応答を返す処理をPythonにて実装します。
- Lambda関数の作成
- Pythonコード作成
- レイヤーの設定(Python3.12ライブラリ)
- OpenAIの環境変数を設定
Lambda関数の作成
Lambdaのコンソール画面から、「関数の作成」ボタンを押下します。

以下の値で作成します。
- 関数名:任意
- ランタイム:Python3.12
- アーキテクチャ:x86_64

「関数の作成」ボタンを押下し、Lambda関数を作成します。
以下のように、関数が作成できていることを確認します。

Pythonコードの作成
Alexaのカスタムスキル起動時は、lambda_function.pyが呼び出されます。
Lambda関数の画面にて、lambda_function.pyコードを作成します。

実際に今回使用したlambda_function.pyのコードは以下のgithubに公開しています。
- リンク:https://github.com/my-repo-441/alexa-openai-img-gene
- コード:
・lambda_function.py(Alexaから呼び出されるコード)
レイヤーの設定(Python3.12ライブラリ)
以下をLambdaのレイヤーに登録します。
上記は、Pythonの実行に必要なライブラリをzip化したものです。(openaiなど)
LambdaにてPythonコードを実行する際は、レイヤーに登録したライブラリが読み込まれます。
- 使用するライブラリ一覧
・requirements.txt

ライブラリは予め別環境のマシンでpip installしたものをzip化します。
EC2でPythonライブラリのzip化

今回は、Lambdaの実行アーキテクチャ(x86_64)とライブラリの形式を合わせるために、同じアーキテクチャのEC2を立ち上げて、Pythonライブラリのzip化を行いました。
実行環境がx86_64とarm64のように異なる場合、同じPythonのライブラリでもバイナリ形式が異なって動作しない場合があるようです。
EC2のコンソール画面から、以下の設定でEC2を起動します。
- Amazonマシンイメージ:Amazon Linux2023 AMI
- アーキテクチャ:64ビット(x86)
- インスタンスタイプ:t2.micro
- ネットワーク設定:EC2からインターネットに接続できる設定にする。
(Python実行環境のインストール、pip install でライブラリをインストールするため。) - ストレージ:8GiB(gp3)



起動したEC2にSSH接続します。

以下のコマンドを実行し、Python3.12をインストールします。
Python3.12は、Lambda関数のPythonランタイムと同じバージョンです。
# Python3.12のインストール
# ---------------------
# 以下の手順では、Amazon Linux 2023にPython3をインストールする方法を示す。
#開発ツールのインストール
sudo yum groupinstall "Development Tools" -y
sudo yum install openssl-devel bzip2-devel libffi-devel -y
#tmpディレクトリの作成
cd /tmp
#python3.12のダウンロード
wget -c https://www.python.org/ftp/python/3.12.2/Python-3.12.2.tgz
#ダウンロードしたアーカイブを解凍し、ビルドする。
tar -xzf Python-3.12.2.tgz
cd Python-3.12.2
./configure --enable-optimizations
make -j $(nproc)
sudo make altinstall
以下のコマンドを実行し、Lambdaレイヤーに登録するPythonライブラリのインストールとzip化をします。

「pip install -r requirements.txt」コマンドの実行前には、EC2にrequirements.txtファイル(上記のgithub内に記載した内容)を作成しておいてください。
# lambdaのレイヤーに登録するライブラリのzipファイルを作成
# ---------------------
# python3.12の仮想環境を作成し、ライブラリをインストールする。
# インストールしたライブラリをzip化する。(zipをLambdaレイヤーに登録する。)
# pipのインストール
# ---------------------
#インストールコマンド
python3.12 -m ensurepip --upgrade
#バージョン確認
python3.12 -m pip --version
#pipのbinファイルのパスをexportする(pipのbinファイルへのパスを記載)
export PATH=$PATH:/pipのbinまでのパス
#pipでもpip3が使えるようにシンボリックリンクを作成
sudo ln -s ~/.local/bin/pip3 ~/.local/bin/pip
# 仮想環境の作成
python3.12 -m venv ~/venv/openai-img-gene
#仮想環境のアクティベート
source ~/venv/openai-img-gene/bin/activate
# requirements.txt に記載のライブラリをファイルにインストール
pip install -r requirements.txt -t ./python
# インストールしたライブラリをzip化
zip -r python.zip ./python/
作成したPython.zipファイルを、ローカル環境に転送します。
#python.zipをEC2からローカル環境に転送する。
scp -i /path/to/your-key.pem ec2-user@your-ec2-instance-public-ip:/path/to/python.zip /local/destination/path
ローカル環境にpython.zipファイルが転送されていることを確認します。
このzipファイルをLambdaレイヤーとしてアップロードします。

Lambdaレイヤーにアップロード
Lambdaのコンソール画面から、レイヤーを選択します。

「レイヤーの作成」を押下し、作成したzipファイルをアップロードしてください。
この時、ランタイムはPython3.12としてください。

OpenAIのAPIキーを環境変数として設定
Lambdaの「設定」から、「環境変数」を選択します。
以下のように、OpenAIのAPIキーを環境変数として追加します。

上記で追加した環境変数は、コードから以下のようにして呼び出すことができます。
import os
openai.api_key = os.getenv('OPENAI_API_KEY')
GPTおよびDALL-E3のAPIを使用するためには、OpenAIのAPIキーが必要です。
APIキーを取得されていない方は、まずOpenAIのAPI発行画面からAPIキーを発行しましょう。
Create new secret keyを押下します。

「Create secret key」を押下します。

作成されたキーをコピーしておきます。
画面を閉じてしまうとキーがコピーできなくなるため、注意してください。

Amazon SNSの設定

DALL-E 3は、生成した画像をURL形式で応答します。
画像のURLを、自身のメールアドレスに送信するように設定します。
- SNSトピックを作成
- 自身のメールをサブスクライブ
SNSトピックを作成
トピックの作成を選択します。
タイプはスタンダードを選択し、名前は任意でOKです。

トピックの作成を押下します。

自身のメールをサブスクライブ
作成したトピックの画面で、サブスクリプションの作成を押下します。



エンドポイントのメールアドレス宛に、以下のように承認の確認メールがきます。Confirm subscriptionを押下することで、SNSからのメールを受け取ることができるようになります。

これで実装は完了です。
Alexaカスタムスキルを実行

上図の処理を実際に動かしてみます。
作成したAlexaカスタムスキルを実行する方法は、以下の3つです。
- Alexa Developer Consoleから実行
- Alexaアプリから実行
- Alexaから実行
Alexa Developer Consoleから実行
カスタムスキル作成するためのAlexa Developer Consoleから実行できます。
この方法は、主にカスタムスキルのテスト目的で使われます。

作成したLambda関数が正常に動作するかを確認するためにも、まずはDeveloper Consoleから実行してみましょう。


↓↓
メールアドレスにURLが届く
↓↓

↓↓
URLから画像が確認できる
↓↓


動作に問題ないことを確認できました。
Alexaアプリから実行
以下のAlexaアプリを使って、スマートフォン上でスキルを実行できます。



「雨の中を散歩する飼い主と豆柴」と入力しました。

↓↓

↓↓

「家の中でくつろぐビションフリーゼとミニチュアダックスフンド」と入力しました。

↓↓

↓↓

Alexaから実行
Alexaから直接カスタムスキルを呼び出すこともできます。

アレクサ、イラスト作成して。

どんな画像が欲しい?
「海で泳ぐシロナガスクジラ」という指示で画像生成してみました。
↓↓

↓↓

指示した通りの画像が生成できていることが確認できました。
lambda_functionの追加修正
どんなプロンプトで画像を作成したか分かるようにしました。
具体的には、SNSでメールアドレスに送信されるメッセージに、プロンプト内容を含めるようにしました。



修正したコードは以下の箇所です。
単純な文字列の結合でURLのハイパーリンクが無効化されないように、json形式にしました。
(画像生成プロンプトと画像URLを、それぞれキーバリューとして指定)
import json
# URLとプロンプトの内容を含むメッセージの組み立て
message = {
"Image URL": image_url,
"Prompt": prompt_img
}
message_json_to_publish = json.dumps(message_to_publish, ensure_ascii=False)
まとめ
今回はAlexaとOpenAIのAPI「gpt」と「DALL-E 3」を使って、Alexaアプリから画像生成ができるようにしてみました。
アレクサから音声入力で画像生成を指示することも可能なので、家族や友人と集まったときにちょっとした遊びとして各々好きなプロンプトで画像生成を楽しんでみるのも良いかもしれません。
最後まで見ていただきありがとうございました。
今回はAlexaからOpenAIの画像生成API「DALL-E 3」を実行して、メールアドレスに画像のURLが届くようにしてみたよ。