[AWS+OpenAI+Next.js]画像を生成するWebアプリを作った

こんにちは。自称デザインエンジニアこときゃのんです。

最近AWSの構成図をなんとなく理解できるようになったので、自分でもAWSを触ってみたくて画像を生成するWebアプリを作りました。今回はそのまとめです。
AWS初めて触りましたが、数時間あれば作れたので入門編にいいかもです。

## 参考にした記事

構成やAWSの使い方はこちらを参考にしました。

https://aws.amazon.com/jp/builders-flash/202402/bedrock-image-generation/ 

OpenAIのAPIの呼び出し方はこちらを参考にしました。

https://qiita.com/nabata/items/3db85197404d2ee55f36

## 今回の設計
**バックエンド側**
言語はpythonで書きました。Lambda関数を使って以下の処理を行うAPIを構築し、API Gateway経由で実行できるようにします。
- クライアントから送られてきたテキストを受け取る
- そのテキストをもとに画像を生成
- 生成した画像をS3に保存
- 保存した画像の署名付きURLを取得してクライアントに返す

![Screenshot 2025-03-29 at 23.58.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628307/9a9823d0-0b24-451a-a5a5-1df4f503431f.png)

当初は過去に生成した画像を一覧で見られるような機能もつけようとしてたのですが、一旦水色で囲った部分だけ今回は作ります。

**フロントエンド側**
今回はNext.jsを使いました。本業デザインやってるとは思えない雑さですが、イメージは以下のような感じです。
- テキスト入力
- 送信
- 生成された画像を表示

をできるようにしておきます。

![Screenshot 2025-03-29 at 23.58.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628307/a9fbfee4-df64-4e40-9b14-a79aaa2ec58b.png)

## AWS編

Lambdaにアップロードするコード以外、[今回参考にした記事](https://aws.amazon.com/jp/builders-flash/202402/bedrock-image-generation/ )そのまんまです。

記事を参考にしつつ、ChatGPTに「画像生成をOpenAIでするパターンのプログラムを書いて」で大体完成です。色々エラーが出るので、1つずつChatGPTに聞きながら直しておきます。

<details close><summary>サンプルコード</summary>

```python:function.py
import json
import os
from base64 import b64decode
from uuid import uuid4

import boto3
from openai import OpenAI

OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]


def handler(event, context):
    request = json.loads(event["body"])

    # OpenAIのDALL・E 3を使用して画像を生成する
    client = OpenAI(api_key=OPENAI_API_KEY)
    response = client.images.generate(
        model="dall-e-3",
        prompt=request["text"],
        n=1,
        size="1024x1024",
        response_format="b64_json",
        quality="standard",
        style="vivid",
    )

    # 画像をLambdaのエフェメラルストレージに保存
    file_name = f"{str(uuid4())}.png"
    with open(f"/tmp/{file_name}", "wb") as file:
        file.write(b64decode(str(response.data[0].b64_json)))

    s3_client = boto3.client("s3", region_name="ap-northeast-1")
    bucket_name = "image-generator-bucket" # バケット名

    # S3に生成した画像をアップロード
    s3_client.upload_file(
        Filename=f"/tmp/{file_name}",
        Bucket=bucket_name,
        Key=file_name,
    )

    # アップロードした画像の署名付きURLを取得
    presigned_url = s3_client.generate_presigned_url(
        ClientMethod="get_object",
        Params={
            "Bucket": bucket_name,
            "Key": file_name,
        },
        ExpiresIn=3600,
    )

    return {
        "statusCode": 200,
        "headers": {
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Headers": "Authorization,Content-Type",
            "Access-Control-Allow-Methods": "POST,OPTIONS",
        },
        "body": json.dumps(
            {
                "presigned_url": presigned_url,
            }
        ),
    }
```
</details>

## 画面実装編

こんな感じでChatGPTに聞くとそれっぽいフロント実装をしてくれました。

>　- 文字を入力して送信ボタンを押すと、そのテキストを送信
>　- そのテキストを元に生成した画像を表示
>　- 以下はAPIにリクエスト送るための命令文
>　curl -X POST SAMPLE_API   // 作ったAPI
>　  -H "Content-Type: application/json" \
>　  -d '{"text": "入力した文章"}'

実際にできたもの

![Screenshot 2025-03-30 at 0.48.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628307/79243ea3-f6e2-4031-99a3-4c2601054e02.png)



## 完成!

無事画像生成できました！

![Screenshot 2025-03-30 at 0.11.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628307/31ad14e3-863a-46be-af0a-35cfdb302572.png)

## 感想
制作時間の7割はエラーとの戦いだったのですが、AWSを使いこなせるようになってきたら多分30分もかからず作れるのだと思うとなかなかすごい時代ですね。