【個人開発記録】画像生成機能を実装する【しりとり画像ジェネレーター】
はじめに
開発中アプリの概要
画像生成機能が子供の興味・動機づけとなり、生成プロンプトとなるしりとりをタイピング形式で行うことで結果的に「ローマ字タイピングの練習につながる」といった狙いがあります。
主要機能である画像生成に関する実装を行う上で前回はプロンプトを英単語に翻訳する翻訳APIを自作する方法を紹介しました。
今回は実際に画像生成を行う Stable Diffusion
のAPIを導入する簡単な手順について紹介します。
最後にRailsにおける導入例も掲載しますので参考になれば幸いです。
(Python
に関する記事しかないんだもん。。。なのでRails使いの方の力になれたらうれしいいいいぃぃぃ)
生成AI系のAPIを導入する
アプリケーションに画像生成機能を実装する上で必要な画像生成API。
DALL-E3
や Midjourney
などの高品質な有料APIを使いたいところですが、
初めてのオリアプ開発でどれだけ費用がかさむのか見通しが読めないのでなるべくなら無料のオープンソースを使いたい。。。
と、いうことで Stable Diffusion
のAPIを導入することにしました。
Stable DiffusionのAPI取得方法
方法論は色々ありますが、私はWeb APIを呼び出す方法を取ります。
Stable Diffusion
のページから直接APIの提供はしておらず、
Hugging Face
(Stable Diffusion
のAPIを管理しているGitHubみたいな仕組み)を通じて画像生成系AIの公開モデルのエンドポイントの情報(Web APIのURL)を拾いに行きます。
(1)アクセストークン(APIキー)の作成
図解手順
- まずはユーザー登録を行います。(ユーザー登録方法は省略)
- 右上のメニューアイコンを展開してSettingをクリック
-
New token
でAPIキーを作成します。 - このAPIキーを
環境変数
として使用します。(環境変数の設定は本題ではないので省略します)
(2)モデルの選定
図解手順
-
Hugging Face
のトップページのヘッダーかフッターにある(画面サイズによって位置が変わる)Models
からText-To-Image
のフィルターがかかった画面を表示します。 - いずれかのモデルページを表示し
Deploy
→InferenceAPI(serverless)
の順にクリック
Stable Diffusion
は Python
で使うことがほとんどのようでコード例などはほぼほぼ Python
で掲載されてます。
のちほど Railsアプリ
で扱う際のコード例を掲載しますのでとりあえず赤枠の部分だけコピーします。
RailsでAPIリクエストのロジックを定義
-
Gemfile
にHTTParty
をインストールする
gem 'httparty'
bundle install
- APIの呼び出しに関するロジックをサービスクラスとして定義する
app/sevices/stable_diffusion_service.rb
ファイルを作成
require 'httparty'
require 'base64'
class StableDiffusionService
API_URL = "https://#{ここに先ほどコピーしたHugging FaceのAPIエンドポイントURLを記載}"
HEADERS = {
"Authorization" => ENV['STABLE_DIFFUSION_API_KEY'] # 作成したAPIキーは環境変数化して取得する
}
TIMEOUT_SECONDS = 60
def self.query(prompt, negative_prompt = nil)
payload = if negative_prompt # negative_promptが指定されていれば、それを含むリクエストペイロードを作成。
{ inputs: prompt, parameters: { negative_prompt: negative_prompt } }
else
{ inputs: prompt }
end
response = HTTParty.post(API_URL, body: payload.to_json, headers: HEADERS, timeout: TIMEOUT_SECONDS) # HTTPartyを使ってPOSTリクエストを送信し、レスポンスを取得。
case response.code # HTTPレスポンスコードによる処理の分岐。
when 200
return response.body # ステータスコード200の場合、レスポンスボディを返す。
when 404
raise StandardError, "リソースが見つかりません。"
when 500
raise StandardError, "サーバー内部エラーが発生しました。"
else
raise StandardError, "API呼び出しで予期しないエラーが発生しました。ステータスコード: #{response.code}" # その他のステータスコードの場合
end
rescue Net::ReadTimeout => e
raise StandardError, "リクエストがタイムアウトしました: #{e.message}"
rescue HTTParty::Error => e
raise StandardError, "HTTPartyでエラーが発生しました: #{e.message}"
rescue StandardError => e
raise StandardError, "API呼び出しでエラーが発生しました: #{e.message}"
end
end
- コントローラーから呼び出す
最後にrender json:
でJavaScript
へデータを返却しています。
# 〜省略〜
def create
words = params[:words].join(", ")
translated_words = TranslationService.translate(words) # 前回記事で紹介したAPIの呼び出し
image_bytes = StableDiffusionService.query(translated_words, negative_prompt)
image_data = Base64.encode64(image_bytes)
render json: { image: image_data }
end
さいごに
モデルの選定にこだわり始めるとキリがないですが、こだわらないと不適切な画像がバンバンでてきてしまうので看過できるレベルの出力ができるモデルを選択しました。
(アプリのターゲットが小学校低学年の子なので)
今日現在で使用しているモデルはこちらです。
もしオススメのモデルがあれば教えてください^_^(切実)
Discussion