Firestore, 벡터 검색, Gemini 2.0으로 문맥 요가 자세 추천 앱을 빌드하세요.

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 플래시 관련 문서 페이지를 참고하세요.

신뢰성을 높이고 추가 리소스를 제공하기 위해 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를 사용 설정합니다.
gcloud services enable firestore.googleapis.com \
                       compute.googleapis.com \
                       cloudresourcemanager.googleapis.com \
                       servicenetworking.googleapis.com \
                       run.googleapis.com \
                       cloudbuild.googleapis.com \
                       cloudfunctions.googleapis.com \
                       aiplatform.googleapis.com \
                       storage.googleapis.com \ 
                       secretmanager.googleapis.com \ 
                       texttospeech.googleapis.com

gcloud 명령어 대신 콘솔에서 각 제품을 검색하거나 이 링크를 사용하는 방법이 있습니다.

누락된 API가 있으면 구현 과정에서 언제든지 사용 설정할 수 있습니다.

gcloud 명령어 및 사용법은 문서를 참조하세요.

3. 데이터베이스 설정

Firestore 인스턴스를 설정하는 방법에 관한 더 완전한 단계는 문서를 참고하세요. 대략적으로 다음 단계를 따르겠습니다.

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

  1. Firestore 위치 선택
  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. 보안 규칙이 앱이 다르게 작동하는 이유인 경우가 많으므로 개발 단계에서 프로젝트를 배포 / 출시하기 전에 보안 규칙을 수정, 모니터링, 테스트해야 합니다.

이 데모에서는 TEST 모드로 사용합니다.

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 스튜디오에서 가져올 수 있습니다.
  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. 기존 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 스튜디오로 이동합니다.
  • '포즈'라는 컬렉션을 만들었는지 확인합니다.
  • 위에 언급된 저장소 파일의 문서를 한 번에 하나씩 수동으로 추가합니다.

또는 다음 단계에 따라 사전 정의된 세트에서 데이터를 한 번에 가져올 수 있습니다.

  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로 이동하여 아래와 같이 default 데이터베이스와 poses 컬렉션을 선택하여 Firestore 데이터베이스와 컬렉션을 확인할 수 있습니다.

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

6. 벡터 검색

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

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

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

단계를 살펴보겠습니다.

확장 프로그램 설치:

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

중요:

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

715426b97c732649.png

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

확장 프로그램 구성:

컬렉션 ('poses'), 삽입할 텍스트가 포함된 필드 ('posture'), 삽입 크기와 같은 기타 매개변수를 지정합니다.

이 단계에 나열된 API를 사용 설정해야 하는 경우 구성 페이지에서 사용 설정할 수 있습니다. 단계에 따라 진행합니다.

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

5ba59b45710c567b.png

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

bb528a04ebb5f976.png

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

LLM: Vertex AI

컬렉션 경로: 포즈

기본 쿼리 한도: 3

거리 측정: 코사인

입력란 이름: posture

출력 필드 이름: 삽입

상태 필드 이름: status

기존 문서 삽입: 예

기존 임베딩 업데이트: 예

Cloud Functions 위치: us-central1

이벤트 사용 설정: 선택 해제됨

fb8cdf1163fac7cb.png

모든 설정이 완료되면 '확장 프로그램 설치' 버튼을 클릭합니다. 3~5분 정도 걸립니다.

임베딩 생성:

'포즈' 컬렉션에 문서를 추가하거나 업데이트하면 확장 프로그램은 선행 학습된 모델 또는 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":{"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 작업을 구현하고, 키워드 기반 검색, 문맥 벡터 검색, 생성된 멀티미디어 콘텐츠를 실행하는 매우 매력적이고 유익한 Yoga 앱을 만들었습니다.

이 접근 방식은 요가 앱에만 국한되지 않습니다. Gemini와 같은 AI 모델이 계속해서 발전함에 따라 더욱 몰입도 높고 맞춤설정된 사용자 환경을 만드는 것이 가능해질 것입니다. Google Cloud와 Firebase의 최신 개발사항과 문서를 확인하여 이러한 기술의 잠재력을 최대한 활용하세요.

이 앱을 확장한다면 Gemini 2.0 Flash로 다음 두 가지 작업을 시도해 보겠습니다.

  1. 사용 사례에 맞는 실시간 비전 및 오디오 스트리밍을 만들어 Multimodal Live API를 사용하세요.
  2. 생각 모드를 사용하면 실시간 데이터와 상호작용할 때 응답의 배경에 있는 생각을 생성하여 더욱 실감나는 환경을 만들 수 있습니다.

언제든지 시도해 보고 pull 요청을 보내주세요. :>D!!!