1. Pengantar
Dalam codelab ini, Anda akan membuat aplikasi yang menggunakan penelusuran vektor untuk merekomendasikan pose Yoga.
Selama mengikuti codelab, Anda akan menggunakan pendekatan langkah demi langkah sebagai berikut:
- Gunakan Set Data Hugging Face yang ada untuk pose Yoga (format JSON).
- Tingkatkan kualitas set data dengan deskripsi kolom tambahan yang menggunakan Gemini untuk membuat deskripsi setiap pose.
- Muat data Pose yoga sebagai kumpulan Dokumen dalam koleksi Firestore dengan embedding yang dihasilkan.
- Buat indeks komposit di Firestore untuk mengizinkan Penelusuran vektor.
- Gunakan Vector Search di Aplikasi Node.js yang menggabungkan semuanya seperti yang ditunjukkan di bawah:

Yang akan Anda lakukan
- Mendesain, Membangun, dan Men-deploy aplikasi web yang menggunakan Vector Search untuk merekomendasikan pose Yoga.
Yang akan Anda pelajari
- Cara menggunakan Gemini untuk membuat konten teks dan dalam konteks codelab ini, membuat deskripsi untuk pose yoga
- Cara memuat rekaman dari set data yang ditingkatkan dari Hugging Face ke Firestore beserta Embedding Vektor
- Cara menggunakan Penelusuran Vektor Firestore untuk menelusuri data berdasarkan kueri bahasa alami
- Cara menggunakan Google Cloud Text to Speech API untuk membuat konten Audio
Yang Anda butuhkan
- Browser web Chrome
- Akun Gmail
- Project Cloud dengan penagihan diaktifkan
Codelab ini, yang dirancang untuk developer dari semua tingkat keahlian (termasuk pemula), menggunakan JavaScript dan Node.js dalam aplikasi contohnya. Namun, pengetahuan tentang JavaScript dan Node.js tidak diperlukan untuk memahami konsep yang disajikan.
2. Sebelum memulai
Membuat project
- Di Konsol Google Cloud, di halaman pemilih project, pilih atau buat project Google Cloud.
- Pastikan penagihan diaktifkan untuk project Cloud Anda. Pelajari cara memeriksa apakah penagihan telah diaktifkan pada suatu project .
- Anda akan menggunakan Cloud Shell, lingkungan command line yang berjalan di Google Cloud yang telah dilengkapi dengan bq. Klik Activate Cloud Shell di bagian atas konsol Google Cloud.

- Setelah terhubung ke Cloud Shell, Anda dapat memeriksa bahwa Anda sudah diautentikasi dan project sudah ditetapkan ke project ID Anda menggunakan perintah berikut:
gcloud auth list
- Jalankan perintah berikut di Cloud Shell untuk mengonfirmasi bahwa perintah gcloud mengetahui project Anda.
gcloud config list project
- Jika project Anda belum ditetapkan, gunakan perintah berikut untuk menetapkannya:
gcloud config set project <YOUR_PROJECT_ID>
- Aktifkan API yang diperlukan melalui perintah yang ditampilkan di bawah. Proses ini mungkin memerlukan waktu beberapa menit, jadi bersabarlah.
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 \
texttospeech.googleapis.com
Setelah perintah berhasil dieksekusi, Anda akan melihat pesan yang mirip dengan yang ditampilkan di bawah:
Operation "operations/..." finished successfully.
Alternatif untuk perintah gcloud adalah melalui konsol dengan menelusuri setiap produk atau menggunakan link ini.
Jika ada API yang terlewat, Anda dapat mengaktifkannya selama proses penerapan.
Baca dokumentasi untuk mempelajari perintah gcloud dan penggunaannya.
Meng-clone repositori dan menyiapkan setelan lingkungan
Langkah berikutnya adalah meng-clone repositori contoh yang akan kita rujuk di bagian codelab lainnya. Dengan asumsi Anda berada di Cloud Shell, berikan perintah berikut dari direktori utama Anda:
git clone https://github.com/rominirani/yoga-poses-recommender-nodejs
Untuk meluncurkan editor, klik Open Editor di toolbar jendela Cloud Shell. Klik panel menu di pojok kiri atas, lalu pilih File → Open Folder seperti yang ditunjukkan di bawah:

Pilih folder yoga-poses-recommender-nodejs dan Anda akan melihat folder terbuka dengan file berikut seperti yang ditunjukkan di bawah ini:

Sekarang kita perlu menyiapkan variabel lingkungan yang akan kita gunakan. Klik file env-template dan Anda akan melihat isinya seperti yang ditunjukkan di bawah:
PROJECT_ID=<YOUR_GOOGLE_CLOUD_PROJECT_ID>
LOCATION=us-<GOOGLE_CLOUD_REGION_NAME>
GEMINI_MODEL_NAME=<GEMINI_MODEL_NAME>
EMBEDDING_MODEL_NAME=<GEMINI_EMBEDDING_MODEL_NAME>
IMAGE_GENERATION_MODEL_NAME=<IMAGEN_MODEL_NAME>
DATABASE=<FIRESTORE_DATABASE_NAME>
COLLECTION=<FIRESTORE_COLLECTION_NAME>
TEST_COLLECTION=test-poses
TOP_K=3
Perbarui nilai untuk PROJECT_ID dan LOCATION sesuai dengan yang telah Anda pilih saat membuat Project Google Cloud dan wilayah Database Firestore. Idealnya, nilai LOCATION harus sama untuk Project Google Cloud dan Database Firestore, misalnya us-central1.
Untuk tujuan codelab ini, kita akan menggunakan nilai berikut (kecuali PROJECT_ID dan LOCATION, yang harus Anda tetapkan sesuai konfigurasi Anda.
PROJECT_ID=<YOUR_GOOGLE_CLOUD_PROJECT_ID>
LOCATION=us-<GOOGLE_CLOUD_REGION_NAME>
GEMINI_MODEL_NAME=gemini-1.5-flash-002
EMBEDDING_MODEL_NAME=text-embedding-004
IMAGE_GENERATION_MODEL_NAME=imagen-3.0-fast-generate-001
DATABASE=(default)
COLLECTION=poses
TEST_COLLECTION=test-poses
TOP_K=3
Simpan file ini sebagai .env di folder yang sama dengan file env-template.
Buka menu utama di kiri atas di Cloud Shell IDE, lalu Terminal → New Terminal.
Buka folder root repositori yang Anda clone melalui perintah berikut:
cd yoga-poses-recommender-nodejs
Instal dependensi Node.js melalui perintah:
npm install
Bagus! Sekarang kita siap melanjutkan ke tugas penyiapan database Firestore.
3. Menyiapkan Firestore
Cloud Firestore adalah database dokumen serverless yang terkelola sepenuhnya yang akan kita gunakan sebagai backend untuk data aplikasi kita. Data di Cloud Firestore disusun dalam koleksi dokumen.
Inisialisasi Database Firestore
Buka halaman Firestore di konsol Cloud.
Jika Anda belum pernah menginisialisasi database Firestore sebelumnya di project, buat database default dengan mengklik Create Database. Selama pembuatan database, gunakan nilai berikut:
- Mode Firestore:
Native. - Pilih Jenis Lokasi sebagai
Regiondan pilih lokasius-central1untuk wilayah. - Untuk Aturan Keamanan, gunakan
Test rules. - Buat Database.

Di bagian berikutnya, kita akan menyiapkan dasar-dasar untuk membuat koleksi bernama poses di database Firestore default. Koleksi ini akan menyimpan sampel data (dokumen) atau informasi pose Yoga, yang kemudian akan kita gunakan dalam aplikasi.
Dengan ini, bagian untuk penyiapan database Firestore telah selesai.
4. Menyiapkan set data pose Yoga
Tugas pertama kita adalah menyiapkan set data Pose Yoga yang akan kita gunakan untuk aplikasi. Kita akan mulai dengan set data Hugging Face yang ada, lalu menyempurnakannya dengan informasi tambahan.
Lihat Set Data Hugging Face untuk Pose Yoga. Perhatikan bahwa meskipun codelab ini menggunakan salah satu set data, Anda dapat menggunakan set data lain dan mengikuti teknik yang sama yang ditunjukkan untuk meningkatkan kualitas set data.

Jika membuka bagian Files and versions, kita bisa mendapatkan file data JSON untuk semua pose.

Kami telah mendownload yoga_poses.json dan memberikan file tersebut kepada Anda. File ini diberi nama yoga_poses_alldata.json dan ada di folder /data.
Buka file data/yoga_poses.json di Cloud Shell Editor dan lihat daftar objek JSON, di mana setiap objek JSON mewakili pose Yoga. Kita memiliki total 3 data dan contoh data ditampilkan di bawah:
{
"name": "Big Toe Pose",
"sanskrit_name": "Padangusthasana",
"photo_url": "https://pocketyoga.com/assets/images/full/ForwardBendBigToe.png",
"expertise_level": "Beginner",
"pose_type": ["Standing", "Forward Bend"]
}
Sekarang adalah kesempatan yang tepat bagi kita untuk memperkenalkan Gemini dan cara menggunakan model default itu sendiri untuk membuat kolom description untuknya.
Di Cloud Shell Editor, buka file generate-descriptions.js. Isi file ini ditampilkan di bawah:
import { VertexAI } from "@langchain/google-vertexai";
import fs from 'fs/promises'; // Use fs/promises for async file operations
import dotenv from 'dotenv';
import pRetry from 'p-retry';
import { promisify } from 'util';
const sleep = promisify(setTimeout);
// Load environment variables
dotenv.config();
async function callGemini(poseName, sanskritName, expertiseLevel, poseTypes) {
const prompt = `
Generate a concise description (max 50 words) for the yoga pose: ${poseName}
Also known as: ${sanskritName}
Expertise Level: ${expertiseLevel}
Pose Type: ${poseTypes.join(', ')}
Include key benefits and any important alignment cues.
`;
try {
// Initialize Vertex AI Gemini model
const model = new VertexAI({
model: process.env.GEMINI_MODEL_NAME,
location: process.env.LOCATION,
project: process.env.PROJECT_ID,
});
// Invoke the model
const response = await model.invoke(prompt);
// Return the response
return response;
} catch (error) {
console.error("Error calling Gemini:", error);
throw error; // Re-throw the error for handling in the calling function
}
}
// Configure logging (you can use a library like 'winston' for more advanced logging)
const logger = {
info: (message) => console.log(`INFO - ${new Date().toISOString()} - ${message}`),
error: (message) => console.error(`ERROR - ${new Date().toISOString()} - ${message}`),
};
async function generateDescription(poseName, sanskritName, expertiseLevel, poseTypes) {
const prompt = `
Generate a concise description (max 50 words) for the yoga pose: ${poseName}
Also known as: ${sanskritName}
Expertise Level: ${expertiseLevel}
Pose Type: ${poseTypes.join(', ')}
Include key benefits and any important alignment cues.
`;
const req = {
contents: [{ role: 'user', parts: [{ text: prompt }] }],
};
const runWithRetry = async () => {
const resp = await generativeModel.generateContent(req);
const response = await resp.response;
const text = response.candidates[0].content.parts[0].text;
return text;
};
try {
const text = await pRetry(runWithRetry, {
retries: 5,
onFailedAttempt: (error) => {
logger.info(
`Attempt ${error.attemptNumber} failed. There are ${error.retriesLeft} retries left. Waiting ${error.retryDelay}ms...`
);
},
minTimeout: 4000, // 4 seconds (exponential backoff will adjust this)
factor: 2, // Exponential factor
});
return text;
} catch (error) {
logger.error(`Error generating description for ${poseName}: ${error}`);
return '';
}
}
async function addDescriptionsToJSON(inputFile, outputFile) {
try {
const data = await fs.readFile(inputFile, 'utf-8');
const yogaPoses = JSON.parse(data);
const totalPoses = yogaPoses.length;
let processedCount = 0;
for (const pose of yogaPoses) {
if (pose.name !== ' Pose') {
const startTime = Date.now();
pose.description = await callGemini(
pose.name,
pose.sanskrit_name,
pose.expertise_level,
pose.pose_type
);
const endTime = Date.now();
const timeTaken = (endTime - startTime) / 1000;
processedCount++;
logger.info(`Processed: ${processedCount}/${totalPoses} - ${pose.name} (${timeTaken.toFixed(2)} seconds)`);
} else {
pose.description = '';
processedCount++;
logger.info(`Processed: ${processedCount}/${totalPoses} - ${pose.name} (${timeTaken.toFixed(2)} seconds)`);
}
// Add a delay to avoid rate limit
await sleep(30000); // 30 seconds
}
await fs.writeFile(outputFile, JSON.stringify(yogaPoses, null, 2));
logger.info(`Descriptions added and saved to ${outputFile}`);
} catch (error) {
logger.error(`Error processing JSON file: ${error}`);
}
}
async function main() {
const inputFile = './data/yoga_poses.json';
const outputFile = './data/yoga_poses_with_descriptions.json';
await addDescriptionsToJSON(inputFile, outputFile);
}
main();
Aplikasi ini akan menambahkan kolom description baru ke setiap rekaman JSON pose Yoga. Deskripsi akan diperoleh melalui panggilan ke model Gemini, tempat kita akan memberikan perintah yang diperlukan. Kolom ditambahkan ke file JSON dan file baru ditulis ke file data/yoga_poses_with_descriptions.json.
Mari kita bahas langkah-langkah utamanya:
- Dalam fungsi
main(), Anda akan menemukan bahwa fungsi tersebut memanggil fungsiadd_descriptions_to_jsondan menyediakan file input serta file output yang diharapkan. - Fungsi
add_descriptions_to_jsonmelakukan hal berikut untuk setiap data JSON, yaitu informasi postingan Yoga: - Fungsi ini mengekstrak
pose_name,sanskrit_name,expertise_level, danpose_types. - Fungsi ini memanggil fungsi
callGeminiyang membuat perintah, lalu memanggil class model LangchainVertexAI untuk mendapatkan teks respons. - Teks respons ini kemudian ditambahkan ke objek JSON.
- Daftar objek JSON yang diperbarui kemudian ditulis ke file tujuan.
Mari kita jalankan aplikasi ini. Buka jendela terminal baru (Ctrl+Shift+C) dan berikan perintah berikut:
npm run generate-descriptions
Jika Anda diminta memberikan otorisasi, berikan otorisasi tersebut.
Anda akan melihat bahwa aplikasi mulai dieksekusi. Kami telah menambahkan penundaan 30 detik di antara data untuk menghindari kuota batas kecepatan yang mungkin ada di akun Google Cloud baru, jadi harap bersabar.
Contoh proses yang sedang berjalan ditampilkan di bawah ini:

Setelah ketiga rekaman ditingkatkan dengan panggilan Gemini, file data/yoga_poses_with_description.json akan dibuat. Anda dapat melihatnya.
Sekarang kita siap dengan file data dan langkah selanjutnya adalah memahami cara mengisi Database Firestore dengan file tersebut, beserta pembuatan sematan.
5. Mengimpor Data ke Firestore dan membuat Embedding Vektor
Kita memiliki file data/yoga_poses_with_description.json dan sekarang perlu mengisi Database Firestore dengan file tersebut dan yang penting, membuat Sematan Vektor untuk setiap catatan. Embedding Vektor akan berguna nanti saat kita harus melakukan penelusuran kesamaan pada embedding tersebut dengan kueri pengguna yang telah diberikan dalam bahasa alami.
Langkah-langkah untuk melakukannya adalah sebagai berikut:
- Kita akan mengonversi daftar objek JSON menjadi daftar objek. Setiap dokumen akan memiliki dua atribut:
contentdanmetadata. Objek metadata akan berisi seluruh objek JSON yang memiliki atribut sepertiname,description,sanskrit_name, dll.contentakan berupa teks string yang akan menjadi gabungan dari beberapa kolom. - Setelah memiliki daftar dokumen, kita akan menggunakan class Vertex AI Embeddings untuk membuat embedding untuk kolom konten. Penyematan ini akan ditambahkan ke setiap rekaman dokumen, lalu kita akan menggunakan Firestore API untuk menyimpan daftar objek dokumen ini dalam koleksi (kita menggunakan variabel
TEST_COLLECTIONyang mengarah ketest-poses).
Kode untuk import-data.js diberikan di bawah (bagian kode telah dipangkas agar lebih singkat):
import { Firestore,
FieldValue,
} from '@google-cloud/firestore';
import { VertexAIEmbeddings } from "@langchain/google-vertexai";
import * as dotenv from 'dotenv';
import fs from 'fs/promises';
// Load environment variables
dotenv.config();
// Configure logging
const logger = {
info: (message) => console.log(`INFO - ${new Date().toISOString()} - ${message}`),
error: (message) => console.error(`ERROR - ${new Date().toISOString()} - ${message}`),
};
async function loadYogaPosesDataFromLocalFile(filename) {
try {
const data = await fs.readFile(filename, 'utf-8');
const poses = JSON.parse(data);
logger.info(`Loaded ${poses.length} poses.`);
return poses;
} catch (error) {
logger.error(`Error loading dataset: ${error}`);
return null;
}
}
function createFirestoreDocuments(poses) {
const documents = [];
for (const pose of poses) {
// Convert the pose to a string representation for pageContent
const pageContent = `
name: ${pose.name || ''}
description: ${pose.description || ''}
sanskrit_name: ${pose.sanskrit_name || ''}
expertise_level: ${pose.expertise_level || 'N/A'}
pose_type: ${pose.pose_type || 'N/A'}
`.trim();
// The metadata will be the whole pose
const metadata = pose;
documents.push({ pageContent, metadata });
}
logger.info(`Created ${documents.length} Langchain documents.`);
return documents;
}
async function main() {
const allPoses = await loadYogaPosesDataFromLocalFile('./data/yoga_poses_with_descriptions.json');
const documents = createFirestoreDocuments(allPoses);
logger.info(`Successfully created Firestore documents. Total documents: ${documents.length}`);
const embeddings = new VertexAIEmbeddings({
model: process.env.EMBEDDING_MODEL_NAME,
});
// Initialize Firestore
const firestore = new Firestore({
projectId: process.env.PROJECT_ID,
databaseId: process.env.DATABASE,
});
const collectionName = process.env.TEST_COLLECTION;
for (const doc of documents) {
try {
// 1. Generate Embeddings
const singleVector = await embeddings.embedQuery(doc.pageContent);
// 2. Store in Firestore with Embeddings
const firestoreDoc = {
content: doc.pageContent,
metadata: doc.metadata, // Store the original data as metadata
embedding: FieldValue.vector(singleVector), // Add the embedding vector
};
const docRef = firestore.collection(collectionName).doc();
await docRef.set(firestoreDoc);
logger.info(`Document ${docRef.id} added to Firestore with embedding.`);
} catch (error) {
logger.error(`Error processing document: ${error}`);
}
}
logger.info('Finished adding documents to Firestore.');
}
main();
Mari kita jalankan aplikasi ini. Buka jendela terminal baru (Ctrl+Shift+C) dan berikan perintah berikut:
npm run import-data
Jika semuanya berjalan lancar, Anda akan melihat pesan yang mirip dengan yang di bawah ini:
INFO - 2025-01-28T07:01:14.463Z - Loaded 3 poses.
INFO - 2025-01-28T07:01:14.464Z - Created 3 Langchain documents.
INFO - 2025-01-28T07:01:14.464Z - Successfully created Firestore documents. Total documents: 3
INFO - 2025-01-28T07:01:17.623Z - Document P46d5F92z9FsIhVVYgkd added to Firestore with embedding.
INFO - 2025-01-28T07:01:18.265Z - Document bjXXISctkXl2ZRSjUYVR added to Firestore with embedding.
INFO - 2025-01-28T07:01:19.285Z - Document GwzZMZyPfTLtiX6qBFFz added to Firestore with embedding.
INFO - 2025-01-28T07:01:19.286Z - Finished adding documents to Firestore.
Untuk memeriksa apakah data berhasil dimasukkan dan sematan telah dibuat, buka halaman Firestore di Konsol Cloud.

Klik database (default), yang akan menampilkan koleksi test-poses dan beberapa dokumen dalam koleksi tersebut. Setiap dokumen adalah satu pose Yoga.

Klik salah satu dokumen untuk menyelidiki kolom. Selain kolom yang kita impor, Anda juga akan menemukan kolom embedding, yang merupakan kolom Vektor, yang nilainya kita buat melalui model Embedding Vertex AI text-embedding-004.

Setelah data diupload ke Database Firestore dengan embedding, kita dapat melanjutkan ke langkah berikutnya dan melihat cara melakukan Penelusuran Kemiripan Vektor di Firestore.
6. Mengimpor pose Yoga lengkap ke dalam koleksi Database Firestore
Sekarang kita akan membuat koleksi poses, yang merupakan daftar lengkap 160 pose Yoga, yang telah kita buatkan file impor databasenya yang dapat Anda impor secara langsung. Hal ini dilakukan untuk menghemat waktu di lab. Proses untuk membuat database yang berisi deskripsi dan penyematan sama dengan yang kita lihat di bagian sebelumnya.
Impor database dengan mengikuti langkah-langkah di bawah:
- Buat bucket di project Anda dengan perintah
gsutilyang diberikan di bawah. Ganti variabel<PROJECT_ID>dalam perintah di bawah dengan ID Project Google Cloud Anda.
gsutil mb -l us-central1 gs://<PROJECT_ID>-my-bucket
- Setelah bucket dibuat, kita perlu menyalin ekspor database yang telah kita siapkan ke dalam bucket ini, sebelum kita dapat mengimpornya ke dalam database Firebase. Gunakan perintah yang diberikan di bawah:
gsutil cp -r gs://yoga-database-firestore-export-bucket/2025-01-27T05:11:02_62615 gs://<PROJECT_ID>-my-bucket
Setelah memiliki data yang akan diimpor, kita dapat melanjutkan ke langkah terakhir untuk mengimpor data ke database Firebase (default) yang telah kita buat.
- Gunakan perintah gcloud yang diberikan di bawah:
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2025-01-27T05:11:02_62615
Impor akan memerlukan waktu beberapa detik dan setelah siap, Anda dapat memvalidasi database dan koleksi Firestore dengan membuka https://console.cloud.google.com/firestore/databases, memilih database default dan koleksi poses seperti yang ditunjukkan di bawah:

Tindakan ini menyelesaikan pembuatan koleksi Firestore yang akan kita gunakan dalam aplikasi.
7. Melakukan Penelusuran Kemiripan Vektor di Firestore
Untuk melakukan penelusuran Kemiripan Vektor, kita akan mengambil kueri dari pengguna. Contoh kueri ini adalah "Suggest me some exercises to relieve back pain".
Lihat file search-data.js. Fungsi utama yang perlu diperhatikan adalah fungsi search, yang ditampilkan di bawah. Secara umum, kode ini membuat class embedding yang akan digunakan untuk membuat embedding untuk kueri pengguna. Kemudian, fungsi ini membuat koneksi ke database dan koleksi Firestore. Kemudian, pada koleksi, metode findNearest dipanggil, yang melakukan Penelusuran Kemiripan Vektor.
async function search(query) {
try {
const embeddings = new VertexAIEmbeddings({
model: process.env.EMBEDDING_MODEL_NAME,
});
// Initialize Firestore
const firestore = new Firestore({
projectId: process.env.PROJECT_ID,
databaseId: process.env.DATABASE,
});
log.info(`Now executing query: ${query}`);
const singleVector = await embeddings.embedQuery(query);
const collectionRef = firestore.collection(process.env.COLLECTION);
let vectorQuery = collectionRef.findNearest(
"embedding",
FieldValue.vector(singleVector), // a vector with 768 dimensions
{
limit: process.env.TOP_K,
distanceMeasure: "COSINE",
}
);
const vectorQuerySnapshot = await vectorQuery.get();
for (const result of vectorQuerySnapshot.docs) {
console.log(result.data().content);
}
} catch (error) {
log.error(`Error during search: ${error.message}`);
}
}
Sebelum menjalankan kueri ini dengan beberapa contoh kueri, Anda harus membuat indeks komposit Firestore terlebih dahulu, yang diperlukan agar kueri penelusuran Anda berhasil. Jika Anda menjalankan aplikasi tanpa membuat indeks, error yang menunjukkan bahwa Anda harus membuat indeks terlebih dahulu akan ditampilkan dengan perintah untuk membuat indeks terlebih dahulu.
Perintah gcloud untuk membuat indeks gabungan ditampilkan di bawah:
gcloud firestore indexes composite create --project=<YOUR_PROJECT_ID> --collection-group=poses --query-scope=COLLECTION --field-config=vector-config='{"dimension":"768","flat": "{}"}',field-path=embedding
Indeks akan memerlukan waktu beberapa menit untuk selesai karena ada lebih dari 150 catatan yang ada dalam database. Setelah selesai, Anda dapat melihat indeks melalui perintah yang ditampilkan di bawah:
gcloud firestore indexes composite list
Anda akan melihat indeks yang baru saja Anda buat dalam daftar.
Coba perintah berikut sekarang:
node search-data.js --prompt "Recommend me some exercises for back pain relief"
Anda akan mendapatkan beberapa rekomendasi. Contoh eksekusi ditampilkan di bawah:
2025-01-28T07:09:05.250Z - INFO - Now executing query: Recommend me some exercises for back pain relief
name: Sphinx Pose
description: A gentle backbend, Sphinx Pose (Salamba Bhujangasana) strengthens the spine and opens the chest. Keep shoulders relaxed, lengthen the tailbone, and engage the core for optimal alignment. Beginner-friendly.
sanskrit_name: Salamba Bhujangasana
expertise_level: Beginner
pose_type: ['Prone']
name: Supine Spinal Twist Pose
description: A gentle supine twist (Supta Matsyendrasana), great for beginners. Releases spinal tension, improves digestion, and calms the nervous system. Keep shoulders flat on the floor and lengthen your spine throughout the twist.
sanskrit_name: Supta Matsyendrasana
expertise_level: Beginner
pose_type: ['Supine', 'Twist']
name: Reverse Corpse Pose
description: Reverse Corpse Pose (Advasana) is a beginner prone pose. Lie on your belly, arms at your sides, relaxing completely. Benefits include stress release and spinal decompression. Ensure your forehead rests comfortably on the mat.
sanskrit_name: Advasana
expertise_level: Beginner
pose_type: ['Prone']
Setelah ini berfungsi, kita telah memahami cara mengoperasikan Database Vektor Firestore untuk mengupload data, membuat embedding, dan melakukan Penelusuran Kemiripan Vektor. Sekarang kita dapat membuat aplikasi web yang akan mengintegrasikan penelusuran vektor ke frontend web.
8. Aplikasi Web
Aplikasi web Python Flask tersedia dalam file app.js dan file HTML frontend ada di views/index.html.
Sebaiknya Anda melihat kedua file tersebut. Mulai dengan file app.js yang berisi handler /search, yang mengambil perintah yang telah diteruskan dari file index.html HTML front-end. Kemudian, metode penelusuran akan dipanggil, yang melakukan penelusuran Kesamaan Vektor yang kita lihat di bagian sebelumnya.
Respons kemudian dikirim kembali ke index.html dengan daftar rekomendasi. Kemudian, index.html menampilkan rekomendasi sebagai kartu yang berbeda.
Jalankan aplikasi secara lokal
Buka jendela terminal baru (Ctrl+Shift+C) atau jendela terminal yang ada, lalu berikan perintah berikut:
npm run start
Contoh eksekusi ditampilkan di bawah:
...
Server listening on port 8080
Setelah berjalan dan beroperasi, buka URL beranda aplikasi dengan mengklik tombol Web Preview yang ditampilkan di bawah:

File index.html yang ditayangkan akan ditampilkan seperti yang ditunjukkan di bawah ini:

Berikan contoh kueri (Contoh : Provide me some exercises for back pain relief), lalu klik tombol Search. Tindakan ini akan mengambil beberapa rekomendasi dari database. Anda juga akan melihat tombol Play Audio, yang akan membuat aliran audio berdasarkan deskripsi, yang dapat Anda dengar secara langsung.

9. (Opsional) Men-deploy ke Google Cloud Run
Langkah terakhir kita adalah men-deploy aplikasi ini ke Google Cloud Run. Perintah deployment ditampilkan di bawah. Pastikan sebelum men-deploy-nya, Anda mengganti berbagai nilai dalam tanda kurung (<<>>) yang ditampilkan di bawah. Ini adalah nilai yang dapat Anda ambil dari file .env.
gcloud run deploy yogaposes --source . \
--port=8080 \
--allow-unauthenticated \
--region=<<YOUR_LOCATION>> \
--platform=managed \
--project=<<YOUR_PROJECT_ID>> \
--set-env-vars=PROJECT_ID="<<YOUR_PROJECT_ID>>",LOCATION="<<YOUR_LOCATION>>",EMBEDDING_MODEL_NAME="<<EMBEDDING_MODEL_NAME>>",DATABASE="<<FIRESTORE_DATABASE_NAME>>",COLLECTION="<<FIRESTORE_COLLECTION_NAME>>",TOP_K=<<YOUR_TOP_K_VALUE>>
Jalankan perintah di atas dari folder root aplikasi. Anda juga dapat diminta untuk mengaktifkan Google Cloud API dan memberikan konfirmasi untuk berbagai izin. Jika demikian, lakukanlah.
Proses deployment akan memerlukan waktu sekitar 5-7 menit hingga selesai, jadi bersabarlah.

Setelah berhasil di-deploy, output deployment akan memberikan URL layanan Cloud Run. Formatnya adalah:
Service URL: https://yogaposes-<UNIQUEID>.us-central1.run.app
Buka URL publik tersebut dan Anda akan melihat aplikasi web yang sama telah di-deploy dan berjalan dengan sukses.

Anda juga dapat membuka Cloud Run dari konsol Google Cloud dan Anda akan melihat daftar layanan di Cloud Run. Layanan yogaposes harus menjadi salah satu layanan (jika bukan satu-satunya) yang tercantum di sana.

Anda dapat melihat detail layanan seperti URL, konfigurasi, log, dan lainnya dengan mengklik nama layanan tertentu (yogaposes dalam kasus ini).

Dengan demikian, pengembangan dan deployment aplikasi web pemberi rekomendasi pose Yoga di Cloud Run telah selesai.
10. Selamat
Selamat, Anda telah berhasil membuat aplikasi yang mengupload set data ke Firestore, membuat embedding, dan melakukan Penelusuran Kemiripan Vektor berdasarkan kueri pengguna.