تطبيق بحث في متجر لعب باستخدام قواعد بيانات السحابة الإلكترونية وعمليات التشغيل بدون خادم عمليات دمج مع مشاريع مفتوحة المصدر

1. نظرة عامة

تخيل أنّك تدخل إلى متجر ألعاب افتراضيًا أو شخصيًا، حيث يمكنك العثور على الهدية المثالية بسهولة. يمكنك وصف ما تبحث عنه أو تحميل صورة للعبة أو حتى تصميم لعبة بنفسك، وسيفهم المتجر احتياجاتك على الفور ويقدّم لك تجربة مخصّصة. هذه ليست قصة خيالية مستقبلية، بل حقيقة مستندة إلى الذكاء الاصطناعي وتكنولوجيا السحابة الإلكترونية ورؤية للتجارة الإلكترونية المخصّصة.

التحدّي: قد يكون من الصعب العثور على المنتج المثالي الذي يطابق خيالك. غالبًا ما لا تؤدي عبارات البحث العامة والكلمات الرئيسية والعمليات البحثية التقريبية إلى النتائج المطلوبة، وقد يكون تصفُّح الصفحات التي لا تنتهي أمرًا مملّاً، كما أنّ عدم تطابق ما تتوقّعه مع ما هو متاح قد يسبب لك الإحباط.

الحلّ: يعالج التطبيق التجريبي هذا التحدي بشكل مباشر، مستفيدًا من إمكانات الذكاء الاصطناعي لتقديم تجربة مخصّصة وسلسّة من خلال البحث السياقي وإنشاء المنتجات المخصّصة التي تتطابق مع سياق البحث.

ما ستُنشئه

كجزء من هذا الدرس التطبيقي، عليك تنفيذ ما يلي:

  1. إنشاء مثيل AlloyDB وتحميل مجموعة بيانات Toys
  2. تفعيل إضافات pgvector ونماذج الذكاء الاصطناعي التوليدي في AlloyDB
  3. إنشاء عمليات تضمين من وصف المنتج وإجراء بحث التشابه باستخدام دالة الجيب الزائد في الوقت الفعلي لنص بحث المستخدم
  4. استدعاء Gemini 2.0 Flash لوصف الصورة التي حمّلها المستخدم من أجل البحث عن ألعاب في سياق معيّن
  5. استدعاء Imagen 3 لإنشاء لعبة مخصّصة استنادًا إلى اهتمامات المستخدم
  6. استدعاء أداة توقّع الأسعار التي تم إنشاؤها باستخدام "مجموعة أدوات الذكاء الاصطناعي التوليدي لقواعد البيانات" للحصول على تفاصيل أسعار اللعبة المخصّصة
  7. نشر الحلّ في وظائف Cloud Run بدون خادم

المتطلبات

  • متصفّح، مثل Chrome أو Firefox
  • مشروع على Google Cloud تم تفعيل الفوترة فيه

2. الهندسة المعمارية

تدفّق البيانات: لنلقِ نظرة عن كثب على كيفية نقل البيانات عبر نظامنا:

  1. البحث السياقي باستخدام ميزة RAG (الإنشاء المعزّز لاسترداد المعلومات) المستندة إلى الذكاء الاصطناعي

فكِّر في الأمر على النحو التالي: بدلاً من البحث عن "سيارة حمراء" فقط، يفهم النظام ما يلي:

"مركبة صغيرة مناسبة لصبي عمره 3 سنوات"

AlloyDB كأساس: نستخدم AlloyDB، وهي قاعدة بيانات متوافقة مع PostgreSQL ومُدارة بالكامل من Google Cloud، لتخزين بيانات الألعاب، بما في ذلك الأوصاف وعناوين URL للصور والسمات الأخرى ذات الصلة.

pgvector للبحث الدلالي: تتيح لنا إضافة pgvector، وهي إضافة PostgreSQL، تخزين عمليات إدراج المتجهات لكلّ من أوصاف الألعاب وطلبات بحث المستخدمين. ويؤدي ذلك إلى تفعيل البحث الدلالي، ما يعني أنّ النظام يفهم المعنى الكامن وراء الكلمات، وليس فقط الكلمات الرئيسية الدقيقة.

تشابه الجيبّوسينوسي لتحديد مدى الصلة: نستخدم تشابه الجيبّوسينوسي لقياس التشابه الدلالي بين متجه البحث الذي يجريه المستخدم ومتجهات أوصاف الألعاب، ما يؤدي إلى عرض النتائج الأكثر صلةً.

فهرس ScaNN للسرعة والدقة: لضمان تحقيق نتائج سريعة ودقيقة، خاصةً مع زيادة مستودع الألعاب لدينا، نُدمج مؤشر ScaNN (العناصر المجاورة القابلة للتوسيع). ويؤدي ذلك إلى تحسين كفاءة البحث المتجه وسرعة استرجاعه بشكل كبير.

  1. البحث والفهم المستنِدَين إلى الصور باستخدام نموذج Gemini 2.0 Flash

بدلاً من كتابة السياق كنص، لنفترض أنّ المستخدم يريد تحميل صورة للعبة مألوفة يريد البحث عنها. يمكن للمستخدمين تحميل صورة للعبة يحبونها والحصول على ميزات ذات صلة بها. نستفيد من نموذج Gemini 2.0 Flash من Google، الذي يتم تشغيله باستخدام LangChain4j، لتحليل الصورة واستخراج السياق ذي الصلة، مثل لون اللعبة ومواد تصنيعها ونوعها والفئة العمرية المستهدفة.

  1. إنشاء لعبة أحلامك المخصّصة باستخدام الذكاء الاصطناعي التوليدي: Imagen 3

يحدث السحر الحقيقي عندما يقرر المستخدمون إنشاء لعبتهم الخاصة. باستخدام Imagen 3، نسمح لهم بوصف لعبتهم الحلم باستخدام طلبات نصية بسيطة. تخيل أنّه يمكنك قول "أريد تنينًا من القطيفة بأجنحة أرجوانية ووجه ودود"، ثم رؤية هذا التنين على الشاشة. بعد ذلك، تنشئ Imagen 3 صورة للّعبة المصمّمة حسب الطلب، ما يمنح المستخدم تصورًا واضحًا لتصميمه.

  1. توقّع الأسعار باستخدام أدوات الذكاء الاصطناعي التوليدي وأدوات مساعدة موظّفي الدعم لقواعد البيانات

لقد نفّذنا ميزة توقّع الأسعار التي تقدّر تكلفة إنتاج اللعبة المصمّمة حسب الطلب. يتم تنفيذ ذلك من خلال وكيل يتضمّن أداة متقدّمة لاحتساب الأسعار.

مجموعة أدوات الذكاء الاصطناعي التوليدي لقواعد البيانات: تم دمج هذا الوكيل بسلاسة مع قاعدة بياناتنا باستخدام أداة Gen AI Toolbox لقواعد البيانات، وهي أداة جديدة مفتوحة المصدر من Google. يتيح ذلك للموظف الوصول إلى بيانات في الوقت الفعلي عن تكاليف المواد وعمليات التصنيع والعوامل الأخرى ذات الصلة لتقديم تقدير دقيق للسعر. يمكنك الاطّلاع على مزيد من المعلومات حول هذا الموضوع هنا.

  1. Java Spring Boot وGemini Code Assist وCloud Run لتطوير التطبيقات ونشرها بدون خادم بشكلٍ سلس

تم إنشاء التطبيق بالكامل باستخدام Java Spring Boot، وهو إطار عمل قوي وقابل للتطوير. لقد استفادنا من ميزة "مساعدة في الترميز" في Gemini طوال عملية التطوير، لا سيما في تطوير الواجهة الأمامية، ما أدى إلى تسريع دورة التطوير بشكل كبير وتحسين جودة الرموز البرمجية. لقد استخدمنا Cloud Run لنشر التطبيق بالكامل وCloud Run Functions لنشر وظائف قاعدة البيانات والوكيل كنقاط نهاية مستقلة.

3- قبل البدء

إنشاء مشروع

  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. فعِّل واجهات برمجة التطبيقات المطلوبة من خلال تنفيذ الأوامر التالية الواحد تلو الآخر في وحدة Cloud Shell الطرفية:

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

gcloud services enable alloydb.googleapis.com
gcloud services enable compute.googleapis.com 
gcloud services enable cloudresourcemanager.googleapis.com 
gcloud services enable servicenetworking.googleapis.com 
gcloud services enable run.googleapis.com 
gcloud services enable cloudbuild.googleapis.com 
gcloud services enable cloudfunctions.googleapis.com 
gcloud services enable aiplatform.googleapis.com

يمكنك استخدام وحدة التحكّم للبحث عن كل منتج أو استخدام هذا الرابط كبديل لأمر gcloud.

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

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

4. إعداد قاعدة البيانات

في هذا البرنامج التدريبي، سنستخدم AlloyDB كقاعدة بيانات لتخزين بيانات متجر الألعاب. ويستخدم المجموعات لتخزين جميع الموارد، مثل قواعد البيانات والسجلات. تحتوي كل مجموعة على مثيل أساسي يقدّم نقطة وصول إلى البيانات. ستحتوي الجداول على البيانات الفعلية.

لننشئ مجموعة ومثيلًا وجدولًا في AlloyDB حيث سيتم تحميل مجموعة بيانات التجارة الإلكترونية.

إنشاء مجموعة ومثيل

  1. انتقِل إلى صفحة AlloyDB في Cloud Console. إنّ البحث عن معظم الصفحات في Cloud Console باستخدام شريط البحث في وحدة التحكّم هو طريقة سهلة للعثور عليها.
  2. اختَر إنشاء مجموعة من هذه الصفحة:

f76ff480c8c889aa.png

  1. ستظهر لك شاشة مثل الشاشة أدناه. أنشئ مجموعة ومثيلًا بالقيم التالية (تأكَّد من تطابق القيم في حال كنت تُنشئ نسخة طبق الأصل من رمز التطبيق من المستودع):
  • معرّف المجموعة: "vector-cluster"
  • password: "alloydb"
  • متوافق مع PostgreSQL 15
  • المنطقة: "us-central1"
  • الشبكات: "default"

538dba58908162fb.png

  1. عند اختيار الشبكة التلقائية، ستظهر لك شاشة مثل الشاشة أدناه.

انقر على إعداد عملية الربط.
7939bbb6802a91bf.png

  1. من هناك، اختَر "استخدام نطاق IP مخصّص تلقائيًا" ثم انقر على "متابعة". بعد مراجعة المعلومات، انقر على "إنشاء اتصال". 768ff5210e79676f.png
  2. بعد إعداد شبكتك، يمكنك مواصلة إنشاء مجموعتك. انقر على إنشاء مجموعة لإكمال إعداد المجموعة كما هو موضّح أدناه:

e06623e55195e16e.png

احرص على تغيير معرّف المثيل إلى "

vector-instance"

.

يُرجى العِلم أنّ إنشاء المجموعة سيستغرق 10 دقائق تقريبًا. بعد اكتمال العملية بنجاح، من المفترض أن تظهر لك شاشة تعرض نظرة عامة على المجموعة التي أنشأتها للتو.

5- نقل البيانات

حان الوقت الآن لإضافة جدول يحتوي على بيانات المتجر. انتقِل إلى AlloyDB، واختَر المجموعة الأساسية ثم AlloyDB Studio:

847e35f1bf8a8bd8.png

قد تحتاج إلى الانتظار حتى تكتمل عملية إنشاء المثيل. بعد ذلك، سجِّل الدخول إلى AlloyDB باستخدام بيانات الاعتماد التي أنشأتها عند إنشاء المجموعة. استخدِم البيانات التالية لمصادقة PostgreSQL:

  • اسم المستخدم : "postgres"
  • قاعدة البيانات : "postgres"
  • كلمة المرور : "alloydb"

بعد المصادقة بنجاح في AlloyDB Studio، يتم إدخال أوامر SQL في المحرِّر. يمكنك إضافة عدّة نوافذ في "المحرِّر" باستخدام رمز الإضافة على يسار النافذة الأخيرة.

91a86d9469d499c4.png

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

تفعيل الإضافات

لإنشاء هذا التطبيق، سنستخدم الإضافة pgvector والإضافة google_ml_integration. تتيح لك إضافة pgvector تخزين عمليات تضمين المتجهات والبحث عنها. توفّر إضافة google_ml_integration الدوالّ التي تستخدمها للوصول إلى نقاط نهاية التوقّعات في Vertex AI للحصول على توقّعات في SQL. فعِّل هذه الإضافات من خلال تنفيذ عبارات DDL التالية:

CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;

إذا كنت تريد التحقّق من الإضافات التي تم تفعيلها في قاعدة بياناتك، نفِّذ الأمر التالي في لغة الاستعلامات البنيوية (SQL):

select extname, extversion from pg_extension;

إنشاء جدول

أنشئ جدولاً باستخدام عبارة DDL أدناه:

CREATE TABLE toys ( id VARCHAR(25), name VARCHAR(25), description VARCHAR(20000), quantity INT, price FLOAT, image_url VARCHAR(200), text_embeddings vector(768)) ;

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

نقل البيانات

في هذا الدرس، لدينا بيانات اختبارية تضمّ حوالي 72 سجلّاً في ملف SQL هذا. يحتوي على حقول id, name, description, quantity, price, image_url. سيتم ملء الحقول الأخرى لاحقًا في هذا الدرس التطبيقي.

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

للاطّلاع على محتوى الجدول، وسِّع قسم "المستكشف" إلى أن يظهر لك الجدول المُسمّى apparels. انقر على النقاط الثلاث (⋮) لعرض خيار "الاستعلام عن الجدول". سيتم فتح عبارة SELECT في علامة تبويب جديدة في "المحرِّر".

cfaa52b717f9aaed.png

منح الإذن

نفِّذ العبارة أدناه لمنح المستخدم postgres حقوق تنفيذ الدالة embedding:

GRANT EXECUTE ON FUNCTION embedding TO postgres;

منح دور مستخدم Vertex AI لحساب خدمة AlloyDB

انتقِل إلى وحدة Cloud Shell الطرفية وأدخِل الأمر التالي:

PROJECT_ID=$(gcloud config get-value project)

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"

6- إنشاء عمليات تضمين للسياق

من الأسهل على أجهزة الكمبيوتر معالجة الأرقام أكثر من معالجة النصوص. يحوّل نظام التضمين النص إلى سلسلة من الأرقام ذات النقطة العائمة التي من المفترض أن تمثّل النص، بغض النظر عن صياغته أو لغته أو غير ذلك.

يمكنك مثلاً وصف موقع على شاطئ البحر. قد يُطلق عليه اسم "على الماء" أو "على شاطئ البحر" أو "المشي من غرفتك إلى المحيط" أو "sur la mer" أو "на берегу океана" وما إلى ذلك. تبدو هذه العبارات مختلفة، ولكن من حيث المعنى الدلالي أو في مصطلحات تعلُّم الآلة، يجب أن تكون عمليات التضمين قريبة جدًا من بعضها.

بعد أن أصبحت البيانات والسياق جاهزين، سننفّذ طلب SQL لإضافة النصوص المضمّنة لوصف المنتج إلى الجدول في الحقل embedding. هناك مجموعة متنوعة من نماذج التضمين التي يمكنك استخدامها. نحن نستخدم text-embedding-005 من Vertex AI. احرص على استخدام نموذج التضمين نفسه في جميع أنحاء المشروع.

ملاحظة: إذا كنت تستخدم مشروعًا حاليًا على Google Cloud تم إنشاؤه منذ فترة، قد تحتاج إلى مواصلة استخدام الإصدارات القديمة من نموذج تضمين النصوص، مثل textembedding-gecko.

ارجع إلى علامة التبويب AlloyDB Studio واكتب لغة الاستعلامات البنيوية التالية:

UPDATE toys set text_embeddings = embedding( 'text-embedding-005', description);

اطّلِع على جدول toys مرة أخرى للاطّلاع على بعض عمليات التضمين. احرص على إعادة تشغيل عبارة SELECT للاطّلاع على التغييرات.

SELECT id, name, description, price, quantity, image_url, text_embeddings FROM toys;

من المفترض أن يؤدي ذلك إلى عرض متجه البيانات المضمّنة، الذي يبدو مثل صفيف من الأعداد العشرية، لوصف اللعبة كما هو موضّح أدناه:

7d32f7cd7204e1f3.png

ملاحظة: قد تواجه مشاريع Google Cloud المنشأة حديثًا ضمن الفئة المجانية مشاكل في الحصة عندما يتعلق الأمر بعدد طلبات التضمين المسموح بها في الثانية إلى نماذج التضمين. نقترح عليك استخدام طلب بحث فلتر للمعرّف، ثم اختيار 1 إلى 5 سجلّات بشكل انتقائي وما إلى ذلك، أثناء إنشاء عملية التضمين.

7- إجراء بحث في Vector

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

لنفترض أنّ المستخدم يسأل:

"I want a white plush teddy bear toy with a floral pattern".

يمكنك العثور على مطابقات لهذا الطلب عن طريق تنفيذ الطلب أدناه:

select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 5;

لنلقِ نظرة على هذا الطلب بالتفصيل:

في هذا الطلب،

  1. نص بحث المستخدم هو: "I want a white plush teddy bear toy with a floral pattern."
  2. نحن بصدد تحويلها إلى عناصر مضمّنة في طريقة embedding() باستخدام النموذج: text-embedding-005. من المفترض أن تكون هذه الخطوة مألوفة بعد الخطوة الأخيرة، حيث طبّقنا دالة التضمين على جميع العناصر في الجدول.
  3. يمثّل "<=>" استخدام طريقة المسافة تشابه الجيبّ cosine. يمكنك العثور على جميع مقاييس التشابه المتاحة في مستندات pgvector.
  4. نحن بصدد تحويل نتيجة طريقة التضمين إلى نوع متجه لجعلها متوافقة مع المتجهات المخزّنة في قاعدة البيانات.
  5. يشير LIMIT 5 إلى أنّنا نريد استخراج 5 جيران أقرب لنص البحث.

تظهر النتيجة على النحو التالي:

fa7f0fc3a4c68804.png

كما يمكنك ملاحظة ذلك في نتائجك، فإنّ المطابقات قريبة جدًا من نص البحث. جرِّب تغيير النص لمعرفة كيفية تغيُّر النتائج.

ملاحظة مهمة:

لنفترض الآن أنّنا نريد زيادة الأداء (وقت طلب البحث) والكفاءة وسرعة استرجاع نتيجة البحث بالاستناد إلى المتجهات هذه باستخدام فهرس ScaNN. يُرجى قراءة الخطوات الواردة في مدوّنة هذه لمقارنة الفرق في النتيجة باستخدام الفهرس وبدونه.

خطوة اختيارية: تحسين الكفاءة وسرعة التذكر باستخدام مؤشر ScaNN

في ما يلي خطوات إنشاء الفهرس للتيسير عليك:

  1. بما أنّنا سبق أن أنشأنا المجموعة والعنصر والسياق والعناصر المضمّنة، ما علينا سوى تثبيت إضافة ScaNN باستخدام العبارة التالية:
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
  1. بعد ذلك، سننشئ الفهرس (ScaNN):
CREATE INDEX toysearch_index ON toys
USING scann (text_embeddings cosine)
WITH (num_leaves=9);

في ملف DDL أعلاه، apparel_index هو اسم الفهرس.

"toys" هو الجدول

"scann" هي طريقة الفهرسة

"embedding" هو العمود في الجدول الذي أريد فهرسته.

"جيب التمام" هي طريقة المسافة التي أريد استخدامها مع الفهرس.

"8" هو عدد الأقسام التي سيتم تطبيقها على هذا المؤشر. اضبطها على أي قيمة تتراوح بين 1 و1048576. لمزيد من المعلومات عن كيفية تحديد هذه القيمة، اطّلِع على مقالة ضبط فهرس ScaNN.

لقد استخدمت جذرًا مربّعًا لعدد نقاط البيانات كما هو مقترَح في مستودع ScaNN (عند التقسيم، يجب أن يكون عدد الأوراق تقريبًا جذرًا مربّعًا لعدد نقاط البيانات).

  1. تحقَّق مما إذا تم إنشاء الفهرس باستخدام الطلب:
SELECT * FROM pg_stat_ann_indexes;
  1. يمكنك إجراء "بحث متجه" باستخدام الطلب نفسه الذي استخدمناه بدون الفهرس:
select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 5;

طلب البحث أعلاه هو نفسه الطلب الذي استخدمناه في المختبر في الخطوة 8. ومع ذلك، تمّت فهرسة الحقل الآن.

  1. يمكنك إجراء اختبار باستخدام طلب بحث بسيط مع الفهرس وبدونه (من خلال إسقاط الفهرس):

تحتوي حالة الاستخدام هذه على 72 سجلًّا فقط، لذا لا يتم تطبيق الفهرس فعليًا. بالنسبة إلى اختبار تم إجراؤه في حالة استخدام أخرى، تكون النتائج على النحو التالي:

يؤدي طلب البحث نفسه باستخدام نموذج البحث بالاستناد إلى المتجهات على بيانات "الترميزات المُدرَجة" إلى تحقيق نتائج بحث عالية الجودة وكفاءة عالية. تم تحسين الكفاءة بشكل كبير (من حيث وقت التنفيذ: 10.37 ملي ثانية بدون ScaNN و0.87 ملي ثانية مع ScaNN) باستخدام الفهرس. لمزيد من المعلومات حول هذا الموضوع، يُرجى الرجوع إلى مدوّنة.

8. التحقّق من المطابقة باستخدام نموذج اللغة الكبيرة

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

التأكّد من إعداد المثيل لخدمة Gemini

تأكَّد أولاً ممّا إذا كان قد سبق أن تم تفعيل ميزة "دمج تكنولوجيات الذكاء الاصطناعي من Google" للمجموعة والوحدة. في AlloyDB Studio، أدخِل الأمر التالي:

show google_ml_integration.enable_model_support;

إذا كانت القيمة معروضة على أنّها "تفعيل"، يمكنك تخطّي الخطوتَين التاليتَين والانتقال مباشرةً إلى إعداد عملية دمج AlloyDB ونموذج Vertex AI.

  1. انتقِل إلى المثيل الأساسي لكتلة AlloyDB وانقر على "تعديل المثيل الأساسي".

cb76b934ba3735bd.png

  1. انتقِل إلى قسم "الإشارات" في "خيارات الإعداد المتقدّم". تأكَّد من ضبط google_ml_integration.enable_model_support flag على "on" كما هو موضّح أدناه:

6a59351fcd2a9d35.png

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

دمج AlloyDB ونموذج Vertex AI

يمكنك الآن الاتصال بـ AlloyDB Studio وتنفيذ عبارة DML التالية لإعداد إمكانية الوصول إلى نموذج Gemini من AlloyDB، باستخدام رقم تعريف مشروعك حيث هو موضَّح. قد يتم تحذيرك من خطأ في البنية قبل تنفيذ الأمر، ولكن من المفترض أن يتم تنفيذه بشكلٍ سليم.

أولاً، ننشئ اتصالاً بنموذج Gemini 1.5 كما هو موضّح أدناه. تذكَّر استبدال $PROJECT_ID في الأمر أدناه بمعرّف مشروعك على Google Cloud.

CALL
 google_ml.create_model( model_id => 'gemini-1.5',
   model_request_url => 'https://us-central1-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/us-central1/publishers/google/models/gemini-1.5-pro:streamGenerateContent',
   model_provider => 'google',
   model_auth_type => 'alloydb_service_agent_iam');

يمكنك التحقّق من النماذج التي تم ضبطها للوصول إليها من خلال الأمر التالي في AlloyDB Studio:

select model_id,model_type from google_ml.model_info_view;        

أخيرًا، علينا منح إذن لمستخدمي قاعدة البيانات بتنفيذ الدالة ml_predict_row لإجراء التوقّعات من خلال نماذج Google Vertex AI. نفِّذ الأمر التالي:

GRANT EXECUTE ON FUNCTION ml_predict_row to postgres;

ملاحظة: إذا كنت تستخدم مشروعًا حاليًا على Google Cloud ومجموعة/مثيل حاليَين من AlloyDB تم إنشاؤهما منذ فترة، قد تحتاج إلى حذف الإشارات القديمة إلى نموذج gemini-1.5 وإنشاءه مرة أخرى باستخدام عبارة CALL أعلاه وتنفيذ grant execute on function ml_predict_row مرة أخرى في حال مواجهة مشاكل في عمليات الاستدعاء القادمة لـ gemini-1.5.

تقييم الردود

على الرغم من أنّنا سنستخدم طلب بحث واحدًا كبيرًا في القسم التالي لضمان أن تكون الردود الواردة من طلب البحث معقولة، قد يكون من الصعب فهم طلب البحث. سنلقي نظرة على القطع الآن وسنرى كيف يتم تجميعها في بضع دقائق.

  1. سنرسل أولاً طلبًا إلى قاعدة البيانات للحصول على أقرب 10 نتائج مطابقة لطلب المستخدم.
  2. لتحديد مدى صلاحية الردود، سنستخدم طلب بحث خارجيًا نوضّح فيه كيفية تقييم الردود. ويستخدم الحقل recommended_text الذي يمثّل نص البحث والحقل content (الذي يمثّل حقل وصف اللعبة) من الجدول الداخلي كجزء من طلب البحث.
  3. باستخدام ذلك، سنراجع بعد ذلك "مدى جودة" الردود التي تم عرضها.
  4. تعرض دالة predict_row النتيجة بتنسيق JSON. يتم استخدام الرمز "-> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text'"" لاستخراج النص الفعلي من ملف JSON هذا. للاطّلاع على تنسيق JSON الفعلي الذي يتم إرجاعه، يمكنك إزالة هذا الرمز.
  5. أخيرًا، للحصول على ردّ من النموذج اللغوي الكبير، نحصل عليه باستخدام REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g')
SELECT id,
       name,
       content,
       quantity,
       price,
       image_url,
       recommended_text,
       REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') AS gemini_validation
  FROM (SELECT id,
               name,
               content,
               quantity,
               price,
               image_url,
               recommended_text,
               CAST(ARRAY_AGG(LLM_RESPONSE) AS TEXT) AS gemini_validation
          FROM (SELECT id,
                       name,
                       content,
                       quantity,
                       price,
                       image_url,
                       recommended_text,
                       json_array_elements(google_ml.predict_row(model_id => 'gemini-1.5',
                                                                   request_body => CONCAT('{ "contents": [ { "role": "user", "parts": [ { "text": "User wants to buy a toy and this is the description of the toy they wish to buy: ',                                                                                              recommended_text,                                                                                              '. Check if the following product items from the inventory are close enough to really, contextually match the user description. Here are the items: ',                                                                                         content,                                                                                         '. Return a ONE-LINE response with 3 values: 1) MATCH: if the 2 contexts are reasonably matching in terms of any of the color or color family specified in the list, approximate style match with any of the styles mentioned in the user search text: This should be a simple YES or NO. Choose NO only if it is completely irrelevant to users search criteria. 2) PERCENTAGE: percentage of match, make sure that this percentage is accurate 3) DIFFERENCE: A clear one-line easy description of the difference between the 2 products. Remember if the user search text says that some attribute should not be there, and the record has it, it should be a NO match. " } ] } ] }')::JSON)) -> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text' :: TEXT AS LLM_RESPONSE
                  FROM (SELECT id,
                               name,
                               description AS content,
                               quantity,
                               price,
                               image_url,
                               'Pink panther standing' AS recommended_text
                          FROM toys
                         ORDER BY text_embeddings <=> embedding('text-embedding-005',
                                                                'Pink panther standing')::VECTOR
                         LIMIT 10) AS xyz) AS X
         GROUP BY id,
                  name,
                  content,
                  quantity,
                  price,
                  image_url,
                  recommended_text) AS final_matches
 WHERE REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') LIKE '%MATCH%:%YES%';

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

يُرجى العِلم أنّ نموذج Gemini مفعَّل تلقائيًا، لذا يتم توزيع الردّ الفعلي على أسطر متعددة:

c2b006aeb3f3a2fc.png

9. نقل ميزة "البحث عن ألعاب" إلى Cloud بدون خادم

هل أنت مستعد لنشر هذا التطبيق على الويب؟ اتّبِع الخطوات التالية لإنشاء محرك معرفة غير مستنِد إلى خادم باستخدام وظائف Cloud Run:

  1. انتقِل إلى "وظائف Cloud Run" في Google Cloud Console من أجل إنشاء "وظيفة Cloud Run" جديدة أو استخدِم الرابط: https://console.cloud.google.com/functions/add.
  2. اختَر "دالة Cloud Run" للبيئة. أدخِل اسم الدالة "get-toys-alloydb" واختَر "us-central1" كالمنطقة. اضبط المصادقة على "السماح بطلبات البيانات غير المعتمَدة" وانقر على التالي. اختَر Java 17 كوقت تشغيل وInline Editor (أداة التعديل المضمّنة) للرمز المصدر.
  3. سيتم ضبط نقطة الدخول تلقائيًا على "gcfv2.HelloHttpFunction". استبدِل الرمز النائب في HelloHttpFunction.java وpom.xml من دالة Cloud Run بالرمز من HelloHttpFunction.java وpom.xml على التوالي.
  4. تذكَّر تغيير العنصر النائب <<YOUR_PROJECT>> وبيانات اعتماد اتصال AlloyDB باستخدام القيم في ملف Java. بيانات اعتماد AlloyDB هي البيانات التي استخدمناها في بداية هذا البرنامج التعليمي. إذا كنت قد استخدمت قيمًا مختلفة، يُرجى تعديلها في ملف Java.
  5. انقر على نشر.

بعد نشر الوظائف، سننشئ موصِّل شبكة VPC للسماح لوظائف Cloud بالوصول إلى مثيل قاعدة بيانات AlloyDB.

خطوة مهمة:

بعد الانتهاء من الإعداد للنشر، من المفترض أن تتمكّن من الاطّلاع على الدوال في وحدة تحكّم Cloud Run Functions من Google. ابحث عن الدالة التي تم إنشاؤها حديثًا (get-toys-alloydb)، وانقر عليها، ثم انقر على تعديل وغيِّر ما يلي:

  1. الانتقال إلى "وقت التشغيل" و"الإصدار" و"عمليات الربط" وإعدادات الأمان
  2. زيادة مهلة الانتظار إلى 180 ثانية
  3. انتقِل إلى علامة التبويب "عمليات الربط":

4e83ec8a339cda08.png

  1. ضمن إعدادات Ingress (الدخول)، تأكَّد من اختيار "Allow all traffic" (السماح بكل الزيارات).
  2. ضمن إعدادات "الخروج"، انقر على القائمة المنسدلة "الشبكة" واختَر "إضافة موصل VPC جديد" واتّبِع التعليمات التي تظهر في مربّع الحوار المنبثق:

8126ec78c343f199.png

  1. أدخِل اسمًا لموصِّل VPC وتأكَّد من أنّ المنطقة هي نفسها التي تستخدمها في المثيل. اترك قيمة "الشبكة" على الإعداد التلقائي واضبط "الشبكة الفرعية" على "نطاق IP مخصّص" باستخدام نطاق IP‏ 10.8.0.0 أو أي نطاق مشابه متاح.
  2. وسِّع SETTINGS FOR SCALING (إعدادات التكبير/التصغير) وتأكَّد من ضبط الإعدادات على ما يلي بالضبط:

7baf980463a86a5c.png

  1. انقر على "إنشاء"، ومن المفترض أن يظهر هذا الموصّل في إعدادات الخروج الآن.
  2. اختَر الموصّل الذي تم إنشاؤه حديثًا.
  3. اختَر توجيه جميع الزيارات من خلال موصِّل VPC هذا.
  4. انقر على التالي ثم على نشر.

10. اختبار دالة Cloud Run

بعد نشر دالة Cloud Functions المعدَّلة، من المفترض أن تظهر لك نقطة النهاية بالتنسيق التالي:

https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net/get-toys-alloydb

بدلاً من ذلك، يمكنك اختبار دالة Cloud Run على النحو التالي:

PROJECT_ID=$(gcloud config get-value project)

curl -X POST https://us-central1-$PROJECT_ID.cloudfunctions.net/get-toys-alloydb \
  -H 'Content-Type: application/json' \
  -d '{"search":"I want a standing pink panther toy"}' \
  | jq .

والنتيجة هي:

23861e9091565a64.png

هذا كل شيء! بهذه البساطة، يمكنك إجراء "بحث متّجه التشابه" باستخدام نموذج "عمليات التضمين" في بيانات AlloyDB.

11. إنشاء "عميل تطبيق الويب"

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

  1. بما أنّنا نستخدم Gemini 2.0 Flash لوصف الصورة التي قد يحمّلها المستخدم للعثور على ألعاب مطابقة، نحتاج إلى الحصول على مفتاح واجهة برمجة التطبيقات لهذا التطبيق. لإجراء ذلك، انتقِل إلى https://aistudio.google.com/apikey واحصل على مفتاح واجهة برمجة التطبيقات لمشروعك النشط على Google Cloud الذي تنفِّذ فيه هذا التطبيق واحفظ المفتاح في مكان ما:

ae2db169e6a94e4a.png

  1. انتقِل إلى وحدة Cloud Shell الطرفية.
  2. يمكنك استنساخ المستودع باستخدام الأمر التالي:
git clone https://github.com/AbiramiSukumaran/toysearch

cd toysearch
  1. بعد استنساخ المستودع، من المفترض أن تتمكّن من الوصول إلى المشروع من محرر Cloud Shell.
  2. عليك حذف المجلدَين "get-toys-alloydb" و "toolbox-toys" من المشروع المُكرّر لأنّ هذين المجلدَين هما رمز وظائف Cloud Run الذي يمكن الرجوع إليه من المستودع عند الحاجة إليه.
  3. تأكَّد من ضبط جميع متغيّرات البيئة اللازمة قبل إنشاء التطبيق ونشره. انتقِل إلى Cloud Shell Terminal ونفِّذ ما يلي:
PROJECT_ID=$(gcloud config get-value project)

export PROJECT_ID $PROJECT_ID

export GOOGLE_API_KEY <YOUR API KEY that you saved>
  1. إنشاء التطبيق وتشغيله على الجهاز:

تأكَّد من أنّك في دليل المشروع، ثم نفِّذ الأوامر التالية:

mvn package

mvn spring-boot:run 
  1. النشر على Cloud Run
gcloud run deploy --source .

12. فهم تفاصيل الذكاء الاصطناعي التوليدي

لا يلزم اتخاذ أي إجراء. يُرجى العِلم بما يلي:

بعد أن حصلت على التطبيق المطلوب نشره، عليك الاطّلاع على كيفية تنفيذنا عملية البحث (النص والصورة) والإنشاء.

  1. البحث المرئي المستنِد إلى نص المستخدم:

سبق أن تمّت معالجة هذه المشكلة في وظائف Cloud Run التي تم نشرها في قسم "الانتقال إلى تطبيق Vector Search على الويب".

  1. البحث باستخدام ملفات "الموجّهات" استنادًا إلى تحميل الصور:

بدلاً من كتابة السياق كنص، لنفترض أنّ المستخدم يريد تحميل صورة للعبة مألوفة يريد البحث عنها. يمكن للمستخدمين تحميل صورة للعبة يحبونها والحصول على ميزات ذات صلة بها.

نستفيد من نموذج Gemini 2.0 Flash من Google، الذي يتم تشغيله باستخدام LangChain4j، لتحليل الصورة واستخراج السياق ذي الصلة، مثل لون اللعبة ومواد تصنيعها ونوعها والفئة العمرية المستهدفة.

في 5 خطوات فقط، أخذنا بيانات المستخدم المتعدّدة الوسائط إلى مطابقة النتائج مع طلب نموذج لغوي كبير باستخدام إطار عمل مفتوح المصدر. تعرف على كيفية إجراء ذلك:

package cloudcode.helloworld.web;

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.model.output.Response;
import dev.langchain4j.data.message.ImageContent;
import dev.langchain4j.data.message.TextContent;
import java.util.Base64;
import java.util.Optional;

public class GeminiCall {
  public String imageToBase64String(byte[] imageBytes) {
    String base64Img = Base64.getEncoder().encodeToString(imageBytes);
    return base64Img;
  }

  public String callGemini(String base64ImgWithPrefix) throws Exception {
    String searchText = "";

    // 1. Remove the prefix
    String base64Img = base64ImgWithPrefix.replace("data:image/jpeg;base64,", "");

    // 2. Decode base64 to bytes
    byte[] imageBytes = Base64.getDecoder().decode(base64Img);
    String image = imageToBase64String(imageBytes);

    // 3. Get API key from environment variable
        String apiKey = Optional.ofNullable(System.getenv("GOOGLE_API_KEY"))
                .orElseThrow(() -> new IllegalArgumentException("GOOGLE_API_KEY environment variable not set"));

    // 4. Invoke Gemini 2.0
    ChatLanguageModel gemini = GoogleAiGeminiChatModel.builder()
        .apiKey(apiKey)
        .modelName("gemini-2.0-flash-001")
        .build();

    Response<AiMessage> response = gemini.generate(
        UserMessage.from(
            ImageContent.from(image, "image/jpeg"),
            TextContent.from(
                "The picture has a toy in it. Describe the toy in the image in one line. Do not add any prefix or title to your description. Just describe that toy that you see in the image in one line, do not describe the surroundings and other objects around the toy in the image. If you do not see any toy in the image, send  response stating that no toy is found in the input image.")));
   
    // 5. Get the text from the response and send it back to the controller
    searchText = response.content().text().trim();
    System.out.println("searchText inside Geminicall: " + searchText);
    return searchText;
  }
}
  1. تعرَّف على كيفية استخدامنا لنموذج Imagen 3 لإنشاء لعبة مخصَّصة استنادًا إلى طلب المستخدم باستخدام الذكاء الاصطناعي التوليدي.

بعد ذلك، تنشئ Imagen 3 صورة للّعبة المصمّمة حسب الطلب، ما يمنح المستخدم تصورًا واضحًا لتصميمه. إليك الخطوات التي اتّبعناها في 5 خطوات فقط:

// Generate an image using a text prompt using an Imagen model
    public String generateImage(String projectId, String location, String prompt)
        throws ApiException, IOException {
      final String endpoint = String.format("%s-aiplatform.googleapis.com:443", location);
      PredictionServiceSettings predictionServiceSettings =
      PredictionServiceSettings.newBuilder().setEndpoint(endpoint).build();
     
      // 1. Set up the context and prompt
      String context = "Generate a photo-realistic image of a toy described in the following input text from the user. Make sure you adhere to all the little details and requirements mentioned in the prompt. Ensure that the user is only describing a toy. If it is anything unrelated to a toy, politely decline the request stating that the request is inappropriate for the current context. ";
      prompt = context + prompt;

      // 2. Initialize a client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      try (PredictionServiceClient predictionServiceClient =
          PredictionServiceClient.create(predictionServiceSettings)) {
 
      // 3. Invoke Imagen 3
        final EndpointName endpointName =
            EndpointName.ofProjectLocationPublisherModelName(
                projectId, location, "google", "imagen-3.0-generate-001"); //"imagegeneration@006"; imagen-3.0-generate-001
        Map<String, Object> instancesMap = new HashMap<>();
        instancesMap.put("prompt", prompt);
        Value instances = mapToValue(instancesMap);
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("sampleCount", 1);
        paramsMap.put("aspectRatio", "1:1");
        paramsMap.put("safetyFilterLevel", "block_few");
        paramsMap.put("personGeneration", "allow_adult");
        paramsMap.put("guidanceScale", 21);
        paramsMap.put("imagenControlScale", 0.95); //Setting imagenControlScale
        Value parameters = mapToValue(paramsMap);
       
      // 4. Get prediction response image
        PredictResponse predictResponse =
            predictionServiceClient.predict(
                endpointName, Collections.singletonList(instances), parameters);

      // 5. Return the Base64 Encoded String to the controller
        for (Value prediction : predictResponse.getPredictionsList()) {
          Map<String, Value> fieldsMap = prediction.getStructValue().getFieldsMap();
          if (fieldsMap.containsKey("bytesBase64Encoded")) {
            bytesBase64EncodedOuput = fieldsMap.get("bytesBase64Encoded").getStringValue();
        }
      }
      return bytesBase64EncodedOuput.toString();
    }
  }

توقّعات الأسعار

في القسم السابق أعلاه، ناقشنا كيف تنشئ Imagen صورة لعبة يريد المستخدم تصميمها بنفسه. لكي يتمكّن المستخدمون من شرائها، يجب أن يحدّد التطبيق سعرًا لها، وقد استخدمنا منطقًا بسيطًا لتحديد سعر اللعبة المخصّصة حسب الطلب. ويستند المنطق إلى استخدام متوسط سعر أهم 5 ألعاب تتطابق بشكل كبير (من حيث الوصف) مع اللعبة التي يصممها المستخدم.

يُعدّ توقّع سعر اللعبة التي تم إنشاؤها جزءًا مهمًا من هذا التطبيق، وقد استخدمنا نهجًا تمثيليًا لإنشاء هذا التوقع. نقدّم لك "مجموعة أدوات الذكاء الاصطناعي التوليدي" لقواعد البيانات.

13. مجموعة أدوات الذكاء الاصطناعي التوليدي لقواعد البيانات

أداة الذكاء الاصطناعي التوليدي لقواعد البيانات هي خادم مفتوح المصدر من Google يسهّل إنشاء أدوات الذكاء الاصطناعي التوليدي للتفاعل مع قواعد البيانات. ويتيح لك تطوير الأدوات بسهولة وسرعة وأمان أكبر من خلال التعامل مع المهام المعقّدة، مثل تجميع الاتصالات والمصادقة وغير ذلك. ويساعدك هذا الإجراء في إنشاء أدوات الذكاء الاصطناعي التوليدي التي تتيح لموظفي الدعم الوصول إلى البيانات في قاعدة بياناتك.

في ما يلي الخطوات التي يجب اتّباعها لتتمكّن من إعداد هذه الميزة لتجهيز أداتك ومنح وكيل التطبيق الإذن بالوصول إلى البيانات: رابط إلى Toolbox Codelab

يمكن لتطبيقك الآن استخدام نقطة نهاية "وظيفة Cloud Run" المنشورة هذه لتعبئة السعر مع نتيجة Imagen التي تم إنشاؤها لصورة اللعبة المخصّصة حسب الطلب.

14. اختبار تطبيق الويب

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

https://www.youtube.com/shorts/ZMqUAWsghYQ

في ما يلي شكل الصفحة المقصودة:

241db19e7176e93e.png

15. تَنظيم

لتجنُّب تحصيل رسوم من حسابك على Google Cloud مقابل الموارد المستخدَمة في هذه المشاركة، اتّبِع الخطوات التالية:

  1. في وحدة تحكّم Google Cloud، انتقِل إلى صفحة إدارة الموارد.
  2. في قائمة المشاريع، اختَر المشروع الذي تريد حذفه، ثم انقر على حذف.
  3. في مربّع الحوار، اكتب رقم تعريف المشروع، ثم انقر على إيقاف لحذف المشروع.

16. تهانينا

تهانينا! لقد أجريت بنجاح عملية البحث السياقي وإنشاء محتوى في متجر لعب باستخدام AlloyDB وpgvector وImagen وGemini 2.0، مع الاستفادة من مكتبات البرامج المفتوحة المصدر لإنشاء عمليات دمج فعّالة. من خلال الجمع بين إمكانات AlloyDB وVertex AI والبحث عن المتّجهات، حققنا قفزة كبيرة إلى الأمام في تسهيل الوصول إلى عمليات البحث السياقي والبحث عن المتّجهات وجعلها أكثر فعالية واستنادًا إلى المعنى.