Dify + Next.jsで天気に合わせた服を提案するアプリを作ってみた

社内イベント Anycloudハッカソン開催しました!の記事にもあるように、2024年の11月末に社内ハッカソンがあり、生成AIを用いたプロダクトを開発しました。
今回は自分のチームで作成したプロダクトの詳細や技術構成について、紹介していこうと思います。
プロダクト概要
自分のチーム(チーム「からあげ」)は、服の画像をアプリに登録しておくと、その日の天気や気温、湿度に合わせた服を提案してくれるアプリを作りました。
冒頭の記事にデモ動画があるので、そちらもぜひ見てください。
このアプリを作ることになった経緯は、チームメンバーと、天気や気温を見ても意外とその日の最適な服って分からないという話から、ここを解決するアプリを作ることになりました。
技術構成
技術構成はシンプルで、フロントエンドにNext.js、バックエンドにDifyを使用しています。
※ Difyの説明は割愛します 🙏
DifyのAPIをNext.jsのAPI Routesから呼び出して、サーバーレスなアプリケーションにしています。
このハッカソンでは、プロダクトをデプロイするとこまでが目標だったため、サーバーやDBは用意しない方針にしました。
天気情報の取得には、無料で使用できてそれなりの精度が出る Open-Meteo を使用しています。
天気の情報は、天気コードで返ってくるのですが、コードの種類が約100個あり驚きました。
参考: 天気コード一覧
今回は、この天気コードを無理やり「晴れ」「曇り」「雨」の3つにマッピングして、天気情報を表示しています。
チームメンバー
チームメンバーは、自分ともう1人(Aさん)の2人でした。
自分が主にフロントエンドを担当して、Aさんはバックエンド(Dify)を担当して進めました。
生成AIを活用している箇所
アプリの機能一覧は、ざっくり以下です。
- 服の画像の登録
- ファイルアップロード
- 服の分析
- 今日の天気に最適な服を提案する
- 今日の天気の閲覧
今回は、服の分析に生成AIを活用しています。
服の分析では、今日の天気に最適な服を提案するために、アップロードされた服の写真を分析して、服ごとに以下の情報を出しています。
- カテゴリ
- トップス、ボトムス、アウターなど
- 最高気温
- 最低気温
- 最高湿度
- 最低湿度
この服の画像を分析する部分で、Difyのワークフローを組んで、gpt-4oに画像ファイルを渡し、以下のプロンプトで実行しています。
1. 画像を分析し、服のカテゴリーを特定してください。カテゴリーは「tops」、「bottoms」、「one-piece」、「outerwear」、「underwear」、「accessories」のいずれかです。また、天気も特定してください。天気は["sunny", "cloudy", "mist", "rain", "snow", "thunder", "hail"]のいずれかです。
2. 服のカテゴリーを特定した後、その服が最適な天気条件を考慮してください。
3. 最適な天気条件には、天気(weather)、最高気温(max_temperature)、最低気温(min_temperature)、最高湿度(max_humidity)、最低湿度(min_humidity)、服に適した天気条件の理由(suitable_weather_reason)を日本語で含めてください。
4. 出力は、カテゴリー名と天気条件を明確に示す形式で行ってください。
5. 出力にはXMLタグを含めないでください。
これによって、それなりに高い精度で、服ごとにカテゴリと天気の情報を持たせることができました。
生成AIがなければ、ハッカソンという限られた時間のなかで、この分析は実装できなかったため、生成AIの恐ろしさを感じました。
UIのコードはv0を活用
フロントのUI作成には、v0を使用して効率化しました。
UI自体は、自分でFigmaで作成していたため、v0にはUIの画像を投げて、コードを出しもらいました。
以下のように雑に画像を投げるだけで、すぐにコードを出力してくれるので、とても便利でした。


v0が出してくれたコードをコピーしつつ、プロダクトのコードに合わせて調整を行いました。
また、v0に投げた画像(自分がFigmaで作成したUI)が以下の画像なのですが、色合いや気温部分のデザインが、v0が出してくれたUIのほうが良かったため、採用させていただきました笑

工夫したこと
服の画像ファイルの保存方法
DBを持たない方針で進めていたため、服の画像を保存するかどうかも論点にありました。
一応ハッカソンのデモのときに、参加者が確認できれば良かったため、保存しないことも考えましたが、プロダクトとしては服が保存できないことは致命的なため、ローカルストレージで保存するようにしました。
また、服の画像アップロードにも、DifyのファイルアップロードAPIを使用しているのですが、Difyにアップロードしたファイルは、数分でアクセスできなくなります。
そのため、Difyにファイルをアップロードした直後に、画像ファイルのバイナリデータをローカルストレージに保存することで、Difyの有効期限が切れたあとでも、アプリ上で画像を表示できるようにしました。
サンプルデータ
アプリを触るためには、服の写真が必要ですが、ハッカソンのデモのときに服の写真を持っている参加者はいないと考えたため、アプリ上でサンプルデータを用意して、スムーズにアプリを触れるにしました。
ハッカソン内にできなかったこと
限られた時間のなかで、それなりのクオリティのアプリを作ることができましたが、時間内でできなかったこともありました。
最適な服の提案
服の分析の部分で、最高気温、最低気温、最高湿度、最低湿度を出したと言いましたが、実際に服を提案するときには、最高気温と最低気温しか考慮できていません。
本当は湿度、風速、紫外線なども考慮した上で提案することが理想でした。
パフォーマンス
今回のハッカソンで、はじめてDifyを触ったため、Dify力が足りず、複数の画像ファイルを受け取って、複数ファイルをgpt-4oに渡すことができませんでした。。
単体ファイルで処理することはできたため、ファイルの数だけDify APIを叩いています。
pngファイル以外の対応
服の画像ファイルのバイナリデータを、ローカルストレージで保持していると書きましたが、この影響により、時間内ではpngファイルしか対応できない結果となりました。。
まとめ
自分は生成AIの知見が浅かったため、このハッカソンで知見が深まり、良い機会でした。
また、この記事では、自分の視点から工夫した点や、できなかったことを書きましたが、Difyのワークフローや、プロンプトの改善、天気と服装における指標などは、チームメンバーがとても工夫してくれました。
今回は書けませんでしたが、DifyのファイルアップロードAPIで少し苦しんだ部分があったので、それは次回の記事で書こうと思います!