Codelab – פיתוח אפליקציה להמלצות על תנוחות יוגה לפי הקשר באמצעות Firestore, ‏ Vector Search, ‏ Langchain ו-Gemini (גרסת Python)

1. מבוא

ב-codelab הזה תבנו אפליקציה שמשתמשת בחיפוש וקטורי כדי להמליץ על תנוחות יוגה.

במהלך ה-codelab, תשתמשו בגישה שלב אחר שלב באופן הבא:

  1. שימוש במערך נתונים קיים של תנוחות יוגה מ-Hugging Face (בפורמט JSON).
  2. משפרים את מערך הנתונים באמצעות תיאור שדה נוסף שנוצר על ידי Gemini לכל אחת מהתנוחות.
  3. משתמשים ב-Langchain כדי ליצור מסמך, ומשתמשים בשילוב של Firestore עם Langchain כדי ליצור את האוסף וההטמעות ב-Firestore.
  4. יוצרים אינדקס מורכב ב-Firestore כדי לאפשר חיפוש וקטורי.
  5. אפשר להשתמש בחיפוש וקטורי באפליקציית Flask שמאגדת את הכול כמו בדוגמה הבאה:

84e1cbf29cbaeedc.png

מה תעשו

  • תכנון, בנייה ופריסה של אפליקציית אינטרנט שמשתמשת בחיפוש וקטורי כדי להמליץ על תנוחות יוגה.

מה תלמדו

  • איך משתמשים ב-Gemini כדי ליצור תוכן טקסטואלי, ובמסגרת ה-codelab הזה, ליצור תיאורים לתנוחות יוגה
  • איך משתמשים ב-Langchain Document Loader for Firestore כדי לטעון רשומות ממערך נתונים משופר מ-Hugging Face ל-Firestore יחד עם הטמעות וקטוריות
  • איך משתמשים ב-Langchain Vector Store for Firestore כדי לחפש נתונים על סמך שאילתה בשפה טבעית
  • איך משתמשים ב-Google Cloud Text to Speech API כדי ליצור תוכן אודיו

מה תצטרכו

  • דפדפן האינטרנט Chrome
  • חשבון Gmail
  • פרויקט ב-Cloud עם חיוב מופעל

ב-codelab הזה, שמיועד למפתחים בכל הרמות (כולל מתחילים), נעשה שימוש ב-Python באפליקציה לדוגמה. עם זאת, לא נדרש ידע ב-Python כדי להבין את המושגים שמוצגים.

‫2. לפני שמתחילים

יצירת פרויקט

  1. ב-מסוף Google Cloud, בדף לבחירת הפרויקט, בוחרים או יוצרים פרויקט ב-Google Cloud.
  2. הקפידו לוודא שהחיוב מופעל בפרויקט שלכם ב-Cloud. כך בודקים אם החיוב מופעל בפרויקט
  3. תשתמשו ב-Cloud Shell, סביבת שורת פקודה שפועלת ב-Google Cloud ומגיעה עם bq שנטען מראש. לוחצים על 'הפעלת Cloud Shell' בחלק העליון של מסוף Google Cloud.

תמונה של לחצן ההפעלה של Cloud Shell

  1. אחרי שמתחברים ל-Cloud Shell, אפשר לבדוק שכבר בוצע אימות ושהפרויקט מוגדר למזהה הפרויקט שלכם באמצעות הפקודה הבאה:
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 \
                       texttospeech.googleapis.com

אם הפקודה תפעל בהצלחה, תוצג הודעה שדומה לזו שמופיעה בהמשך:

Operation "operations/..." finished successfully.

אפשר גם לחפש כל מוצר במסוף או להשתמש בקישור הזה במקום בפקודת gcloud.

אם פספסתם API כלשהו, תמיד תוכלו להפעיל אותו במהלך ההטמעה.

אפשר לעיין במאמרי העזרה בנושא פקודות gcloud ושימוש בהן.

שכפול מאגר והגדרת הגדרות הסביבה

השלב הבא הוא לשכפל את מאגר הדוגמאות שאליו נתייחס בהמשך ה-codelab. אם אתם נמצאים ב-Cloud Shell, מריצים את הפקודה הבאה מספריית הבית:

git clone https://github.com/rominirani/yoga-poses-recommender-python

כדי לפתוח את העורך, לוחצים על Open Editor בסרגל הכלים שבחלון של Cloud Shell. לוחצים על סרגל התפריטים בפינה הימנית העליונה ובוחרים באפשרות 'קובץ' ← 'פתיחת תיקייה' כמו שמוצג בהמשך:

66221fd0d0e5202f.png

בוחרים בתיקייה yoga-poses-recommender-python. התיקייה תיפתח ויוצגו בה הקבצים הבאים, כמו שמוצג בהמשך:

44699efc7fb1b911.png

עכשיו צריך להגדיר את משתני הסביבה שבהם נשתמש. לוחצים על הקובץ config.template.yaml ורואים את התוכן כמו שמוצג בהמשך:

project_id: your-project-id
location: us-central1
gemini_model_name: gemini-1.5-flash-002
embedding_model_name: text-embedding-004
image_generation_model_name: imagen-3.0-fast-generate-002
database: (default)
collection: poses
test_collection: test-poses
top_k: "3"

צריך לעדכן את הערכים של project_id ושל location בהתאם למה שבחרתם כשיצרתם את פרויקט Google Cloud ואת האזור של מסד הנתונים של Firestore. הכי טוב שהערכים של location יהיו זהים בפרויקט Google Cloud ובמסד הנתונים של Firestore, למשל us-central1.

לצורך ה-codelab הזה, נשתמש בערכים שהוגדרו מראש (חוץ מproject_id וlocation, שצריך להגדיר בהתאם להגדרה שלכם).

צריך לשמור את הקובץ הזה בשם config.yaml באותה תיקייה שבה נמצא הקובץ config.template.yaml.

השלב האחרון הוא ליצור סביבת Python שבה נשתמש באופן מקומי, עם כל יחסי התלות של Python שהוגדרו עבורנו. כדאי לבדוק את קובץ pyproject.toml שמכיל את הפרטים של אותו פריט. התוכן של הקובץ מוצג בהמשך:

dependencies = [
    "datasets>=3.2.0",
    "flask>=3.1.0",
    "google-cloud-aiplatform>=1.78.0",
    "google-cloud-texttospeech>=2.24.0",
    "langchain-community>=0.3.15",
    "langchain-core>=0.3.31",
    "langchain-google-community>=2.0.4",
    "langchain-google-firestore>=0.5.0",
    "langchain-google-vertexai>=2.0.7",
    "pydantic-settings>=2.7.1",
    "pyyaml>=6.0.2",
    "tenacity>=9.0.0",
]

התלות הזו כבר נעולה בגרסה ב-requirements.txt. לסיכום, צריך ליצור סביבת Python וירטואלית עם התלויות של חבילת Python ב-requirements.txt כדי להתקין אותה בסביבה הווירטואלית. כדי לעשות את זה, עוברים אל Command Palette (Ctrl+Shift+P) בסביבת הפיתוח המשולבת של Cloud Shell ומקלידים Python: Create Environment. פועלים לפי השלבים הבאים כדי לבחור קובץ Virtual Environment(venv), קובץ Python 3.x interpreter וקובץ requirements.txt.

אחרי שיוצרים את הסביבה, צריך להפעיל אותה באמצעות הפקודה הבאה

source .venv/bin/activate

צריך לראות את המחרוזת ‎ (.venv) במסוף. לדוגמה: -> (.venv) yourusername@cloudshell:

מעולה! עכשיו אפשר להמשיך למשימה של הגדרת מסד הנתונים ב-Firestore.

3. הגדרת Firestore

Cloud Firestore הוא מסד נתונים מנוהל למסמכים, שניתן להתאמה ללא שרת (serverless), שישמש כקצה עורפי לנתוני האפליקציה. הנתונים ב-Cloud Firestore מובנים באוספים של מסמכים.

הפעלה של מסד נתונים ב-Firestore

נכנסים לדף Firestore במסוף Cloud.

אם לא הפעלתם מסד נתונים של Firestore בפרויקט, צריך ליצור את מסד הנתונים default על ידי לחיצה על Create Database. במהלך יצירת מסד הנתונים, משתמשים בערכים הבאים:

  • מצב Firestore: ‏ Native.
  • בוחרים באפשרות Region בתור Location Type ובוחרים את המיקום us-central1 לאזור.
  • בקטע 'כללי אבטחה', בוחרים באפשרות Test rules.
  • יוצרים את מסד הנתונים.

61d0277510803c8d.png

בקטע הבא נניח את היסודות ליצירת אוסף בשם poses במסד הנתונים של Firestore שמוגדר כברירת מחדל. האוסף הזה יכיל נתוני דוגמה (מסמכים) או מידע על תנוחות יוגה, שבהם נשתמש באפליקציה שלנו.

בשלב הזה מסיימים את ההגדרה של מסד הנתונים של Firestore.

4. הכנת מערך הנתונים של תנוחות יוגה

המשימה הראשונה שלנו היא להכין את מערך הנתונים של תנוחות היוגה שבו נשתמש באפליקציה. נתחיל עם מערך נתונים קיים של Hugging Face ואז נשפר אותו עם מידע נוסף.

אפשר לעיין במערך הנתונים של Hugging Face לתנוחות יוגה. שימו לב: ב-codelab הזה נעשה שימוש באחת מקבוצות הנתונים, אבל למעשה אפשר להשתמש בכל קבוצת נתונים אחרת וליישם את אותן טכניקות שמוצגות כאן כדי לשפר את קבוצת הנתונים.

298cfae7f23e4bef.png

אם עוברים לקטע Files and versions, אפשר לקבל את קובץ נתוני ה-JSON של כל התנוחות.

3fe6e55abdc032ec.png

הורדנו את yoga_poses.json ושלחנו לך את הקובץ הזה. הקובץ הזה נקרא yoga_poses_alldata.json והוא נמצא בתיקייה /data.

עוברים לקובץ data/yoga_poses.json בעורך Cloud Shell ומעיינים ברשימת אובייקטי ה-JSON, שכל אחד מהם מייצג תנוחת יוגה. יש לנו 3 רשומות בסך הכול, ודוגמה לרשומה מוצגת בהמשך:

{
   "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"]
 }

זו הזדמנות מצוינת להציג את Gemini ואת האופן שבו אפשר להשתמש במודל ברירת המחדל כדי ליצור שדה description.

ב-Cloud Shell Editor, עוברים לקובץ generate-descriptions.py. התוכן של הקובץ מוצג בהמשך:

import json
import time
import logging
import vertexai
from langchain_google_vertexai import VertexAI
from tenacity import retry, stop_after_attempt, wait_exponential
from settings import get_settings

settings = get_settings()
logging.basicConfig(
    level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
# Initialize Vertex AI SDK
vertexai.init(project=settings.project_id, location=settings.location)
logging.info("Done Initializing Vertex AI SDK")


@retry(
    stop=stop_after_attempt(5),
    wait=wait_exponential(multiplier=1, min=4, max=10),
)
def generate_description(pose_name, sanskrit_name, expertise_level, pose_types):
    """Generates a description for a yoga pose using the Gemini API."""

    prompt = f"""
    Generate a concise description (max 50 words) for the yoga pose: {pose_name}
    Also known as: {sanskrit_name}
    Expertise Level: {expertise_level}
    Pose Type: {", ".join(pose_types)}

    Include key benefits and any important alignment cues.
    """
    try:
        model = VertexAI(model_name=settings.gemini_model_name, verbose=True)
        response = model.invoke(prompt)
        return response
    except Exception as e:
        logging.info(f"Error generating description for {pose_name}: {e}")
        return ""


def add_descriptions_to_json(input_file, output_file):
    """Loads JSON data, adds descriptions, and saves the updated data."""

    with open(input_file, "r") as f:
        yoga_poses = json.load(f)

    total_poses = len(yoga_poses)
    processed_count = 0

    for pose in yoga_poses:
        if pose["name"] != " Pose":
            start_time = time.time()  # Record start time
            pose["description"] = generate_description(
                pose["name"],
                pose["sanskrit_name"],
                pose["expertise_level"],
                pose["pose_type"],
            )
            end_time = time.time()  # Record end time

            processed_count += 1
            end_time = time.time()  # Record end time
            time_taken = end_time - start_time
            logging.info(
                f"Processed: {processed_count}/{total_poses} - {pose['name']} ({time_taken:.2f} seconds)"
            )

        else:
            pose["description"] = ""
            processed_count += 1
            logging.info(
                f"Processed: {processed_count}/{total_poses} - {pose['name']} ({time_taken:.2f} seconds)"
            )
        # Adding a delay to avoid rate limit
        time.sleep(30)

    with open(output_file, "w") as f:
        json.dump(yoga_poses, f, indent=2)


def main():
    # File paths
    input_file = "./data/yoga_poses.json"
    output_file = "./data/yoga_poses_with_descriptions.json"

    # Add descriptions and save the updated JSON
    add_descriptions_to_json(input_file, output_file)


if __name__ == "__main__":
    main()

האפליקציה הזו תוסיף שדה חדש description לכל רשומה של תנוחת יוגה ב-JSON. התיאור יתקבל באמצעות קריאה למודל Gemini, שבו נספק לו את ההנחיה הדרושה. השדה מתווסף לקובץ ה-JSON והקובץ החדש נכתב לקובץ data/yoga_poses_with_descriptions.json.

בואו נסביר את השלבים העיקריים:

  1. בפונקציה main(), תראו שהיא מפעילה את הפונקציה add_descriptions_to_json ומספקת את קובץ הקלט ואת קובץ הפלט הצפוי.
  2. הפונקציה add_descriptions_to_json מבצעת את הפעולות הבאות לכל רשומת JSON, כלומר לכל פרט בפוסט של Yoga:
  3. הוא מחלץ את pose_name, sanskrit_name, expertise_level ו-pose_types.
  4. היא מפעילה את הפונקציה generate_description שיוצרת הנחיה, ואז מפעילה את מחלקת המודלים Langchain VertexAI כדי לקבל את טקסט התגובה.
  5. טקסט התגובה הזה מתווסף לאובייקט JSON.
  6. לאחר מכן, רשימת האובייקטים המעודכנת בפורמט JSON נכתבת לקובץ היעד.

אנחנו רוצים להריץ את האפליקציה הזו. מפעילים חלון טרמינל חדש (Ctrl+Shift+C) ומזינים את הפקודה הבאה:

python generate-descriptions.py

אם תתבקש לתת הרשאה, עליך לעשות זאת.

האפליקציה תתחיל לפעול. הוספנו עיכוב של 30 שניות בין הרשומות כדי למנוע חריגה ממכסות של הגבלת קצב, שיכולות להיות בחשבונות חדשים ב-Google Cloud. לכן, צריך להתאזר בסבלנות.

דוגמה להרצה בתהליך:

8e830d9ea9b6c60.png

אחרי שכל 3 הרשומות ישופרו באמצעות השיחה עם Gemini, ייווצר קובץ data/yoga_poses_with_description.json. אתם יכולים לעיין בזה.

קובץ הנתונים מוכן, ועכשיו נסביר איך לאכלס איתו מסד נתונים של Firestore, ואיך ליצור הטמעות.

5. ייבוא נתונים ל-Firestore ויצירת הטמעות וקטוריות

יש לנו את הקובץ data/yoga_poses_with_description.json ועכשיו אנחנו צריכים לאכלס איתו את מסד הנתונים של Firestore, וחשוב מכך, ליצור את הטמעות הווקטורים לכל אחד מהרשומות. הטמעות וקטוריות יהיו שימושיות בהמשך כשנצטרך לבצע חיפוש דמיון על הטמעות כאלה עם שאילתת המשתמש שסופקה בשפה טבעית.

אנחנו נשתמש ברכיבי Langchain Firestore כדי להטמיע את התהליך שלמעלה.

כדי לעשות את זה, צריך לפעול לפי השלבים הבאים:

  1. נמיר את רשימת אובייקטי ה-JSON לרשימה של אובייקטים מסוג Langchain Document. לכל מסמך יהיו שני מאפיינים: page_content ו-metadata. אובייקט המטא-נתונים יכיל את אובייקט ה-JSON כולו עם מאפיינים כמו name,‏ description,‏ sanskrit_name וכו'. המאפיין page_content יהיה מחרוזת טקסט שתהיה שרשור של כמה שדות.
  2. אחרי שנקבל רשימה של אובייקטים מסוג Document, נשתמש במחלקה FirestoreVectorStore Langchain ובשיטה from_documents באופן ספציפי עם רשימת המסמכים הזו, שם האוסף (אנחנו משתמשים במשתנה TEST_COLLECTION שמצביע על test-poses), מחלקת Vertex AI Embedding ופרטי החיבור ל-Firestore (השם PROJECT_ID והשם DATABASE). הפעולה הזו תיצור את האוסף ותפיק גם שדה embedding לכל אחד מהמאפיינים.

הקוד של import-data.py מופיע בהמשך (חלקים מהקוד קוצרו כדי שיהיה קצר יותר):

... 

def create_langchain_documents(poses):
   """Creates a list of Langchain Documents from a list of poses."""
   documents = []
   for pose in poses:
       # Convert the pose to a string representation for page_content
       page_content = (
           f"name: {pose.get('name', '')}\n"
           f"description: {pose.get('description', '')}\n"
           f"sanskrit_name: {pose.get('sanskrit_name', '')}\n"
           f"expertise_level: {pose.get('expertise_level', 'N/A')}\n"
           f"pose_type: {pose.get('pose_type', 'N/A')}\n"
       ).strip()
       # The metadata will be the whole pose
       metadata = pose

       document = Document(page_content=page_content, metadata=metadata)
       documents.append(document)
   logging.info(f"Created {len(documents)} Langchain documents.")
   return documents

def main():
    all_poses = load_yoga_poses_data_from_local_file(
        "./data/yoga_poses_with_descriptions.json"
    )
    documents = create_langchain_documents(all_poses)
    logging.info(
        f"Successfully created langchain documents. Total documents: {len(documents)}"
    )

    embedding = VertexAIEmbeddings(
        model_name=settings.embedding_model_name,
        project=settings.project_id,
        location=settings.location,
    )

    client = firestore.Client(project=settings.project_id, database=settings.database)

    vector_store = FirestoreVectorStore.from_documents(
        client=client,
        collection=settings.test_collection,
        documents=documents,
        embedding=embedding,
    )
    logging.info("Added documents to the vector store.")


if __name__ == "__main__":
    main()

אנחנו רוצים להריץ את האפליקציה הזו. מפעילים חלון טרמינל חדש (Ctrl+Shift+C) ומזינים את הפקודה הבאה:

python import-data.py

אם הכול יתנהל כשורה, תוצג הודעה שדומה לזו שבהמשך:

2025-01-21 14:50:06,479 - INFO - Added documents to the vector store.

כדי לבדוק אם הרשומות הוכנסו בהצלחה וההטמעות נוצרו, עוברים אל הדף של Firestore במסוף Cloud.

504cabdb99a222a5.png

לוחצים על מסד הנתונים (ברירת המחדל). אמורה להופיע הקולקציה test-poses ומסמכים רבים מתחת לקולקציה הזו. כל מסמך הוא תנוחת יוגה אחת.

d0708499e403aebc.png

לוחצים על אחד המסמכים כדי לבדוק את השדות. בנוסף לשדות שייבאנו, תמצאו גם את השדה embedding, שהוא שדה וקטורי שנוצר אוטומטית באמצעות המחלקה VertexAIEmbeddings של Langchain שבה השתמשנו, שבה סיפקנו את מודל ההטמעה של Vertex AI‏ text-embedding-004.

d67113e2dc63cd6b.png

אחרי שהעלינו את הרשומות למסד הנתונים של Firestore עם ההטמעות, אפשר לעבור לשלב הבא ולראות איך מבצעים חיפוש דמיון וקטורי ב-Firestore.

6. ייבוא תנוחות יוגה מלאות לאוסף של מסד נתונים ב-Firestore

עכשיו ניצור את אוסף poses, שהוא רשימה מלאה של 160 תנוחות יוגה, שעבורן יצרנו קובץ לייבוא למסד נתונים שאפשר לייבא ישירות. הפעולה הזו נעשית כדי לחסוך זמן במעבדה. התהליך ליצירת מסד הנתונים שמכיל את התיאור וההטמעות זהה לתהליך שראינו בקטע הקודם.

כדי לייבא את מסד הנתונים, פועלים לפי השלבים הבאים:

  1. יוצרים קטגוריה בפרויקט באמצעות הפקודה gsutil שמופיעה בהמשך. מחליפים את המשתנה <PROJECT_ID> בפקודה שלמטה במזהה הפרויקט ב-Google Cloud.
gsutil mb -l us-central1 gs://<PROJECT_ID>-my-bucket
  1. אחרי שיוצרים את הדלי, צריך להעתיק אליו את קובץ הייצוא של מסד הנתונים שהכנו, כדי שנוכל לייבא אותו למסד הנתונים של Firebase. משתמשים בפקודה שמופיעה בהמשך:
gsutil cp -r gs://yoga-database-firestore-export-bucket/2025-01-27T05:11:02_62615  gs://<PROJECT_ID>-my-bucket

עכשיו שיש לנו את הנתונים לייבוא, אפשר לעבור לשלב האחרון של ייבוא הנתונים למסד הנתונים של Firebase‏ (default) שיצרנו.

  1. משתמשים בפקודה הבאה של gcloud:
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2025-01-27T05:11:02_62615

הייבוא יימשך כמה שניות. כשהוא יסתיים, תוכלו לאמת את מסד הנתונים של Firestore ואת האוסף. לשם כך, עוברים אל https://console.cloud.google.com/firestore/databases, בוחרים במסד הנתונים default ובאוסף poses כמו שמוצג בהמשך:

a8f5a6ba69bec69b.png

כך מסיימים ליצור את האוסף של Firestore שבו נשתמש באפליקציה שלנו.

7. ביצוע חיפוש דמיון וקטורי ב-Firestore

כדי לבצע חיפוש דמיון וקטורי, אנחנו מקבלים את השאילתה מהמשתמש. דוגמה לשאילתה כזו היא "Suggest me some exercises to relieve back pain".

מעיינים בקובץ search-data.py. הפונקציה העיקרית שצריך לבדוק היא פונקציית החיפוש, שמוצגת בהמשך. באופן כללי, הוא יוצר מחלקה של הטמעה שתשמש ליצירת ההטמעה של שאילתת המשתמש. לאחר מכן, הוא משתמש במחלקה FirestoreVectorStore כדי להפעיל את הפונקציה similarity_search שלה.

def search(query: str):
    """Executes Firestore Vector Similarity Search"""
    embedding = VertexAIEmbeddings(
        model_name=settings.embedding_model_name,
        project=settings.project_id,
        location=settings.location,
    )

    client = firestore.Client(project=settings.project_id, database=settings.database)

    vector_store = FirestoreVectorStore(
        client=client, collection=settings.collection, embedding_service=embedding
    )

    logging.info(f"Now executing query: {query}")
    results: list[Document] = vector_store.similarity_search(
        query=query, k=int(settings.top_k), include_metadata=True
    )
    for result in results:
        print(result.page_content)

לפני שמריצים את הפקודה עם כמה דוגמאות לשאילתות, צריך קודם ליצור אינדקס מורכב של Firestore, שנדרש כדי ששאילתות החיפוש יצליחו. אם מריצים את האפליקציה בלי ליצור את האינדקס, תוצג שגיאה שמציינת שצריך ליצור את האינדקס קודם, יחד עם הפקודה ליצירת האינדקס.

הפקודה gcloud ליצירת האינדקס המורכב מוצגת בהמשך:

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

תהליך יצירת האינדקס יימשך כמה דקות כי יש יותר מ-150 רשומות במסד הנתונים. אחרי שהפעולה מסתיימת, אפשר לראות את האינדקס באמצעות הפקודה שמוצגת למטה:

gcloud firestore indexes composite list

הרשימה אמורה לכלול את האינדקס שיצרתם.

מנסים עכשיו את הפקודה הבאה:

python search-data.py --prompt "Recommend me some exercises for back pain relief"

אמורות להופיע כמה המלצות. דוגמה להרצה:

2025-01-21 15:48:51,282 - INFO - Now executing query: Recommend me some exercises for back pain relief
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 the spine.

sanskrit_name: Supta Matsyendrasana
expertise_level: Beginner
pose_type: ['Supine', 'Twist']
name: Cow Pose
description: Cow Pose (Bitilasana) is a gentle backbend, stretching the chest, shoulders, and abdomen.  Maintain a neutral spine, lengthen the tailbone, and avoid hyperextension.  Benefits include improved posture and stress relief.

sanskrit_name: Bitilasana
expertise_level: Beginner
pose_type: ['Arm Leg Support', 'Back Bend']
name: Locust I Pose
description: Locust Pose I (Shalabhasana A) strengthens the back, glutes, and shoulders.  Lie prone, lift chest and legs simultaneously, engaging back muscles.  Keep hips grounded and gaze slightly forward.

sanskrit_name: Shalabhasana A
expertise_level: Intermediate
pose_type: ['Prone', 'Back Bend']

אחרי שמוודאים שהכל עובד, אפשר להבין איך להשתמש במסד הנתונים הווקטורי של Firestore כדי להעלות רשומות, ליצור הטמעות ולבצע חיפוש של דמיון וקטורי. עכשיו אפשר ליצור אפליקציית אינטרנט שתשלב את החיפוש הווקטורי בחלק הקדמי של האתר.

8. אפליקציית האינטרנט

אפליקציית האינטרנט Python Flask זמינה בקובץ main.py וקובץ ה-HTML של חזית האתר נמצא בקובץ templates/index.html.

מומלץ לעיין בשני הקבצים. מתחילים עם קובץ main.py שמכיל את ה-handler‏ /search, שמקבל את ההנחיה שהועברה מקובץ ה-HTML של ה-front-end‏ index.html. לאחר מכן מופעלת שיטת החיפוש, שמבצעת את החיפוש של דמיון וקטורי שראינו בקטע הקודם.

התשובה נשלחת בחזרה אל index.html עם רשימת ההמלצות. אחרי מכן, ההמלצות מוצגות בכרטיסים שונים בindex.html.

הרצת האפליקציה באופן מקומי

מפעילים חלון טרמינל חדש (Ctrl+Shift+C) או חלון טרמינל קיים ומריצים את הפקודה הבאה:

python main.py

דוגמה להרצה:

 * Serving Flask app 'main'
 * Debug mode: on
2025-01-21 16:02:37,473 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:8080
 * Running on http://10.88.0.4:8080
2025-01-21 16:02:37,473 - INFO - Press CTRL+C to quit
2025-01-21 16:02:37,474 - INFO -  * Restarting with stat
2025-01-21 16:02:41,462 - WARNING -  * Debugger is active!
2025-01-21 16:02:41,484 - INFO -  * Debugger PIN: 440-653-555

אחרי שהאפליקציה תפעל, לוחצים על לחצן התצוגה המקדימה באינטרנט שמופיע למטה כדי להיכנס לכתובת ה-URL של דף הבית של האפליקציה:

de297d4cee10e0bf.png

הוא אמור להציג את הקובץ index.html שמוצג כמו שמופיע בהמשך:

20240a0e885ac17b.png

מזינים שאילתה לדוגמה (למשל : Provide me some exercises for back pain relief) ולוחצים על הכפתור Search. אמורות להתקבל כמה המלצות ממסד הנתונים. יופיע גם לחצן Play Audio, שבאמצעותו אפשר ליצור זרם אודיו על סמך התיאור ולהאזין לו ישירות.

789b4277dc40e2be.png

9. (אופציונלי) פריסה ב-Google Cloud Run

השלב האחרון יהיה פריסת האפליקציה הזו ב-Google Cloud Run. פקודת הפריסה מוצגת בהמשך. לפני שפורסים אותה, צריך להחליף את הערכים של המשתנה (<<YOUR_PROJECT_ID>>) בערכים שספציפיים לפרויקט שלכם. אלה ערכים שאפשר לאחזר מקובץ config.yaml.

gcloud run deploy yogaposes --source . \
  --port=8080 \
  --allow-unauthenticated \
  --region=us-central1 \
  --platform=managed  \
  --project=<<YOUR_PROJECT_ID>> \
  --env-vars-file=config.yaml

מריצים את הפקודה שלמעלה מתיקיית הבסיס של האפליקציה. יכול להיות שתתבקשו גם להפעיל ממשקי Google Cloud API ולתת אישור להרשאות שונות.

תהליך הפריסה יימשך כ-5 עד 7 דקות, אז כדאי לחכות בסבלנות.

3a6d86fd32e4a5e.png

אחרי הפריסה, כתובת ה-URL של שירות Cloud Run תופיע בפלט של הפריסה. הפורמט יהיה:

Service URL: https://yogaposes-<<UNIQUEID>.us-central1.run.app

אם תיכנסו לכתובת ה-URL הציבורית הזו, תוכלו לראות את אפליקציית האינטרנט שפרסתם, והיא תפעל בצורה תקינה.

84e1cbf29cbaeedc.png

אפשר גם להיכנס אל Cloud Run דרך מסוף Google Cloud, ושם תופיע רשימת השירותים ב-Cloud Run. השירות yogaposes צריך להיות אחד מהשירותים (אם לא היחיד) שמופיעים שם.

f2b34a8c9011be4c.png

כדי לראות את פרטי השירות כמו כתובת URL, הגדרות, יומנים ועוד, לוחצים על שם השירות הספציפי (yogaposes במקרה שלנו).

faaa5e0c02fe0423.png

כך מסיימים את הפיתוח והפריסה של אפליקציית האינטרנט להמלצות על תנוחות יוגה ב-Cloud Run.

10. מזל טוב

מזל טוב, הצלחתם ליצור אפליקציה שמעלה מערך נתונים ל-Firestore, יוצרת את ההטמעות ומבצעת חיפוש דמיון וקטורי על סמך השאילתה של המשתמש.

מאמרי עזרה