التطبيقات الذكية

السماح للوكلاء بإنشاء واجهة مستخدم في تطبيقات Android باستخدام A2UI

سماعات

لمحة

لمحة عن المحاضرة

يتم نقل A2UI من المكوّنات المستندة إلى الويب إلى نظام Android الأساسي. يتيح محرّك العرض الجديد Jetpack Compose في الإصدار 0.9 من A2UI للمطوّرين عرض واجهة مستخدم ديناميكية يتم إنشاؤها باستخدام النماذج اللغوية الكبيرة (LLM) بشكلٍ أصلي. وبدلاً من استخدام WebView، يعتمد على إطار عمل Actor المستند إلى Coroutine، ومراحل النشاط من فئة Sealed، والتكامل مع Material 3 الأصلي.

تتناول هذه الجلسة البنية الجديدة، وتوضّح كيفية ترجمة شجرات المكوّنات المستندة إلى الخادم إلى عُقد Compose تفاعلية، وكيفية تعامل انتقالات التنسيق المضمّنة مع التحديثات الهيكلية بسلاسة بدون حظر واجهة المستخدم.

ملخّص

  • توفّر واجهة A2UI بروتوكول JSON مفتوحًا وتوضيحيًا للأنظمة الخلفية المستندة إلى الوكلاء لوصف واجهات المستخدم الديناميكية بدلاً من الردود النصية.
  • يعتمد البروتوكول على كتالوجات تحدّد المكوّنات والوظائف المسموح بها، بالإضافة إلى مساحات العرض التي تمثّل أجزاء واجهة المستخدم التي يتحكّم فيها الوكيل.
  • تعرض مكتبة A2UI في Jetpack Compose نماذج واجهات المستخدم التي يتم بثها بشكل أصلي باستخدام مكوّنات Material 3 مع ميزات تسهيل الاستخدام المضمّنة والعرض التدريجي.
  • تعمل نماذج البيانات في الذاكرة على تحديث عناصر في واجهة المستخدم المرتبطة بها على الفور بدون التواصل مع الوكيل، بينما توجّه الأحداث الصادرة إجراءات المستخدم مرة أخرى.
  • يمكن للمطوّرين تخصيص عناصر الكتالوج الحالية أو إنشاء مكوّنات مخصّصة للتحكّم بدقة في ما يمكن للوكيل عرضه.

الموارد

Gemini Notebook

المواضيع

  • a2ui
  • generative-ui
  • jetpack-compose
  • Android
  • وكلاء الذكاء الاصطناعي
  • التصميم المتعدد الأبعاد

النص

تنزيل النص

مقدّمة حول واجهة المستخدم التوليدية وA2UI

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

  • اسمي "نيك بوتشر"، وأنا مدير منتجات أعمل على Jetpack Compose.

  • مرحبًا، أنا "أنطون"، مهندس في فريق Compose.

  • أعمل على أداة عرض Jetpack Compose A2UI الجديدة التي يسرّنا إطلاعك عليها اليوم.

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

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

  • ولكن للأسف، في الوقت الحالي، تكون ردود العديد من الأنظمة الخلفية للوكلاء محصورة في نصوص طويلة، مثل هذا النص.

  • إليكم مثال طلبت فيه من وكيل إنشاء ميزة جديدة لحجز رحلة.

  • إليك الطلب.

  • وكما ترون، قدّم Gemini إجابة جيدة، ولكنّها محصورة في هذا النص الطويل الذي لا يمكنني التفاعل معه بسهولة، ولا يشبه بقية تطبيقي.

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

  • إليكم مثال على واجهة مستخدم تم إنشاؤها باستخدام مكوّنات عادية ومدمجة.

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

  • ‫A2UI، وهو اختصار لـ Agent-to-UI، هو بروتوكول مفتوح بتنسيق JSON لتحديد كل هذه العناصر.

  • من الأمور التي تعجبني في A2UI هو أنّه تنسيق تعريفي.

  • يعرض الوكيل تمثيل JSON لواجهة المستخدم التي سيتم عرضها.

  • ولا يعرض أي رمز يحتاج العميل إلى تنفيذه، ما قد يعرّضك لثغرات أمنية معيّنة.

  • إنّها مجرّد لغة تعريفية.

  • إذًا، ما هي المفاهيم الأخرى التي يجب معرفتها حول A2UI؟

المفاهيم الأساسية: الكتالوجات ومساحات العرض

  • هناك مفهومان رئيسيان فقط: الكتالوجات ومساحات العرض.

  • يحتوي الكتالوج على مكوّنات مثل النص والزر والصف والعمود التي يمكن للوكيل استخدامها لإنشاء واجهة المستخدم.

  • يحتوي الكتالوج أيضًا على وظائف يمكن للوكيل استخدامها لتنسيق النص أو التحقّق من صحة إدخالات المستخدم أو فتح عناوين URL.

  • الكتالوج هو عقد يحدّد المكوّنات والوظائف التي يتيحها تطبيقك، ولا يمكن للوكيل إنشاء المحتوى إلا باستخدامها.

  • هذا يعني، كما ذكر "نيك"، أنّ الوكيل لا ينفّذ أبدًا رمزًا عشوائيًا في تطبيقك.

  • فهي تنشئ واجهة مستخدم من اللبنات الأساسية التي تصمّمها وتثق بها.

  • هناك مفهوم آخر مهم وهو السطح.

  • السطح هو جزء واحد من واجهة المستخدم يتحكّم فيه الوكيل، مثل مثال مخطِّط الرحلات هذا على الشريحة.

  • يصف الوكيل واجهة المستخدم لمساحة عرض في JSON باستخدام رسائل بروتوكول A2UI، مثل createSurface وupdateComponents، وباستخدام المكوّنات والوظائف المحدّدة في الكتالوج.

  • بالحديث عن الكتالوج، فهو مفهوم أساسي جدًا في A2UI، لأنّه يتحكّم في المكوّنات التي يمكن للوكيل استخدامها لإنشاء واجهة.

  • تحدّد مواصفات A2UI ما يُعرف باسم "الكتالوج الأساسي"، وهو مجموعة من المكوّنات الشائعة التي يمكنك استخدامها لإنشاء معظم واجهات المستخدم.

  • يوفّر محرّك عرض Jetpack Compose A2UI طريقة لتنفيذ الكتالوج الأساسي باستخدام مكوّنات Material 3.

  • معظم مكوّنات الكتالوج جاهزة للاستخدام على الفور.

  • هناك ثلاثة مكوّنات للوسائط: مشغّل الصور والفيديو والصوت، حيث تحتاج إلى توصيل مكتبتك التي تختارها.

  • على سبيل المثال، يمكنك اختيار Coil لتحميل الصور وMedia3 لمشغّل الفيديو والصوت.

  • لكنّ القوة الحقيقية لـ A2UI ومكتبة العرض الجديدة تكمن في إمكانية إنشاء مكوّنات وكتالوجات مخصّصة بالكامل، والتحكّم بشكل كامل في ما يمكن للوكيل استخدامه لإنشاء واجهة المستخدم.

  • سنعود إلى الكتالوجات لاحقًا.

  • حسنًا، لنلقِ نظرة على شكل ذلك.

  • لذا، إذا كان بإمكاننا التبديل إلى جهاز العرض التوضيحي، من فضلك.

  • هذا هو تطبيقنا التجريبي الذي سنستخدمه، وسننشئ عارض A2UI لنوضّح لك مدى سهولة ذلك.

  • وهي مجموعة من الطلبات، كما ترون في هذه الشرائح الصغيرة في منتصف الشاشة، يمكنكم إرسالها إلى الوكيل.

  • لذا، إذا نقرنا على أحد الطلبات، سيتم إرساله إلى موظف دعم حقيقي، لذا نأمل أن ينجح العرض التوضيحي، وبالإضافة إلى الطلب، نُضيف أيضًا بعض تعليمات النظام.

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

  • إنّ تنفيذ جلسة المحادثة في تطبيقنا التجريبي يعرف مسبقًا كيفية استخراج رسائل JSON A2UI الأولية من ردود الوكيل.

  • في هذه الحالة، ردّ الوكيل ببعض النصوص متبوعة برسائل بروتوكول A2UI: ‏createSurface وupdateComponents.

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

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

  • ها نحن ذا.

بنية التطبيق ومعالجة الرسائل

  • إليك الخطة.

  • لذا، يرسل وكيل الذكاء الاصطناعي ردًا إلى تطبيقنا يتلقّاه الصف ChatSession.

  • يستخرج ChatSession رسائل JSON الأولية من A2UI من ردود الوكيل أثناء بثها ويمررها إلى معالج رسائل A2UI.

  • يتم ضبط معالج الرسائل باستخدام محلّل لغوي يحوّل رسائل JSON الأولية إلى تمثيل دلالي.

  • بعد ذلك، يتحقّق المعالج من صحة الرسائل وفقًا لتعريف الكتالوج ويربطها بمجموعة من نماذج العرض.

  • نماذج السطح: تحدّد هذه النماذج مظهر واجهة المستخدم وأجزاء واجهة المستخدم التي يتحكّم فيها الوكيل.

  • بعد ذلك، يتم عرض نماذج الواجهات هذه كواجهة مستخدم Compose أصلية باستخدام الدالة المركّبة لواجهة A2UI التي توفّرها مكتبتنا.

  • يكون الاتصال بين الوكيل وواجهة المستخدم ثنائي الاتجاه، لذا عندما يتفاعل المستخدم مع واجهة المستخدم، يتم إرسال إجراءات المستخدم والأخطاء إلى الوكيل.

  • باختصار، هناك ثلاث وحدات أساسية: الكتالوج ومعالج الرسائل ومساحة العرض.

  • لنكتب الرمز البرمجي لذلك.

  • نعم، لننشئها إذا كان بإمكاننا تبديل الأجهزة.

  • حسنًا، الخطوة الأولى هي إضافة التبعية.

  • يمكنكم هنا رؤية أنّنا أضفنا تبعية Material 3 A2UI، وقمنا بمزامنة المشروع حتى لا نضطر إلى الانتظار لمشاهدة Gradle.

  • هذه هي التبعية ذات المستوى الأعلى التي تحدّد تنفيذ الكتالوج الأساسي باستخدام مكوّنات Material 3، ولكن هناك تبعيات أخرى أكثر دقة تحتها.

  • لذا، إذا كنت لا تريد استخدام الكتالوج الأساسي، والذي سنشرح سبب ذلك لاحقًا، يمكنك استخدام تلك الكتالوجات الأكثر دقة.

  • ولكن هذا سيجلب-- سيسحب الباقي بشكل متعدٍ.

  • حسنًا

  • قلنا إنّ هناك ثلاثة أمور.

  • الخطوة الأولى هي تحديد الكتالوج.

  • في تطبيقنا، سننشئ دالة مصنع للمساعدة في إنشاء نسخة من تنفيذ Material 3 للكتالوج الأساسي.

  • لذلك، نستخدم دالة المكتبة هذه هنا، وهي الكتالوج الأساسي لمادة A2UI، والذي تم إصداره أيضًا.

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

  • على سبيل المثال، أنشأ "أنطون" هذا الغلاف حول الدالة المركّبة AsyncImage في Coil، والتي سنستخدمها لتحميل الصور، بالإضافة إلى بعض المنطق الإضافي للعرض التوضيحي للبحث عن الصور من Wikipedia.

  • وبالتالي، يمكننا بسهولة إدخال هذه البيانات في مكوّنات الكتالوج.

  • وبالمثل، لدينا عمليات تنفيذ مماثلة للعرض والفيديو والصوت، حيث سنستخدم مكتبة Media3 لعرضها باستخدام ExoPlayer.

  • ببساطة، يمكننا توصيل مكوّناتنا الخاصة به.

  • الشيء التالي الذي يحتاجه الكتالوج هو مجموعة من الوظائف القياسية.

  • هذه هي الدوال التي يمكن للعميل توفيرها.

  • مرة أخرى، نقدّم تنفيذًا لذلك مع الكتالوج الأساسي، ولكننا نحتاج إلى تزويده بسياق، والذي ستستخدمه لتنفيذ إجراءات معيّنة، مثل فتح معرّف موارد منتظم (URI) إذا نقر المستخدم على عنصر.

  • وهكذا، نكون قد أكملنا الخطوة الأولى.

  • لقد أنشأنا كتالوجًا.

  • الخطوة التالية التي كان علينا القيام بها هي إعداد معالج الرسائل.

  • هذا هو المكوّن الذي يحلّل الردود وما إلى ذلك.

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

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

  • هناك مكوّن آخر نحتاج إلى إنشائه وهو المحلل اللغوي، وهو في الواقع الكائن المسؤول عن تحليل رسائل JSON عند عودتها.

  • هنا ننشئ كائن ChatSession.

  • كما ذكرتُ سابقًا، يستخرج ChatSession الرسائل الأولية من A2UI من ردود الوكيل.

  • وعندما تصبح كل رسالة جديدة من A2UI جاهزة، يتم استدعاء دالة ردّ الاتصال onA2uiMessage.

  • لذا، كل ما نحتاج إلى فعله هو تمرير كل من هذه الرسائل عند وصولها إلى المعالج.

  • نستدعي الدالة processInput، ونمنحها محللاً لغويًا ورسالة.

  • لذلك، تحلّل الدالة processInput كل رسالة ثم تضع العمل في قائمة انتظار المعالج للتحقّق من صحته مقارنةً بالكتالوج وتعديل نماذج العرض.

  • لذلك، يعرض المعالج المجموعة الحالية من نماذج الواجهات النشطة على شكل activeSurfaces StateFlow.

  • يحتوي ChatSession على بعض المنطق لإضافة نماذج العرض إلى حالات واجهة المستخدم لردود الوكيل التي سيتم عرضها.

  • لذا، نمرّر activeSurfaces StateFlow كمَعلمة إلى ChatSession.

  • كما ذكرتُ، تضع الدالة processInput العمل في قائمة انتظار المعالج.

  • ولكن لبدء المعالجة فعليًا، نحتاج إلى تشغيل دالة coroutine في سلسلة مهام في الخلفية.

  • لذا، سنستخدم نطاق نموذج العرض لذلك ونضبط المُرسِل التلقائي.

  • وفي هذا الروتين، نحتاج فقط إلى استدعاء processor.collectMessages.

  • لذلك، عندما يكون هذا الروتين التعاوني نشطًا، سيتعامل المعالج مع الرسائل من قائمة انتظار الرسائل.

  • لذا، هناك إجراء آخر يجب اتّخاذه، وهو أنّه عندما يمحو المستخدم سجلّ المحادثات، يجب أيضًا محو مساحات العرض الحالية.

  • لذلك، نستدعي clearSurfaces.

عرض نماذج مساحات العرض في واجهة المستخدم

  • حسنًا

  • لقد أكملنا الخطوتَين الأوليَين.

  • أنشأنا الكتالوج، وأنشأنا المعالج لتحليل الرسائل.

  • الخطوة التالية التي يجب اتّخاذها هي عرض هذه الردود في واجهة المستخدم.

  • لذلك، نجمع مساحات العرض هذه أثناء تحليلها بواسطة المحلل اللغوي.

  • والآن في واجهة المستخدم، سنمرّر هذه الروابط في عنصر ردّ الوكيل هذا وسنكرّرها ببساطة.

  • بعد ذلك، سنستخدم الدالة المركّبة A2UI surface ونمرّر إليها كل نموذج من النماذج أثناء تكرارها لعرض المحتوى في المكان الذي نريده.

  • ملاحظة واحدة هنا هي أن الوكيل قد يختار استخدام شيء مثل القائمة إذا اختار عرض، كما تعلم، كمية كبيرة من المحتوى.

  • لذلك، علينا ضبط الارتفاع المحدود على أقصى ارتفاع في هذا المكوّن لضمان عرضه بشكل صحيح.

  • وبذلك، نكون قد نفّذنا أداة عرض أساسية لـ A2UI.

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

  • لذلك نحن فقط نرمز ذلك مباشرة.

  • هذا ليس مثل الدخان والمرايا.

  • نعم، إنّها تستخدم صورًا حقيقية.

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

  • لأنّ هذا تطبيق حقيقي يستخدم مكوّنات Material حقيقية، فهو يؤدي المهام التي تؤديها المكوّنات الحقيقية.

  • ويتميز بأداء يشبه الأداء الأصلي.

  • فهو ينفّذ إجراءات مثل الاستجابة للوضع الداكن هنا.

  • هذه هي مكوّنات Material.

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

  • كما ذكر "نيك"، بما أنّ هذه المكوّنات أصلية في Compose، فهي تتضمّن دلالات أصلية.

  • وهذا يعني أنّ جميع ميزات تسهيل الاستخدام المضمّنة في Compose متاحة.

  • لذلك، تعمل ميزات مثل TalkBack وتغيير حجم الخط والتنقّل باستخدام لوحة المفاتيح تلقائيًا.

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

  • قد تضطر إلى الانتظار حتى يردّ عليك موظّف الدعم.

  • وتعمل المكتبة على تقليل وقت الاستجابة هذا قدر الإمكان.

  • لذا، إذا استخدمنا هذا النوع من الانتظار، فسنقوم بحقن بعض الانتظار من أجل إظهار المزيد ببطء لإظهار ما يحدث وكيفية تقليل ذلك.

  • بما أنّ الوكيل قد يستغرق بعض الوقت لبث الردّ الكامل، نستخدم ما يُعرف باسم "العرض التدريجي".

  • لذلك، فور وصول المكوّن الجذر، نبدأ بعرض واجهة المستخدم الخاصة بالسطح.

  • تعرض جميع مكوّنات الحاوية عناصر نائبة للتحميل للعناصر الفرعية إذا لم تصل العناصر الفرعية بعد.

  • عند وصول المكوّنات الفرعية، يتم تحريكها باستخدام مخطط الحركة في Material 3.

  • حسنًا

  • وإذا كان بإمكاننا الانتقال إلى الطلب التالي لعرض ميزة أخرى في المكتبة.

  • إليكم طلب آخر لحجز طاولة للعشاء.

  • وهنا يختار الوكيل استخدام مكوّن شريط التمرير هذا، نعم، لقد استخدمه.

  • يمكنكم هنا سحب واجهة المستخدم التي أنشأها الوكيل والتفاعل معها فورًا.

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

  • أليس من المفترض أن يتم إرسال هذه المعلومات إلى الوكيل لتحديثها؟

  • هذا ربط ثنائي الاتجاه.

  • لذلك، يرتبط مكوّن شريط التمرير بنموذج البيانات في الذاكرة لهذه المساحة.

  • يتم تلقائيًا تعديل جميع المكوّنات المرتبطة بالمسار نفسه في نموذج البيانات عند تغيير القيمة.

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

  • يتم تنفيذ كل هذه الإجراءات محليًا بدون الحاجة إلى إرسال طلب ذهاب وعودة إلى الوكيل.

  • ويمكننا أيضًا أن نطلب من الوكيل تعديل البيانات.

  • لنفترض أنّ عدد الأشخاص هو 6.

  • انتبه إلى شريط التمرير عندما يردّ الوكيل.

  • لقد قفز إلى 6.

  • لنرَ ما تلقّيناه من الوكيل.

  • بدلاً من إرسال وصف جديد بالكامل لواجهة المستخدم، أرسل الوكيل رسالة صغيرة واحدة updateDataModel عدّلت مسار شريط التمرير.

  • بما أنّ شريط التمرير مرتبط بهذا المسار، تم تعديله في مكانه.

  • لذلك، يتم إنشاء نموذج بيانات كل سطح على حالة لقطة Compose، وكل سمة مكوّن مرتبطة بمسار هي حالة مشتقة.

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

  • حسنًا

  • لنفترض أنّنا نريد اتّخاذ إجراء ونريد النقر على زر الحجز، ماذا سيحدث هنا يا "أنطون"؟

  • لا يحدث شيء في الوقت الحالي.

  • يؤدي الزر إلى إرسال إجراء، ولكننا لا نرسله إلى الوكيل بعد.

  • لذا، لنصلحها.

التعامل مع إجراءات المستخدم وتدفقات الأحداث

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

  • لإجراء ذلك، نستخدم تدفق outboundEvents الذي يعرضه المعالج، ونجمعه في هذا.

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

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

  • لذا، قام أنطون هنا بتوصيله، والآن عندما نضغط على إجراء تأكيد الحجز، سيتم إرسال هذا الإجراء الذي اتخذته مرة أخرى إلى الوكيل.

  • وهنا، يمكنك في الخلفية حتى أن تقرر استدعاء بعض الوظائف.

  • لِنلقِ نظرة على ما نرسله إلى الوكيل.

  • هذه هي رسالة الإجراء في A2UI.

  • ويتضمّن سياقًا يحتوي على مجموعة من السمات التي طلب الوكيل إرسالها عند تنفيذ هذا الإجراء.

  • لذلك، عندما أنقر على الزر، يتم حلّ هذه السمات المحدّدة في تلك اللحظة استنادًا إلى القيم الحالية في نموذج البيانات، وهذا ما نرسله إلى الوكيل.

  • حسنًا، حتى الآن، كان الوكيل متعاونًا معنا إلى حد كبير، ولكننا نتحدث عن الذكاء الاصطناعي هنا، ويمكن أن يرتكب الذكاء الاصطناعي أخطاء.

  • لِنلقِ نظرة على ما يحدث إذا أخطأ الوكيل في واجهة المستخدم التي يصفها لنا.

  • في هذا الطلب الأخير، نطلب من الوكيل ارتكاب خطأ لنتمكّن من توضيح ذلك لكم.

  • لنرى ما سيحدث.

  • أجل

  • كما ترون، تم وضع علامة خطأ على أحد المكوّنات.

  • وتم حلّها الآن.

  • هذه هي حلقة التصحيح الذاتي للوكيل.

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

  • إذا لم يتطابق المكوّن مع المخطط، يتم وضع علامة عليه كخطأ.

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

  • وراء الكواليس، يرسل المعالج رسالة خطأ إلى الوكيل لإعلامه بالمشكلة.

  • لذلك في هذه الحالة، أرسلنا رسالة تفيد بأن نوع المكون غير معروف نوع غير موجود لم يتم العثور عليه في الكتالوج.

  • بعد ذلك، أتيحت للوكيل فرصة الردّ وإرسال ردّ متابعة عدّل واجهة المستخدم الحالية وتم إصلاح واجهة المستخدم في مكانها.

  • أجل

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

  • وبهذه الطريقة، قد يتم إخفاء الخطأ تمامًا عن المستخدم.

إنشاء مكوّنات مخصّصة وتوسيع الكتالوجات

  • بالحديث عن الكتالوجات والمكوّنات المخصّصة، لقد استخدمنا حتى الآن الكتالوج الأساسي كما هو، ولكن يمكنك بالطبع تخصيصه حسب احتياجاتك.

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

  • لذلك يمكنك بسهولة توصيل المكونات الخاصة بك إذا أردت.

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

  • لذا، سنلغي هذه المَعلمة عند إنشاء نسخة من الكتالوج، وسننشئ تعريف المكوّن هذا.

  • لذا، إذا أنشأنا فئة جديدة لتنفيذ ذلك، يمكنكم رؤية واجهة هنا، وهي الكتالوج الأساسي A2UI من نوع الزر.

  • لذا، إذا نفّذنا هذه الواجهة، يمكننا توصيل المكوّن الخاص بنا.

  • أجل

  • بما أنّنا نتجاوز مكوّنًا في الكتالوج الأساسي، علينا تنفيذ واجهة زر الكتالوج الأساسي A2UI هذه.

  • لذا، تتضمّن هذه الواجهة بعض المعلومات عن المكوّن، مثل الاسم والوصف ومخطّط السمة.

  • لذا، كل ما علينا فعله لتنفيذ نسختنا الخاصة هو تنفيذ هذه الدالة المركّبة.

  • وتتطلّب بعض المَعلمات.

  • لذا، فإنّ هذه المَعلمات هي قيم يتم تلقّيها من الوكيل بعد التحقّق من صحتها.

  • هذه هي أشياء مثل معرّف الطفل، وهو الذي يشير إلى مكوّن سيكون محتوى الزر.

  • وتتضمّن أيضًا صيغة تصف نوع الزر وتعريف الإجراء وبعض المَعلمات الأخرى.

  • في عملية تنفيذ الزر في مرحلة الإنتاج، سنحتاج إلى استخدام كل هذه المعلمات، ولكن لأغراض العرض التوضيحي، نحتاج فقط إلى العنصر الفرعي والإجراء.

  • لذا، لننفّذ هذه الدالة المركّبة.

  • حسنًا، في هذه الدالة المركّبة، سنُصدر نوع زر الإعجاب المخصّص هنا.

  • وكما ترون، يمكننا استخدام المَعلمات التي تم تقديمها والتحقّق من صحتها من خلال A2UI.

  • على سبيل المثال، في دالة onClick، يمكننا إرسال هذا الإجراء.

  • يمكننا استخدام نوع المكتبة هذا DispatchAction وتمرير الإجراء الذي حددته A2UI إليه.

  • لذلك، نستخدم الزر الخاص بنا، ولكننا نريد عرض المحتوى الفرعي أو التصنيف أو أي شيء قرر الوكيل استخدامه.

  • لذا، نستخدم دالة observeA2uiComponentState ونمرّر إليها childId للحصول على المحتوى الفرعي الذي يجب عرضه.

  • بعد ذلك، سنستخدم الدالة المركّبة A2uiComponent ونمرّر إليها حالة المكوّن الفرعي لعرضه.

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

  • لذا، إذا عدنا إلى أحد نماذج الطلبات في تطبيقنا التجريبي واستبدلنا الزر الآن باستخدام زر Material العادي.

  • إنّه دقيق جدًا، وآمل أن تتمكّنوا من رؤيته.

  • يمكنك أن ترى أننا نستخدم زرًا مخصصًا للغاية هنا أيضًا.

  • رائع، هذه هي الطريقة التي يمكنك من خلالها استبدال بعض أنواع المكتبات، ولكن ماذا لو أردت توسيع المكتبة بأنواعك المخصصة؟

  • ويمكننا إجراء ذلك بسهولة من خلال الإضافة إلى الكتالوج نفسه.

  • لذا، سينشئ "أنطون" فئة جديدة هنا لتنفيذ مكوّن تقييم بالنجوم.

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

  • بما أنّنا لا نستبدل مكوّنًا حاليًا، نستخدم هذه الواجهة الأكثر عمومية، وهي واجهة المكوّن A2UI، والتي تحتوي على بعض المَعلمات التي نحتاج إلى إلغائها.

  • لذا، فإن أول اثنين هما الاسم والوصف.

  • يصف هذا ما هو المكوّن وما يفعله.

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

  • لذلك، عليك أن تكون وصفيًا للغاية وأن تخبر الذكاء الاصطناعي أنك تعرف بالضبط ما يفعله هذا.

  • السمة التالية التي نحتاج إلى إلغائها هي سمة properties، والتي تحدّد بشكل أساسي البيانات التي يتعامل معها هذا المكوّن.

  • لذا، سننشئ شريط تقييم بالنجوم لكي تتمكّن من تقييم مطعم، وسنحتاج إلى سمتَين.

  • ستكون القيمة، مثل عدد النجوم التي اختارها المستخدم، والتي ستكون خاصية قابلة للتغيير يمكن للمستخدم التفاعل معها وتغييرها، والحد الأقصى لعدد النجوم.

  • لذا، يمكننا هنا رؤية استخدام "أنطون" لهذه السمة الديناميكية من نوع الأرقام للقيمة.

  • هذا يمثّل عدد النجوم التي تم اختيارها.

  • والذي يحتوي بدوره على نوع من الوصف يخبر الوكيل بالغرض من هذه القيمة.

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

  • بعد تحديد هاتين السمتَين، علينا فقط إرجاعهما.

  • لذا، من خلال إلغاء سمة properties هذه، سننشئ قائمة بها ونعرضها.

  • هذه هي الطريقة التي تخبر بها الوكيل بأنّ هذا هو ما يتعامل معه هذا المكوّن.

  • أجل

  • كما ذكر "نيك"، يتم إرسال تعريفات السمات هذه كجزء من مخطط الكتالوج ليعرف الوكيل كيفية استخدام هذا المكوّن.

  • ولكن هذه السمة، يتم أيضًا استخدام تعريفات السمات نفسها لاستخراج القيم المكتوبة في وقت التشغيل.

  • وبالتالي، هناك مصدر وحيد للحقيقة.

  • لنتعرّف على ما يجب فعله لتنفيذ ذلك.

  • أولاً، للوصول إلى سمة max مثلاً، بما أنّها سمة ثابتة، يعني ذلك أنّ الوكيل يرسل قيمتها مضمّنة في عنصر السمات.

  • لذا، للوصول إليه، نحتاج فقط إلى الحصول عليه من كائن الخصائص من خلال الإشارة إليه باستخدام كائن خاصية proper- max كمفتاح.

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

  • الشيء التالي هو خاصية القيمة.

  • بما أنّ سمة القيمة هي سمة ديناميكية، يعني ذلك أنّها تشير إلى عنصر في نموذج البيانات.

  • للوصول إليها، نحتاج إلى استخدام واجهة برمجة التطبيقات properties.bind وتمرير عنصر السمة كمفتاح كمعلمة.

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

  • وبالتالي، كلما تم تعديل نموذج البيانات، ستتم إعادة إنشاء هذا المكوّن تلقائيًا.

  • لذلك، وبالمثل، قمنا أيضًا بالتحويل إلى int وقمنا بتعيين بعض الإعدادات الافتراضية.

  • هناك شيء آخر نحتاج إلى القيام به وهو إعداد الربط ثنائي الاتجاه حتى نتمكن من تغيير التقييم.

  • لإجراء ذلك، نستخدم واجهة برمجة التطبيقات bindUpdater.

  • نمرر نفس كائن الخاصية الذي يحدد الخاصية، ونتيجة لذلك، نحصل على So، يقوم bindUpdater بإرجاع دالة lambda التي تسمح لنا بتغيير قيمة هذه الخاصية في نموذج البيانات.

  • نحن الآن جاهزون لإصدار مكوّن التقييم بالنجوم.

  • حسنًا

  • بعد أن حدّدنا المكوّن المخصّص، علينا إضافته إلى الكتالوج الذي نستخدمه.

  • في السابق، كنا نستخدم الكتالوج الأساسي كما هو.

  • لذا، ما نحتاج إلى فعله الآن هو إنشاء كتالوج جديد، والذي سيأخذ كل الكتالوج الأساسي ويضيفه إلى المكون المخصص لدينا.

  • لذلك، يتم تحديد الكتالوج من خلال ثلاثة عناصر.

  • وهو عبارة عن معرّف ومجموعة من المكوّنات ومجموعة من الدوال.

  • بالنسبة إلى المعرّف، سنستخدم معرّف موارد منتظم (URI) لتحديد الكتالوج الذي يحدّد بشكل فريد بالإضافة إلى الإصدار الذي نعمل عليه.

  • وبالنسبة إلى المكوّنات، سنأخذ جميع المكوّنات من الكتالوج الأساسي، ثم سنستخدم عامل الإضافة لإضافة المكوّن المخصّص الذي أنشأناه للتو.

  • وبالنسبة إلى الدوال، سنستخدم الدوال من الكتالوج الأساسي.

  • وهكذا، نكون قد وسّعنا الكتالوج الأساسي لإضافة نوع المكوّن المخصّص الجديد.

  • كما ترى، من السهل جدًا إنشاء كتالوج مخصّص.

  • وبالتالي، يتعرّف الوكيل على كيفية استخدام الكتالوج من تعليمات النظام التي نرسلها إليه.

  • بما أنّنا أنشأنا الآن كتالوجًا مخصّصًا، لنعدّل أيضًا تعليمات النظام.

  • لذا، سنمرّر عنصر الكتالوج إلى الدالة التي تنشئ تعليمات النظام.

  • إليكم ما توصّلنا إليه.

  • حتى الآن، كنا نرسل تعريفًا ثابتًا للمخطط الخاص بالكتالوج الأساسي لأننا كنا نستخدم هذا الكتالوج العادي.

  • بعد أن أصبح لدينا كتالوج مخصّص، يمكننا إنشاء المخطط ديناميكيًا باستخدام الدالة toJsonSchemaString.

  • سيؤدي ذلك إلى إنشاء تمثيل JSON كامل لهذا الكتالوج، بما في ذلك مكوّن التقييم بالنجوم الذي أضفناه للتو.

  • تتضمّن تعليمات النظام أيضًا بعض الأمثلة على الردود التي يمكن للوكيل استخدامها.

  • لذلك، نغيّر أيضًا معرّف الكتالوج هنا، لكي تشير الأمثلة إلى الكتالوج الصحيح.

  • حسنًا

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

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

  • بعد ذلك، يردّ الوكيل.

  • وهنا، يمكنك أن ترى أن مكوّن النجمة هذا هو هذا المكوّن الجديد تمامًا الذي لم يره الوكيل أبدًا حتى قمنا بتنفيذه الآن.

  • هذا ليس جزءًا من الكتالوج الأساسي، لقد أنشأنا هذا للتو.

  • عند النقر على النجمة، يتم استدعاء دالة lambda bindUpdater ويتم تعديل القيمة في نموذج البيانات.

  • وإذا أرسلنا التقييمات، يمكننا إلقاء نظرة على الإجراء وسيتضمن سياق الإجراء القيم التي حددناها للتو.

  • حسنًا، لنعد الآن إلى الشرائح.

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

النقاط الرئيسية المستخلصة والمراجع

  • نأمل أن نكون قد أوضحنا لك أنّ عملية الدمج سهلة للغاية.

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

  • نأمل أن نكون قد أوضحنا أنّ المكتبة تقدّم الكثير من الميزات الجاهزة للاستخدام، مثل العرض التدريجي أو التحقّق من صحة المخطط، وحلقات التصحيح الذاتي أو معالجة الأخطاء، وغيرها الكثير.

  • نأمل أن نكون قد أثبتنا اليوم بسرعة أنّه من السهل جدًا تخصيصها.

  • لقد أوضحنا كيف يستجيب الكتالوج الأساسي بالفعل لتخصيص التصميم المتعدد الأبعاد إذا كنت تستخدم التصميم المتعدد الأبعاد، ولكن من السهل حقًا توسيع أو استبدال المكونات داخل الكتالوج.

  • ولكن أعتقد أنّ بعضًا من أقوى الميزات تأتي من إنشاء الكتالوج الخاص بك.

  • إذا أردت التحكّم بشكل أكبر في واجهة المستخدم التي يمكن للوكيل استخدامها، يمكنك إنشاء مكوّنات مخصّصة بالكامل.

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

  • إذا كنت تريد المزيد من التحكم، يمكنك إنشاء مكونات أكثر تفصيلاً والقول، "هذه هي الأشياء الوحيدة التي يمكنك استخدامها".

  • وبالتالي، يمكنك التحكّم في ما يمكن للوكيل تنفيذه وعرضه للمستخدمين.

  • هذه هي مكتبة العرض الجديدة A2UI ومكتبة Jetpack التي أطلقناها للتو.

    implementation("androidx.compose.material3:material3-a2ui:1.0.0-alpha02")
  • وهو حاليًا في مرحلة الإصدار الأوّلي، وقد تم طرح الإصدار الأوّلي 02 مؤخرًا.

  • لذا، يمكنك الاطّلاع على هذه الروابط.

  • لدينا مستندات على developer.android.com، بالإضافة إلى بعض النماذج.

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

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

  • لذا يُرجى الاطّلاع على المكتبة وإرسال ملاحظاتك إلينا.

  • وهذا ما حصلنا عليه.

  • ولا يسعني الانتظار لرؤية ما ستبتكره أنت ووكلاؤك باستخدامه.

  • شكرًا جزيلاً.

  • شكرًا لك.

الرمز

مقتطفات الرمز البرمجي

مقتطف Kotlin Script في الدقيقة 27:40 في "الاستنتاجات والمراجع الرئيسية"
implementation("androidx.compose.material3:material3-a2ui:1.0.0-alpha02")