AIコーディネーターに聞いてみた！「明日のコーデ」をImagen3とGemini2.0 Flashで完全再現！🤖👗

## はじめに
みなさま、毎日の服装選びに悩んでいませんか？ この記事では、そんな悩みを解決してくれるAI搭載のコーディネートアプリを開発する方法を紹介します。
また最近GAされたImagen3とバージョンアップしたGemini2.0を使っておりますのでご参考程度にご覧いただければと思います。

## 開発環境や利用する技術など
### 開発環境
- OS: MacOS14.5(Sonoma)
- 開発言語: Python
- 使用ブラウザ: Google Chrome

### 利用する技術や主要サービス
- Vertex AI(Google Cloud)
    - gemini-2.0-flash-exp
    - imagen-3.0-generate-001
- Streamlit
- venv(仮想環境用)

## ソースコード
https://github.com/okinao/weather-wear-ai

## 1. 気象情報の取得
こちらのAPIを使用して気象庁が配信している天気予報を取得します。

https://weather.tsukumijima.net/

利用方法はベースとなるURLに天気予報を取得したい地域のID番号を付与してリクエストを送ることでJSON形式のレスポンスを受け取ることができます。

### 地点定義表を検索する
リクエストのパラメータ(地域ID)は全国の地点定義表を検索して取得したい地域のIDを使用します。

https://weather.tsukumijima.net/primary_area.xml

### 地域別に天気予報を取得する
例えば東京(130010)の天気予報を取得したい場合は以下2パターンのいずれかでリクエストを送ります。

```
https://weather.tsukumijima.net/api/forecast/city/130010
```
または
```
https://weather.tsukumijima.net/api/forecast?city=130010
```

### 実装例
```python
url = f"https://weather.tsukumijima.net/api/forecast?city={city}"
response  = requests.get(url)
response.raise_for_status()

data_json = response.json()

date_str = data_json["forecasts"][1]["date"]
date = datetime.strptime(date_str,"%Y-%m-%d").strftime("%Y年%m月%d日")
title = data_json["title"]
weather = data_json["forecasts"][1]["telop"]
max_temp = data_json["forecasts"][1]["temperature"]["max"]["celsius"]
min_temp = data_json["forecasts"][1]["temperature"]["min"]["celsius"]

results = f"{date}の{title}は{weather}です。\n最高気温は{max_temp}度、最低気温は{min_temp}度です。\n"
T00_06 = data_json['forecasts'][1]['chanceOfRain']['T00_06']
T06_12 = data_json['forecasts'][1]['chanceOfRain']['T06_12']
T12_18 = data_json['forecasts'][1]['chanceOfRain']['T12_18']
T18_24 = data_json['forecasts'][1]['chanceOfRain']['T18_24']

results += f"降水確率は0時から6時まで{T00_06}、6時から12時まで{T06_12}、12時から18時まで{T12_18}、18時から24時まで{T18_24}です。"
```

簡単に解説すると天気予報APIにリクエストを送るとJSON形式でレスポンスが返ってきますので、必要な情報を取り出して変数に格納しています。取り出した天気予報のデータを元にGeminiへ与える気象情報プロンプトを作成します。

![気象情報取得.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799071/67519398-2e9b-fdd0-8cd3-e7d34af6bdbf.gif)


## 2. Gemini2.0でコーディネート案を作成
次にAPIで取得した気象情報からプロンプトを作成してGeminiにリクエストを行います。
「トップス」、「ボトムス」、「アウター」、「足元」、「小物」の5つに分けてシンプルに回答を返すようにします。

今回はGoogle CloudのVertex AI Studioを使って検証を行い、コンソール画面で提示してくれるソースコードを利用していきます。

![VertexAI検証.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799071/a3c1702d-ad05-5701-a215-49b6bd3c3768.png)

期待する回答が得られそうですのでこのソースコードを使用します。Vertex AIでは画面右上の`コードを取得`をクリックすると、同じ処理を再現可能なソースコードを提示してくれます。

![スクリーンショット 2025-01-04 18.29.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799071/ef2f3de1-6e50-07ef-c146-58795ddec521.png)

### 実装例

```python
def generate(conditions: str) -> str:
  client = genai.Client(
      vertexai=True,
      project=PROJECT_ID,
      location=LOCATION
  )

  text1 = types.Part.from_text(f"""{conditions}
上記の条件にあう服装を考えてください。
回答は以下の形式で必要な内容だけ回答してください。
トップス：
ボトムス：
アウター：
足元：
小物：""")

  contents = [
    types.Content(
      role="user",
      parts=[
        text1
      ]
    )
  ]
  generate_content_config = types.GenerateContentConfig(
    temperature = 0,
    top_p = 0.95,
    max_output_tokens = 8192,
    response_modalities = ["TEXT"],
    safety_settings = [types.SafetySetting(
      category="HARM_CATEGORY_HATE_SPEECH",
      threshold="OFF"
    ),types.SafetySetting(
      category="HARM_CATEGORY_DANGEROUS_CONTENT",
      threshold="OFF"
    ),types.SafetySetting(
      category="HARM_CATEGORY_SEXUALLY_EXPLICIT",
      threshold="OFF"
    ),types.SafetySetting(
      category="HARM_CATEGORY_HARASSMENT",
      threshold="OFF"
    )],
    system_instruction=[types.Part.from_text("""あなたはプロフェッショナルの服装コーディネーターです。""")],
  )

  result = client.models.generate_content(
    model = GEMINI_MODEL,
    contents = contents,
    config = generate_content_config,
  )
  return result.text
```

汎用性を持たせたいので気象条件の部分は変数conditionsにして、動的にリクエストできるよう変更しています。

![コーディネート案作成.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799071/a003e290-4443-047c-4e02-094eb98b87f7.gif)

## 3. Imagen3でコーディネート画像を生成
次にGeminiで考えてもらったコーディネート案を元に、画像生成モデルのImagen3を使ってモデル画像を生成していきます。

画像生成もVertex AI Studioを使って軽く動作を見てみます。
以下は実行後の結果ですがプロンプトを入力してリクエストを送ると画像が生成されていることが確認できます。

![スクリーンショット 2025-01-04 18.47.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799071/ea8f1860-6cbf-831c-1c47-7253fccbb3b9.png)

Imagenのコンソール画面では現状ソースコードの提示はありませんので、公式のドキュメントに記載されているソースコードを利用します。

https://cloud.google.com/vertex-ai/generative-ai/docs/image/generate-images?hl=ja#text-image-gen

### 実装例

複数の画像を保存できるようにループ処理を追加しています。

```python
def generate_image(prompt: str) -> None:
    model = ImageGenerationModel.from_pretrained(IMAGEN_MODEL)

    images = model.generate_images(
        prompt=prompt,
        number_of_images=2,
        language="ja",
        aspect_ratio="1:1",
        safety_filter_level="block_some",
        person_generation="allow_adult",
    )

    for i, image in enumerate(images, 1):
        output_file = f"images/image-{i}.png"
        image.save(location=output_file, include_generation_parameters=False)
```

アプリ側で生成した画像を表示してみました。

![スクリーンショット 2025-01-04 18.57.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799071/de21d9b2-a14a-d8a5-4374-955372abeba9.png)

ちなみにImagenでの画像生成では画像のアスペクト比や生成する画像の枚数、セーフティフィルターの設定などを行うことが可能です。

## 4. Geminiでコーディネート画像のAI解説を生成
画像を表示するだけだとコーディネートのポイントがわからないので、Geminiに画像とプロンプトを渡してAI解説を生成するようにします。

解説の観点は「全体的な印象」、「各アイテムの詳細」、「コーディネートのポイント」、「その他」、「おすすめのシーン」の5つにしています。

### 実装例

```python
def generate_description(image_path: str) -> str:
  vertexai.init(project=PROJECT_ID, location=LOCATION)
  model = GenerativeModel(GEMINI_MODEL)

  contents = [
    Image.load_from_file(image_path),
    """添付画像のコーディネートを以下の内容で解説してください。前置きは不要で以下の内容だけ返してください。

全体的な印象：
各アイテムの詳細：
コーディネートのポイント：
その他：
おすすめのシーン："""]

  # Query the model
  response = model.generate_content(contents=contents)
  return response.text
```

アプリで生成したAI解説を表示させてみます。
![スクリーンショット 2025-01-04 19.04.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799071/84ccadf3-5a1c-71a4-def8-037639d3857a.png)

それらしいAI解説がされていてコーディネートの納得感がでますね！

## 5. 人物像の設定
このままでも試作としては満足していますが、性別や年齢は設定できた方が良いのでセレクトボックスを追加します。

![スクリーンショット 2025-01-04 19.10.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799071/9a877e73-3f70-7570-3fb5-401fc040e7f5.png)

Streamlitではほんの数行のソースコードでUI実装ができるので、かなり使い勝手が良かったです。


## 実行
通しで実行してみるとこのような感じです。

![服装コーディネートAI.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799071/e685bb00-62d8-9fab-781a-62969b3f9a2c.gif)

福岡の天気予報が曇のち一時雨で寒い1日になるということで暖かい服装かつ冬らしい落ち着いた色使い、そして雨対策に傘を持っているのは良い点です。また20代の男性という条件でイメージ画像が生成されているので精度も悪くないように思います。

改良案としてはコーディネートの色合いを設定できたり、手持ちのアイテムを組み合わせられたりするとより実用的になるかなと思います。


## さいごに
最後までご覧いただきありがとうございます。冬季休暇中のお勉強のため、気になっていたImagen3とGemini2.0、Streamlitを使って服装コーディネートAIのアプリを試作してみました。
Google Cloudのサービスは使い方がシンプルだったり公式のドキュメントが充実しているため検証や開発が進めやすかったです。
ImagenのSDKも初めて使ってみて面白かったのでもう少し遊んでみようと思います。