Firestore、ベクトル検索、Gemini 2.0(Java バージョン)を使用して、コンテキストに応じたヨガのポーズ レコメンダー アプリを構築します。

1. 概要

ウェルネスやフィットネスのアプリの世界では、ユーザーにリッチで魅力的なエクスペリエンスを提供することが重要です。ヨガアプリの場合、ポーズの簡単なテキスト説明だけでなく、包括的な情報、マルチメディア コンテンツ、インテリジェントな検索機能を提供する必要があります。このブログでは、Google Cloud の Firestore を使用して堅牢なヨガポーズ データベースを構築し、コンテキスト マッチングにベクトル検索拡張機能を利用し、マルチモーダル コンテンツの操作に Gemini 2.0 Flash(試験運用版)の機能を統合する方法について説明します。

Firestore を選ぶ理由

Google Cloud のサーバーレス NoSQL ドキュメント データベースである Firestore は、スケーラブルで動的なアプリケーションの構築に最適です。Yoga アプリに最適な理由を以下に示します。

  • スケーラビリティとパフォーマンス: Firestore は自動的にスケーリングして数百万人のユーザーと大規模なデータセットを処理するため、アプリが成長しても応答性を維持できます。
  • リアルタイム更新: 組み込みのリアルタイム同期により、接続されているすべてのクライアントでデータの一貫性が保たれます。ライブ授業や共同練習などの機能に最適です。
  • 柔軟なデータモデル: Firestore のドキュメント ベースの構造により、テキスト、画像、エンベディングなど、さまざまなデータ型を保存できます。これにより、複雑なヨガのポーズ情報を表現するのに最適です。
  • 強力なクエリ: Firestore は、等式、不等式、新しい拡張機能によるベクトル類似性検索など、複雑なクエリをサポートしています。
  • オフライン サポート: Firestore はデータをローカルにキャッシュに保存するため、ユーザーがオフラインの場合でもアプリを機能させることができます。

Firestore ベクトル検索拡張機能による検索の強化

従来のキーワード ベースの検索は、ヨガのポーズのような複雑なコンセプトを扱う場合には限界があります。ユーザーは、特定のポーズの名前を知らなくても、「股関節を開く」ポーズや「バランスを改善する」ポーズを検索できます。ここでベクトル検索が役立ちます。

Firestore のベクトル検索では、次のことができます。

  • エンベディングを生成する: Vertex AI で利用可能なモデルやカスタムモデルなどのモデルを使用して、テキストの説明(将来的には画像や音声も)を、その意味を捉える数値ベクトル表現(エンベディング)に変換します。
  • エンベディングを保存する: これらのエンベディングを Firestore ドキュメントに直接保存します。
  • 類似性検索を実行する: データベースにクエリを実行して、指定されたクエリ ベクトルと意味的に類似するドキュメントを検索し、コンテキスト マッチングを可能にします。

Gemini 2.0 Flash(試験運用版)の統合

Gemini 2.0 Flash は、Google の最先端のマルチモーダル AI モデルです。試験運用中ではありますが、この技術はヨガアプリを充実させるためのエキサイティングな可能性を秘めています。

  • テキスト生成: Gemini 2.0 Flash を使用して、ヨガのポーズの詳細な説明(メリット、修正、禁忌など)を生成します。
  • 画像生成(模倣): Gemini を使用した直接的な画像生成はまだ一般公開されていませんが、Google の Imagen を使用してこれをシミュレートし、ポーズを視覚的に表現する画像を生成しました。
  • 音声生成(模倣): 同様に、テキスト読み上げ(TTS)サービスを使用して、各ポーズの音声指示を作成し、ユーザーが練習を進められるようにします。

アプリを強化するために、モデルの次の機能を使用する統合を提案することを想定しています。

  • Multimodal Live API: この新しい API を使用すると、ツールを使用してリアルタイムのビジョンと音声のストリーミング アプリケーションを作成できます。
  • 速度とパフォーマンス: Gemini 2.0 Flash は、Gemini 1.5 Flash よりも最初のトークンまでの時間(TTFT)が大幅に改善されています。
  • エージェント エクスペリエンスの改善: Gemini 2.0 では、マルチモーダルな理解、コーディング、複雑な指示の実行、関数呼び出しが改善されています。これらの改善が連携することで、エージェント エクスペリエンスが向上します。

詳細については、Gemini 1.5 Flash に関するこちらのドキュメントページをご覧ください。

信頼性を高め、さらなるリソースを提供するために、Google 検索を統合してアプリが提供する情報をグラウンディングできます。つまり、

  • コンテキスト検索: 管理ユーザーがポーズの詳細を入力すると、ポーズ名を使用して Google 検索を実行できます。
  • URL の抽出: 検索結果から、記事、動画、信頼できるヨガ関連のウェブサイトなどの関連性の高い URL を抽出し、アプリ内に表示できます。

作成するアプリの概要

このラボでは、次の作業を行います。

  1. Firestore コレクションを作成して Yoga ドキュメントを読み込む
  2. Firestore で CRUD アプリケーションを作成する方法を学習する
  3. Gemini 2.0 Flash を使用してヨガのポーズの説明を生成する
  4. Firestore との統合で Firebase ベクトル検索を有効にする
  5. ヨガの説明からエンベディングを生成する
  6. ユーザーの検索テキストの類似性検索を行う

要件

  • ブラウザ(ChromeFirefox など)
  • 課金を有効にした Google Cloud プロジェクト

2. 始める前に

プロジェクトを作成する

  1. Google Cloud コンソールのプロジェクト選択ページで、Google Cloud プロジェクトを選択または作成します。
  2. Cloud プロジェクトに対して課金が有効になっていることを確認します。詳しくは、プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください。
  3. Cloud Shell(Google Cloud で動作するコマンドライン環境)を使用します。この環境には bq がプリロードされています。Google Cloud コンソールの上部にある [Cloud Shell をアクティブにする] をクリックします。

[Cloud Shell をアクティブにする] ボタンの画像

  1. Cloud Shell に接続したら、次のコマンドを使用して、すでに認証済みであることと、プロジェクトがプロジェクト ID に設定されていることを確認します。
gcloud auth list
  1. Cloud Shell で次のコマンドを実行して、gcloud コマンドがプロジェクトを認識していることを確認します。
gcloud config list project
  1. プロジェクトが設定されていない場合は、次のコマンドを使用して設定します。
gcloud config set project <YOUR_PROJECT_ID>
  1. [有効にする] ボタンをクリックできるようになるまで、このリンクに沿って必要な API を有効にします。

API が見つからない場合は、実装中にいつでも有効にできます。

gcloud コマンドとその使用方法については、ドキュメントをご覧ください。

3. データベースの設定

ドキュメントには、Firestore インスタンスの設定方法に関するより完全な手順が記載されています。大まかな手順は次のとおりです。

Firestore Viewer に移動し、[データベース サービスの選択] 画面で [ネイティブ モードの Firestore] を選択します。

  1. Firestore のロケーションを選択します(us-central1 を選択してください。この Codelab 全体でリージョン / ロケーションを選択する際は、この選択に従ってください)。
  2. [データベースを作成] をクリックします(初めての場合は、データベースを「(default)」のままにします)。

Firestore プロジェクトを作成すると、Cloud API Manager で API も有効になります。

  1. 重要: データにアクセスできるように、セキュリティ ルールのテスト(本番環境ではない)バージョンを選択します。
  2. 設定が完了すると、次の図に示すように、ネイティブ モードの Firestore データベース、コレクション、ドキュメント ビューが表示されます。

f7136d53253c59a.png

  1. まだこの手順は行いませんが、記録として残しておきます。[コレクションを開始] をクリックして、新しいコレクションを作成できます。コレクション ID を「poses」に設定します。[保存] ボタンをクリックします。

a26eb470aa9bfda9.png

本番環境アプリケーションのプロのヒント:

  1. データモデルを確定し、さまざまな種類のドキュメントにアクセスできるユーザーを特定したら、Firebase インターフェースからセキュリティ ルールを作成、編集、モニタリングできます。セキュリティ ルールには、次のリンクからアクセスできます。https://console.firebase.google.com/u/0/project/<<your_project_id>>/firestore/rules
  2. 開発フェーズからプロジェクトをデプロイ / ロールアウトする前に、セキュリティ ルールを編集、モニタリング、テストしてください。セキュリティ ルールは、アプリの動作が異なる原因となることがよくあります。

このデモでは、テストモードで使用します。

4. Firestore REST API

  1. REST API は、次のような場合に役立ちます。完全なクライアント ライブラリを実行できないリソースが制約された環境から Firestore にアクセスする場合。データベース管理の自動化または詳細なデータベース メタデータの取得
  2. Firestore を使用する場合、ネイティブのクライアント ライブラリを使用するのが最も簡単な方法ですが、REST API を直接呼び出すと便利な場合もあります。
  3. このブログでは、ネイティブ クライアント ライブラリではなく、Firestore REST API の使用方法とデモを紹介します。
  4. 認証では、Firestore REST API は Firebase Authentication ID トークンまたは Google Identity OAuth 2.0 トークンのいずれかを受け取ります。認証と認可の詳細については、ドキュメントをご覧ください。
  5. すべての REST API エンドポイントは、ベース URL https://firestore.googleapis.com/v1/ の下にあります。

Spring Boot と Firestore API

Spring Boot Framework のこのソリューションは、Firestore API を使用してヨガのポーズと呼吸の詳細を収集および変更するクライアント アプリケーションを、ユーザー インタラクティブなエクスペリエンスでデモンストレーションするものです。

ヨガのポーズ アプリの Firestore CRUD ソリューション部分の詳細な手順については、ブログのリンクをご覧ください。

現在のソリューションに焦点を当て、CRUD 部分をその場で学習するには、Cloud Shell ターミナルから以下のリポジトリにあるこのブログに焦点を当てたソリューション全体を複製し、コードベースのコピーを取得します。

git clone https://github.com/AbiramiSukumaran/firestore-poserecommender

注意:

  1. このリポジトリをクローンしたら、プロジェクト ID や API などの変更を少し行うだけで、アプリケーションを起動して実行できます。以降のセクションでは、アプリケーションの各コンポーネントについて説明します。変更内容は次のとおりです。
  2. src/main/java/com/example/demo/GenerateImageSample.java ファイルで、"<<YOUR_PROJECT_ID>>" を実際のプロジェクト ID に置き換えます。
  3. src/main/java/com/example/demo/GenerateEmbeddings.java ファイルで、"<<YOUR_PROJECT_ID>>" を実際のプロジェクト ID に置き換えます。
  4. src/main/java/com/example/demo/PoseController.java で、"<<YOUR_PROJECT_ID>>" とデータベース名,(この場合は "(default)",)" のすべてのインスタンスを、構成の適切な値に置き換えます。
  5. src/main/java/com/example/demo/PoseController.java で、「[YOUR_API_KEY]」を Gemini 2.0 Flash の API キーに置き換えます。これは AI Studio から取得できます。
  6. ローカルでテストする場合は、Cloud Shell ターミナルのプロジェクト フォルダから次のコマンドを実行します。
mvn package

mvn spring-boot:run

現在、Cloud Shell ターミナルから [ウェブでプレビュー] オプションをクリックすると、実行中のアプリケーションを表示できます。テストを実行してアプリケーションを試す準備がまだ整っていません。

  1. 省略可: Cloud Run にアプリをデプロイする場合は、Cloud Shell エディタで新しい Java Cloud Run アプリケーションをゼロからブートストラップし、リポジトリの src ファイルとテンプレート ファイルを新しいプロジェクトのそれぞれのフォルダに追加する必要があります(現在の GitHub リポジトリ プロジェクトは、Cloud Run デプロイ構成用にデフォルトで設定されていません)。その場合、既存のリポジトリのクローンを作成する代わりに、次の手順に沿って操作します。
  2. Cloud Shell エディタに移動します(エディタが開いていて、ターミナルが開いていないことを確認してください)。ステータスバーの左側にある Google Cloud プロジェクト名アイコン(下のスクリーンショットでブロックされている部分)をクリックします。

d3f0de417094237d.png

  1. 選択肢のリストから [New application] -> [Cloud Run Application] -> [Java: Cloud Run] を選択し、「firestore-poserecommender」という名前を付けます。

d5ef8b4ca8bf3f85.png

  1. これで、Java Cloud Run アプリケーションのフルスタック テンプレートが事前構成され、すぐに使用できる状態になっているはずです。
  2. 既存の Controller クラスを削除し、次のファイルをプロジェクト構造のそれぞれのフォルダにコピーします。

firestore-poserecommender/src/main/java/com/example/demo/

  1. FirestoreSampleApplication.java
  2. GenerateEmbeddings.java
  3. GenerateImageSample.java
  4. Pose.java
  5. PoseController.java
  6. ServletInitializer.java
             firestore-poserecommender/src/main/resources/static/
    
  7. Index.html

firestore-poserecommender/src/main/resources/templates/

  1. contextsearch.html
  2. createpose.html
  3. errmessage.html
  4. pose.html
  5. ryoq.html
  6. searchpose.html
  7. showmessage.html

firestore-poserecommender/

  1. Dockerfile
  2. 対応するファイルで変更を行い、PROJECT ID と API KEY をそれぞれの値に置き換える必要があります。(上記のステップ 1 a、b、c、d)。

5. データの取り込み

アプリのデータは、次の data.json ファイルで入手できます。https://github.com/AbiramiSukumaran/firestore-poserecommender/blob/main/data.json

事前に定義されたデータから始める場合は、JSON をコピーして、「<<YOUR_PROJECT_ID>>」のすべての出現箇所を自分の値に置き換えます。

  • Firestore Studio に移動します。
  • 「poses」という名前のコレクションを作成していることを確認します。
  • 上記の repo ファイルからドキュメントを 1 つずつ手動で追加します。

次の手順を実行して、作成済みの事前定義セットからデータを一括でインポートすることもできます。

  1. Cloud Shell ターミナルに移動し、アクティブな Google Cloud プロジェクトが設定され、承認されていることを確認します。次の gsutil コマンドを使用して、プロジェクトにバケットを作成します。次のコマンドの <PROJECT_ID> 変数を Google Cloud プロジェクト ID に置き換えます。

gsutil mb -l us gs://<PROJECT_ID>-yoga-poses-bucket

  1. バケットが作成されたので、Firebase データベースにインポートする前に、準備したデータベース エクスポートをこのバケットにコピーする必要があります。次のコマンドを使用します。

gsutil cp -r gs://demo-bq-gemini-public/yoga_poses gs://<PROJECT_ID>-yoga-poses-bucket

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

  1. Firestore コンソールに移動し、左側のナビゲーション メニューから [インポート/エクスポート] をクリックします。

[インポート] を選択し、作成した Cloud Storage パスを選択して、ファイル「yoga_poses.overall_export_metadata」を選択できるまで移動します。

f5c1d16df7d5a64a.png

  1. [インポート] をクリックします。

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

  1. 別の方法として、[Create a New Pose] アクションを使用してデプロイした後、アプリケーションから手動でレコードを作成することもできます。

6. ベクトル検索

Firestore ベクトル検索拡張機能を有効にする

この拡張機能を使用すると、新しいベクトル検索機能で Firestore ドキュメントを自動的に埋め込み、クエリを実行できます。Firebase Extensions Hub に移動します。

ベクトル検索拡張機能をインストールするときに、コレクションとドキュメント フィールド名を指定します。このフィールドを含むドキュメントを追加または更新すると、この拡張機能がトリガーされ、ドキュメントのベクトル エンベディングが計算されます。このベクトル エンベディングは同じドキュメントに書き戻され、ドキュメントはベクトルストアにインデックス登録され、クエリの対象となります。

手順は次のとおりです。

拡張機能をインストールする:

Firebase 拡張機能 Marketplace で [Firebase コンソールにインストール] をクリックして、「Vector Search with Firestore」拡張機能をインストールします。

重要:

この拡張機能ページに初めて移動するときは、Firebase コンソールに表示されている Google Cloud コンソールで作業しているのと同じプロジェクトを選択する必要があります。

715426b97c732649.png

プロジェクトがリストに表示されない場合は、Firebase でプロジェクトを追加します(リストから既存の Google Cloud プロジェクトを選択します)。

拡張機能を構成する:

コレクション(「poses」)、埋め込むテキストを含むフィールド(「posture」)、エンベディング ディメンションなどの他のパラメータを指定します。

この手順に、有効にする必要がある API がリストされている場合は、構成ページで有効にできます。手順に沿って操作してください。

API を有効にしてからしばらく経ってもページが応答しない場合は、更新するだけで、有効になっている API を確認できます。

5ba59b45710c567b.png

次のいずれかの手順で、選択した LLM を使用してエンベディングを生成できます。[Vertex AI] を選択します。

bb528a04ebb5f976.png

次の設定は、コレクションと埋め込むフィールドに関連しています。

LLM: Vertex AI

コレクションのパス: poses

デフォルトのクエリ上限: 3

距離測定: コサイン

入力フィールド名: posture

出力フィールド名: embedding

ステータス フィールド名: status

既存のドキュメントを埋め込む: はい

既存のエンベディングを更新する: はい

Cloud Functions のロケーション: us-central1

Enable Events(イベントを有効にする): チェックされていない

fb8cdf1163fac7cb.png

すべての設定が完了したら、[Install Extension] ボタンをクリックします。この処理には 3 ~ 5 分かかります。

エンベディングを生成する:

「poses」コレクションでドキュメントを追加または更新すると、拡張機能は API エンドポイントを介して、事前トレーニング済みモデルまたは選択したモデルを使用してエンベディングを自動的に生成します。この例では、拡張機能の構成で Vertex AI を選択しています。

インデックスの作成

アプリケーションでエンベディングを使用する際に、エンベディング フィールドにインデックスを作成することが必須になります。

Firestore は基本的なクエリのインデックスを自動的に作成しますが、インデックスのないクエリを実行して Firestore にインデックス構文を生成させることもできます。この場合、アプリケーション側のエラー メッセージに、生成されたインデックスへのリンクが表示されます。ベクトル インデックスを作成する手順は次のとおりです。

  1. Cloud Shell ターミナルに移動する
  2. 次のコマンドを実行します。
gcloud firestore indexes composite create --collection-group="poses" --query-scope=COLLECTION --database="(default)" --field-config vector-config='{"dimension":"768", "flat": "{}"}',field-path="embedding"

詳しくは、こちらをご覧ください。

ベクトル インデックスを作成したら、ベクトル エンベディングで最近傍検索を実行できます。

注意事項:

この時点以降は、ソースを変更する必要はありません。アプリケーションの動作を理解するために、手順に沿って操作してください。

新しく構築したアプリケーションがベクトル検索にどのようにアプローチするかを見てみましょう。エンベディングを保存したら、Firestore Java SDK の VectorQuery クラスを使用してベクトル検索を実行し、最近傍の結果を取得できます。

CollectionReference coll = firestore.collection("poses");
    VectorQuery vectorQuery = coll.findNearest(
        "embedding",
        userSearchTextEmbedding, 
        /* limit */ 3,
        VectorQuery.DistanceMeasure.EUCLIDEAN,
        VectorQueryOptions.newBuilder().setDistanceResultField("vector_distance")
         .setDistanceThreshold(2.0)
          .build());
ApiFuture<VectorQuerySnapshot> future = vectorQuery.get();
VectorQuerySnapshot vectorQuerySnapshot = future.get();
List<Pose> posesList = new ArrayList<Pose>();
// Get the ID of the closest document (assuming results are sorted by distance)
String closestDocumentId = vectorQuerySnapshot.getDocuments().get(0).getId();

このスニペットは、ユーザーの検索テキストのエンベディングと Firestore 内のドキュメントのエンベディングを比較し、コンテキスト的に最も近いものを抽出します。

7. Gemini 2.0 Flash

Gemini 2.0 Flash の統合(説明の生成用)

新しく構築したアプリケーションが、説明の生成のために Gemini 2.0 Flash の統合をどのように処理するかを見てみましょう。

ここで、管理者ユーザーまたはヨガインストラクターが Gemini 2.0 Flash を使用してポーズの詳細を入力し、検索を実行して最も近い一致を確認するとします。これにより、一致するポーズの詳細と、結果をサポートするマルチモーダル オブジェクトが抽出されます。

String apiUrl = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent?key=[YOUR_API_KEY]";
Map<String, Object> requestBody = new HashMap<>();
List<Map<String, Object>> contents = new ArrayList<>();
List<Map<String, Object>> tools = new ArrayList<>();
Map<String, Object> content = new HashMap<>();
List<Map<String, Object>> parts = new ArrayList<>();
Map<String, Object> part = new HashMap<>();
part.put("text", prompt);
parts.add(part);
content.put("parts", parts);
contents.add(content);
requestBody.put("contents", contents);
/**Setting up Grounding*/
Map<String, Object> googleSearchTool = new HashMap<>();
googleSearchTool.put("googleSearch", new HashMap<>());
tools.add(googleSearchTool);
requestBody.put("tools", tools);

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> response = restTemplate.exchange(apiUrl, HttpMethod.POST, requestEntity, String.class);
System.out.println("Generated response: " + response);
String responseBody = response.getBody();
JSONObject jsonObject = new JSONObject(responseBody);
JSONArray candidates = jsonObject.getJSONArray("candidates");
JSONObject candidate = candidates.getJSONObject(0);
JSONObject contentResponse = candidate.getJSONObject("content");
JSONArray partsResponse = contentResponse.getJSONArray("parts");
JSONObject partResponse = partsResponse.getJSONObject(0);
String generatedText = partResponse.getString("text");
System.out.println("Generated Text: " + generatedText);

a. 画像と音声の生成を模倣する

Gemini 2.0 Flash Experimental はマルチモーダル結果を生成できますが、まだ早期アクセスに登録していないため、Imagen API と TTS API を使用して画像とオーディオ出力をそれぞれ模倣しました。Gemini 2.0 Flash への 1 回の API 呼び出しでこれらすべてが生成されることを想像してみてください。

try (PredictionServiceClient predictionServiceClient =
          PredictionServiceClient.create(predictionServiceSettings)) {
  
        final EndpointName endpointName =
            EndpointName.ofProjectLocationPublisherModelName(
                projectId, location, "google", "imagen-3.0-generate-001");
  
        Map<String, Object> instancesMap = new HashMap<>();
        instancesMap.put("prompt", prompt);
        Value instances = mapToValue(instancesMap);
  
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("sampleCount", 1);
        paramsMap.put("aspectRatio", "1:1");
        paramsMap.put("safetyFilterLevel", "block_few");
        paramsMap.put("personGeneration", "allow_adult");
        Value parameters = mapToValue(paramsMap);
  
        PredictResponse predictResponse =
            predictionServiceClient.predict(
                endpointName, Collections.singletonList(instances), parameters);
  
        for (Value prediction : predictResponse.getPredictionsList()) {
          Map<String, Value> fieldsMap = prediction.getStructValue().getFieldsMap();
          if (fieldsMap.containsKey("bytesBase64Encoded")) {
            bytesBase64Encoded = fieldsMap.get("bytesBase64Encoded").getStringValue();
       }
      }
      return bytesBase64Encoded;
    }
 try {
            // Create a Text-to-Speech client
            try (TextToSpeechClient textToSpeechClient = TextToSpeechClient.create()) {
                // Set the text input to be synthesized
                SynthesisInput input = SynthesisInput.newBuilder().setText(postureString).build();

                // Build the voice request, select the language code ("en-US") and the ssml
                // voice gender
                // ("neutral")
                VoiceSelectionParams voice =
                        VoiceSelectionParams.newBuilder()
                                .setLanguageCode("en-US")
                                .setSsmlGender(SsmlVoiceGender.NEUTRAL)
                                .build();

                // Select the type of audio file you want returned
                AudioConfig audioConfig =
                        AudioConfig.newBuilder().setAudioEncoding(AudioEncoding.MP3).build();

                // Perform the text-to-speech request on the text input with the selected voice
                // parameters and audio file type
                SynthesizeSpeechResponse response =
                        textToSpeechClient.synthesizeSpeech(input, voice, audioConfig);

                // Get the audio contents from the response
                ByteString audioContents = response.getAudioContent();

                // Convert to Base64 string
                String base64Audio = Base64.getEncoder().encodeToString(audioContents.toByteArray());

                // Add the Base64 encoded audio to the Pose object
               return base64Audio;
            }

        } catch (Exception e) {
            e.printStackTrace(); // Handle exceptions appropriately. For a real app, log and provide user feedback.
            return "Error in Audio Generation";
        }
}

b. Google 検索によるグラウンディング:

ステップ 6 で Gemini 呼び出しコードを確認すると、LLM レスポンスの Google 検索グラウンディングを有効にする次のコード スニペットが表示されます。

 /**Setting up Grounding*/
Map<String, Object> googleSearchTool = new HashMap<>();
googleSearchTool.put("googleSearch", new HashMap<>());
tools.add(googleSearchTool);
requestBody.put("tools", tools);

これは、以下のことを確実にするためです。

  • 実際の検索結果に基づいてモデルをグラウンディングする
  • 検索で参照されている関連性の高い URL を抽出する

8. アプリケーションを実行する

シンプルな Thymeleaf ウェブ インターフェースを使用して、新しく構築した Java Spring Boot アプリケーションのすべての機能を見てみましょう。

  1. Firestore CRUD オペレーション(作成、読み取り、更新、削除)
  2. キーワード検索
  3. 生成 AI ベースのコンテキスト作成
  4. コンテキスト検索(ベクトル検索)
  5. 検索に関連するマルチモーダル出力
  6. 独自のクエリを実行する(structuredQuery 形式のクエリ)

例: {"structuredQuery":{"select":{"fields":[{"fieldPath":"name"}]},"from":[{"collectionId":"fitness_poses"}]}}

ここまで説明した機能はすべて、リポジトリ(https://github.com/AbiramiSukumaran/firestore-poserecommender)から作成したアプリケーションの一部です。

ビルド、実行、デプロイを行うには、Cloud Shell ターミナルから次のコマンドを実行します。

mvn package

mvn spring-boot:run

結果が表示され、アプリケーションの機能を試すことができます。出力のデモについては、以下の動画をご覧ください。

Firestore、ベクトル検索、Gemini 2.0 Flash を使用したポーズ レコメンダー

省略可能な手順:

Cloud Run にデプロイするには(Dockerfile を使用して新しいアプリケーションをブートストラップし、必要に応じてファイルをコピーしたと仮定します)、プロジェクト ディレクトリ内の Cloud Shell ターミナルから次のコマンドを実行します。

gcloud run deploy --source .

アプリケーション名、リージョン コード(us-central1 を選択)を指定し、プロンプトが表示されたら未認証の呼び出しに「Y」を選択します。デプロイが成功すると、ターミナルにアプリケーション エンドポイントが表示されます。

9. クリーンアップ

この投稿で使用したリソースについて、Google Cloud アカウントに課金されないようにするには、次の手順を行います。

  1. Google Cloud コンソールで、[リソースの管理] ページに移動します。
  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

10. 完了

おめでとうございます!Firestore を活用して、堅牢でインテリジェントなヨガのポーズ管理アプリケーションを作成できました。Firestore、ベクトル検索拡張機能、Gemini 2.0 Flash の機能(画像と音声の生成をシミュレート)を組み合わせることで、CRUD オペレーションの実装、キーワード ベースの検索、コンテキスト ベクトル検索、生成されたマルチメディア コンテンツの実行を行う、真に魅力的で有益なヨガアプリを作成しました。

このアプローチはヨガアプリに限定されません。Gemini などの AI モデルが進化を続けるにつれて、より没入感があり、パーソナライズされたユーザー エクスペリエンスを生み出す可能性はますます高まります。Google Cloud と Firebase の最新の開発とドキュメントを常に確認して、これらのテクノロジーの可能性を最大限に活用してください。

このアプリを拡張するなら、Gemini 2.0 Flash で次の 2 つのことを試します。

  1. ユースケースでリアルタイムのビジョンと音声のストリーミングを作成して、Multimodal Live API を使用します。
  2. 思考モードを有効にすると、リアルタイム データとのやり取りに対する回答の背景にある思考が生成され、よりリアルな体験が実現します。

ぜひお試しいただき、プルリクエストをお送りください :>D!!!