1. Giriş
Bu codelab'de, yoga pozları önermek için vektör aramayı kullanan bir uygulama oluşturacaksınız.
Codelab'de aşağıdaki gibi adım adım bir yaklaşım uygulayacaksınız:
- Yoga pozlarının yer aldığı mevcut bir Hugging Face veri kümesini (JSON biçiminde) kullanın.
- Veri kümesini, her bir poz için açıklama oluşturmak üzere Gemini'i kullanan ek bir alan açıklamasıyla zenginleştirin.
- Yoga pozu verilerini, oluşturulan yerleştirilmiş öğelerle Firestore koleksiyonunda bir doküman koleksiyonu olarak yükleyin.
- Vektör aramaya izin vermek için Firestore'da birleşik dizin oluşturun.
- Aşağıda gösterildiği gibi her şeyi bir araya getiren bir Node.js uygulamasında Vektör Arama'yı kullanın:
Yapacaklarınız
- Yoga pozları önermek için Vektör Arama'yı kullanan bir web uygulaması tasarlayın, oluşturun ve dağıtın.
Neler öğreneceksiniz?
- Metin içeriği oluşturmak için Gemini'yi kullanma ve bu kod laboratuvarının bağlamında yoga pozları için açıklamalar oluşturma
- Hugging Face'taki gelişmiş bir veri kümesinden kayıtları Firestore'a vektör yerleştirmeleriyle birlikte yükleme
- Doğal dil sorgusuna göre veri aramak için Firestore Vektör Arama'yı kullanma
- Ses içeriği oluşturmak için Google Cloud Text-to-Speech API'yi kullanma
Gerekenler
- Chrome web tarayıcısı
- Gmail hesabı
- Faturalandırmanın etkin olduğu bir Cloud projesi
Her seviyedeki geliştiriciler (yeni başlayanlar dahil) için tasarlanan bu codelab'de, örnek uygulamada JavaScript ve Node.js kullanılmaktadır. Ancak sunulan kavramları anlamak için JavaScript ve Node.js bilgisine sahip olmanız gerekmez.
2. Başlamadan önce
Proje oluşturma
- Google Cloud Console'daki proje seçici sayfasında bir Google Cloud projesi seçin veya oluşturun.
- Cloud projenizde faturalandırmanın etkinleştirildiğinden emin olun. Projede faturalandırmanın etkin olup olmadığını nasıl kontrol edeceğinizi öğrenin .
- Google Cloud'da çalışan ve bq ile önceden yüklenmiş bir komut satırı ortamı olan Cloud Shell'i kullanacaksınız. Google Cloud Console'un üst kısmından Cloud Shell'i etkinleştir'i tıklayın.
- Cloud Shell'e bağlandıktan sonra aşağıdaki komutu kullanarak kimliğinizin doğrulanıp doğrulanmadığını ve projenin proje kimliğinize ayarlanıp ayarlanmadığını kontrol edin:
gcloud auth list
- gcloud komutunun projeniz hakkında bilgi sahibi olduğunu onaylamak için Cloud Shell'de aşağıdaki komutu çalıştırın.
gcloud config list project
- Projeniz ayarlanmadıysa ayarlamak için aşağıdaki komutu kullanın:
gcloud config set project <YOUR_PROJECT_ID>
- Aşağıda gösterilen komutu kullanarak gerekli API'leri etkinleştirin. Bu işlem birkaç dakika sürebilir. Lütfen bekleyin.
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
Komut başarıyla yürütüldüğünde aşağıdakine benzer bir mesaj görürsünüz:
Operation "operations/..." finished successfully.
gcloud komutunun alternatifi, her ürünü arayarak veya bu bağlantıyı kullanarak konsoldan geçmektir.
Atlanan bir API varsa uygulama sırasında istediğiniz zaman etkinleştirebilirsiniz.
gcloud komutları ve kullanımı için belgelere bakın.
Depoyu klonlama ve ortam ayarlarını yapma
Sonraki adım, codelab'in geri kalanında referans vereceğimiz örnek deposunu klonlamaktır. Cloud Shell'de olduğunuzu varsayarak, ana dizininizden aşağıdaki komutu verin:
git clone https://github.com/rominirani/yoga-poses-recommender-nodejs
Düzenleyiciyi başlatmak için Cloud Shell penceresinin araç çubuğunda Düzenleyiciyi Aç'ı tıklayın. Sol üst köşedeki menü çubuğunu tıklayın ve aşağıda gösterildiği gibi Dosya → Klasör Aç'ı seçin:
yoga-poses-recommender-nodejs
klasörünü seçin. Klasör, aşağıdaki gibi aşağıdaki dosyalarla açılacaktır:
Şimdi kullanacağımız ortam değişkenlerini ayarlamamız gerekiyor. env-template
dosyasını tıkladığınızda, içeriği aşağıdaki gibi görürsünüz:
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
Lütfen PROJECT_ID
ve LOCATION
değerlerini, Google Cloud projesini ve Firestore veritabanı bölgesini oluştururken seçtiğiniz değerlere göre güncelleyin. İdeal olarak, LOCATION
değerlerinin Google Cloud projesi ve Firestore veritabanı için aynı olmasını isteriz (ör. us-central1
).
Bu kod laboratuvarının amacı doğrultusunda aşağıdaki değerleri kullanacağız (tabii ki yapılandırmanıza göre ayarlamanız gereken PROJECT_ID
ve LOCATION
hariç).
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
Lütfen bu dosyayı env-template
dosyasıyla aynı klasöre .env
olarak kaydedin.
Cloud Shell IDE'de sol üstteki ana menüye, ardından Terminal → New Terminal
simgesine gidin.
Aşağıdaki komutu kullanarak klonladığınız deponun kök klasörüne gidin:
cd yoga-poses-recommender-nodejs
Node.js bağımlılıklarını şu komutla yükleyin:
npm install
Mükemmel. Artık Firestore veritabanını oluşturma görevine geçebiliriz.
3. Firestore'u ayarlama
Cloud Firestore, uygulama verilerimiz için arka uç olarak kullanacağımız, tümüyle yönetilen bir sunucusuz belge veritabanıdır. Cloud Firestore'daki veriler, dokümanlardan oluşan koleksiyonlar halinde yapılandırılır.
Firestore veritabanı ilk başlatma
Cloud Console'daki Firestore sayfasını ziyaret edin.
Projede daha önce bir Firestore veritabanı başlatmadıysanız Create Database
simgesini tıklayarak default
veritabanını oluşturun. Veritabanı oluştururken aşağıdaki değerleri kullanın:
- Firestore modu:
Native.
- Konum: Varsayılan konum ayarlarını kullanın.
- Güvenlik Kuralları için
Test rules
seçeneğini belirleyin. - Veritabanını oluşturun.
Sonraki bölümde, varsayılan Firestore veritabanımızda poses
adlı bir koleksiyon oluşturmak için temel hazırlığı yapacağız. Bu koleksiyonda, daha sonra uygulamamızda kullanacağımız örnek veriler (belgeler) veya yoga pozu bilgileri yer alır.
Firestore veritabanı oluşturma bölümü tamamlandı.
4. Yoga duruşları veri kümesini hazırlama
İlk işimiz, uygulamada kullanacağımız Yoga Pozları veri kümesini hazırlamaktır. Mevcut bir Hugging Face veri kümesiyle başlayıp daha sonra ek bilgilerle geliştireceğiz.
Yoga Pozları İçin Sarılma Yüzü Veri Kümesi'ne göz atın. Bu kod laboratuvarının veri kümelerinden birini kullandığını ancak başka herhangi bir veri kümesini de kullanabileceğinizi ve veri kümesini geliştirmek için gösterilen teknikleri uygulayabileceğinizi unutmayın.
Files and versions
bölümüne gidersek tüm pozların JSON veri dosyasını alabiliriz.
yoga_poses.json
dosyasını indirip size gönderdik. Bu dosya yoga_poses_alldata.json
olarak adlandırılmış ve /data
klasöründe yer alıyor.
Cloud Shell Düzenleyici'deki data/yoga_poses.json
dosyasına gidin ve her JSON nesnesinin bir yoga pozunu temsil ettiği JSON nesnelerinin listesine göz atın. Toplam 3 kaydımız var. Aşağıda bir örnek kayıt gösterilmektedir:
{
"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"]
}
Şimdi, Gemini'yi ve varsayılan modeli kullanarak nasıl description
alanı oluşturabileceğimizi tanıtmak için mükemmel bir fırsat.
Cloud Shell Düzenleyici'de generate-descriptions.js
dosyasına gidin. Bu dosyanın içeriği aşağıda gösterilmiştir:
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();
Bu uygulama, her yoga pozu JSON kaydına yeni bir description
alanı ekler. Açıklama, Gemini modeline yapılan bir çağrıyla elde edilir. Bu çağrıda, gerekli istemi sağlarız. Alan JSON dosyasına eklenir ve yeni dosya data/yoga_poses_with_descriptions.json
dosyasına yazılır.
Ana adımları inceleyelim:
main()
işlevinde,add_descriptions_to_json
işlevinin çağrıldığını ve beklenen giriş dosyasını ve çıkış dosyasını sağladığını göreceksiniz.add_descriptions_to_json
işlevi, her JSON kaydı (ör. yoga gönderisi bilgileri) için aşağıdakileri yapar:pose_name
,sanskrit_name
,expertise_level
vepose_types
öğelerini ayıklayın.- Bir istem oluşturan
callGemini
işlevini çağırır ve ardından yanıt metnini almak için LangchainVertexAI model sınıfını çağırır. - Ardından bu yanıt metni JSON nesnesine eklenir.
- Ardından, güncellenen nesnelerin JSON listesi hedef dosyaya yazılır.
Bu uygulamayı çalıştıralım. Yeni bir terminal penceresi (Ctrl+Üst Karakter+C) açıp aşağıdaki komutu verin:
npm run generate-descriptions
Sizden yetkilendirme istenirse lütfen bunu sağlayın.
Uygulamanın çalışmaya başladığını görürsünüz. Yeni Google Cloud hesaplarında olabilecek hız sınırı kotalarını önlemek için kayıtlar arasına 30 saniyelik bir gecikme ekledik. Lütfen bekleyin.
Aşağıda, devam eden bir örnek çalıştırma gösterilmektedir:
3 kayıtın tümü Gemini görüşmesiyle geliştirildikten sonra bir dosya data/yoga_poses_with_description.json
oluşturulur. Buna göz atabilirsiniz.
Veri dosyamız hazır. Sonraki adımda, Firestore veritabanını bu dosyayla nasıl dolduracağımızı ve yerleşik öğe oluşturmayı öğreneceğiz.
5. Verileri Firestore'a aktarma ve vektör yerleştirme işlemleri yapma
data/yoga_poses_with_description.json
dosyasını aldık. Şimdi Firestore veritabanını bu dosyayla doldurmamız ve daha da önemlisi, her bir kayıt için vektör yerleştirmelerini oluşturmamız gerekiyor. Vektör Embedding'leri, daha sonra doğal dilde sağlanan kullanıcı sorgusuyla benzerlik araması yapmamız gerektiğinde faydalı olacaktır.
Bunun için aşağıdaki adımları uygulayın:
- JSON nesnelerinin listesini bir nesne listesine dönüştürürüz. Her dokümanın iki özelliği vardır:
content
vemetadata
. Meta veri nesnesi,name
,description
,sanskrit_name
gibi özelliklere sahip JSON nesnesinin tamamını içerir.content
, birkaç alanın birleştirilmesiyle oluşturulan bir dize metni olacaktır. - Belgelerin listesini aldıktan sonra, içerik alanının gömmesini oluşturmak için Vertex AI Embeddings sınıfını kullanacağız. Bu yerleştirme her doküman kaydına eklenir ve ardından bu doküman nesnesi listesini koleksiyona kaydetmek için Firestore API'yi kullanırız (
test-poses
öğesini işaret edenTEST_COLLECTION
değişkenini kullanırız).
import-data.js
için kod aşağıda verilmiştir (kodun bazı kısımları kısaltılmıştır):
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();
Bu uygulamayı çalıştıralım. Yeni bir terminal penceresi (Ctrl+Üst Karakter+C) açıp aşağıdaki komutu verin:
npm run import-data
Her şey yolunda giderse aşağıdakine benzer bir mesaj görürsünüz:
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.
Kayıtların başarıyla eklenip eklenmediğini ve yerleştirilmelerin oluşturulup oluşturulmadığını kontrol etmek için Cloud Console'daki Firestore sayfasını ziyaret edin.
(Varsayılan) veritabanını tıklayın. Bu işlem, test-poses
koleksiyonunu ve bu koleksiyon altındaki birden fazla dokümanı gösterir. Her doküman bir yoga duruşudur.
Alanları incelemek için dokümanlardan birini tıklayın. İçe aktardığımız alanlara ek olarak, değerini text-embedding-004
Vertex AI gömme modeli aracılığıyla oluşturduğumuz bir vektör alanı olan embedding
alanını da görürsünüz.
Firestore veritabanına yerleştirilmiş yerleştirmelerle birlikte kayıtları yüklediğimize göre, bir sonraki adıma geçip Firestore'da vektör benzerliği aramasının nasıl yapıldığını öğrenebiliriz.
6. Tam yoga pozlarını Firestore veritabanı koleksiyonuna aktarma
Şimdi, 160 yoga duruşunun tam listesini içeren poses
koleksiyonunu oluşturacağız. Bu koleksiyon için doğrudan içe aktarabileceğiniz bir veritabanı içe aktarma dosyası oluşturduk. Bu işlem, laboratuvarda zaman kazanmak için yapılır. Açıklamayı ve yerleştirmeleri içeren veritabanını oluşturma işlemi, önceki bölümde gördüğümüzle aynıdır.
Aşağıdaki adımları uygulayarak veritabanını içe aktarın:
- Aşağıda verilen
gsutil
komutuyla projenizde bir paket oluşturun. Aşağıdaki komuttaki<PROJECT_ID>
değişkenini Google Cloud proje kimliğinizle değiştirin.
gsutil mb -l us-central1 gs://<PROJECT_ID>-my-bucket
- Paket oluşturulduğuna göre, Firebase veritabanına aktarmadan önce hazırladığımız veritabanı dışa aktarma işlemini bu pakete kopyalamamız gerekiyor. Aşağıdaki komutu kullanın:
gsutil cp -r gs://yoga-database-firestore-export-bucket/2025-01-27T05:11:02_62615 gs://<PROJECT_ID>-my-bucket
İçe aktarılacak verilere sahip olduğumuza göre, verileri oluşturduğumuz Firebase veritabanına (default
) aktarma işleminin son adımına geçebiliriz.
- Aşağıda verilen gcloud komutunu kullanın:
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2025-01-27T05:11:02_62615
İçe aktarma işlemi birkaç saniye sürer. İşlem tamamlandıktan sonra https://console.cloud.google.com/firestore/databases adresini ziyaret ederek Firestore veritabanınızı ve koleksiyonunuzu doğrulayabilirsiniz. Aşağıda gösterildiği gibi default
veritabanını ve poses
koleksiyonunu seçin:
Bu işlemle, uygulamamızda kullanacağımız Firestore koleksiyonunun oluşturulması tamamlanır.
7. Firestore'da vektör benzerliği araması yapma
Vektör Benzerliği araması yapmak için kullanıcıdan sorguyu alırız. Bu sorguya örnek olarak "Suggest me some exercises to relieve back pain"
verilebilir.
search-data.js
dosyasına göz atın. Dikkat edilmesi gereken temel işlev, aşağıda gösterilen search
işlevidir. Genel hatlarıyla, kullanıcı sorgusunun yerleştirilmesini sağlamak için kullanılacak bir yerleşik sınıf oluşturur. Ardından Firestore veritabanı ve koleksiyonuyla bağlantı kurar. Ardından koleksiyonda, bir Vektör Benzerliği Araması yapan findNearest yöntemini çağırır.
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}`);
}
}
Bunu birkaç sorgu örneğiyle çalıştırmadan önce, arama sorgularınızın başarılı olması için gereken bir Firestore birleşik dizini oluşturmanız gerekir. Uygulamayı dizin oluşturmadan çalıştırırsanız önce dizini oluşturmanız gerektiğini belirten bir hata mesajı ve önce dizini oluşturma komutu gösterilir.
Bileşik dizini oluşturmak için kullanılan gcloud
komutu aşağıda gösterilmiştir:
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
Veritabanında 150'den fazla kayıt bulunduğundan dizinin oluşturulması birkaç dakika sürer. İşlem tamamlandığında dizini aşağıdaki komutla görüntüleyebilirsiniz:
gcloud firestore indexes composite list
Az önce oluşturduğunuz dizini listede görürsünüz.
Aşağıdaki komutu hemen deneyin:
node search-data.js --prompt "Recommend me some exercises for back pain relief"
Size birkaç öneri sunulur. Aşağıda örnek bir çalıştırma gösterilmektedir:
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']
Bu işlemi tamamladığınızda, kayıt yüklemek, yerleştirme oluşturmak ve vektör benzerliği araması yapmak için Firestore vektör veritabanı ile nasıl çalışacağınızı anlamış olursunuz. Artık vektör aramayı bir web ön ucu ile entegre edecek bir web uygulaması oluşturabiliriz.
8. Web Uygulaması
Python Flask web uygulaması app.js
dosyasında, kullanıcı arayüzü HTML dosyası ise views/index.html.
dosyasında bulunur.
Her iki dosyayı da incelemeniz önerilir. Öncelikle, kullanıcı arayüzü HTML index.html
dosyasından iletilen istemi alan /search
işleyicisini içeren app.js
dosyasıyla başlayın. Bu işlem, önceki bölümde incelediğimiz vektör benzerliği aramasını yapan arama yöntemini çağırır.
Ardından yanıt, öneri listesini de ekleyerek index.html
'e geri gönderilir. index.html
, önerileri farklı kartlar olarak gösterir.
Uygulamayı yerel olarak çalıştırma
Yeni bir terminal penceresi (Ctrl+Üst Karakter+C) veya mevcut bir terminal penceresi açıp aşağıdaki komutu verin:
npm run start
Aşağıda örnek bir yürütme gösterilmektedir:
...
Server listening on port 8080
Uygulamayı çalıştırdıktan sonra, aşağıda gösterilen Web Önizlemesi düğmesini tıklayarak uygulamanın ana sayfa URL'sini ziyaret edin:
Aşağıda gösterildiği gibi, yayınlanan index.html
dosyasını gösterir:
Örnek bir sorgu girin (Örnek : Provide me some exercises for back pain relief
) ve Search
düğmesini tıklayın. Bu işlem, veritabanından bazı öneriler getirir. Ayrıca, açıklamaya göre doğrudan dinleyebileceğiniz bir ses akışı oluşturan bir Play Audio
düğmesi de görürsünüz.
9. (İsteğe bağlı) Google Cloud Run'a dağıtma
Son adımımız bu uygulamayı Google Cloud Run'a dağıtmaktır. Dağıtım komutu aşağıda gösterilmiştir. Dağıtmadan önce aşağıda kalın olarak gösterilen değerleri değiştirdiğinizden emin olun. Bunlar, .env
dosyasından alabileceğiniz değerlerdir.
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>>
Yukarıdaki komutu uygulamanın kök klasöründen yürütün. Google Cloud API'lerini etkinleştirmeniz ve çeşitli izinleri onaylamanız da istenebilir. Lütfen bunu yapın.
Dağıtım işleminin tamamlanması yaklaşık 5-7 dakika sürer. Lütfen bekleyin.
Dağıtım başarıyla tamamlandığında dağıtım çıkışında Cloud Run hizmet URL'si sağlanır. Şekli şu şekildedir:
Service URL: https://yogaposes-<UNIQUEID>.us-central1.run.app
Bu herkese açık URL'yi ziyaret ettiğinizde aynı web uygulamasının dağıtıldığını ve başarıyla çalıştığını görürsünüz.
Google Cloud Console'dan Cloud Run'u da ziyaret edebilirsiniz. Burada Cloud Run'daki hizmetlerin listesini görebilirsiniz. yogaposes
hizmeti, burada listelenen hizmetlerden biri (tek hizmet değilse) olmalıdır.
Belirli bir hizmet adını (bizim durumumuzda yogaposes
) tıklayarak hizmetin URL'si, yapılandırmaları, günlükleri ve diğer ayrıntılarını görüntüleyebilirsiniz.
Bu işlemle, Cloud Run'da yoga pozu önerici web uygulamamızın geliştirilmesi ve dağıtımı tamamlanmış olur.
10. Tebrikler
Tebrikler, Firestore'a veri kümesi yükleyen, yerleştirmeleri oluşturan ve kullanıcı sorgusuna göre bir Vektör Benzerliği Araması yapan bir uygulamayı başarıyla oluşturdunuz.