Firestore, 벡터 검색, Gemini 2.0 (Java 버전)으로 문맥 기반 요가 자세 추천 앱을 빌드하세요.

1. 개요

웰니스 및 피트니스 앱의 세계에서는 사용자에게 풍부하고 매력적인 경험을 제공하는 것이 중요합니다. 요가 앱의 경우 자세에 대한 간단한 텍스트 설명을 넘어 포괄적인 정보, 멀티미디어 콘텐츠, 지능형 검색 기능을 제공해야 합니다. 이 블로그에서는 Google Cloud의 Firestore를 사용하여 강력한 요가 자세 데이터베이스를 빌드하고, 컨텍스트 기반 매칭을 위해 벡터 검색 확장 프로그램을 활용하고, 멀티모달 콘텐츠 작업을 위해 Gemini 2.0 Flash (실험적)의 기능을 통합하는 방법을 살펴봅니다.

Firestore를 사용해야 하는 이유

Google Cloud의 서버리스 NoSQL 문서 데이터베이스인 Firestore는 확장 가능하고 동적인 애플리케이션을 빌드하는 데 적합합니다. 요가 앱에 적합한 이유는 다음과 같습니다.

  • 확장성 및 성능: 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. 사용자 검색 텍스트에 대한 유사성 검색 실행

요구사항

  • 브라우저(Chrome 또는 Firefox 등)
  • 결제가 사용 설정된 Google Cloud 프로젝트.

2. 시작하기 전에

프로젝트 만들기

  1. Google Cloud 콘솔의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.
  2. Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다. 프로젝트에 결제가 사용 설정되어 있는지 확인하는 방법을 알아보세요 .
  3. bq가 미리 로드되어 제공되는 Google Cloud에서 실행되는 명령줄 환경인 Cloud Shell을 사용합니다. 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 인스턴스를 설정하는 방법에 관한 더 완전한 단계가 있습니다. 처음 시작할 때 대략적으로 다음 단계를 따릅니다.

1 Firestore 뷰어로 이동하고 데이터베이스 서비스 선택 화면에서 기본 모드의 Firestore를 선택합니다.

  1. Firestore의 위치를 선택합니다 (이 Codelab 전체에서 리전 / 위치를 선택할 때마다 us-central1을 선택해야 함).
  2. 데이터베이스 만들기를 클릭합니다 (처음인 경우 '(기본값)' 데이터베이스로 둡니다).

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가 유용할 수 있습니다.a. 전체 클라이언트 라이브러리를 실행할 수 없는 리소스 제한 환경에서 Firestore에 액세스하는 경우 데이터베이스 관리를 자동화하거나 상세한 데이터베이스 메타데이터를 검색할 때
  2. Firestore를 사용하는 가장 쉬운 방법은 기본 클라이언트 라이브러리 중 하나를 사용하는 것이지만 경우에 따라서는 REST API를 직접 호출하는 방법이 유용할 수 있습니다.
  3. 이 블로그에서는 네이티브 클라이언트 라이브러리가 아닌 Firestore REST API의 사용 및 데모를 확인할 수 있습니다.
  4. 인증을 위해 Firestore REST API가 Firebase 인증 ID 토큰이나 Google ID OAuth 2.0 토큰을 허용합니다. 인증 및 승인 주제에 대한 자세한 내용은 문서를 참고하세요.
  5. 모든 REST API 엔드포인트는 기본 URL https://firestore.googleapis.com/v1/에 존재합니다.

Spring Boot 및 Firestore API

Spring Boot 프레임워크의 이 솔루션은 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 애플리케이션을 부트스트랩하고 repo의 src 파일과 템플릿 파일을 새 프로젝트의 해당 폴더에 추가해야 합니다 (현재 GitHub 저장소 프로젝트는 Cloud Run 배포 구성용으로 기본적으로 설정되어 있지 않음). 이 경우 기존 저장소를 클론하는 대신 다음 단계를 따라야 합니다.
  2. Cloud Shell 편집기로 이동하여 편집기가 열려 있고 터미널이 아닌지 확인한 후 상태 표시줄의 왼쪽에 있는 Google Cloud 프로젝트 이름 아이콘(아래 스크린샷에서 차단된 부분)을 클릭합니다.

d3f0de417094237d.png

  1. 선택 목록에서 새 애플리케이션 -> Cloud Run 애플리케이션 -> Java: Cloud Run을 선택하고 이름을 'firestore-poserecommender'로 지정합니다.

d5ef8b4ca8bf3f85.png

  1. 이제 사전 구성되어 바로 사용할 수 있는 Java Cloud Run 애플리케이션의 전체 스택 템플릿이 표시됩니다.
  2. 기존 컨트롤러 클래스를 삭제하고 다음 파일을 프로젝트 구조의 각 폴더에 복사합니다.

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. 해당 파일에서 프로젝트 ID와 API 키를 각 값으로 바꾸는 변경사항을 적용해야 합니다. (위의 1 a,b, c, d 단계)

5. 데이터 수집

애플리케이션 데이터는 다음 파일 data.json에서 확인할 수 있습니다. https://github.com/AbiramiSukumaran/firestore-poserecommender/blob/main/data.json

미리 정의된 데이터로 시작하려면 json을 복사하고 '<<YOUR_PROJECT_ID>>'를 모두 값으로 대체하세요.

  • Firestore Studio로 이동
  • '포즈'라는 컬렉션을 만들었는지 확인합니다.
  • 위에서 언급한 저장소 파일에서 문서를 한 번에 하나씩 수동으로 추가합니다.

또는 다음 단계를 실행하여 Google에서 만든 사전 정의된 세트에서 한 번에 데이터를 가져올 수 있습니다.

  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 데이터베이스 (default)로 데이터를 가져오는 마지막 단계로 이동할 수 있습니다.

  1. 지금 Firestore 콘솔로 이동하여 왼쪽 탐색 메뉴에서 가져오기/내보내기를 클릭합니다.

가져오기를 선택하고 방금 만든 Cloud Storage 경로를 선택한 후 'yoga_poses.overall_export_metadata' 파일을 선택할 수 있을 때까지 이동합니다.

f5c1d16df7d5a64a.png

  1. 가져오기를 클릭합니다.

가져오기는 몇 초가 걸리며 완료되면 https://console.cloud.google.com/firestore/databases로 이동하여 Firestore 데이터베이스와 컬렉션을 검증할 수 있습니다. 아래와 같이 default 데이터베이스와 poses 컬렉션을 선택하세요.

  1. '새 포즈 만들기' 작업을 사용하여 배포한 후 애플리케이션을 통해 레코드를 수동으로 만들 수도 있습니다.

6. 벡터 검색

Firestore 벡터 검색 확장 프로그램 사용 설정

확장 프로그램을 사용하여 새로운 벡터 검색 기능으로 Firestore 문서를 자동으로 삽입하고 쿼리하세요. 이렇게 하면 Firebase 확장 프로그램 허브로 이동합니다.

벡터 검색 확장 프로그램을 설치할 때 컬렉션과 문서 필드 이름을 지정합니다. 이 필드가 포함된 문서를 추가하거나 업데이트하면 이 확장 프로그램이 트리거되어 문서의 벡터 삽입을 계산합니다. 이 벡터 임베딩은 동일한 문서에 다시 작성되고, 문서는 벡터 스토어에 색인이 생성되어 쿼리할 준비가 됩니다.

단계를 살펴보겠습니다.

확장 프로그램 설치:

Firebase Extensions Marketplace에서 'Firebase Console에 설치'를 클릭하여 'Firestore를 사용한 벡터 검색' 확장 프로그램을 설치합니다.

중요:

이 확장 프로그램 페이지로 처음 이동할 때는 Firebase Console에 나열된 Google Cloud 콘솔에서 작업 중인 것과 동일한 프로젝트를 선택해야 합니다.

715426b97c732649.png

프로젝트가 목록에 없으면 Firebase에서 프로젝트를 추가합니다 (목록에서 기존 Google Cloud 프로젝트 선택).

확장 프로그램 구성:

컬렉션 ('자세'), 삽입할 텍스트가 포함된 필드 ('자세'), 임베딩 차원과 같은 기타 매개변수를 지정합니다.

이 단계에 사용 설정해야 하는 API가 나열되어 있으면 구성 페이지에서 사용 설정할 수 있습니다. 단계에 따라 진행하세요.

API를 사용 설정한 후 한동안 페이지가 응답하지 않으면 새로고침하면 사용 설정된 API가 표시됩니다.

5ba59b45710c567b.png

다음 단계 중 하나에서 원하는 LLM을 사용하여 임베딩을 생성할 수 있습니다. 'Vertex AI'를 선택합니다.

bb528a04ebb5f976.png

다음 몇 가지 설정은 컬렉션과 삽입하려는 필드와 관련이 있습니다.

LLM: Vertex AI

컬렉션 경로: 포즈

기본 쿼리 한도: 3

거리 측정: 코사인

입력 필드 이름: 자세

출력 필드 이름: embedding

상태 필드 이름: status

기존 문서 삽입: 예

기존 임베딩 업데이트: 예

Cloud Functions 위치: us-central1

이벤트 사용 설정: 선택되지 않음

fb8cdf1163fac7cb.png

이 모든 항목을 설정한 후 확장 프로그램 설치 버튼을 클릭합니다. 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 실험 버전은 멀티모달 결과를 생성할 수 있지만 아직 사전 체험에 등록하지 않았으므로 Imagen 및 TTS API를 사용하여 각각 이미지와 오디오 출력을 모방했습니다. Gemini 2.0 Flash에 대한 하나의 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로 다음 두 가지 작업을 시도해 볼 것입니다.

  1. 사용 사례에 맞게 실시간 비전 및 오디오 스트리밍을 만들어 Multimodal Live API를 사용합니다.
  2. 사고 모드를 사용하면 실시간 데이터와의 상호작용에 대한 대답의 배경이 되는 생각을 생성하여 경험을 더욱 생생하게 만들 수 있습니다.

언제든지 사용해 보고 풀 요청을 보내주세요 :>D!!!