Safie Engineers' Blog!

Safieのエンジニアが書くブログです

新卒エンジニアが初めてAWSでアプリをデプロイして学んだこと

この記事はSafie Engineers' Blog! Advent Calendar 2日目の記事です。

はじめに

こんにちは!セーフィーに25新卒で入社し、AI開発部に配属された川上です。

学生時代は研究で、人の歩き方を解析するAIの開発をしていました。

そして配属前に行われた研修では、社内備品を管理するアプリTreasure Collectionを開発しました。(Treasure Collectionの記事は後日掲載されるのでぜひご一読ください。)

この記事では私が新たな技術領域を身に付けるためにアプリの開発に挑戦した話をしたいと思います。

私にできること

先に述べたように、学生時代はPythonをつかって映像の研究をしていました。そして研修のTreasure Collectionの開発では、入社するまでに体験したことがなかったフロントエンド領域を担当しました。研修を終えて、フロントエンドとバックエンド(データ処理)の領域を経験したエンジニアになれました。

しかしながら、インフラ領域が分からないという気づきも得ました。

Treasure CollectionはWebアプリで、デプロイなどのインフラ回りはすべてチームメンバーが実装してくれました。フロントエンドの技術は身につけられましたが、アプリをユーザーに届ける方法が分からないという状況になりました。

新たに作ったもの

これから、研修を終えた後に開発したice-breakerというWebアプリの紹介をします。このアプリを作ったことで新たな技術領域を体験でき、ユーザーに作ったものを届けられるようになったのでそこを共有できればと思います。

アプリの紹介

ice-breakerはミーティングなどの冒頭で行うアイスブレイク・チェックインのお題を提供します。

アイスブレイクとチェックインは少し異なるものですが、大まかに以下のように説明できます。

アイスブレイク、チェックインとは
目的:集まりの冒頭で、参加者の間の緊張をほぐし、場に活気や一体感を生み出すこと。

特徴:「場」の雰囲気づくりに焦点を当てる。
多くの場合、ゲームや簡単なアクティビティ形式で行われる。
参加者同士が気軽に話せるきっかけを提供し、本題に入る前の心理的な障壁を取り除く。

このアイスブレイク、チェックインはセーフィーに入社してから何度も行ってきました。そしてこの度、アイスブレイク、チェックインに役立つアプリを開発しました。

アプリにアクセスすると次のような画面が表示されます。

画面左側の“話題を生成”ボタンを押すとボタンの下にお題が表示されます。

参加者一覧に名前を入力し”追加”ボタンを押すと参加者が追加されていきます。

“次の発表者”ボタンを押すとボタンの左に次の発表者が表示され、発表済みに発表者が追加されます。

“次の発表者”ボタンを何度か押して、全員が発表済みに追加されると”終了!全員話し終わりました”と表示されます。

作ったきっかけ

配属前に行っていた研修の週次定例の冒頭に、10分程度のアイスブレイクを行っていました。

アイスブレイクのお題はその都度考えていたために、お題に困ることがありました。

また進め方はお題を考えた人が最初に発表して、発表した人が次の発表者を指名するという方式をとっていました。この進め方はアイスブレイクが盛り上がるいい方法でした。しかし、「全員発表した?」と確認したり「次誰にしよう」と悩んだりして、時間を使ってしまうためにアイスブレイクの予定時間を少し超えてしまうという問題もありました。

行っていたアイスブレイクのよさを保ちながら、困りごとを解決するためのアプリを作ってみようと思ったことがこのアプリを作ったきっかけです。

作り方

ここからはアプリの作り方を説明します。

AWS Bedrockでお題を生成

まず、アプリの核となるお題の生成についてです。

お題の生成は生成AIで行っています。生成AIはAWS Bedrockから利用しました。AWS Bedrockにアクセスし、APIキーを発行します。

Next.jsでUI実装

UIはNext.jsで実装しました。Next.jsを使った理由は研修で唯一身につけたフロントエンドの技術スタックだからです。

アプリの構成は以下のようになっています。

src/app/
├── page.tsx              # メインUI(クライアントコンポーネント)
├── api/
│   └── bedrock/
│       └── route.ts      # Bedrock API呼び出し(サーバーサイド)
└── components/
    ├── addNames.tsx      # 参加者追加コンポーネント
    └── participants.tsx  # 参加者表示コンポーネント

UIはシンプルなのですべての紹介は控えますが、工夫したことを2つ紹介します。

  1. 同じ話題が表示されないようにプロンプトを改善

    api/bedrock/route.tsではAWS BedrockのAPIにプロンプトを含んだ、API Requestを送信しています。そのコードは以下のようになっています。

     import { BedrockRuntimeClient, ConverseCommand } from "@aws-sdk/client-bedrock-runtime";
     import { NextRequest, NextResponse } from "next/server";
    
     export async function POST(request: NextRequest) {
       try {
         const url = "xxx";
         const history = (await request.json()).history || [];
    
         const payload = {
           "messages": [
             {
               "role": "user",
               "content": [{"text": 
                 "ちょっと変わったアイスブレイクの話題を1つ返して。" +
                 "過去の話題履歴: " + history.join(", ")
               }]
             }
           ],
           "inferenceConfig": {
             "temperature": 1.0,
             "maxTokens": 500,
             "topP": 1.0,
           }
         };
    
         const response = await fetch(url, {
           method: "POST",
           headers: {
             "Content-Type": "application/json",
             "Authorization": `Bearer ${process.env.NEXT_PUBLIC_API_KEY}`
           },
           body: JSON.stringify(payload)
         });
    
         const data = await response.json();
         return NextResponse.json({
           output: data
         });
       } catch (error) {
         console.error("API Error:", error);
       }
     }
    

    過去の話題履歴を page.tsxと連携してプロンプトに含めながら話題を何度か生成したときに同じ話題が表示されないようにしました。

  2. Next.jsのサーバーサイドからAPI Rrequestを送信

    以下のコードは page.tsxに実装した、話題を生成するときに実行される関数です。この関数ではまず api/bedrock にAPI Requestを送信します。これはNext.jsのサーバーサイドで実装されているAPIです。

     const onGenerate = async () => {
       setloading(true);
       const data = await fetch("/api/bedrock", {
         method: "POST",
         headers: {
           "Content-Type": "application/json",
         },
         body: JSON.stringify({
           history: history,
         }),
       })
         .then((res) => res.json())
         .then((data) => {
           setResult(data.output.output.message.content[0].text);
           setHistory([...history, data.output.output.message.content[0].text]);
         })
         .catch((error) => {
           console.error("Error fetching data:", error);
         });
       setloading(false);
    
     };
    

    先に説明したようにAWS BedrockへのAPI Requestの送信は api/bedrock から行われます。

    このようにAPIを経由してAWS Bedrockを利用していることには理由があります。それはAWS Bedrock への API Requestの送信はフロントエンドから行えないからです。セキュリティ上の理由でその仕様になっています。

    今回開発に用いたNext.jsでは別途バックエンドサーバーを立てずにサーバーサイドにAPIエンドポイントを立てることができます。図らずも、開発中に生じた課題が解決され、スムーズな開発を進めることができました。

AWS Amplifyでデプロイ

ローカル環境で動作確認を完了したら、デプロイの準備です。

デプロイはAWS Amplifyで行いました。AWS Amplifyを使って想像以上に手軽にデプロイを行えました。

AWS AmplifyへはGithub経由でアプリをデプロイできます。

作成したアプリをGithubへpushしたら以下のAWSのマニュアルに従って設定を行います。

https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/setting-up-GitHub-access.html#setting-up-github-app

設定後にAWS Amplifyにアクセスし、以下の流れでAWS Amplify上にアプリを作成します。プロバイダーはGithubを選択しました。

ここまで進めて、問題がなければすべてのアプリから、デプロイが始まっていることが確認できます。5分程度待つと、デプロイ済みに変わっていました。

この時点でもアプリはデプロイされアクセスすることができますが、もう一つ必要な設定があります。

環境変数の設定です。

すべてのアプリから、デプロイしたアプリをクリックします。サイドメニューのホスティング、環境変数を選択して、以下の画面に遷移します。

ここで変数はローカル環境で使う.envファイルで決めた変数名です。値は取得済みのAWS BedrockのAPIキーを入力します。

ここまで行うとアプリはローカルと同じように動作します。デプロイ・リリースの完了です。

終わりに

この記事では私が初めて自身の力でデプロイを行ったアプリの紹介をしました。

アプリを作ってみて考えたことが大きく2つあります。

1つ目はソフトウェアサービスの理解度が上がったことです。これまではどうやったらサービスとして動作するんだろうという漠然とした疑問を抱えながら開発などを行っていました。そこをどうやったらいいか、手段を1つでも知れたことはとても良いことだと思います。

2つ目は別のAWSサービスも利用したいと思ったことです。私はAI開発に長い間携わってきましたが、それらはローカル環境のマシンで動作させるだけでした。これを機にオリジナリティを持ったAIを使ったアプリをユーザーに届けてみたいと思いました。

私がセーフィーに入社して8カ月経ちましたが、その間新しい技術領域を体験し身に着けながら課題解決に取り組めています。この記事を読んでいただいた人にとって、セーフィーで働きながらどのように技術を身に着け成長できるかが伝わると幸いです。

© Safie Inc.