1. Introduzione
In questo codelab, creerai un'applicazione che utilizza la ricerca vettoriale per consigliare posizioni yoga.
Nel codelab, seguirai un approccio passo passo come segue:
- Utilizza un set di dati esistente di Hugging Face di pose di yoga (formato JSON).
- Migliora il set di dati con una descrizione di campo aggiuntiva che utilizza Gemini per generare descrizioni per ciascuna delle pose.
- Carica i dati delle pose di yoga come raccolta di documenti nella raccolta Firestore con gli incorporamenti generati.
- Crea un indice composto in Firestore per consentire la ricerca vettoriale.
- Utilizza la ricerca vettoriale in un'applicazione Node.js che riunisce tutto come mostrato di seguito:

Attività previste
- Progetta, crea ed esegui il deployment di un'applicazione web che utilizza Vector Search per consigliare posizioni yoga.
Cosa imparerai a fare
- Come utilizzare Gemini per generare contenuti di testo e, nel contesto di questo codelab, generare descrizioni per le posizioni yoga
- Come caricare record da un set di dati avanzato di Hugging Face in Firestore insieme ai vector embedding
- Come utilizzare la ricerca vettoriale di Firestore per cercare dati in base a una query in linguaggio naturale
- Come utilizzare l'API Google Cloud Text to Speech per generare contenuti audio
Che cosa ti serve
- Browser web Chrome
- Un account Gmail
- Un progetto cloud con fatturazione abilitata
Questo codelab, progettato per sviluppatori di tutti i livelli (inclusi i principianti), utilizza JavaScript e Node.js nella sua applicazione di esempio. Tuttavia, la conoscenza di JavaScript e Node.js non è necessaria per comprendere i concetti presentati.
2. Prima di iniziare
Crea un progetto
- Nella console Google Cloud, nella pagina di selezione del progetto, seleziona o crea un progetto Google Cloud.
- Verifica che la fatturazione sia attivata per il tuo progetto Cloud. Scopri come verificare se la fatturazione è abilitata per un progetto .
- Utilizzerai Cloud Shell, un ambiente a riga di comando in esecuzione in Google Cloud precaricato con bq. Fai clic su Attiva Cloud Shell nella parte superiore della console Google Cloud.

- Una volta eseguita la connessione a Cloud Shell, verifica di essere già autenticato e che il progetto sia impostato sul tuo ID progetto utilizzando il seguente comando:
gcloud auth list
- Esegui questo comando in Cloud Shell per verificare che il comando gcloud conosca il tuo progetto.
gcloud config list project
- Se il progetto non è impostato, utilizza il seguente comando per impostarlo:
gcloud config set project <YOUR_PROJECT_ID>
- Abilita le API richieste tramite il comando mostrato di seguito. L'operazione potrebbe richiedere alcuni minuti.
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
Se il comando viene eseguito correttamente, dovresti visualizzare un messaggio simile a quello mostrato di seguito:
Operation "operations/..." finished successfully.
L'alternativa al comando gcloud è tramite la console, cercando ogni prodotto o utilizzando questo link.
Se manca un'API, puoi sempre abilitarla durante l'implementazione.
Consulta la documentazione per i comandi e l'utilizzo di gcloud.
Clona il repository e configura le impostazioni dell'ambiente
Il passaggio successivo consiste nel clonare il repository di esempio a cui faremo riferimento nel resto del codelab. Supponendo che tu sia in Cloud Shell, esegui questo comando dalla tua home directory:
git clone https://github.com/rominirani/yoga-poses-recommender-nodejs
Per avviare l'editor, fai clic su Apri editor nella barra degli strumenti della finestra di Cloud Shell. Fai clic sulla barra dei menu nell'angolo in alto a sinistra e seleziona File → Apri cartella come mostrato di seguito:

Seleziona la cartella yoga-poses-recommender-nodejs e dovresti visualizzarla aperta con i seguenti file, come mostrato di seguito:

Ora dobbiamo configurare le variabili di ambiente che utilizzeremo. Fai clic sul file env-template e dovresti visualizzare i contenuti come mostrato di seguito:
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
Aggiorna i valori per PROJECT_ID e LOCATION in base a ciò che hai selezionato durante la creazione del progetto Google Cloud e della regione del database Firestore. Idealmente, vorremmo che i valori di LOCATION fossero gli stessi per il progetto Google Cloud e il database Firestore, ad esempio us-central1.
Ai fini di questo codelab, utilizzeremo i seguenti valori (ad eccezione, ovviamente, di PROJECT_ID e LOCATION, che devi impostare in base alla tua configurazione.
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
Salva questo file come .env nella stessa cartella del file env-template.
Vai al menu principale in alto a sinistra nell'IDE Cloud Shell, quindi Terminal → New Terminal.
Vai alla cartella radice del repository che hai clonato utilizzando questo comando:
cd yoga-poses-recommender-nodejs
Installa le dipendenze Node.js tramite il comando:
npm install
Ottimo. Ora siamo pronti per passare alla configurazione del database Firestore.
3. Configura Firestore
Cloud Firestore è un database di documenti serverless completamente gestito che utilizzeremo come backend per i dati della nostra applicazione. I dati in Cloud Firestore sono strutturati in raccolte di documenti.
Inizializzazione del database Firestore
Visita la pagina Firestore nella console Cloud.
Se non hai inizializzato un database Firestore in precedenza nel progetto, crea il database default facendo clic su Create Database. Durante la creazione del database, utilizza i seguenti valori:
- Modalità Firestore:
Native. - Seleziona Tipo di località come
Regione seleziona la localitàus-central1per la regione. - Per le regole di sicurezza, scegli
Test rules. - Crea il database.

Nella sezione successiva, prepareremo il terreno per la creazione di una raccolta denominata poses nel nostro database Firestore predefinito. Questa raccolta conterrà dati di esempio (documenti) o informazioni sulle posizioni di yoga, che utilizzeremo nella nostra applicazione.
Con questo si conclude la sezione per la configurazione del database Firestore.
4. Prepara il set di dati Pose di yoga
Il nostro primo compito è preparare il set di dati Yoga Poses che utilizzeremo per l'applicazione. Inizieremo con un set di dati Hugging Face esistente e lo miglioreremo con ulteriori informazioni.
Dai un'occhiata al set di dati di Hugging Face per le pose yoga. Tieni presente che, sebbene questo codelab utilizzi uno dei set di dati, puoi utilizzare qualsiasi altro set di dati e seguire le stesse tecniche dimostrate per migliorarlo.

Se andiamo alla sezione Files and versions, possiamo ottenere il file di dati JSON per tutte le pose.

Abbiamo scaricato il file yoga_poses.json e te l'abbiamo fornito. Questo file si chiama yoga_poses_alldata.json e si trova nella cartella /data.
Vai al file data/yoga_poses.json in Cloud Shell Editor e dai un'occhiata all'elenco degli oggetti JSON, dove ogni oggetto JSON rappresenta una posizione di yoga. Abbiamo un totale di tre record e di seguito è mostrato un record di esempio:
{
"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"]
}
Ora è un'ottima opportunità per presentare Gemini e mostrare come possiamo utilizzare il modello predefinito stesso per generare un campo description.
Nell'editor di Cloud Shell, vai al file generate-descriptions.js. I contenuti di questo file sono mostrati di seguito:
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();
Questa applicazione aggiungerà un nuovo campo description a ogni record JSON della posa di yoga. Otterrà la descrizione tramite una chiamata al modello Gemini, a cui forniremo il prompt necessario. Il campo viene aggiunto al file JSON e il nuovo file viene scritto nel file data/yoga_poses_with_descriptions.json.
Vediamo i passaggi principali:
- Nella funzione
main(), vedrai che richiama la funzioneadd_descriptions_to_jsone fornisce il file di input e il file di output previsti. - La funzione
add_descriptions_to_jsonesegue le seguenti operazioni per ogni record JSON, ovvero le informazioni del post di Yoga: - Estrae
pose_name,sanskrit_name,expertise_levelepose_types. - Invoca la funzione
callGeminiche crea un prompt e poi invoca la classe del modello LangchainVertexAI per ottenere il testo della risposta. - Questo testo di risposta viene quindi aggiunto all'oggetto JSON.
- L'elenco JSON aggiornato degli oggetti viene quindi scritto nel file di destinazione.
Eseguiamo questa applicazione. Avvia una nuova finestra del terminale (Ctrl+Maiusc+C) ed esegui il seguente comando:
npm run generate-descriptions
Se ti viene richiesta un'autorizzazione, forniscila.
Vedrai che l'applicazione inizia l'esecuzione. Abbiamo aggiunto un ritardo di 30 secondi tra i record per evitare eventuali quote di limite di frequenza che potrebbero essere presenti nei nuovi account Google Cloud, quindi ti invitiamo a pazientare.
Di seguito è riportata un'esecuzione di esempio in corso:

Una volta migliorati tutti e tre i record con la chiamata a Gemini, verrà generato un file data/yoga_poses_with_description.json. Puoi dare un'occhiata.
Ora abbiamo il file di dati e il passaggio successivo consiste nel capire come popolare un database Firestore con questo file, insieme alla generazione di incorporamenti.
5. Importa i dati in Firestore e genera vector embedding
Abbiamo il file data/yoga_poses_with_description.json e ora dobbiamo popolarlo nel database Firestore e, soprattutto, generare gli incorporamenti vettoriali per ogni record. I vector embedding saranno utili in un secondo momento, quando dovremo eseguire una ricerca di similarità con la query dell'utente fornita in linguaggio naturale.
Ecco i passaggi da seguire:
- Convertiremo l'elenco di oggetti JSON in un elenco di oggetti. Ogni documento avrà due attributi:
contentemetadata. L'oggetto dei metadati conterrà l'intero oggetto JSON con attributi comename,description,sanskrit_namee così via.contentsarà una stringa di testo che sarà la concatenazione di alcuni campi. - Una volta ottenuta una lista di documenti, utilizzeremo la classe Vertex AI Embeddings per generare l'incorporamento per il campo dei contenuti. Questo incorporamento verrà aggiunto a ogni record del documento e poi utilizzeremo l'API Firestore per salvare questo elenco di oggetti documento nella raccolta (utilizziamo la variabile
TEST_COLLECTIONche punta atest-poses).
Di seguito è riportato il codice per import-data.js (alcune parti del codice sono state troncate per brevità):
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();
Eseguiamo questa applicazione. Avvia una nuova finestra del terminale (Ctrl+Maiusc+C) ed esegui il seguente comando:
npm run import-data
Se tutto va bene, dovresti visualizzare un messaggio simile a quello riportato di seguito:
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.
Per verificare se i record sono stati inseriti correttamente e se gli incorporamenti sono stati generati, visita la pagina Firestore nella console Cloud.

Fai clic sul database (predefinito). Dovresti visualizzare la raccolta test-poses e più documenti al suo interno. Ogni documento è una posizione yoga.

Fai clic su uno dei documenti per esaminare i campi. Oltre ai campi che abbiamo importato, troverai anche il campo embedding, che è un campo vettoriale il cui valore è stato generato tramite il modello di embedding text-embedding-004 di Vertex AI.

Ora che abbiamo caricato i record nel database Firestore con gli incorporamenti, possiamo passare al passaggio successivo e vedere come eseguire la ricerca di similarità vettoriale in Firestore.
6. Importa le posizioni yoga complete nella raccolta del database Firestore
Ora creeremo la raccolta poses, che è un elenco completo di 160 posizioni di yoga, per le quali abbiamo generato un file di importazione del database che puoi importare direttamente. Questa operazione viene eseguita per risparmiare tempo nel lab. La procedura per generare il database contenente la descrizione e gli incorporamenti è la stessa che abbiamo visto nella sezione precedente.
Importa il database seguendo i passaggi riportati di seguito:
- Crea un bucket nel tuo progetto con il comando
gsutilriportato di seguito. Sostituisci la variabile<PROJECT_ID>nel comando seguente con il tuo ID progetto Google Cloud.
gsutil mb -l us-central1 gs://<PROJECT_ID>-my-bucket
- Ora che il bucket è stato creato, dobbiamo copiarvi l'esportazione del database che abbiamo preparato prima di poterla importare nel database Firebase. Utilizza il comando riportato di seguito:
gsutil cp -r gs://yoga-database-firestore-export-bucket/2025-01-27T05:11:02_62615 gs://<PROJECT_ID>-my-bucket
Ora che abbiamo i dati da importare, possiamo passare al passaggio finale dell'importazione nel database Firebase (default) che abbiamo creato.
- Utilizza il comando gcloud riportato di seguito:
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2025-01-27T05:11:02_62615
L'importazione richiederà alcuni secondi e, una volta pronta, potrai convalidare il database Firestore e la raccolta visitando la pagina https://console.cloud.google.com/firestore/databases, selezionando il database default e la raccolta poses come mostrato di seguito:

In questo modo viene completata la creazione della raccolta Firestore che utilizzeremo nella nostra applicazione.
7. Esegui la ricerca di similarità vettoriale in Firestore
Per eseguire la ricerca di similarità vettoriale, prendiamo in considerazione la query dell'utente. Un esempio di questa query può essere "Suggest me some exercises to relieve back pain".
Dai un'occhiata al file search-data.js. La funzione principale da esaminare è search, mostrata di seguito. A livello generale, crea una classe di incorporamento che verrà utilizzata per generare l'incorporamento per la query dell'utente. Quindi, stabilisce una connessione al database e alla raccolta Firestore. Quindi, nella raccolta richiama il metodo findNearest, che esegue una ricerca sulla similarità vettoriale.
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}`);
}
}
Prima di eseguire questa operazione con alcuni esempi di query, devi prima generare un indice composto Firestore, necessario per l'esecuzione delle query di ricerca. Se esegui l'applicazione senza creare l'indice, verrà visualizzato un errore che indica che devi prima creare l'indice con il comando per creare l'indice.
Il comando gcloud per creare l'indice composito è mostrato di seguito:
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
Il completamento dell'indice richiede alcuni minuti perché nel database sono presenti più di 150 record. Una volta completata, puoi visualizzare l'indice tramite il comando mostrato di seguito:
gcloud firestore indexes composite list
Dovresti vedere l'indice che hai appena creato nell'elenco.
Prova subito il seguente comando:
node search-data.js --prompt "Recommend me some exercises for back pain relief"
Dovresti ricevere alcuni consigli. Di seguito è riportato un esempio di esecuzione:
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']
Una volta che tutto funziona, abbiamo capito come utilizzare il database vettoriale Firestore per caricare record, generare incorporamenti ed eseguire una ricerca di somiglianze vettoriali. Ora possiamo creare un'applicazione web che integrerà la ricerca vettoriale in un front-end web.
8. L'applicazione web
L'applicazione web Python Flask è disponibile nel file app.js e il file HTML di frontend è presente in views/index.html.
Ti consigliamo di dare un'occhiata a entrambi i file. Inizia con il file app.js che contiene il gestore /search, che accetta il prompt passato dal file HTML index.html del front-end. Viene quindi richiamato il metodo di ricerca, che esegue la ricerca di similarità vettoriale esaminata nella sezione precedente.
La risposta viene quindi inviata di nuovo a index.html con l'elenco dei consigli. index.html mostra quindi i suggerimenti come schede diverse.
Esegui l'applicazione localmente
Avvia una nuova finestra del terminale (Ctrl+Maiusc+C) o una finestra del terminale esistente ed esegui il comando seguente:
npm run start
Di seguito è riportato un esempio di esecuzione:
...
Server listening on port 8080
Una volta che l'applicazione è in esecuzione, visita l'URL della home page facendo clic sul pulsante Anteprima web mostrato di seguito:

Dovrebbe mostrare il file index.html pubblicato come mostrato di seguito:

Fornisci una query di esempio (ad esempio : Provide me some exercises for back pain relief) e fai clic sul pulsante Search. In questo modo dovresti recuperare alcuni consigli dal database. Vedrai anche un pulsante Play Audio, che genererà un flusso audio basato sulla descrizione, che potrai ascoltare direttamente.

9. (Facoltativo) Eseguire il deployment in Google Cloud Run
Il passaggio finale sarà il deployment di questa applicazione in Google Cloud Run. Il comando di deployment è mostrato di seguito. Prima di eseguirlo, assicurati di sostituire i vari valori tra parentesi (<<>>) mostrati di seguito. Questi sono i valori che potrai recuperare dal 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>>
Esegui il comando riportato sopra dalla cartella principale dell'applicazione. Potrebbe anche esserti chiesto di abilitare le API Google Cloud e di dare la tua approvazione per varie autorizzazioni.
Il completamento della procedura di deployment richiede circa 5-7 minuti, quindi ti invitiamo ad avere pazienza.

Una volta eseguito il deployment, l'output del deployment fornirà l'URL del servizio Cloud Run. Avrà il formato:
Service URL: https://yogaposes-<UNIQUEID>.us-central1.run.app
Visita l'URL pubblico e dovresti vedere la stessa applicazione web di cui è stato eseguito il deployment e che è in esecuzione.

Puoi anche visitare Cloud Run dalla console Google Cloud e visualizzare l'elenco dei servizi in Cloud Run. Il servizio yogaposes deve essere uno dei servizi (se non l'unico) elencati.

Puoi visualizzare i dettagli del servizio, come URL, configurazioni, log e altro ancora, facendo clic sul nome del servizio specifico (yogaposes nel nostro caso).

In questo modo, lo sviluppo e il deployment della nostra applicazione web di consigli sulle posizioni di yoga su Cloud Run sono completati.
10. Complimenti
Congratulazioni, hai creato correttamente un'applicazione che carica un set di dati in Firestore, genera gli incorporamenti ed esegue una ricerca di somiglianza vettoriale in base alla query degli utenti.