Gemini Code Assist で開発ワークフローを強化

1. はじめに

e5b98fd4e417c877.png

この Codelab では、設計、ビルドとテスト、デプロイなど、ソフトウェア開発ライフサイクル(SDLC)の主要な段階で Gemini Code Assist がどのようにサポートできるかを見ていきます。アプリケーション全体を設計および開発し、Google Cloud にデプロイします。

このチュートリアルでは、技術イベントのセッションを検索する API とアプリケーションを構築します。各セッションには、タイトル、概要、所要時間、カテゴリ、1 人以上の講演者が含まれます。

演習内容

  • OpenAPI 仕様に基づいてウェブ アプリケーションを設計、構築、テスト、デプロイする

学習内容

  • Gemini Code Assist を使用して OpenAPI 仕様を生成する方法
  • Gemini Code Assist のコード生成機能を使用して OpenAPI 仕様の Python Flask アプリケーションを開発する方法
  • Gemini Code Assist を使用して Python Flask アプリケーションのウェブ フロントエンドを生成する方法
  • Gemini Code Assist を使用して、アプリケーションを Google Cloud Run にデプロイする方法についてサポートを受ける
  • アプリケーションのビルドとテスト中に、コードの説明やテストケースの生成などの Gemini Code Assist 機能を使用する

必要なもの

  • Chrome ウェブブラウザ
  • Gmail アカウント
  • 課金が有効になっている Cloud プロジェクト
  • Cloud プロジェクトで Gemini Code Assist が有効になっている

このラボは、初心者を含むあらゆるレベルのデベロッパーを対象としています。サンプルアプリは Python 言語で記述されていますが、内容を理解するために Python プログラミングに精通している必要はありません。Gemini Code Assist の機能に慣れていただくことを目的としています。

2. Gemini Code Assist を設定する

このセクションでは、このラボを始めるために必要なすべての手順について説明します。

Cloud Shell IDE で Gemini Code Assist を有効にする

この Codelab の以降の部分では、フルマネージドの Code OSS ベースの開発環境である Cloud Shell IDE を使用します。Cloud Shell IDE で Code Assist を有効にして構成する必要があります。手順は次のとおりです。

  1. ide.cloud.google.com にアクセスします。IDE が表示されるまでしばらく時間がかかることがあります。しばらくお待ちいただき、設定のデフォルトの選択肢をそのまま使用してください。IDE の設定に関する手順が表示された場合は、デフォルト設定で完了してください。
  2. 下のステータスバーにある [Cloud Code - Sign in] ボタンをクリックします。指示に従ってプラグインを承認します。ステータスバーに「Cloud Code - no project」と表示されている場合は、それを選択して、使用するプロジェクトのリストから特定の Google Cloud プロジェクトを選択します。

6f5ce865fc7a3ef5.png

  1. 右下にある [Code Assist] ボタンをクリックして、正しい Google Cloud プロジェクトをもう一度選択します。Cloud AI Companion API を有効にするよう求められた場合は、有効にして次に進んでください。
  2. Google Cloud プロジェクトを選択したら、下の図のようにステータスバーの Cloud Code ステータス メッセージが表示されていることと、その右側で Code Assist が有効になっていることを確認します。

709e6c8248ac7d88.png

Gemini Code Assist を使用できるようになりました。

3. Firestore を設定する

Cloud Firestore は、アプリケーション データのバックエンドとして使用するフルマネージドのサーバーレス ドキュメント データベースです。Cloud Firestore のデータは、ドキュメントコレクションに構造化されています。

デフォルトの Firestore データベースに sessions という名前のコレクションを作成する必要があります。このコレクションには、アプリケーションで使用するサンプルデータ(ドキュメント)が格納されます。

次の図に示すように、Cloud Shell IDE 内のメインメニューからターミナルを開きます。

f1535e14c9beeec6.png

sessions という名前のコレクションを作成する必要があります。ここには、セッション ドキュメントのサンプル リストが格納されます。各ドキュメントには次の属性があります。

  1. title: 文字列
  2. categories: 文字列の配列
  3. speakers: 文字列の配列
  4. duration: 文字列
  5. summary: 文字列

サンプルデータを含むファイルを独自のプロジェクトのバケットにコピーして、このコレクションにサンプルデータを入力します。その後、gcloud firestore import コマンドを使用してコレクションをインポートできます。

Firestore データベースの初期化

Cloud コンソールの Firestore ページに移動します。

プロジェクトで Firestore データベースを初期化したことがない場合は、default データベースを作成します。データベースの作成時に、次の値を使用します。

  • Firestore モード: Native
  • ロケーション: ロケーション タイプを Region に選択し、アプリケーションに適したリージョンを選択します。この場所は次のステップでバケットの場所として必要になるため、メモしておきます。
  • データベースを作成します。

504cabdb99a222a5.png

次の手順に沿って sessions コレクションを作成します。

  1. 次の gsutil コマンドを使用して、プロジェクトにバケットを作成します。次のコマンドの <PROJECT_ID> 変数を Google Cloud プロジェクト ID に置き換えます。<BUCKET_LOCATION> は、デフォルトの Firestore データベースの地理的エリアに対応するリージョン名(前の手順でメモしたとおり)に置き換えます。これは US-WEST1、EUROPE-WEST1、ASIA-EAST1 のいずれかになります。
gsutil mb -l <BUCKET-LOCATION> gs://<PROJECT_ID>-my-bucket
  1. バケットが作成されたので、Firebase データベースにインポートする前に、準備したデータベース エクスポートをこのバケットにコピーする必要があります。次のコマンドを使用します。
gsutil cp -r gs://sessions-master-database-bucket/2024-03-26T09:28:15_95256  gs://<PROJECT_ID>-my-bucket

インポートするデータが用意できたので、作成した Firebase データベース(default)にデータをインポートする最終手順に進みます。

  1. 次の gcloud コマンドを使用します。
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2024-03-26T09:28:15_95256

インポートには数秒かかります。準備ができたら、https://console.cloud.google.com/firestore/databases にアクセスして Firestore データベースとコレクションを検証します。次に示すように、default データベースと sessions コレクションを選択します。

d3e294d46ba29cd5.png

これで、アプリケーションで使用する Firestore コレクションの作成が完了しました。

4. アプリケーション テンプレートを作成する

この Codelab の以降の部分で使用するサンプル アプリケーション(Python Flask アプリケーション)を作成します。このアプリケーションは、技術カンファレンスで提供されるセッションを検索します。

手順は次のとおりです。

  1. 下のステータスバーで Google Cloud プロジェクト名をクリックします。

f151759c156c124e.png

  1. オプション一覧が表示されます。下のリストで [New Application] をクリックします。

91ea9836f38b7f74.png

  1. [Cloud Run application] を選択します(これがアプリのランタイムになります)。
  2. [Python (Flask): Cloud Run] アプリケーション テンプレートを選択します。
  3. アプリケーションに名前を付けて、任意の場所に保存します。
  4. アプリケーションが作成されたことを確認する通知が表示され、下に示すように、アプリケーションが読み込まれた状態で新しいウィンドウが開きます。README.md ファイルが開きます。このビューは一旦閉じて構いません。

aaa3725b17ce27cf.png

5. Gemini Code Assist の操作

このラボでは、VS Code の Cloud Code 拡張機能の一部として Cloud Shell IDE 内で使用できる Gemini Code Assist Chat を使用します。左側のナビゲーション バーにあるコード アシスト ボタンをクリックして表示できます。左側のナビゲーション ツールバーで Code Assist アイコン a489f98a34898727.png をクリックします。

Cloud Shell IDE 内に Code Assist チャット ペインが表示され、Code Assist とチャットできます。

14ad103efaa0ddaa.png

上部のゴミ箱アイコンは、Code Assist のチャット履歴のコンテキストをリセットするためのものです。また、このチャットのやり取りは、IDE で作業しているファイルに関連付けられています。

6. API 設計

最初のステップは、設計フェーズで Gemini Code Assist の支援を受けることです。このステップでは、検索対象のエンティティ(イベントのテクニカル セッション)の OpenAPI 仕様を生成します。

次のプロンプトを入力します。

Generate an Open API spec that will allow me to retrieve all sessions, sessions by category, session by id. Each session has the following attributes: id, title, list of speakers, list of categories, summary and duration.

これにより、さまざまなクエリ パラメータを使用してセッションを検索するための OpenAPI 仕様が生成されます。仕様のサンプルを以下に示します。

openapi: 3.0.0
info:
 title: Sessions API
 description: This API allows you to retrieve all sessions, sessions by category, and session by id.
 version: 1.0.0
servers:
 - url: https://sessions.example.com
paths:
 /sessions:
   get:
     summary: Get all sessions
     operationId: getSessions
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               type: array
               items:
                 $ref: '#/components/schemas/Session'
 /sessions/{id}:
   get:
     summary: Get session by id
     operationId: getSessionById
     parameters:
       - name: id
         in: path
         required: true
         description: The id of the session
         schema:
           type: string
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               $ref: '#/components/schemas/Session'
 /sessions/categories/{category}:
   get:
     summary: Get sessions by category
     operationId: getSessionsByCategory
     parameters:
       - name: category
         in: path
         required: true
         description: The category of the sessions
         schema:
           type: string
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               type: array
               items:
                 $ref: '#/components/schemas/Session'
components:
 schemas:
   Session:
     type: object
     properties:
       id:
         type: string
         description: The id of the session
       title:
         type: string
         description: The title of the session
       speakers:
         type: array
         items:
           type: string
         description: The list of speakers for the session
       categories:
         type: array
         items:
           type: string
         description: The list of categories for the session
       summary:
         type: string
         description: The summary of the session
       duration:
         type: string
         description: The duration of the session

仕様には次のものがあります。

  • セッション タイプに定義されたスキーマ。
  • 複数の API パスが定義されています。
  • /sessions
  • /sessions/{id}
  • /sessions/categories/{category}

最上位フォルダに sessionsapi.yaml というファイルを作成し、コードアシストのチャット ウィンドウから [現在のファイルに挿入] オプション(+ ボタン)を使用してコンテンツをコピーし、Cloud Shell IDE でファイルを開いたままにします。

ここで、Gemini Code Assist の興味深い機能である引用について説明します。この情報は、生成されたコードが既存のオープンソース コードなど、別のソースからある程度の長さをそのまま引用している場合に、デベロッパーに表示されます。デベロッパーがソースとライセンスを取得して、それらをどのように使用するかを決定できます。

生成されたコンテンツで問題がないと仮定すると、この仕様ドキュメントを使用して、Python Flask アプリケーションを生成できます。

7. アプリケーションを生成する

次に、コード アシスタントにアプリケーションの生成をリクエストします。sessionsapi.yaml ファイルを開いた状態で、次のプロンプトを入力します。

Generate a Python Application using the Flask framework, based on the sessionsapi.yaml file. This application uses a local in memory list of sessions. Do not use any Flask extensions.

これにより、OpenAPI 仕様ファイルで指定された機能とパスに基づいて、Python Flask アプリケーションのスケルトンが提供されます。

提供される Python Flask アプリケーション コードは、次のようになります。

from flask import Flask, jsonify, request

app = Flask(__name__)

sessions = [
    {
        "id": "1",
        "title": "Session 1",
        "speakers": ["Speaker 1", "Speaker 2"],
        "categories": ["Category 1", "Category 2"],
        "summary": "This is a summary of session 1.",
        "duration": "1 hour",
    },
    {
        "id": "2",
        "title": "Session 2",
        "speakers": ["Speaker 3", "Speaker 4"],
        "categories": ["Category 3", "Category 4"],
        "summary": "This is a summary of session 2.",
        "duration": "1 hour 30 minutes",
    },
]

@app.route('/sessions', methods=['GET'])
def get_sessions():
    return jsonify(sessions)

@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
    session = next((session for session in sessions if session['id'] == id), None)
    if session is None:
        return jsonify({}), 404
    return jsonify(session)

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
    sessions_by_category = [session for session in sessions if category in session['categories']]
    return jsonify(sessions_by_category)

if __name__ == '__main__':
    app.run()

前の手順の一部として生成された既存の app.py ファイルがある。その内容を Code Assist によって生成されたコードに置き換えて、ファイルを保存するだけです。

app.run() 行を変更して、ポート 8080、ホスト アドレス 0.0.0.0 を使用し、ローカル実行中にデバッグモードで実行します。その方法を次に示します。まず、行をハイライト表示または選択します。

app.run()

次に、Code Assist Chat インターフェースで、プロンプト「Explain this.」を入力します。

この行の詳細な説明が表示されます。以下に例を示します。

58ec896a32a4fb68.png

次のプロンプトを使用します。

update the code to run the application on port 8080, host address 0.0.0.0, and in debug mode

生成された候補コードは次のようになります。

app.run(host='0.0.0.0', port=8080, debug=True)

このスニペットで app.py ファイルを更新してください。

アプリケーションをローカルで実行する

ここでアプリケーションをローカルで実行して、最初に設定したアプリケーション要件を検証しましょう。

まず、requirements.txt にある Python パッケージの依存関係を使用して、仮想環境にインストールする仮想 Python 環境を作成します。これを行うには、Cloud Shell IDE のコマンド パレット(Ctrl+Shift+P)に移動し、「Python 環境を作成」と入力します。次の手順に沿って、仮想環境(venv)Python 3.x インタプリタrequirements.txt ファイルを選択します。

環境が作成されたら、新しいターミナル ウィンドウ(Ctrl+Shift+`)を開き、次のコマンドを入力します。

python app.py

以下に実行例を示します。

(.venv) romin@cloudshell: $ python app.py 
 * Serving Flask app 'app'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:8080
 * Running on http://10.88.0.3:8080
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 132-247-368

次の URL で API をプレビューできるようになりました。開発用サーバーがポート 8080 で実行されていることを前提としています。そうでない場合は、適切なポート番号に変更してください。

  • https://<host-name>:8080/sessions
  • https://<host-name>:8080/sessions/{id}
  • https://<host-name>:8080/sessions/categories/{category}

以下の手順に沿って、これらの URL を使用して app.py ファイルに含まれる JSON データを取得できるようにします。

新しいターミナル ウィンドウを開き、次のいずれかのコマンドを試します。

curl -X GET http://127.0.0.1:8080/sessions
curl -X GET http://127.0.0.1:8080/sessions/<ID>
curl -X GET http://127.0.0.1:8080/sessions/categories/<CATEGORY_NAME> 

8. コードのリファクタリング

app.py にサンプル JSON データをハードコードするのではなく、コードとデータの分離を維持できるように、別のモジュールに分離/抽出することをおすすめします。やってみましょう。

app.py ファイルを開いたまま、次のプロンプトを入力します。

Can I improve this code and separate out the sessions data from this app.py file?

これにより、その方法に関する提案が表示されます。以下に、取得した提案の例を示します。同様の提案が表示されるはずです。

9b9c56cb527dac4c.png

Code Assist の提案に従って、データを sessions.py ファイルに分離しましょう。

sessions.py という名前の新しいファイルを作成します。

, コンテンツは JSON リストです。生成されたデータは次のとおりです。

sessions = [
   {
       "id": "1",
       "title": "Session 1",
       "speakers": ["Speaker 1", "Speaker 2"],
       "categories": ["Category 1", "Category 2"],
       "summary": "This is a summary of session 1.",
       "duration": "1 hour",
   },
   {
       "id": "2",
       "title": "Session 2",
       "speakers": ["Speaker 3", "Speaker 4"],
       "categories": ["Category 3", "Category 4"],
       "summary": "This is a summary of session 2.",
       "duration": "1 hour 30 minutes",
   },
]

app.py ファイルは大幅に簡略化され、次のようになります。

from flask import Flask, jsonify, request
from sessions import sessions

app = Flask(__name__)

@app.route('/sessions', methods=['GET'])
def get_sessions():
   return jsonify(sessions.sessions)

@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
   session = next((session for session in sessions.sessions if session['id'] == id), None)
   if session is None:
       return jsonify({}), 404
   return jsonify(session)

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
   sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
   return jsonify(sessions_by_category)

if __name__ == '__main__':
   app.run(host='0.0.0.0', port=8080, debug=True)

リファクタリングされた変更で、アプリケーションをローカルで実行し、API を使用できることを確認します。Python 開発サーバーはまだ実行されている可能性が高いため、前のステップの curl コマンドを呼び出すだけで済みます。

9. Firestore コレクションと統合する

次のステップでは、セッション用に用意したローカルのインメモリ JSON リストから離れ、この Codelab の冒頭で作成した Firestore データベースの sessions コレクションにアプリケーションを接続します。

sessions.py ファイルを開いたまま、次のプロンプトを入力します。

Can you further refactor the sessions.py code to read from a Firestore database that has a collection named sessions. The collection has the same attributes as the session object that we have defined. Use the Python module google-cloud-firestore. 

Firestore コレクションからすべてのセッションを読み取るという提案がありました。

import google.cloud.firestore

# Create a Firestore client
db = google.cloud.firestore.Client()

# Get the sessions collection
sessions_collection = db.collection("sessions")

# Create a list of sessions
sessions = []

# Iterate over the documents and add them to the list
for doc in sessions_collection.stream():
   session = doc.to_dict()
   session["id"] = doc.id
   sessions.append(session)

sessions.py にコードを組み込んでください。

Flask 開発用サーバーをローカルで実行している場合、Python モジュールが見つからないというエラー メッセージが表示されてアプリケーションが終了することがあります。

たとえば、次のように、requirements.txt ファイルに追加する必要がある Python モジュールについて Code Assist に質問できます。

Which Python package needs to be installed to make the firestore code work?

これにより、Python モジュールの名前(例: google-cloud-firestore)が返されます。この名前を requirements.txt ファイルに追加します。

新しく追加されたモジュール(google-cloud-firestore)を使用して Python 環境を再作成する必要があります。そのためには、既存のターミナル ウィンドウで次のコマンドを実行します。

pip install -r requirements.txt

アプリケーションを再度実行(python app.py で再起動)し、/sessions URL にアクセスします。sessions コレクションに追加したサンプル ドキュメントが取得されます。

975d05e6518f1a6a.png

前の手順で説明したように、他の URI をクエリして、特定のセッションや特定のカテゴリのすべてのセッションを取得することもできます。

10. コードの説明

ここで、Gemini Code Assist の "Explain this" 機能を使用して、コードをよく理解しておきましょう。ファイルを開いたり、特定のコード スニペットを選択して、プロンプト Explain this を使用して Code Assist に質問したりできます。

演習として、sessions.py ファイルにアクセスし、Firestore 固有のコードをハイライト表示して、そのコードの説明を取得します。Python コードだけでなく、プロジェクト内の他のファイルでもこの機能を使用してみてください。

11. ウェブ アプリケーションを生成する

API を生成してライブ Firestore コレクションと統合したので、アプリケーションのウェブベースのフロントエンドを生成しましょう。現在の Web フロントエンドの機能は最小限に抑えられています。つまり、特定のカテゴリに属するセッションを検索できます。/sessions/categories/{category} という API パスがあるため、ウェブ アプリケーションでそれを呼び出して結果を取得する必要があります。

それでは、早速見ていきましょう。Code Assist に次のプロンプトを入力します。

Generate a web application that allows me to search for sessions by category and uses the Flask application that we created. Please use basic HTML, CSS and JS. Embed all the Javascript and CSS code into a single HTML file only.

これにより、JavaScript と CSS が埋め込まれたウェブ アプリケーションの HTML が生成されます。また、ルートまたはベース URL にアクセスするユーザーにホームページが提供されるように、app.py ファイルに新しいルートを追加するよう求められます。その情報が記載されていない場合は、お客様に確認するか、以下のスニペットを使用します。

@app.route('/')
def index():
   return render_template('index.html')

このファイルは index.html として保存できますが、このファイルを保存する場所(どのフォルダか)について疑問が生じる可能性があります。Code Assist にフォローアップの質問をすることができます。

Given that I am using the flask framework, where should I put the index.html file?

render_template フレームワークを使用しているため、index.html ファイルを templates フォルダに配置する必要があることを明確に示しています。このフォルダは、この Codelab の冒頭で Flask テンプレートに基づいてアプリケーションを生成したときに作成されています。その結果、既存の index.html ファイルが存在するため、その内容をここで生成された新しい内容に置き換えるだけで済みます。Code Assist は、app.py ファイルで render_template をインポートすることも提案します。

ウェブ アプリケーションのコードを index.html ファイルに保存し、そのファイルを templates フォルダに配置してください。

アプリケーションをローカルで実行する

ここでアプリケーションをローカルで実行して、最初に設定したアプリケーション要件を検証しましょう。

ローカルの Flask サーバーがまだ実行中で、エラーが表示されていないことを確認します。エラーが発生した場合は、エラーに対処してサーバーを起動します。

起動したら、アプリケーションのホーム URL にアクセスします。次のように、提供された index.html ファイルが表示されます。

8ca586acc4536879.png

データからカテゴリの 1 つを入力(例: AI)し、[Search] ボタンをクリックします。AI カテゴリでタグ付けされたセッションが表示されます。

165faded790a6c.png

オプションの演習として、各セッションの所要時間、カテゴリ、スピーカー、概要などの追加のメタデータを表示します。

12. テストケースの生成

セッション API を生成しました。次に、Gemini Code Assist を使用して、さまざまな API パスの単体テストケースを生成します。

app.py ファイルを開いたまま、次のプロンプトを入力します。

Generate unit test cases for app routes. Use unittest module.

次のようなレスポンスが返されました。

import unittest
from app import app

class FlaskAppTestCase(unittest.TestCase):

    def test_index(self):
        tester = app.test_client()
        response = tester.get('/')
        self.assertEqual(response.status_code, 200)

    def test_get_sessions(self):
        tester = app.test_client()
        response = tester.get('/sessions')
        self.assertEqual(response.status_code, 200)

    def test_get_session_by_id(self):
        tester = app.test_client()
        response = tester.get('/sessions/1')
        self.assertEqual(response.status_code, 200)

    def test_get_sessions_by_category(self):
        tester = app.test_client()
        response = tester.get('/sessions/categories/category1')
        self.assertEqual(response.status_code, 200)

if __name__ == '__main__':
    unittest.main()

上記のコードを含む tests.py という名前のファイルを作成します。

テストケースの生成に関する注意事項

上記のコードとは異なるコードが表示されることがあります。その場合、テストケースの実行で問題が発生する可能性があります。たとえば、一部の実行では、次の重要なコードが欠落していました。

from app import app

上記のコードは、テストケースを呼び出す既存の Flask アプリをインポートするために必要です。

if __name__ == '__main__':

`unittest.main()`

上記のコードは、テストケースを実行するために必要です。

各テストケースを確認し、生成されたコードの assertEqual などの条件をチェックして、動作することを確認することをおすすめします。データは Firestore コレクションの外部にあるため、アクセスできない可能性があり、その結果、ダミーデータが使用されてテストが失敗する可能性があります。したがって、テストケースを適宜変更するか、すぐに必要にならないテストケースをコメントアウトします。

デモンストレーションとして、次のコマンドを使用してテストケースを実行しました(ローカル API エンドポイントが呼び出されるため、ローカルの開発用サーバーを必ず実行してください)。

python tests.py

次の要約結果が得られました。

Ran 4 tests in 0.274s

FAILED (failures=2)

3 回目のテストではセッション ID が正しくなく、category1 というカテゴリ名が存在しないため、これは正しい結果です。

したがって、テストケースを適宜調整してテストします。

13. テスト駆動開発

次に、テスト駆動開発(TDD)手法に従って、セッション API に新しい検索メソッドを追加する方法を見てみましょう。TDD は、まずテストケースを作成し、実装がないためにテストを失敗させ、Gemini Code Assist を使用して不足している実装を生成してテストを合格させる手法です。

tests.py ファイルに移動します(tests.py ファイルを修正して、すべてのテストが合格するようにしたとします)。Code Assist に次のプロンプトを入力します。

Generate a new test case to search for sessions by speaker

これにより、次のテストケース実装が得られ、これを tests.py ファイルに挿入しました。

  def test_get_sessions_by_speaker(self):
        tester = app.test_client()
        response = tester.get('/sessions/speakers/speaker1')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json, [sessions.sessions[0], sessions.sessions[1]])

テストを実行すると、次のエラーが表示されます。

$ python tests.py 
.F.
======================================================================
FAIL: test_get_sessions_by_speaker (__main__.FlaskAppTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/romin/hello-world-5/tests.py", line 21, in test_get_sessions_by_speaker
    self.assertEqual(response.status_code, 200)
AssertionError: 404 != 200

----------------------------------------------------------------------
Ran 3 tests in 0.010s

FAILED (failures=1)

これは、テストケースがパス (/sessions/speakers/) を呼び出しているにもかかわらず、app.py にその実装がないためです。

Code Assist に実装を依頼してみましょう。app.py ファイルに移動し、Code Assist に次のプロンプトを指定します。

Add a new route to search for sessions by a specific speaker

Code Assist から次の実装が提案されたので、app.py ファイルに追加しました。

@app.route('/sessions/speakers/<speaker>', methods=['GET'])
def get_sessions_by_speaker(speaker):
    sessions_by_speaker = [session for session in sessions.sessions if speaker in session['speakers']]
    return jsonify(sessions_by_speaker)

tests.py ファイルを再度確認し、簡単なチェックのためにテストケースを次のように変更しました。

   def test_get_sessions_by_speaker(self):
       tester = app.test_client()
       response = tester.get('/sessions/speakers/Romin Irani')
       self.assertEqual(response.status_code, 200)
       self.assertEqual(len(response.json), 1)

テストは正常に実行されました。生成されたテストケースを確認し、Firestore に存在する可能性のあるデータに応じて少し調整して、Python 単体テストケースに適切な assert* メソッドを設定するのは、読者の練習問題とします。

14. Google Cloud Run へのデプロイ

開発の品質に自信が持てたので、最後のステップとして、このアプリケーションを Google Cloud Run にデプロイします。念のため、Code Assist に何か忘れていることがないか確認してみましょう。app.py を開いた状態で、次のプロンプトを送信します。

Is there something here I should change before I deploy to production?

デバッグ フラグをオフに設定するのを忘れていたので、質問していただいて助かりました。

2f87ed3a811fb218.png

指示どおりにデバッグをオフにして、Gemini Code Assist に、ソースから直接 Cloud Run にアプリケーションをデプロイするために使用できる gcloud コマンド(最初にコンテナをビルドする必要がない)について質問します。

次のプロンプトを入力します。

I would like to deploy the application to Cloud Run directly from source. What is the gcloud command to do that?

上記のプロンプトのバリエーションをいくつか試してみましょう。もう 1 つ試したのは次のとおりです。

I would like to deploy this application to Cloud Run. I don't want to build a container image locally but deploy directly from source to Cloud Run. What is the gcloud command for that?

理想的には、次の gcloud コマンドを取得する必要があります。

gcloud run deploy sessions --source .

また、次のこともできます。

gcloud run deploy <service-name> --source . \
—-platform managed \
—-allow-unauthenticated

上記のコマンドは、アプリケーションのルートフォルダから実行します。region を求められたら us-central1 を選択し、unauthenticated invocations を許可するかどうかを求められたら Y を選択します。Artifact Registry、Cloud Build、Cloud Run などの Google Cloud API を有効にするよう求められることや、Artifact Registry リポジトリを作成する権限を付与するよう求められることがあります。その場合は、権限を付与してください。

デプロイ プロセスが完了するまで約 2 分かかります。しばらくお待ちください。

デプロイが正常に完了すると、Cloud Run サービスの URL が表示されます。そのパブリック URL にアクセスすると、同じウェブ アプリケーションがデプロイされ、正常に実行されていることがわかります。

c5322d0fd3e0f616.png

おめでとうございます。よくできました。

15. (省略可)Cloud Logging を使用する

アプリケーション ログが Google Cloud サービス(Cloud Logging)のいずれかに一元化されるように、アプリケーションにロギングを導入できます。また、オブザーバビリティ Gemini 機能を使用して、ログエントリを理解することもできます。

これを行うには、まず Google Cloud の既存の Python Cloud Logging ライブラリを使用して、情報、警告、エラー メッセージ(ログ / 重大度レベルに応じて)のロギングに使用する必要があります。

まず、Code Assist にこの質問をしてみましょう。次のプロンプトを試してください。

How do I use the google-cloud-logging package in Python?

次のような情報を含むレスポンスが返されます。

2472e1ccaf8a217d.png

カテゴリ別にセッションを検索する関数にロギング ステートメントを追加しましょう。

まず、google-cloud-logging Python パッケージを requirements.txt ファイルに追加します。

次は、ロギングを実装するコードを統合した方法を示すコード スニペットです。

...
from google.cloud import logging
...
app = Flask(__name__)

# Create a logger
logger = logging.Client().logger('my-log')

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
   logger.log_text(f"Fetching sessions with category {category}")
   sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
   logger.log_text(f'Found {len(sessions_by_category)} sessions with category {category}')
   return jsonify(sessions_by_category)

# # Other App Routes

前のセクションと同じコマンドを使用して、サービスを Cloud Run に再度デプロイします。デプロイが完了したら、/sessions/categories/<category> エンドポイントに対していくつかの呼び出しを実行します。

Cloud Console → Logs Explorer に移動します

59e297577570695.png

以下のように、これらのロギング ステートメントにフィルタリングできます。

914f1fb6cac30a89.png

ログステートメントのいずれかをクリックして展開し、[Explain this log entry] をクリックします。これにより、Gemini がログエントリの説明を行います。Gemini for Google Cloud を有効にしていない場合は、Cloud AI Companion API を有効にするよう求められます。指示に従って手続きを進めてください。

レスポンスの例を次に示します。

7fc9783910fa92cc.png

16. 完了

おめでとうございます。アプリケーションをゼロから作成し、設計、ビルド、テスト、デプロイなど、SDLC の複数の側面で Gemini Code Assist を使用しました。

次のステップ

以下の Codelab をご覧ください。

リファレンス ドキュメント