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

1. はじめに

e5b98fd4e417c877.png

この Codelab では、Gemini Code Assist がソフトウェア開発ライフサイクル(SDLC)の主なステージ(設計、構築、デプロイします。アプリケーション全体を設計、開発し、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. category: 文字列の配列
  3. speakers: 文字列の配列
  4. duration: 文字列
  5. summary: string

サンプルデータを含むファイルを自分のプロジェクトのバケットにコピーして、このコレクションにサンプルデータを追加しましょう。バケットから 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

インポートには数秒かかります。準備が整ったら、Firestore データベースとコレクションを検証できます。https://console.cloud.google.com/firestore/databases にアクセスし、以下に示すように 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. アプリケーションを生成する

次に、Code Assist にアプリケーションの生成を依頼します。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 ファイルがあります。コード アシスタンスによって生成されたコードに置き換えて、ファイルを保存するだけです。

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

app.run()

次に、コード アシスト チャット インターフェースで、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)に移動し、「Create Python environment」と入力します。次の数ステップに従って、仮想環境(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. コードのリファクタリング

ハードコードされたサンプル JSON データを app.py に含める代わりに、これを別のモジュールに分離/抽出することで、コードとデータを明確に分離できます。やってみる!

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

それでは詳しく見ていきましょう。コード アシスタンスに次のプロンプトを入力します。

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 またはベース 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

データのカテゴリのいずれか(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 に新しい検索メソッドを追加してみましょう。まずテストケースを作成し、実装不足により失敗させ、Gemini Code Assist を使用して不足している実装を生成し、テストに合格するようにします。

test.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 ファイルに移動し、コード アシスタンスに次のプロンプトを入力します。

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?

デバッグ フラグを off に設定するのを忘れていたため、お問い合わせいただきありがとうございます。

2f87ed3a811fb218.png

示されているように、デバッグをオフにし、gcloud コマンドを使用して Gemini Code Assist にサポートを依頼してください。このコマンドを使用すると、最初にコンテナをビルドすることなく、ソースから直接 Cloud Run にアプリケーションをデプロイできます。

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

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

上記のプロンプトのバリエーションをいくつか試してみましょう。もう一つ試した方法:

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 をご覧ください。

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