الدرس التطبيقي حول الترميز: إنشاء تطبيق مقترَح لـ "وضعيات اليوغا" بالاستناد إلى السياق باستخدام Firestore وVector Search وLangchain وGemini (إصدار Python)

1. مقدمة

في هذا الدرس التطبيقي حول الترميز، ستُنشئ تطبيقًا يستخدم البحث بالاستناد إلى المتجهات لاقتراح أوضاع اليوغا.

من خلال ورشة رموز البرامج، ستطبّق نهجًا خطوة بخطوة على النحو التالي:

  1. استخدِم مجموعة بيانات حالية من Hugging Face تتضمّن أوضاع اليوغا (بتنسيق JSON).
  2. يمكنك تحسين مجموعة البيانات من خلال إضافة وصف حقل إضافي يستخدم Gemini لإنشاء أوصاف لكل وضع من الأوضاع.
  3. استخدِم Langchain لإنشاء مستند، واستخدِم عملية دمج Langchain في Firestore لإنشاء المجموعة والعناصر المضمّنة في Firestore.
  4. أنشئ فهرسًا مركبًا في Firestore للسماح بميزة "البحث باستخدام المتجهات".
  5. استخدِم ميزة "البحث بالاستناد إلى المتجهات" في تطبيق Flask الذي يجمع كل العناصر معًا كما هو موضّح أدناه:

84e1cbf29cbaeedc.png

المهام التي ستنفّذها

  • تصميم وإنشاء ونشر تطبيق ويب يستخدم ميزة "البحث بالاستناد إلى المتجهات" لاقتراح أوضاع اليوغا

ما ستتعرّف عليه

  • كيفية استخدام Gemini لإنشاء محتوى نصي، وضمن سياق هذا الدليل التعليمي حول رموز البرامج، إنشاء أوصاف لحركات اليوغا
  • كيفية استخدام Langchain Document Loader لتطبيق Firestore لتحميل السجلات من مجموعة بيانات محسّنة من Hugging Face إلى Firestore مع إدراجات المتجهات
  • كيفية استخدام Langchain Vector Store لـ Firestore للبحث عن البيانات استنادًا إلى طلب بحث باللغة الطبيعية
  • كيفية استخدام واجهة برمجة التطبيقات Google Cloud Text to Speech API لإنشاء محتوى صوتي

المتطلبات

  • متصفّح الويب Chrome
  • حساب Gmail
  • مشروع على Cloud تم تفعيل الفوترة فيه

تم تصميم هذا المختبر البرمجي للمطوّرين من جميع المستويات (بما في ذلك المبتدئين)، ويستخدم لغة بايثون في تطبيقه النموذجي. ومع ذلك، لا يُشترط معرفة Python لفهم المفاهيم المعروضة.

2. قبل البدء

إنشاء مشروع

  1. في Google Cloud Console، في صفحة أداة اختيار المشاريع، اختَر مشروعًا على 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. فعِّل واجهات برمجة التطبيقات المطلوبة من خلال الأمر الموضَّح أدناه. قد تستغرق هذه العملية بضع دقائق، لذا يُرجى الانتظار.
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.

في حال عدم تفعيل أي واجهة برمجة تطبيقات، يمكنك تفعيلها في أي وقت أثناء عملية التنفيذ.

راجِع المستندات لمعرفة أوامر gcloud وكيفية استخدامها.

استنساخ المستودع وإعداد إعدادات البيئة

الخطوة التالية هي استنساخ نموذج المستودع الذي سنشير إليه في بقية ورشة رموز البرامج. لنفترض أنّك تستخدم Cloud Shell، أدخِل الأمر التالي من دليلك الرئيسي:

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

لتشغيل المحرِّر، انقر على "فتح المحرِّر" في شريط الأدوات في نافذة Cloud Shell. انقر على شريط القوائم في أعلى يمين الشاشة واختَر ملف (File) → فتح مجلد (Open Folder) كما هو موضّح أدناه:

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.

لأغراض هذا الدليل التعليمي حول الرموز البرمجية، سنستخدم القيم التي تم ضبطها مسبقًا (باستثناء 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 IDE واكتب 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 هي قاعدة بيانات مستندات بدون خادم تتم إدارتها بالكامل وسنستخدمها كخدمة خلفية لبيانات تطبيقنا. يتم تنظيم البيانات في Cloud Firestore في مجموعات من المستندات.

تهيئة قاعدة بيانات Firestore

انتقِل إلى صفحة Firestore في Cloud Console.

إذا لم يسبق لك إعداد قاعدة بيانات Firestore في المشروع، أنشئ قاعدة بيانات default بالنقر على Create Database. أثناء إنشاء قاعدة البيانات، استخدِم القيم التالية:

  • وضع Firestore: Native.
  • الموقع الجغرافي: يمكنك استخدام الإعدادات التلقائية للموقع الجغرافي.
  • بالنسبة إلى قواعد الأمان، اختَر Test rules.
  • أنشئ قاعدة البيانات.

504cabdb99a222a5.png

في القسم التالي، سنضع الأساس لإنشاء مجموعة باسم poses في قاعدة بيانات Firestore التلقائية. ستحتوي هذه المجموعة على نماذج بيانات (مستندات) أو معلومات عن وضعيات اليوغا، وسنستخدمها بعد ذلك في تطبيقنا.

وبهذا نكون قد أكملنا قسم إعداد قاعدة بيانات Firestore.

4. إعداد مجموعة بيانات وضعيات اليوغا

مهمتنا الأولى هي إعداد مجموعة بيانات أوضاع اليوغا التي سنستخدمها في التطبيق. سنبدأ بمجموعة بيانات حالية من Hugging Face ثم نُحسِّنها بمعلومات إضافية.

اطّلِع على مجموعة بيانات "التعرّف على الوجه" لتحديد أوضاع اليوغا. تجدر الإشارة إلى أنّه على الرغم من أنّ هذا الدليل التعليمي للترميز يستخدم إحدى مجموعات البيانات، يمكنك في الواقع استخدام أي مجموعة بيانات أخرى واتّباع الأساليب نفسها الموضّحة لتحسين مجموعة البيانات.

298cfae7f23e4bef.png

إذا انتقلنا إلى قسم Files and versions، يمكننا الحصول على ملف بيانات JSON لجميع الوضعيات.

3fe6e55abdc032ec.png

لقد نزّلنا yoga_poses.json وقدّمنا إليك هذا الملف. اسم هذا الملف هو yoga_poses_alldata.json، وهو متوفّر في المجلد /data.

انتقِل إلى ملف data/yoga_poses.json في محرِّر Cloud Shell واطّلِع على قائمة عناصر JSON، حيث يمثّل كل عنصر 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، انتقِل إلى ملف 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، أي معلومات مشاركة اليوغا:
  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

بعد تحسين جميع السجلات الثلاثة من خلال مكالمة Gemini، سيتم إنشاء ملف data/yoga_poses_with_description.json. يمكنك الاطّلاع على ذلك.

أصبحنا الآن جاهزين باستخدام ملف البيانات، والخطوة التالية هي فهم كيفية تعبئة قاعدة بيانات Firestore به، بالإضافة إلى إنشاء الحِزم.

5- استيراد البيانات إلى Firestore وإنشاء embeddings في النصوص

لدينا ملف data/yoga_poses_with_description.json ونحتاج الآن إلى تعبئة قاعدة بيانات Firestore به، والأهم من ذلك، إنشاء إدراجات في نموذج Vector لكل سجل. ستكون ميزة "إدراج المتجهات" مفيدة لاحقًا عندما نحتاج إلى إجراء بحث تشابه عليها باستخدام طلب بحث المستخدم الذي تم تقديمه بلغة طبيعية.

سنستخدم مكوّنات 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، وهو حقل متّجه تم إنشاؤه تلقائيًا لك من خلال فئة Langchain VertexAIEmbeddings التي استخدمناها، والتي قدّمنا فيها نموذج text-embedding-004 لدمج Vertex AI.

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 Vector لتحميل السجلّات وإنشاء عمليات التضمين وإجراء بحث تشابه في النماذج. يمكننا الآن إنشاء تطبيق ويب يدمج البحث بالاستناد إلى المتجهات في واجهة مستخدم الويب.

8. تطبيق الويب

يتوفّر تطبيق الويب Python Flask في ملف main.py، ويتوفر ملف HTML للواجهة الأمامية في templates/index.html..

ننصحك بالاطّلاع على كلا الملفَّين. ابدأ أولاً بملف main.py الذي يحتوي على معالِج /search الذي يتلقّى الطلب الذي تم تمريره من ملف HTML 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 APIs، وتقديم تأكيد على الأذونات المختلفة، يُرجى إجراء ذلك.

ستستغرق عملية النشر مدة تتراوح بين 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، وينشئ الحِزم ويُجري بحثًا عن التشابه بين المتجهات استنادًا إلى طلب بحث المستخدمين.

المستندات المرجعية