🦓

[Laravel]OpenAI APIを使って画像を生成する

2023/11/08に公開

はじめに

LaravelアプリにOpenAIを導入しユーザーのアバターを生成する機能を作っていきます。

https://github.com/openai-php/laravel

https://platform.openai.com/docs/api-reference/images

環境

PHP 8.x
Laravel 10.x
MySQL 8.x

tl;dr

  1. OpenAIパッケージをインストールする
  2. OpenAI設定ファイルを作成する
  3. APIキーを作成する
  4. POSTリクエスト用ルートを追加する
  5. ビューにボタンーを追加する
  6. 画像を保存するロジックを追加する
  7. 画像を表示する
ユーザーテーブルとアバター用カラムが作成された上で進めていきます。

OpenAIパッケージをインストールする

composer require openai-php/laravel

OpenAI API設定ファイルを作成する

➜   php artisan vendor:publish --provider="OpenAI\Laravel\ServiceProvider"

   INFO  Publishing assets.  

  Copying file [vendor/openai-php/laravel/config/openai.php] to [config/openai.php] ..... DONE

vendor/openai-php/laravel/config/openai.phpを作成されました。

APIキーを作成する

OpenAI APIは有料なのでご注意くださいー
新規アカウントを作成すると5ドル分のトライアルクレジットをもらえるので新規アカウントを作成し、
作成されたキーをコピーし、アプリの.envファイルに環境変数として追加します。
こちらのURLからAPIキーを作成します。
https://platform.openai.com/api-keys

.env
OPENAI_API_KEY=************

POSTリクエスト用ルートを追加する

APIにPOSTリクエストを送るルートを追加します。

routes/web.php
Route::middleware('auth')->group(function () {
    Route::post('/profile/avatar/ai', [ProfileController::class, 'generateAvatar'])->name('profile.avatar.ai');
});

ビューにボタンーを追加する

ユーザーがボタンをクリックしてアバター画像を生成されることを想定しているのでボタンを追加していきます。

resources/views/profiles/partials/update-profile-information-form.blade.php
<form method="POST" action="{{ route('profile.avatar.ai') }}">
    @csrf
    <button type="submit">アバターを生成する</button>
</form>

画像を保存するロジックを追加する

生成された画像をUserテーブルのimageカラムに保存するコードを追加します。

app/https/controllers/ProfileController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Support\Str;
use OpenAI\Laravel\Facades\OpenAI;

    public function generateAvatar(ProfileUpdateRequest $request)
    {
        $avatar = OpenAI::images()->create([
            "prompt" => "", // プロンプト
            "n" => 1, // 枚数
            "size" => "256x256", // サイズ
        ]);
    
       // 画像のURLを取得する
        $url = $avatar->data[0]->url;
    
       // 画像名を生成する
        $filename = Str::random(10);
	// 保存する場所を指定する
        $path = "uploads/$filename.jpg";
    
       // 古い画像を削除する
        if ($currentImage = $request->user()->image) {
            Storage::disk('s3')->delete($currentImage);
        }
    
        // URLから取得した画像を指定した$pathに保存する
	// fopen()はURLを読み込むメソッド
        $path = Storage::disk('s3')->put($path, fopen($url, 'r'), 'public');
	
	// s3から画像のパスを取得する
	$path = Storage::disk('s3')->url($path);
   
        $request->user()->image = $path;
        $request->user()->save();
    
        return Redirect::route('profile.edit')->with('status', 'プロフィールを更新しました!');
    }

https://www.php.net/manual/en/function.fopen.php

dd($avatar)で取得した生成された画像のプロパティ:

OpenAI\Responses\Images\CreateResponse {#2012 ▼ // app/Http/Controllers/ProfileController.php:69
  +created: 1699362550
  +data: array:1 [0 => OpenAI\Responses\Images\CreateResponseData {#2240 ▼
      +url: "https://oaidalleapiprodscus.blob.core.windows.net/private/org-OTDHHR8TMCN1dPrPXll3Dt2y/user-CHz1JdDOH0IojfSzz5TQZ8zw/img-o4g7hPaUzWL24Eo3Cy6xkhNZ.png?************** ◀"
      +b64_json: ""
    }
  ]
  -meta: OpenAI\Responses\Meta\MetaInformation {#2284 ▼
    +requestId: "d91cc448b391df6930db253feae3d78c"
    +openai: OpenAI\Responses\Meta\MetaInformationOpenAI {#2266 ▼
      +model: null
      +organization: "user-chz1jddoh0iojfszz5tqz8zw"
      +version: "2020-10-01"
      +processingMs: 6486
    }
    +requestLimit: null
    +tokenLimit: null
  }

リクエストのパラメーターについて公式を参考にしています:

パラメーター 説明
prompt(必須) 生成する画像の説明や要件を指定します。AIに対してどのような画像を生成するかの指示を含めることができます。
model 使用するモデルのバージョンを指定します。デフォルトはdell-e-3です。
n 生成する画像の数を指定します。複数の画像を一度に生成する場合に使用します。
size 生成する画像のサイズを指定します。例: "256x256"。
response_format 画像のフォーマットを指定します。urlb64_jsonを指定できます。
style 画像のスタイルを指定します。vividnatureを指定できます。
user ユーザーと紐付けします。

https://platform.openai.com/docs/api-reference/images/create

画像を表示する

前回にアップロード機能を実装する時のコードをそのまま使えるのでコードを載せます。

resources/views/components/user-image.blade.php
<div x-data="imagePreview()">
    <input @change="showPreview(event)" type="file" id="image" name="image" class="mt-1">
    <img src="{{ isset(Auth::user()->image) ? Auth::user()->image : asset('images/no-image.png') }}" alt="" class="w-9 h-9 mt-3 rounded-md object-cover" id="preview">

    <script>
        function imagePreview(){
            return {
                showPreview: (event) => {
                    if (event.target.files.length > 0){
                        var src = URL.createObjectURL(event.target.files[0]);
                        document.getElementById('preview').src = src;
                    }
                }
            }
        }
    </script>
</div>

終わりに

Open AIを使ってユーザーのアバターを生成することができましたー
今回は指定したプロンプトで画像を生成してるのですが、他のプロンプトの出し方も試してみたいと思います。

Discussion