【AI駆動開発】3時間で完成!AI勢揃い+Amplifyを使って、弁当注文アプリを爆速開発&リリース!(前編) #AI #v0 #ChatGPT #Phind #Amplify

はじめに
AI駆動開発シリーズです。今回は、様々なAIを駆使して実践的なアプリを作成してみましょう。バックエンドもAWS Amplifyを利用して、全体を高速に開発&リリースしていきます。
作るもの
機能
社員向けの弁当注文サービスを作ります。

機能はシンプルで、Employee numberを入力して弁当を選ぶと、注文完了です。(バックエンドへのデータ保存のみ。)
注文の全履歴をCSVとして取得する機能も作ります。
構成
フロントエンド:React
バックエンド:AWS Amplify(GraphQLなAPI)
利用するAI
v0
v0は自然言語で入力した指示からUIを生成してくれるAIです。
当blogでも下記の記事で紹介していますので、こちらをご参照ください。
- 【AI駆動開発】v0ならこんなに簡単!UIデザインからフロント実装までが爆速に!
- 【AI駆動開発】AIを利用してUIデザインを作成してみよう!
- 【AI駆動開発】チャットベースでフロントエンドを作成できる「v0」を使ってみる
ChatGPT
おなじみのChatGPTです。今回はGPT-4を使っていきます。
Phind
PhindはChatGPTの開発者向け特化版のような位置付けになります。

機能面はChatGPTとほぼ同等になりますが、以下のような特徴があります。
- モデル(LLM)はGPTシリーズではなく、独自のものです。
- 開発者向けに特化されていて、優秀です。(一般的な質問にも対応できます。)
- GPT-4より高速です。体感ではGPT-3.5と同等です。
- ファイルの添付は有料プランでのみ可能です。
- インターネット検索ができます。
- GPT-4でもできますが、ChatGPT Plusへ加入する必要があり、有料です。Phindなら無料です。
- 不明瞭な質問をすると、意図を明確にする質問を返してきます。
- Visual Studio Code用の拡張機能があります。
- 「人間であることの確認」が頻繁に発生します。数分放置すると以下の画面に飛ばされてしまいます。

「人間であることの確認」が少し面倒ではありますが、それを踏まえても開発のお供にはChatGPTより優秀だと感じています。
今回は、原則としてChatGPTではなくPhindを使い、状況によってChatGPTも併用していきます。
実装
下記の流れで実装していきます。
- v0でUIを生成。(10分)
- create-react-appでアプリのベースを作成。(30分)
- v0で生成したUI(HTML)をアプリに取り込み。(30分)
- UIを調整。(30分)
- フロントを実装。
- 注文処理(10分)
- CSV出力処理(60分)
- Amplifyでバックエンドと結合。
- 初期設定(60分)
- 保存処理(5分)
- データ取得処理(5分)
カッコ内はおよその実績値です。
ゼロの状態から一通り動く状態まで、3時間程度で完成できました。
v0でUIを生成
まずはUIを作成して、これから開発するアプリのイメージを固めていきましょう。
v0を使って生成し、対話的に精錬していきます。
最初に投入したのは下記のプロンプトです。
弁当注文サービスを作りたい。
画面に必要な要素は下記の通り。
- 社員番号入力欄
- 弁当4種類の画像
- 内容は固定。
- 押すと、注文を実行するかのconfirmが表示される。
- 注文を実行すると
- その内容がDBに保存される。
- 画面上は「注文しました」のalertが表示され、元の画面に戻る。
- CSV出力ボタン
- 押すと、全注文についての日付・社員番号・弁当種類がCSVファイルとしてダウンロードされる。
3つのUIが生成(提案)されました。



A案がイメージに一番近いので、これをベースにして進めることにします。
次に投入したプロンプトは下記です。
弁当名は画像の下に配置する。
ラジオボタンは不要で、画像をクリックすると注文になる。
Orderボタンは不要。
Orderボタンの下にある説明は不要。

不要な要素は消え去ってくれました。
画像の配置は変わってくれませんでしたが、今のままの方がよい気がしてきたので、これで進めます。
次のプロンプトを投入しましょう。Orderなどと表示されている部分が不要なので、そこをクリックして指示します。
このあたりにある3行の説明は不要。

残念。何も変わってくれませんでした。この部分は後ほどコード上で削除することにしましょう。
UIとしてはこれでよさそうなので、完成とします。(最終的なUI)
create-react-appでアプリのベースを作成
いつものnpx create-react-app bento
でReactアプリのベースを作成します。
続けて、Yarnの初期化とESLint・Prettierの組み込みも行っておきました。
Visual Studio Code用のデバッグ設定とCI/CDの設定もしておきます。

v0で生成したUI(HTML)をアプリに取り込み
先ほどv0で作成したUIをアプリに取り込んでいきます。
v0上にはUIに対応するコードも生成されています。

この画面に表示されているnpx v0 add w1UzOcXfEI5
というコマンドでReactコンポーネントを取り込めるのですが、対応しているのはNext.jsだけで、素のReactではエラーになります。
表示されているコードを全てコピーして持ってきてもよいのですが、そのためには依存コンポーネントになっているshadcn/uiを導入する必要があり、大がかりなことになります。
今回は省力化のためにHTML版のコードを取り込むことにします。

HTML版を取り込む場合、必要なのはTailwind CSSだけです。v0からHTMLを取り込む前に、アプリ側にTailwind CSSを導入しておきましょう。やり方が分からないのでPhindに質問してみます。


指示通りに導入しておきました。
次は、v0に表示されているHTMLをコピーして、新しいコンポーネントを作成しましょう。

App.tsx
に組み込んで、表示を確認してみます。

画像がないのでalt
に設定してある文言が表示されていますが、それ以外は問題なさそうです。取り込みが成功しました!
UIを調整
機能実装の前に、まずは以下の調整を加えていきます。
- 不要な要素を廃止。
- 繰り返し部分を
map
に変更。 - 弁当の名前と画像を設定。
input
の文字色を変更。(背景色と同じで見えなかったため。)- 余白やフォントサイズなどを微調整。

UIはこれで完成です!
フロントを実装(注文処理)
弁当選択時の注文処理を実装します。

実装内容は下記の通りです。
input
をcontrolled component化。- 弁当が選択された際のイベントハンドラを実装。
- 社員番号が未入力なら、その旨を表示。
- 選択された弁当名を表示して、注文するかを確認。
- 注文する場合は、成功の旨を表示。

フロントを実装(CSV出力処理)
CSV出力では、APIから配列データを取得して、それをフロント側でCSVファイルとして保存させる予定です。APIからの取得は後ほど実装することにして、まずは配列データをCSVファイルとして保存する機能を実装しておきましょう。おそらく便利なパッケージがあると思うので、Phindで調べてみます。

なるほど、react-csv
というパッケージがあるようです。

クリックされたタイミングでデータを提供することもできそうです。もう少し質問を重ねてみます。





分かりました。asyncOnClick
をtrue
にしておいて、onClick
でデータを生成しdata
に読み込ませればよいのですね。
・・・その通りに実装したのですが、うまく行きません。クリックした瞬間に、その時点でのデータを使ってCSV出力されてしまいます。
公式ドキュメントで確認するとdone
という関数を使って制御するようです。これを組み込んでみたのですが、挙動が変わりません。そもそもdone
を呼ばないと出力が開始されない仕様のはずですが、最初に実装したものはdone
を呼んでいないのに出力が開始されてしまっています。
今度は公式のIssueを確認します。同様の問題が大量に報告されています。どうやら、react-csv
自体の問題のようです。
仕方がないので、こちらで提案されているexport-to-csv
を使うことにします。そのまま公式サイトにジャンプして記載されているとおりに組み込んだところ、問題なく動作しました。
これで、ダミーデータをCSV出力できるようになりました。
念のため、データはモックAPIから取得するようにしておきます。JSONを投げるとそのままのJSONが返されるモックサービスがあった気がするので、Phindに聞いてみます。

これです。私が使いたかったのはPostman Echoです。
APIから取得できる予定のデータをPostman Echoに投げて、そこから返されるデータをCSV出力するようにしてみました。

組み込んだのですが、Postman Echoへのリクエスト時に謎のエラーが発生します。curlでは問題ないので、Reactから呼び出す時だけの問題です。まずはPhindに質問してみます。

よく分からないので、いったん保留にして、今度はChatGPTにも聞いてみます。



どうやらプロキシの設定をすればよさそうです。指示通りに設定を入れたところ、問題なく動作するようになりました!
あとは、データの取得元をAmplifyに変更するだけでよいはずです。
(後編へ続く)