LoginSignup
25
14

GPT-4oとPower Appsで食材の写真から料理とレシピを提供するアプリをサクッと作る

Last updated at Posted at 2024-05-18

はじめに

昨日、Power AppsでGPT-4oを用いた画像から中身を判別するアプリを作成しました。
驚きの手軽さで作れることができます。

今回は作成のもととなった記事に挑戦し、食材の写真から料理を提案するアプリをサクっと作っていきましょう!

image.png

流れ

昨日作成したPower Automate フロープロンプトを変えれば、ほとんどできてしまいます。
プロンプトを変えます。

作成アクション
{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "system",
      "content": "あなたはプロの栄養士です。提供された画像から食材を分析し、作成できる料理を推定してください。"
    },
    {
      "role": "user",
      "content": [
        {
          "type": "image_url",
          "image_url": {
            "url": "@{triggerBody()?['text']}",
            "detail": "high"
          }
        },
        {
          "type": "text",
          "text": "画像にある食材から料理を提案してください。料理の名前、レシピ、カロリー、食材を推定し回答してください。調理にかかる時間も教えてください。回答は日本語でしてください。## JSON Schema {\"type\": \"object\",\"properties\": {\"cooking\": {\"type\":\"string\", \"description\": \"提案される料理名\"}},{ \"recipe\": {\"type\": \"string\", \"description\": \"料理のレシピ\"}},{\"calorie\": {\"type\": \"string\", \"description\": \"カロリー\"}},{\"ingredient\": {\"type\": \"string\", \"description\": \"食材\"}},{\"hour\": {\"type\": \"string\", \"description\": \"調理にかかる時間\"}},\"required\": [\"cooking\",\"recipe\",\"calorie\",\"ingredient\",\"hour\"],}"
        }
      ]
    }
  ],
  "temperature": 1,
  "response_format": {
    "type": "json_object"
  }
}

上記の中のコチラ↓

JSONのなかで定義をしているJSON Schema
## JSON Schema {\"type\": \"object\",\"properties\": {\"cooking\": {\"type\":\"string\", \"description\": \"提案される料理名\"}},{ \"recipe\": {\"type\": \"string\", \"description\": \"料理のレシピ\"}},{\"calorie\": {\"type\": \"string\", \"description\": \"カロリー\"}},{\"ingredient\": {\"type\": \"string\", \"description\": \"食材\"}},{\"hour\": {\"type\": \"string\", \"description\": \"調理にかかる時間\"}},\"required\": [\"cooking\",\"recipe\",\"calorie\",\"ingredient\",\"hour\"],}"

の箇所です。

propertiesに戻り値を追加します。

キー データ型 内容
cooking string 提案される料理名
recipe string 料理のレシピ
calorie string カロリー
ingredient string 食材
hour string 調理にかかる時間

JSONのなかでJSONスキーマを定義するため、ダブルクオーテーション" のまえに、 エスケープ文字\ が入ります。
ひじょーに書きづらいですね…。

こういうのもGPT-4oにお願いしちゃいましょう!

image.png

すげー!

GPT-4oに渡すJSONの定義は、作成アクションで実施します。

image.png

作成アクションで記載する中でも、JSONの形式が異常であればエラーを表示するため、誤りを見つけやすいです。

image.png

image.png

中身の文字列が変わっただけで、やっていることは一緒ですね。

  1. PowerApps (V2) トリガーで、画像のbase64文字列を、Power Appsから受け取る
  2. 作成アクションで、GPT-4oに渡す値を定義
  3. Azure Key VaultからAPIキーを取得
  4. GPT-4oHTTP要求を送信
  5. 結果をPower Appsに返す

さらっと上手くいってしまう・・・。
Power Appsのデザインに時間を投入しましょう。

前回と戻り値が異なるため、JSON の解析アクションでスキーマを再定義する必要があります。
今回の例では下記の通りとなります。

Schema
{
    "type": "object",
    "properties": {
        "cooking": {
            "type": "string"
        },
        "recipe": {
            "type": "string"
        },
        "calorie": {
            "type": "string"
        },
        "ingredient": {
            "type": "string"
        },
        "Hour": {
            "type": "string"
        }
    }
}

Power Appsに戻す値も、設定しましょう。

image.png

Power App またはフローに応答する
{
  "type": "Response",
  "kind": "PowerApp",
  "inputs": {
    "schema": {
      "type": "object",
      "properties": {
        "cooking": {
          "title": "cooking",
          "type": "string",
          "x-ms-content-hint": "TEXT",
          "x-ms-dynamically-added": true
        },
        "recipe": {
          "title": "recipe",
          "type": "string",
          "x-ms-content-hint": "TEXT",
          "x-ms-dynamically-added": true
        },
        "calorie": {
          "title": "calorie",
          "type": "string",
          "x-ms-content-hint": "TEXT",
          "x-ms-dynamically-added": true
        },
        "ingredient": {
          "title": "ingredient",
          "type": "string",
          "x-ms-content-hint": "TEXT",
          "x-ms-dynamically-added": true
        },
        "hour": {
          "title": "hour",
          "type": "string",
          "x-ms-content-hint": "TEXT",
          "x-ms-dynamically-added": true
        }
      },
      "additionalProperties": {}
    },
    "statusCode": 200,
    "body": {
      "cooking": "@body('JSON_の解析')?['cooking']",
      "recipe": "@body('JSON_の解析')?['recipe']",
      "calorie": "@body('JSON_の解析')?['calorie']",
      "ingredient": "@body('JSON_の解析')?['ingredient']",
      "hour": "@body('JSON_の解析')?['Hour']"
    }
  },
  "runAfter": {
    "JSON_の解析": [
      "Succeeded"
    ]
  }
}

Power Apps

完成系はTwitterで紹介させていただきました。

レイアウトの着想は、Power Apps loverの師匠Reza Dorrani氏のYouTubeで紹介されたアプリをオマージュしています。

コントロールのツリー図

コントロールのツリー図
Main
├─ grpComplete // 完了画面
│  ├─ btnComplete // ボタンで完了画面を閉じる
│  ├─ txtComplete
│  └─ backgroundComplete
├─ grpProgress // ロード画面
│  ├─ txtProgress
│  ├─ imgProgress
│  ├─ Progress
│  └─ backgroundProgress
└─ ScreenContainer
   ├─ HeaderContainer
   │  ├─ imgTop
   │  ├─ lblTitle
   │  ├─ Avatar
   │  └─ lblMyname
   ├─ BottomContainer
   │  └─  SidebarContainer
   │  └─ galMode // 写真のアップロードかカメラか選択
   │  │  ├─  shpSelected
   │  │  ├─ icoMenu
   │  │  ├─ lblMode
   │  │  └─ shpSelectedBackground
   │  ├─ conBadge
   │  │  └─ Badge
   │  ├─ InfoContainer
   │  │  ├─ InfoButton
   │  │  └─ lblInfo
   │  ├─ conPicture // galModeに応じて表示、非表示
   │  │  ├─ ImageContainer
   │  │  │  ├─ AddPicture
   │  │  │  └─ Image
   │  │  └─ ButtonPicture
   │  └─ conCamera // galModeに応じて表示、非表示
   │     ├─ CameraContainer
   │     └─ ButtonCamera
   └─ MainContainer
      ├─ conHeaderMain
      │  ├─ LogoImage
      │  ├─ lblHeaderMain
      │  ├─ lblCooking // 料理名を表示するテキストラベル
      │  └─ barHeaderMain
      ├─ conMainRecipe
      │  └─ txtRecipe // レシピを表示するテキスト入力
      ├─ conCalorie
      │  ├─ imgCalorie
      │  ├─ keyCalorie
      │  └─ txtCalorie // カロリーを表示するテキストラベル
      ├─ conIngredient
      │  ├─ imgIngredient
      │  ├─ keyIngredient
      │  └─ txtIngredient // 食材を表示するテキストラベル
      └─ conHour
         ├─ imgHour
         ├─ keyHour
         └─ txtHour // 時間を表示するテキストラベル

モダンコントロールでSharePointを選択。

image.png

これをもとに、コントロールのカラーに統一感を持たせます。
色の濃淡はApp.Theme.Colorsで表現しましょう

モダン コントロールのほとんどが、このテーマに沿って色の表現するため、非常に便利です。

今回はヘッダーを自作します。アバターが追加されましたね。

image.png

image.png

アイコンは下記のサイトから使わせていただいています。

image.png

ドーナツ🍩のアイコンは、PowerPointにてストック画像の色を変えて、挿入しています。

image.png

画像の追加カメラからも画像認識をすることを見据えてコントロールを用意します。
メニューの切り替えは、ギャラリーで実施します。

  • 画像の追加 モード
    image.png

  • カメラ モード
    image.png

写真を直接追加する方法カメラから写真を送る方法で、コンテナー単位でコントロールを分けます。

image.png

ギャラリーSelectedの値Visibleを連動させ、切り替えを実現します。

conPicture.Visible
(galMode.Selected.Mode="Attachment")
conCamera.Visible
(galMode.Selected.Mode="Camera")

GPT-4oから

  1. 料理名
  2. レシピ
  3. カロリー
  4. 食材
  5. かかる時間

合計5つの値を受け取るため、受け皿を加えます。
Power Automateの戻り値を受け取り、それぞれのプロパティで値を設定。

ツリー図
   └─ MainContainer
      ├─ conHeaderMain
      │  ├─ LogoImage
      │  ├─ lblHeaderMain
      │  ├─ lblCooking // 料理名を表示するテキストラベル
      │  └─ barHeaderMain
      ├─ conMainRecipe
      │  └─ txtRecipe // レシピを表示するテキスト入力
      ├─ conCalorie
      │  ├─ imgCalorie
      │  ├─ keyCalorie
      │  └─ txtCalorie // カロリーを表示するテキストラベル
      ├─ conIngredient
      │  ├─ imgIngredient
      │  ├─ keyIngredient
      │  └─ txtIngredient // 食材を表示するテキストラベル
      └─ conHour
         ├─ imgHour
         ├─ keyHour
         └─ txtHour // 時間を表示するテキストラベル

あとはPower Automate実行中の待機画面です。
GPT-4oの強みで全然時間がかからないのですが、昨日と全く一緒では芸がないので、ロード画面完了画面を入れます。

image.png

  • ロード画面 四角形に、テキストラベルとプログレスバーを入れる
  • 完了画面 四角形に、テキストラベルとボタンを入れる
ツリー図
Main
├─ grpComplete // 完了画面
│  ├─ btnComplete // ボタンで完了画面を閉じる
│  ├─ txtComplete
│  └─ backgroundComplete
├─ grpProgress // ロード画面
│  ├─ txtProgress
│  ├─ imgProgress
│  ├─ Progress
│  └─ backgroundProgress

それぞれ作成します。

画面の真ん中にコントロールが配置されるようにするには、XYのプロパティを下記のように設定します。

X
(Parent.Width - Self.Width) / 2
Y
(Parent.Height - Self.Height) / 2

ギャラリーの中のコントロールの場合は、

  • (Parent.TemplateWidth - Self.Width) / 2
  • (Parent.TemplateHeight - Self.Height) / 2

上記で定義できます。

しょっちゅう使いまわすので、覚えておいて損はないです。

これで、GPT-4oを呼び出すボタンコントロールに下記の式を設定すれば

OnSelect
/*
* ロード画面を表示する
*/
Set(varVisible1,true);
/*
* Power AutomateでGPT-4oを呼び出す
*/
UpdateContext({Response:'GPT-4o-Image-observe'.Run(Substitute(JSON(Image.Image,JSONFormat.IncludeBinaryData),"""",""))});
/*
* 完了画面を表示する
*/
Set(varVisible2,true);

ロード画面のグループ、完了画面のグループが順番に表示され、映えます!

タイトルなし 4.gif

Power Automateの昨日と異なるポイントが、ほとんどないためPower Appsの説明に重きを置きました。

ChatGPT用のカスタムコネクタを作ると、Power Automateを経由せずにできるので、さらに便利ですね。
カスタムコネクタの作り方は、Microsoftの吉野様のQiitaの記事が大変わかりやすいです。

おわりに

強力な機能が、こんなに簡単に使えて本当にいいのかと震えます。

image.png

今度は何を作ろう・・・。
ワクワクが止まりませんね!

皆様、良いPower lifeを!

25
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
14