Amazon Bedrockを使って日本語テキストから画像生成する

スポンサーリンク
ハンズオン
スポンサーリンク

はじめに

AWSのAIサービスをつかったハンズオンです。

最近X(旧Twitter)ではGrokが一般ユーザにも無料で利用できるようになりました。
実際に「元気に草原を走り回るハムスターの画像」を生成してもらったところ、以下の画像が生成されました。

かわいらしい画像ですね!

AWSでも生成AIサービスBedrockで画像生成モデルを利用すると画像を生成することができます。
過去の記事でBedrockのStability AIモデルを使って画像を生成してみました。
Amazon Bedrockを使って画像を生成してみる

こちらの記事の中で、日本語で画像生成してみましたが、文章と全く違う画像が生成されました。
インプットテキスト

元気に走り回るゴールデンハムスターの写真を生成してください。

結果

金の装飾がある和をイメージとした車…?日本語には対応していないようです。

日本語には対応していないのであれば英訳を挟むことで解決できるのでは?

ということで、今回はAIサービスでも日本語の文章を「Amazon Translate」を使って英訳し、英訳した文章で「Amazon Bedrock」画像を生成してみます。

前提条件

  • Amazon Bedrockのモデルの対応の関係で バージニア北部(us-east-1) リージョンを利用します。
  • Amazon Bedrockの「Stability AI」モデルを有効化しておいてください。(参考:【AWS AI ハンズオン】:Amazon Bedrockを使って画像を生成してみる
  • Amazon Translateはサービスを有効化しておいてください。
  • ハンズオンのためLambdaはVPCなしの設定で作成しています。内部的な通信を利用する場合はS3とTranslateのエンドポイントをVPCに作成してください。

環境構成

本ハンズオンの環境構成は以下の通りです。

①日本語のテキストファイルを【テキストを格納するバケット】にアップロード
②アップロードをトリガーにLambda関数起動、アップロードされたファイルのテキストを読み込み
③読み込んだテキストをAmazon Translateで英訳
④英訳したテキストを使ってAmazon Bedrockで画像生成し、【生成した画像を格納するバケット】にアップロード

料金目安

本ハンズオンの料金目安です。
インプットの文章量によりますが、1000文字の文章で画像を生成すると1回あたり8円程度になります。(無料枠の除いて計算しています)

詳細

  • S3: 入力用のテキストファイルと結果のjsonファイルのみなので、ほぼ無料
  • Lambda: 処理回数や利用リソース/利用時間はわずかなのため、ほぼ無料(無料枠範囲)
  • Amazon Translate: 1000文字あたり$0.015(約2円)。リクエストから最初の12か月は無料枠範囲
  • Amazon Bedrock: Stability AIモデル(SDXL 1.0)は標準の画像1枚あたり$0.04(約6円)

1. S3バケットの作成

今回のハンズオンで利用する2つのバケットを作成します。

  • 1.テキストを格納するバケット
  • 2.生成した画像を格納するバケット

AWS管理コンソールから「S3」の画面を開き、「バケットの作成」を選択します。

入力用のテキストファイルを格納するバケットと生成した画像ファイルを格納するS3バケットを作成します。必ず バージニア北部 us-east-1 リージョンでバケットを作成してください。

2. Lambda関数の作成

作成したS3にファイルがアップロードされたことをトリガーに起動するLambda関数を作成します。このLambda関数では、アップロードされたテキストを読み込み、英訳をし、画像生成して画像格納用のS3にアップロードします。

AWS管理コンソールから「Lambda」の画面を開き、「関数の作成」を選択します。必ず バージニア北部 us-east-1リージョンでLambda関数を作成してください

任意の関数名、ランタイム:Node.js 22.x、アーキテクチャ:x86_64として、関数を作成します。

関数が作成できたら、設定タブを選択してください。一般設定から「編集」を選択します。

基本設定の画面が表示されます。タイムアウト値は10秒に変更してください。画像生成には時間がかかる場合があるため、タイムアウト値を延長します。
実行ロールにS3バケットとTranslateの実行権限を付与します。「IAMコンソールで****ロールの表示」を選択してください。

ロールの設定画面が表示されます。許可を追加から「インラインポリシーを作成」を選択してください。

ポリシーエディタが表示されます。JSONを選択して以下のポリシーを入力してください。入力後「次へ」を選択します。

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Action": "s3:GetObject",
			"Resource": "arn:aws:s3:::【テキストを格納するバケット名】/*"
		},
		{
			"Effect": "Allow",
			"Action": "s3:PutObject",
			"Resource": "arn:aws:s3:::【生成した画像を格納するバケット名】/*"
		},
		{
			"Effect": "Allow",
			"Action": "bedrock:InvokeModel",
			"Resource": "arn:aws:bedrock:*::foundation-model/*"
		},
        {
			"Effect": "Allow",
			"Action": "translate:TranslateText",
			"Resource": "*"
		}
	]
}

確認して作成の画面で「ポリシーを作成」を選択します。

Lambdaの画面に戻って環境変数の追加をします。設定タブ>左メニューの「環境変数」を選択し「編集」を選択します。

環境変数を設定します。

キー
REGION リージョン名(今回はus-east-1固定)
TARGETBUCKET 【生成した画像を格納するバケット名】

以下のソースを反映し、「index.mjs」を「index.js」に名前を変えてください。

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.handler = void 0;
const client_s3_1 = require("@aws-sdk/client-s3");
const client_bedrock_runtime_1 = require("@aws-sdk/client-bedrock-runtime"); // ES Modules import
const client_translate_1 = require("@aws-sdk/client-translate");
const stream_1 = require("stream");
// 環境変数のチェック
if (!process.env.REGION || !process.env.TARGETBUCKET) {
    throw new Error("環境変数が指定されていません");
}
// S3クライアント/Translateクライアント/ Bedrockクライアントの初期化
const s3Client = new client_s3_1.S3Client({ region: process.env.REGION });
const translateClient = new client_translate_1.TranslateClient({ region: process.env.REGION });
const bedrockClient = new client_bedrock_runtime_1.BedrockRuntimeClient({ region: process.env.REGION });
// S3の読み取り用ヘルパー関数
const streamToString = async (stream) => {
    const chunks = [];
    for await (const chunk of stream) {
        chunks.push(chunk);
    }
    return Buffer.concat(chunks).toString('utf-8');
};
// S3からファイル読み込み
const getObjectContent = async (bucket, key) => {
    // S3からテキストファイルを取得
    const getObjectParams = {
        Bucket: bucket,
        Key: key
    };
    const getObjectCommand = new client_s3_1.GetObjectCommand(getObjectParams);
    const s3Response = await s3Client.send(getObjectCommand);
    if (!s3Response.Body || !(s3Response.Body instanceof stream_1.Readable)) {
        throw new Error("アップロードされたオブジェクトが不正です");
    }
    const fileContent = await streamToString(s3Response.Body);
    return fileContent;
};
// イメージを生成しS3にターゲットの格納する
const generateImage = async (input_text, file_name) => {
    const seed = Math.floor(Math.random() * 4294967295);
    const prompt = {
        "text_prompts": [
            {
                "text": input_text
            }
        ],
        "style_preset": "photographic",
        "seed": seed,
        "cfg_scale": 10,
        "steps": 30,
    };
    const invokeModelInput = {
        body: JSON.stringify(prompt),
        contentType: "application/json",
        accept: "image/png",
        modelId: "stability.stable-diffusion-xl-v1",
        trace: "DISABLED",
        performanceConfigLatency: "standard",
    };
    const invokeModelCommand = new client_bedrock_runtime_1.InvokeModelCommand(invokeModelInput);
    const response = await bedrockClient.send(invokeModelCommand);
    const targetBucket = process.env.TARGETBUCKET;
    const targetKey = `generated-images/${file_name}.png`;
    const putObjectParams = {
        Bucket: targetBucket,
        Key: targetKey,
        Body: response.body,
        ContentType: 'image/png',
    };
    const putObjectCommand = new client_s3_1.PutObjectCommand(putObjectParams);
    await s3Client.send(putObjectCommand);
};
// 日本語から英語に翻訳
const translateJaToEn = async (inputText) => {
    const translateParams = {
        Text: inputText,
        SourceLanguageCode: 'ja', // 元の言語 (日本語)
        TargetLanguageCode: 'en', // 翻訳先言語 (英語)
    };
    const translateCommand = new client_translate_1.TranslateTextCommand(translateParams);
    const translation = await translateClient.send(translateCommand);
    return translation.TranslatedText || '';
};
// Lambdaハンドラー
const handler = async (event) => {
    // イベントのフォーマットが不正の場合は異常終了
    if (!event.Records || event.Records.length === 0 || !event.Records[0].s3) {
        throw new Error("eventの構造が不正です");
    }
    // イベントからバケット名とオブジェクトキーを取得
    const sourceBucket = event.Records[0].s3.bucket.name;
    const sourceKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
    try {
        const orgText = await getObjectContent(sourceBucket, sourceKey);
        if (!orgText) {
            throw new Error("アップロードされたテキストが空白です。");
        }
        console.log("原文: " + orgText);
        const translatedText = await translateJaToEn(orgText);
        if (!translatedText) {
            throw new Error("翻訳結果が空白です。");
        }
        console.log("英訳: " + translatedText);
        await generateImage(translatedText, sourceKey);
    }
    catch (e) {
        console.error("S3イベントでエラーが発生しました。", { error: e, bucket: sourceBucket, key: sourceKey });
        throw e;
    }
};
exports.handler = handler;

反映と名前の変更が完了したら、「Deploy」を選択します。

S3のアップロードをトリガーとする設定を追加します。「トリガーを追加」を選択します。

トリガーの設定でS3を選択し、バケットは【テキストを格納するバケット名】を入力してください。イベントタイプは「PUT」、サフィックスは「.txt」を入力して「追加」を選択します。

3. 動作確認

今回は以下の文章で画像生成してみます。

元気に草原を走り回るハムスターの画像

こちらの文章で画像生成をしていきます。

こちらの文章をテキストに保存し、【テキストを格納するバケット】に格納します。

しばらくすると【生成した画像を格納するバケット】に画像が格納されています。

生成された画像は以下です。3回実行してみました。


いい感じに画像が生成できていますね!

※うまく画像が生成できない場合は、CloudWatch Logsを確認しエラーを特定してみてください。

まとめ

このハンズオンではAWSの生成AIサービスBedrockの画像生成モデルを利用して日本語から画像を生成してみました。

このハンズオンを利用することで、以下のようなサービスを作成できます。

  • テキストから一括で画像を生成するサービス
  • APIリクエストの文字列から、画像を生成するAPIサービス

また今回利用したモデルの上位モデルを利用することでマーケティング用に広告画像を生成することができます。(参考:AWS Machine Learning ブログ

このハンズオンを応用して画像生成にチャレンジしてみてください。

以下AWSのAIサービス関連のおすすめ書籍です。

 

 

タイトルとURLをコピーしました