إنشاء تطبيق Flutter مزوّد بخدمة Gemini

إنشاء تطبيق Flutter مزوّد بخدمة Gemini

لمحة عن هذا الدرس التطبيقي حول الترميز

subjectتاريخ التعديل الأخير: مايو 19, 2025
account_circleتأليف: Brett Morgan

1. إنشاء تطبيق Flutter مزوّد بخدمة Gemini

ما ستُنشئه

في هذا الدليل التعليمي حول الرموز البرمجية، ستُنشئ تطبيق Colorist التفاعلي الذي يقدّم إمكانات Gemini API مباشرةً في تطبيقك المكتوب بلغة Flutter. هل أردت يومًا السماح للمستخدمين بالتحكم في تطبيقك باستخدام لغة طبيعية ولكنك لم تكن تعرف من أين تبدأ؟ يوضّح لك هذا الدليل التعليمي كيفية إجراء ذلك.

يتيح تطبيق Colorist للمستخدمين وصف الألوان بلغة طبيعية (مثل "البرتقالي لغروب الشمس" أو "الأزرق الداكن للمحيط")، ويعمل التطبيق على ما يلي:

  • معالجة هذه الأوصاف باستخدام واجهة برمجة التطبيقات Gemini API من Google
  • تفسير الأوصاف إلى قيم ألوان دقيقة بالنموذج اللوني أحمر أخضر أزرق
  • عرض اللون على الشاشة في الوقت الفعلي
  • توفّر تفاصيل فنية عن اللون وسياقًا مثيرًا للاهتمام حوله
  • الاحتفاظ بسجلّ للألوان التي تم إنشاؤها مؤخرًا

لقطة شاشة لتطبيق Colorist تعرض شاشة الألوان وواجهة المحادثة

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

أهمية ذلك لمطوّري Flutter

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

رحلة التعلّم الخاصة بك

يرشدك هذا الدرس التطبيقي حول الترميز إلى كيفية إنشاء Colorist خطوة بخطوة:

  1. إعداد المشروع: ستبدأ ببنية تطبيق Flutter أساسية وحزمة colorist_ui.
  2. التكامل الأساسي مع Gemini: يمكنك ربط تطبيقك بخدمة Vertex AI في Firebase وتنفيذ عملية تواصل بسيطة مع النموذج اللغوي الكبير.
  3. طلبات فعّالة: أنشئ طلبًا من النظام يوجّه النموذج اللغوي الكبير إلى فهم أوصاف الألوان
  4. إعلانات الدوالّ: لتحديد الأدوات التي يمكن لنظام إدارة التعلم (LLM) استخدامها لضبط الألوان في تطبيقك
  5. معالجة الأداة: معالجة طلبات استدعاء الدوالّ من نموذج اللغة القليلة اللفظ وربطها بحالة تطبيقك
  6. عرض الردود تدريجيًا: يمكنك تحسين تجربة المستخدم من خلال عرض الردود من نماذج اللغة الكبيرة (LLM) تدريجيًا في الوقت الفعلي.
  7. مزامنة سياق النموذج اللغوي الكبير: يمكنك إنشاء تجربة متماسكة من خلال إبلاغ النموذج اللغوي الكبير بإجراءات المستخدمين.

المُعطيات

  • ضبط Vertex AI في Firebase لتطبيقات Flutter
  • صياغة طلبات نظام فعّالة لتوجيه سلوك النماذج اللغوية الكبيرة
  • تنفيذ تعريفات الدوالّ التي تربط بين اللغة الطبيعية وميزات التطبيق
  • معالجة الردود على أحداث البث لتوفير تجربة مستخدم سريعة الاستجابة
  • مزامنة الحالة بين أحداث واجهة المستخدم ونموذج اللغة الكبير
  • إدارة حالة المحادثة في نموذج اللغة الكبيرة باستخدام Riverpod
  • التعامل مع الأخطاء بشكلٍ آمن في التطبيقات المستندة إلى نموذج اللغة الكبير

معاينة الرمز البرمجي: لمحة عن ما سيتم تنفيذه

في ما يلي لمحة عن بيان الدالة الذي ستُنشئه للسماح لنموذج "التعلم الآلي للصور" بضبط الألوان في تطبيقك:

FunctionDeclaration get setColorFuncDecl => FunctionDeclaration(
  'set_color',
  'Set the color of the display square based on red, green, and blue values.',
  parameters: {
    'red': Schema.number(description: 'Red component value (0.0 - 1.0)'),
    'green': Schema.number(description: 'Green component value (0.0 - 1.0)'),
    'blue': Schema.number(description: 'Blue component value (0.0 - 1.0)'),
  },
);

فيديو يقدّم نظرة عامة على هذا الدرس التطبيقي حول الترميز

يمكنك مشاهدة Craig Labenz وAndrew Brogdon وهما يناقشان هذا الدليل التعليمي في الحلقة 59 من Observable Flutter:

المتطلبات الأساسية

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

  • خبرة في تطوير Flutter: يجب أن تكون على دراية بأساسيات Flutter وبنية Dart
  • معرفة البرمجة غير المتزامنة: فهم Futures وasync/await وstreams
  • حساب Firebase: ستحتاج إلى حساب Google لإعداد Firebase.
  • مشروع على Firebase تم تفعيل ميزة الفوترة فيه: تتطلّب خدمة Vertex AI في Firebase حساب فوترة.

لنبدأ بإنشاء تطبيقك الأول المستنِد إلى نموذج اللغة الكبير (LLM) باستخدام Flutter.

2. إعداد المشروع وخدمة الصدى

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

ما ستتعرّف عليه في هذه الخطوة

  • إعداد مشروع Flutter باستخدام التبعيات المطلوبة
  • العمل مع حزمة colorist_ui لمكونات واجهة المستخدم
  • تنفيذ خدمة رسائل صدى وربطها بواجهة المستخدم

ملاحظة مهمة حول الأسعار

إنشاء مشروع جديد باستخدام Flutter

ابدأ بإنشاء مشروع Flutter جديد باستخدام الأمر التالي:

flutter create -e colorist --platforms=android,ios,macos,web,windows

تشير علامة -e إلى أنّك تريد إنشاء مشروع فارغ بدون تطبيق counter التلقائي. تم تصميم التطبيق للعمل على أجهزة الكمبيوتر المكتبي والأجهزة الجوّالة والويب. يُرجى العِلم أنّ flutterfire لا يتوافق مع نظام التشغيل Linux في الوقت الحالي.

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

انتقِل إلى دليل مشروعك وأضِف التبعيات المطلوبة:

cd colorist
flutter pub add colorist_ui flutter_riverpod riverpod_annotation
flutter pub add
--dev build_runner riverpod_generator riverpod_lint json_serializable custom_lint

سيؤدي ذلك إلى إضافة الحِزم الرئيسية التالية:

  • colorist_ui: حزمة مخصّصة توفّر عناصر واجهة المستخدم لتطبيق Colorist
  • flutter_riverpod وriverpod_annotation: لإدارة الحالة
  • logging: لتسجيل البيانات بشكل منظَّم
  • تبعيات التطوير لإنشاء الرموز البرمجية وفحصها

سيظهر pubspec.yaml بالشكل التالي:

pubspec.yaml

name: colorist
description: "A new Flutter project."
publish_to: 'none'
version: 0.1.0

environment:
  sdk: ^3.8.0

dependencies:
  flutter:
    sdk: flutter
  colorist_ui: ^0.2.3
  flutter_riverpod: ^2.6.1
  riverpod_annotation: ^2.6.1

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^5.0.0
  build_runner: ^2.4.15
  riverpod_generator: ^2.6.5
  riverpod_lint: ^2.6.5
  json_serializable: ^6.9.5
  custom_lint: ^0.7.5

flutter:
  uses-material-design: true

ضبط خيارات التحليل

أضِف custom_lint إلى ملف analysis_options.yaml في جذر مشروعك:

include: package:flutter_lints/flutter.yaml

analyzer:
  plugins:
    - custom_lint

يُفعِّل هذا الإعداد أدوات فحص الأخطاء الخاصة بـ Riverpod للمساعدة في الحفاظ على جودة الرموز البرمجية.

تنفيذ ملف main.dart

استبدِل محتوى lib/main.dart بما يلي:

lib/main.dart

import 'package:colorist_ui/colorist_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() async {
 
runApp(ProviderScope(child: MainApp()));
}

class MainApp extends ConsumerWidget {
 
const MainApp({super.key});

 
@override
 
Widget build(BuildContext context, WidgetRef ref) {
   
return MaterialApp(
     
theme: ThemeData(
       
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
     
),
     
home: MainScreen(
       
sendMessage: (message) {
         
sendMessage(message, ref);
       
},
     
),
   
);
 
}

 
// A fake LLM that just echoes back what it receives.
 
void sendMessage(String message, WidgetRef ref) {
   
final chatStateNotifier = ref.read(chatStateNotifierProvider.notifier);
   
final logStateNotifier = ref.read(logStateNotifierProvider.notifier);

   
chatStateNotifier.addUserMessage(message);
   
logStateNotifier.logUserText(message);
   
chatStateNotifier.addLlmMessage(message, MessageState.complete);
   
logStateNotifier.logLlmText(message);
 
}
}

يؤدي ذلك إلى إعداد تطبيق Flutter لتنفيذ خدمة صدى بسيطة تحاكي سلوك نموذج اللغة الكبير من خلال إعادة رسالة المستخدم ببساطة.

فهم البنية

لنلقِ نظرة على بنية تطبيق colorist:

حزمة colorist_ui

توفّر حزمة colorist_ui مكونات واجهة مستخدِم مُعدّة مسبقًا وأدوات لإدارة الحالات:

  1. MainScreen: مكوّن واجهة المستخدِم الرئيسي الذي يعرض ما يلي:
    • تنسيق تقسيم الشاشة على الكمبيوتر المكتبي (منطقة التفاعل ولوحة السجلّ)
    • واجهة تنقّل بين علامات تبويب على الأجهزة الجوّالة
    • شاشة ملونة وواجهة المحادثة والصور المصغّرة للسجلّ
  2. إدارة الحالة: يستخدم التطبيق عدة أدوات إشعار بالحالة:
    • ChatStateNotifier: يدير رسائل المحادثة
    • ColorStateNotifier: يدير اللون الحالي والسجلّ
    • LogStateNotifier: يدير إدخالات السجلّ لتصحيح الأخطاء
  3. معالجة الرسائل: يستخدم التطبيق نموذج رسالة بحالات مختلفة:
    • رسائل المستخدم: التي يُدخلها المستخدم
    • رسائل النماذج اللغوية الكبيرة: يتم إنشاؤها بواسطة النموذج اللغوي الكبير (أو خدمة الصدى في الوقت الحالي)
    • MessageState: تتتبّع ما إذا كانت رسائل LLM مكتملة أو لا تزال يتم بثها

بنية التطبيق

يتّبع التطبيق البنية التالية:

  1. طبقة واجهة المستخدم: تقدّمها حزمة colorist_ui
  2. إدارة الحالة: يستخدم Riverpod لإدارة الحالة التفاعلية
  3. طبقة الخدمة: تحتوي حاليًا على خدمة صدى بسيطة، وسيتم استبدالها بخدمة Gemini Chat
  4. دمج LLM: ستتم إضافته في الخطوات اللاحقة

يتيح لك هذا الفصل التركيز على تنفيذ عملية دمج نموذج "التعلم الآلي للترجمة" مع الاهتمام بمكونات واجهة المستخدم.

تشغيل التطبيق

شغِّل التطبيق باستخدام الأمر التالي:

flutter run -d DEVICE

استبدِل DEVICE بالجهاز المستهدَف، مثل macos أو windows أو chrome أو رقم تعريف الجهاز.

لقطة شاشة لتطبيق Colorist تعرِض تنسيق Markdown الذي تُنشئه خدمة Echo

من المفترض أن يظهر لك الآن تطبيق Colorist مع ما يلي:

  1. منطقة عرض ملوّنة بلون تلقائي
  2. واجهة محادثة يمكنك من خلالها كتابة الرسائل
  3. لوحة سجلّ تعرض تفاعلات المحادثة

جرِّب كتابة رسالة مثل "أريد لونًا أزرق داكنًا" واضغط على "إرسال". ستعيد خدمة "الردّ" رسالتك ببساطة. في الخطوات اللاحقة، ستستبدل ذلك بتفسير اللون الفعلي باستخدام Gemini API من خلال Vertex AI في Firebase.

ما هي الخطوات التالية؟

في الخطوة التالية، عليك ضبط Firebase وتنفيذ عملية الدمج الأساسية لواجهة برمجة التطبيقات Gemini API لاستبدال خدمة صدى الصوت بخدمة محادثات Gemini. سيتيح ذلك للتطبيق تفسير أوصاف الألوان وتقديم ردود ذكية.

تحديد المشاكل وحلّها

مشاكل حزمة واجهة المستخدم

إذا واجهت مشاكل في حزمة colorist_ui:

  • تأكَّد من استخدام أحدث إصدار.
  • التأكّد من إضافة التبعية بشكل صحيح
  • البحث عن أي إصدارات حِزم متعارضة

أخطاء الإصدار

إذا ظهرت لك أخطاء في عملية الإنشاء:

  • تأكَّد من تثبيت أحدث إصدار من حزمة تطوير البرامج (SDK) في قناة Flutter الثابتة.
  • تشغيل flutter clean متبوعًا بـ flutter pub get
  • التحقّق من إخراج وحدة التحكّم بحثًا عن رسائل خطأ معيّنة

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

  • إعداد مشروع Flutter باستخدام التبعيات اللازمة
  • فهم بنية التطبيق ومسؤوليات المكوّنات
  • تنفيذ خدمة بسيطة تحاكي سلوك نموذج لغوي كبير
  • ربط الخدمة بمكونات واجهة المستخدم
  • استخدام Riverpod لإدارة الحالة

3. الدمج الأساسي لمحادثات Gemini

في هذه الخطوة، ستستبدل خدمة الصدى من الخطوة السابقة بدمج Gemini API باستخدام Vertex AI في Firebase. ستضبط Firebase، وتُعدّ مقدّمي الخدمات الضروريين، وتنفّذ خدمة محادثة أساسية تتواصل مع Gemini API.

ما ستتعرّف عليه في هذه الخطوة

  • إعداد Firebase في تطبيق Flutter
  • ضبط Vertex AI في Firebase للوصول إلى Gemini
  • إنشاء مقدّمي خدمات Riverpod لخدمات Firebase وGemini
  • تنفيذ خدمة محادثة أساسية باستخدام Gemini API
  • التعامل مع حالات الأخطاء والردود غير المتزامنة من واجهة برمجة التطبيقات

إعداد Firebase

أولاً، عليك إعداد Firebase لمشروعك على Flutter. يشمل ذلك إنشاء مشروع على Firebase وإضافة تطبيقك إليه وضبط إعدادات Vertex AI اللازمة.

إنشاء مشروع على Firebase

  1. انتقِل إلى Firebase Console وسجِّل الدخول باستخدام حسابك على Google.
  2. انقر على إنشاء مشروع على Firebase أو اختَر مشروعًا حاليًا.
  3. اتّبِع خطوات معالج الإعداد لإنشاء مشروعك.
  4. بعد إنشاء مشروعك، عليك الترقية إلى خطة Blaze (الدفع حسب الاستخدام) للوصول إلى خدمات Vertex AI. انقر على الزر ترقية في أسفل يمين وحدة تحكّم Firebase.

إعداد Vertex AI في مشروعك على Firebase

  1. في "وحدة تحكّم Firebase"، انتقِل إلى مشروعك.
  2. في الشريط الجانبي الأيمن، اختَر AI.
  3. في بطاقة Vertex AI في Firebase، انقر على البدء.
  4. اتّبِع التعليمات لتفعيل Vertex AI في واجهات برمجة تطبيقات Firebase لمشروعك.

تثبيت واجهة سطر أوامر FlutterFire

تعمل أداة FlutterFire CLI على تبسيط عملية إعداد Firebase في تطبيقات Flutter:

dart pub global activate flutterfire_cli

إضافة Firebase إلى تطبيقك المكتوب باستخدام Flutter

  1. أضِف حِزم Firebase core وVertex AI إلى مشروعك:
flutter pub add firebase_core firebase_vertexai
  1. نفِّذ أمر ضبط FlutterFire:
flutterfire configure

سيؤدي هذا الأمر إلى:

  • سيُطلب منك اختيار مشروع Firebase الذي أنشأته للتو.
  • تسجيل تطبيقاتك المبرمَجة باستخدام Flutter في Firebase
  • إنشاء ملف firebase_options.dart يتضمّن إعدادات مشروعك

سيرصد الأمر تلقائيًا الأنظمة الأساسية التي اخترتها (iOS وAndroid وmacOS وWindows والويب) ويضبطها بشكلٍ مناسب.

الإعدادات الخاصة بالمنصة

تتطلّب Firebase استخدام إصدارات أحدث من الحد الأدنى لإصدارات Flutter التلقائية. وتتطلّب أيضًا إمكانية الوصول إلى الشبكة للتواصل مع Vertex AI في خوادم Firebase.

ضبط أذونات macOS

بالنسبة إلى نظام التشغيل macOS، عليك تفعيل إذن الوصول إلى الشبكة في أذونات تطبيقك:

  1. افتح macos/Runner/DebugProfile.entitlements وأضِف ما يلي:

macos/Runner/DebugProfile.entitlements

<key>com.apple.security.network.client</key>
<true/>
  1. افتح أيضًا macos/Runner/Release.entitlements وأضِف الإدخال نفسه.
  2. عدِّل الحد الأدنى لإصدار macOS في أعلى macos/Podfile:

macos/Podfile

# Firebase requires at least macOS 10.15
platform
:osx, '10.15'

ضبط أذونات iOS

بالنسبة إلى أجهزة iOS، عدِّل الحدّ الأدنى للإصدار في أعلى ios/Podfile:

ios/Podfile

# Firebase requires at least iOS 13.0
platform
:ios, '13.0'

ضبط إعدادات Android

بالنسبة إلى Android، يُرجى تحديث android/app/build.gradle.kts:

android/app/build.gradle.kts

android {
   
// ...
    ndkVersion
= "27.0.12077973"

    defaultConfig
{
       
// ...
        minSdk
= 23
       
// ...
   
}
}

إنشاء مقدّمي نماذج Gemini

ستنشئ الآن مقدّمي خدمات Riverpod لكلّ من Firebase وGemini. إنشاء ملف جديد lib/providers/gemini.dart:

lib/providers/gemini.dart

import 'dart:async';

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_vertexai/firebase_vertexai.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../firebase_options.dart';

part 'gemini.g.dart';

@riverpod
Future<FirebaseApp> firebaseApp(Ref ref) =>
   
Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);

@riverpod
Future<GenerativeModel> geminiModel(Ref ref) async {
 
await ref.watch(firebaseAppProvider.future);

 
final model = FirebaseVertexAI.instance.generativeModel(
   
model: 'gemini-2.0-flash',
 
);
 
return model;
}

@Riverpod(keepAlive: true)
Future<ChatSession> chatSession(Ref ref) async {
 
final model = await ref.watch(geminiModelProvider.future);
 
return model.startChat();
}

يحدِّد هذا الملف الأساس لثلاثة مقدّمي خدمات مفاتيح التشفير. يتم إنشاء مقدّمي الخدمة هؤلاء عند تشغيل dart run build_runner بواسطة أدوات إنشاء الرموز البرمجية في Riverpod.

  1. firebaseAppProvider: لإعداد Firebase باستخدام إعدادات مشروعك
  2. geminiModelProvider: لإنشاء مثيل نموذج توليدي في Gemini
  3. chatSessionProvider: لإنشاء جلسة محادثة مع نموذج Gemini والحفاظ عليها

يضمن التعليق التوضيحي keepAlive: true في جلسة المحادثة استمرارها طوال دورة حياة التطبيق، مع الحفاظ على سياق المحادثة.

تنفيذ خدمة Gemini Chat

أنشئ ملفًا جديدًا lib/services/gemini_chat_service.dart لتنفيذ خدمة المحادثة:

lib/services/gemini_chat_service.dart

import 'dart:async';

import 'package:colorist_ui/colorist_ui.dart';
import 'package:firebase_vertexai/firebase_vertexai.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../providers/gemini.dart';

part 'gemini_chat_service.g.dart';

class GeminiChatService {
 
GeminiChatService(this.ref);
 
final Ref ref;

 
Future<void> sendMessage(String message) async {
   
final chatSession = await ref.read(chatSessionProvider.future);
   
final chatStateNotifier = ref.read(chatStateNotifierProvider.notifier);
   
final logStateNotifier = ref.read(logStateNotifierProvider.notifier);

   
chatStateNotifier.addUserMessage(message);
   
logStateNotifier.logUserText(message);
   
final llmMessage = chatStateNotifier.createLlmMessage();
   
try {
     
final response = await chatSession.sendMessage(Content.text(message));

     
final responseText = response.text;
     
if (responseText != null) {
       
logStateNotifier.logLlmText(responseText);
       
chatStateNotifier.appendToMessage(llmMessage.id, responseText);
     
}
   
} catch (e, st) {
     
logStateNotifier.logError(e, st: st);
     
chatStateNotifier.appendToMessage(
       
llmMessage.id,
       
"\nI'm sorry, I encountered an error processing your request. "
       
"Please try again.",
     
);
   
} finally {
     
chatStateNotifier.finalizeMessage(llmMessage.id);
   
}
 
}
}

@riverpod
GeminiChatService geminiChatService(Ref ref) => GeminiChatService(ref);

تشمل هذه الخدمة ما يلي:

  1. قبول رسائل المستخدمين وإرسالها إلى Gemini API
  2. تعديل واجهة المحادثة باستخدام الردود الواردة من النموذج
  3. تسجيل جميع المراسلات لتسهيل فهم مسار نموذج اللغة الضخمة
  4. معالجة الأخطاء من خلال ملاحظات المستخدمين المناسبة

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

إنشاء رمز Riverpod

شغِّل الأمر build runner لإنشاء رمز Riverpod اللازم:

dart run build_runner build --delete-conflicting-outputs

سيؤدي ذلك إلى إنشاء ملفات .g.dart التي يحتاج إليها Riverpod للعمل.

تعديل ملف main.dart

تعديل ملف lib/main.dart لاستخدام خدمة المحادثة الجديدة Gemini Chat:

lib/main.dart

import 'package:colorist_ui/colorist_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'providers/gemini.dart';
import 'services/gemini_chat_service.dart';

void main() async {
 
runApp(ProviderScope(child: MainApp()));
}

class MainApp extends ConsumerWidget {
 
const MainApp({super.key});

 
@override
 
Widget build(BuildContext context, WidgetRef ref) {
   
final model = ref.watch(geminiModelProvider);

   
return MaterialApp(
     
theme: ThemeData(
       
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
     
),
     
home: model.when(
       
data: (data) => MainScreen(
         
sendMessage: (text) {
           
ref.read(geminiChatServiceProvider).sendMessage(text);
         
},
       
),
       
loading: () => LoadingScreen(message: 'Initializing Gemini Model'),
       
error: (err, st) => ErrorScreen(error: err),
     
),
   
);
 
}
}

في ما يلي التغييرات الرئيسية في هذا التعديل:

  1. استبدال خدمة صدى الصوت بخدمة محادثات مستندة إلى Gemini API
  2. إضافة شاشات التحميل والأخطاء باستخدام نمط AsyncValue في Riverpod مع طريقة when
  3. ربط واجهة المستخدم بخدمة المحادثة الجديدة من خلال طلب sendMessage

تشغيل التطبيق

شغِّل التطبيق باستخدام الأمر التالي:

flutter run -d DEVICE

استبدِل DEVICE بالجهاز المستهدَف، مثل macos أو windows أو chrome أو رقم تعريف الجهاز.

لقطة شاشة لتطبيق Colorist تعرض النموذج اللغوي الكبير (LLM) في Gemini وهو يردّ على طلب للحصول على لون أصفر مشمس

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

فهم تواصل النماذج اللغوية الكبيرة

لنلقِ نظرة على ما يحدث عند التواصل مع Gemini API:

مسار التواصل

  1. مدخلات المستخدم: يُدخل المستخدم نصًا في واجهة المحادثة.
  2. تنسيق الطلب: يُعدِّل التطبيق النص كعنصر Content لواجهة برمجة التطبيقات Gemini API.
  3. التواصل مع واجهة برمجة التطبيقات: يتم إرسال النص إلى Gemini API من خلال Vertex AI في Firebase.
  4. معالجة النموذج اللغوي الكبير: يعالج نموذج Gemini النص وينشئ ردًا.
  5. معالجة الردّ: يتلقّى التطبيق الردّ ويُعدّل واجهة المستخدم.
  6. التسجيل: يتم تسجيل جميع المراسلات من أجل الشفافية

جلسات المحادثة وسياق المحادثة

تحافظ جلسة المحادثة في Gemini على السياق بين الرسائل، ما يتيح إجراء تفاعلات في المحادثات. وهذا يعني أنّ نموذج اللغة الكبيرة "يتذكر" التبادلات السابقة في الجلسة الحالية، ما يتيح إجراء محادثات أكثر اتساقًا.

يضمن التعليق التوضيحي keepAlive: true في مقدّم جلسة المحادثة استمرار هذا السياق طوال دورة حياة التطبيق. وهذا السياق الدائم مهم للحفاظ على سير المحادثة بشكل طبيعي مع نموذج اللغة الكبيرة.

ما هي الخطوات التالية؟

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

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

تحديد المشاكل وحلّها

مشاكل في إعدادات Firebase

إذا واجهت أخطاء في عملية إعداد Firebase:

  • التأكّد من إنشاء ملف firebase_options.dart بشكل صحيح
  • التأكّد من أنّك أجريت ترقية إلى خطة Blaze للوصول إلى Vertex AI

أخطاء الوصول إلى واجهة برمجة التطبيقات

إذا ظهرت لك أخطاء عند الوصول إلى Gemini API:

  • التأكّد من إعداد الفوترة بشكلٍ صحيح في مشروعك على Firebase
  • التأكّد من تفعيل Vertex AI وCloud AI API في مشروعك على Firebase
  • التحقّق من اتصال الشبكة وإعدادات جدار الحماية
  • تأكَّد من أنّ اسم الطراز (gemini-2.0-flash) صحيح ومتاح.

مشاكل سياق المحادثة

إذا لاحظت أنّ Gemini لا يتذكر السياق السابق من المحادثة:

  • تأكَّد من أنّ دالة chatSession مُعلَق عليها تعليقات توضيحية باستخدام @Riverpod(keepAlive: true).
  • تأكَّد من إعادة استخدام جلسة المحادثة نفسها لجميع عمليات تبادل الرسائل.
  • التأكّد من بدء جلسة المحادثة بشكل صحيح قبل إرسال الرسائل

المشاكل المتعلّقة بالمنصة

بالنسبة إلى المشاكل المتعلّقة بالمنصة:

  • ‫iOS/macOS: التأكّد من ضبط الأذونات المناسبة وضبط الحد الأدنى للإصدارات
  • Android: التأكّد من ضبط الحد الأدنى لإصدار حزمة SDK بشكل صحيح
  • الاطّلاع على رسائل الخطأ الخاصة بالنظام الأساسي في وحدة التحكّم

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

  • إعداد Firebase في تطبيق Flutter
  • ضبط Vertex AI في Firebase للوصول إلى Gemini
  • إنشاء موفّري Riverpod للخدمات غير المتزامنة
  • تنفيذ خدمة محادثة تتواصل مع نموذج معالجة لغوية كبيرة
  • التعامل مع حالات واجهة برمجة التطبيقات غير المتزامنة (التحميل والخطأ والبيانات)
  • فهم سير عمل ميزة "الردّ الذكي على المحادثات" وجلسات المحادثة

4. طلبات فعّالة لوصف الألوان

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

ما ستتعرّف عليه في هذه الخطوة

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

فهم طلبات النظام

قبل البدء في التنفيذ، لنلقِ نظرة على طلبات النظام وأهمية استخدامها:

ما هي طلبات النظام؟

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

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

يمكنك اعتبار طلب النظام بمثابة "وصف الوظيفة" لنموذج اللغة الضخمة، فهو يوجّه النموذج إلى كيفية التصرف خلال المحادثة.

أهمية طلبات النظام

إنّ طلبات النظام مهمة لإنشاء تفاعلات مفيدة ومتسقة مع النماذج اللغوية الكبيرة، وذلك لأنّها:

  1. ضمان الاتّساق: يمكنك توجيه النموذج لتقديم الردود بتنسيق متّسق.
  2. تحسين مدى الصلة بالموضوع: يمكنك تركيز النموذج على نطاق معيّن (في حالتك، الألوان).
  3. تحديد الحدود: حدِّد ما يجب أن يفعله النموذج وما لا يجب أن يفعله.
  4. تحسين تجربة المستخدم: أنشئ نمط تفاعل أكثر طبيعية وإفادة.
  5. تقليل عمليات ما بعد المعالجة: يمكنك الحصول على الردود بتنسيقات يسهل تحليلها أو عرضها.

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

إنشاء مادة عرض لطلب النظام

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

أنشئ ملفًا جديدًا assets/system_prompt.md يتضمّن المحتوى التالي:

assets/system_prompt.md

# Colorist System Prompt

You are a color expert assistant integrated into a desktop app called Colorist. Your job is to interpret natural language color descriptions and provide the appropriate RGB values that best represent that description.

## Your Capabilities

You are knowledgeable about colors, color theory, and how to translate natural language descriptions into specific RGB values. When users describe a color, you should:

1. Analyze their description to understand the color they are trying to convey
2. Determine the appropriate RGB values (values should be between 0.0 and 1.0)
3. Respond with a conversational explanation and explicitly state the RGB values

## How to Respond to User Inputs

When users describe a color:

1. First, acknowledge their color description with a brief, friendly response
2. Interpret what RGB values would best represent that color description
3. Always include the RGB values clearly in your response, formatted as: `RGB: (red=X.X, green=X.X, blue=X.X)`
4. Provide a brief explanation of your interpretation

Example:
User: "I want a sunset orange"
You: "Sunset orange is a warm, vibrant color that captures the golden-red hues of the setting sun. It combines a strong red component with moderate orange tones.

RGB: (red=1.0, green=0.5, blue=0.25)

I've selected values with high red, moderate green, and low blue to capture that beautiful sunset glow. This creates a warm orange with a slightly reddish tint, reminiscent of the sun low on the horizon."


## When Descriptions are Unclear

If a color description is ambiguous or unclear, please ask the user clarifying questions, one at a time.

## Important Guidelines

- Always keep RGB values between 0.0 and 1.0
- Always format RGB values as: `RGB: (red=X.X, green=X.X, blue=X.X)` for easy parsing
- Provide thoughtful, knowledgeable responses about colors
- When possible, include color psychology, associations, or interesting facts about colors
- Be conversational and engaging in your responses
- Focus on being helpful and accurate with your color interpretations

فهم بنية طلب النظام

لنوضّح ما يفعله هذا الطلب:

  1. تعريف الدور: يحدّد نموذج اللغة المحوسبة (LLM) كـ "مساعد خبير في الألوان".
  2. شرح المهمة: يحدّد المهمة الأساسية على أنّها تفسير أوصاف الألوان إلى قيم RGB
  3. تنسيق الاستجابة: يحدّد بدقة كيفية تنسيق قيم RGB لتحقيق الاتساق
  4. مثال على عملية التبادل: يوفّر مثالاً ملموسًا على نمط التفاعل المتوقّع
  5. معالجة الحالات الهامشية: تعليمات حول كيفية التعامل مع الأوصاف غير الواضحة
  6. القيود والإرشادات: لضبط الحدود، مثل إبقاء قيم RGB بين 0.0 و1.0

يضمن هذا النهج المُنظَّم أن تكون ردود النماذج اللغوية الكبيرة متسقة ومفيدة ومنسَّقة بطريقة يسهل تحليلها إذا أردت استخراج قيم RGB آليًا.

تعديل pubspec.yaml

الآن، عدِّل الجزء السفلي من pubspec.yaml لتضمين دليل مواد العرض:

pubspec.yaml

flutter:
  uses-material-design: true

  assets:
    - assets/

شغِّل flutter pub get لإعادة تحميل حِزمة مواد العرض.

إنشاء موفِّر طلبات النظام

أنشئ ملفًا جديدًا lib/providers/system_prompt.dart لتحميل طلب النظام:

lib/providers/system_prompt.dart

import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'system_prompt.g.dart';

@riverpod
Future<String> systemPrompt(Ref ref) =>
   
rootBundle.loadString('assets/system_prompt.md');

يستخدم هذا المزوّد نظام تحميل مواد العرض في Flutter لقراءة ملف الطلب أثناء التشغيل.

تعديل موفِّر نموذج Gemini

عدِّل الآن ملف lib/providers/gemini.dart لتضمين طلب النظام:

lib/providers/gemini.dart

import 'dart:async';

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_vertexai/firebase_vertexai.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../firebase_options.dart';
import 'system_prompt.dart';                                          // Add this import

part 'gemini.g.dart';

@riverpod
Future<FirebaseApp> firebaseApp(Ref ref) =>
   
Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);

@riverpod
Future<GenerativeModel> geminiModel(Ref ref) async {
 
await ref.watch(firebaseAppProvider.future);
 
final systemPrompt = await ref.watch(systemPromptProvider.future);  // Add this line

 
final model = FirebaseVertexAI.instance.generativeModel(
   
model: 'gemini-2.0-flash',
   
systemInstruction: Content.system(systemPrompt),                  // And this line
 
);
 
return model;
}

@Riverpod(keepAlive: true)
Future<ChatSession> chatSession(Ref ref) async {
 
final model = await ref.watch(geminiModelProvider.future);
 
return model.startChat();
}

التغيير الرئيسي هو إضافة systemInstruction: Content.system(systemPrompt) عند إنشاء النموذج التوليدي. يطلب هذا من Gemini استخدام تعليماتك كطلب من النظام لجميع التفاعلات في جلسة المحادثة هذه.

إنشاء رمز Riverpod

شغِّل الأمر build runner لإنشاء رمز Riverpod المطلوب:

dart run build_runner build --delete-conflicting-outputs

تشغيل التطبيق واختباره

شغِّل تطبيقك الآن:

flutter run -d DEVICE

لقطة شاشة لتطبيق Colorist تعرض ردًا من نموذج اللغة الكبيرة (LLM) في Gemini بأسلوب كتابة مناسبة لتطبيق اختيار الألوان

جرِّب اختباره باستخدام أوصاف ألوان مختلفة:

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

من المفترض أن تلاحظ أنّ Gemini يقدّم الآن ردودًا تتضمّن شرحًا للمحادثة حول الألوان بالإضافة إلى قيم RGB منسقة بشكلٍ متّسق. لقد وجّه طلب النظام النموذج اللغوي الكبير (LLM) بفعالية لتقديم نوع الردود التي تحتاج إليها.

حاوِل أيضًا طلب محتوى خارج سياق الألوان. على سبيل المثال، الأسباب الرئيسية لـ "حروب الورد". من المفترض أن تلاحظ اختلافًا عن الخطوة السابقة.

أهمية تصميم الطلبات للمهام المتخصصة

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

تشمل هندسة الطلبات الفعّالة ما يلي:

  1. تعريف واضح للدور: تحديد الغرض من نموذج اللغة القليلة المصادر
  2. تعليمات صريحة: توضّح بالتفصيل كيفية ردّ النموذج اللغوي الكبير
  3. أمثلة محدّدة: عرض شكل الردود الجيدة بدلاً من وصفها فقط
  4. معالجة الحالات الهامشية: توجيه نموذج اللغة الضخمة (LLM) إلى كيفية التعامل مع السيناريوهات المُبهمة
  5. مواصفات التنسيق: التأكّد من تنظيم الردود بطريقة متّسقة وقابلة للاستخدام

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

ما هي الخطوات التالية؟

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

تحديد المشاكل وحلّها

مشاكل في تحميل مواد العرض

إذا واجهت أخطاء في تحميل طلب النظام، اتّبِع الخطوات التالية:

  • تأكَّد من أنّ pubspec.yaml يسرد دليل مواد العرض بشكل صحيح.
  • تأكَّد من أنّ المسار في rootBundle.loadString() يتطابق مع موقع ملفك.
  • تشغيل flutter clean متبوعًا بـ flutter pub get لإعادة تحميل حِزمة مواد العرض

الردود غير المتسقة

إذا لم يتّبع نموذج LLM تعليمات التنسيق بشكلٍ متّسق:

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

تقييد معدّل طلبات البيانات من واجهة برمجة التطبيقات

في حال ظهور أخطاء متعلّقة بتقييد معدّل الإرسال:

  • يُرجى العِلم أنّ خدمة Vertex AI لها حدود استخدام.
  • ننصحك بتنفيذ منطق إعادة المحاولة باستخدام خوارزمية الرقود الأسي الثنائي.
  • التحقّق من "وحدة تحكّم Firebase" بحثًا عن أي مشاكل في الحصة

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

  • فهم دور طلبات النظام وأهميتها في تطبيقات الذكاء الاصطناعي اللغوي
  • إنشاء طلبات فعّالة باستخدام تعليمات وأمثلة وقيود واضحة
  • تحميل طلبات النظام واستخدامها في تطبيق Flutter
  • توجيه سلوك ذاكرة التخزين المؤقت للطبقة العليا للمهام الخاصة بالنطاق
  • استخدام هندسة الطلبات لصياغة ردود النماذج اللغوية الكبيرة

توضِّح هذه الخطوة كيفية إجراء تخصيص كبير لسلوك LLM بدون تغيير الرمز البرمجي، وذلك ببساطة من خلال تقديم تعليمات واضحة في طلب النظام.

5. نماذج تعريف الدوالّ لأدوات المعالجة المحدودة للغة

في هذه الخطوة، ستبدأ في تفعيل Gemini لاتّخاذ إجراء في تطبيقك من خلال تنفيذ تعريفات الدوالّ. تتيح هذه الميزة القوية لنموذج التعلّم الآلي المتقدّم (LLM) عدم اقتراح قيم RGB فحسب، بل ضبطها في واجهة مستخدم تطبيقك من خلال طلبات أدوات مخصّصة. ومع ذلك، ستتطلّب الخطوة التالية الاطّلاع على طلبات LLM التي تم تنفيذها في تطبيق Flutter.

ما ستتعرّف عليه في هذه الخطوة

  • فهم استدعاء دوال النماذج اللغوية الكبيرة ومزاياها لتطبيقات Flutter
  • تحديد نماذج الدوال المستندة إلى المخططات في Gemini
  • دمج تعريفات الدوالّ مع نموذج Gemini
  • تعديل طلب النظام للاستفادة من إمكانات الأداة

فهم استدعاء الدوالّ

قبل تنفيذ تعريفات الدوالّ، لنتعرّف على ماهيتها وسبب أهميتها:

ما هو استدعاء الدالة؟

إنّ استدعاء الدوالّ (يُشار إليه أحيانًا باسم "استخدام الأداة") هو ميزة تسمح للنموذج اللغوي الكبير (LLM) بما يلي:

  1. التعرّف على الحالات التي يمكن فيها للمستخدم الاستفادة من استدعاء وظيفة معيّنة
  2. إنشاء عنصر JSON منظَّم يتضمّن المَعلمات المطلوبة لهذه الدالة
  3. اسمح لتطبيقك بتنفيذ الدالة باستخدام هذه المَعلمات.
  4. تلقّي نتيجة الدالة ودمجها في الاستجابة

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

أهمية استدعاء الدوالّ في تطبيقات Flutter

تُنشئ طلبات الدالة جسرًا قويًا بين اللغة الطبيعية وميزات التطبيق:

  1. الإجراء المباشر: يمكن للمستخدمين وصف ما يريدون بلغة طبيعية، ويردّ التطبيق بإجراءات ملموسة.
  2. الإخراج المنظَّم: يُنشئ النموذج اللغوي الكبير بيانات نظيفة ومنظَّمة بدلاً من نص يحتاج إلى تحليل.
  3. العمليات المعقّدة: تتيح لـ LLM الوصول إلى البيانات الخارجية أو إجراء عمليات حسابية أو تعديل حالة التطبيق.
  4. تجربة مستخدم أفضل: توفّر عملية دمج سلسة بين المحادثة والوظائف

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

تحديد تعريفات الدوالّ

أنشئ ملفًا جديدًا lib/services/gemini_tools.dart لتعريف تعريفات الدوالّ:

lib/services/gemini_tools.dart

import 'package:firebase_vertexai/firebase_vertexai.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'gemini_tools.g.dart';

class GeminiTools {
 
GeminiTools(this.ref);

 
final Ref ref;

 
FunctionDeclaration get setColorFuncDecl => FunctionDeclaration(
   
'set_color',
   
'Set the color of the display square based on red, green, and blue values.',
   
parameters: {
     
'red': Schema.number(description: 'Red component value (0.0 - 1.0)'),
     
'green': Schema.number(description: 'Green component value (0.0 - 1.0)'),
     
'blue': Schema.number(description: 'Blue component value (0.0 - 1.0)'),
   
},
 
);

 
List<Tool> get tools => [
   
Tool.functionDeclarations([setColorFuncDecl]),
 
];
}

@riverpod
GeminiTools geminiTools(Ref ref) => GeminiTools(ref);

فهم تعريفات الدوالّ

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

  1. تسمية الدوالّ: يمكنك تسمية الدالة set_color للإشارة بوضوح إلى الغرض منها.
  2. وصف الدالة: يمكنك تقديم وصف واضح يساعد نموذج اللغة الضخمة على فهم الحالات التي يجب استخدامها فيها.
  3. تعريفات المَعلمات: يمكنك تحديد المَعلمات المنظَّمة مع أوصافها الخاصة:
    • red: المكوّن الأحمر للنموذج اللوني أحمر أخضر أزرق (RGB)، ويتم تحديده كعدد بين 0.0 و1.0
    • green: المكوّن الأخضر للنموذج اللوني أحمر أخضر أزرق، ويتم تحديده كعدد بين 0.0 و1.0
    • blue: المكوّن الأزرق للنموذج اللوني أحمر أخضر أزرق، ويتم تحديده كعدد يتراوح بين 0.0 و1.0
  4. أنواع المخططات: استخدِم Schema.number() للإشارة إلى أنّ هذه قيم رقمية.
  5. مجموعة الأدوات: يمكنك إنشاء قائمة بالأدوات التي تحتوي على بيان الدالة.

يساعد هذا النهج المُنظَّم نموذج المحاكاة القانونية الذكية في Gemini على فهم ما يلي:

  • الحالات التي يجب فيها استدعاء هذه الدالة
  • المَعلمات التي يجب تقديمها
  • القيود التي تنطبق على هذه المَعلمات (مثل نطاق القيمة)

تعديل موفِّر نموذج Gemini

الآن، عدِّل ملف lib/providers/gemini.dart لتضمين تعريفات الدوالّ عند إعداد نموذج Gemini:

lib/providers/gemini.dart

import 'dart:async';

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_vertexai/firebase_vertexai.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../firebase_options.dart';
import '../services/gemini_tools.dart';                              // Add this import
import 'system_prompt.dart';

part 'gemini.g.dart';

@riverpod
Future<FirebaseApp> firebaseApp(Ref ref) =>
   
Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);

@riverpod
Future<GenerativeModel> geminiModel(Ref ref) async {
 
await ref.watch(firebaseAppProvider.future);
 
final systemPrompt = await ref.watch(systemPromptProvider.future);
 
final geminiTools = ref.watch(geminiToolsProvider);                // Add this line

 
final model = FirebaseVertexAI.instance.generativeModel(
   
model: 'gemini-2.0-flash',
   
systemInstruction: Content.system(systemPrompt),
   
tools: geminiTools.tools,                                        // And this line
 
);
 
return model;
}

@Riverpod(keepAlive: true)
Future<ChatSession> chatSession(Ref ref) async {
 
final model = await ref.watch(geminiModelProvider.future);
 
return model.startChat();
}

يتمثل التغيير الرئيسي في إضافة المَعلمة tools: geminiTools.tools عند إنشاء النموذج التوليدي. يُعلِم ذلك Gemini بالوظائف المتاحة له.

تعديل طلب النظام

عليك الآن تعديل طلب النظام لتوجيه نموذج اللغة الضخمة إلى استخدام أداة set_color الجديدة. تعديل assets/system_prompt.md:

assets/system_prompt.md

# Colorist System Prompt

You are a color expert assistant integrated into a desktop app called Colorist. Your job is to interpret natural language color descriptions and set the appropriate color values using a specialized tool.

## Your Capabilities

You are knowledgeable about colors, color theory, and how to translate natural language descriptions into specific RGB values. You have access to the following tool:

`set_color` - Sets the RGB values for the color display based on a description

## How to Respond to User Inputs

When users describe a color:

1. First, acknowledge their color description with a brief, friendly response
2. Interpret what RGB values would best represent that color description
3. Use the `set_color` tool to set those values (all values should be between 0.0 and 1.0)
4. After setting the color, provide a brief explanation of your interpretation

Example:
User: "I want a sunset orange"
You: "Sunset orange is a warm, vibrant color that captures the golden-red hues of the setting sun. It combines a strong red component with moderate orange tones."

[Then you would call the set_color tool with approximately: red=1.0, green=0.5, blue=0.25]

After the tool call: "I've set a warm orange with strong red, moderate green, and minimal blue components that is reminiscent of the sun low on the horizon."

## When Descriptions are Unclear

If a color description is ambiguous or unclear, please ask the user clarifying questions, one at a time.

## Important Guidelines

- Always keep RGB values between 0.0 and 1.0
- Provide thoughtful, knowledgeable responses about colors
- When possible, include color psychology, associations, or interesting facts about colors
- Be conversational and engaging in your responses
- Focus on being helpful and accurate with your color interpretations

في ما يلي التغييرات الرئيسية التي طرأت على طلب النظام:

  1. مقدمة عن الأداة: بدلاً من طلب قيم RGB منسقة، يمكنك الآن إخبار نموذج اللغة الضخم (LLM) بأداة set_color.
  2. العملية المعدَّلة: يمكنك تغيير الخطوة 3 من "تنسيق القيم في الاستجابة" إلى "استخدام الأداة لضبط القيم".
  3. مثال معدَّل: توضّح كيفية تضمين طلب أداة في الردّ بدلاً من نص منسَّق.
  4. إزالة شرط التنسيق: بما أنّك تستخدِم طلبات استدعاء الدوالّ منظَّمة، لم تعُد بحاجة إلى تنسيق نص معيّن.

يوجّه هذا الطلب المعدَّل نموذج اللغة المحوسبة الطويلة (LLM) إلى استخدام طلب الدالة بدلاً من تقديم قيم RGB بتنسيق نصي فقط.

إنشاء رمز Riverpod

شغِّل الأمر build runner لإنشاء رمز Riverpod المطلوب:

dart run build_runner build --delete-conflicting-outputs

تشغيل التطبيق

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

شغِّل تطبيقك:

flutter run -d DEVICE

لقطة شاشة لتطبيق Colorist تعرِض ردًا جزئيًا من النموذج اللغوي الكبير (LLM) في Gemini

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

عملية استدعاء الدالة

لنلقِ نظرة على ما يحدث عندما يستخدم Gemini طلب الوظيفة:

  1. اختيار الدالة: يحدّد نموذج اللغة الكبيرة ما إذا كان سيتم استدعاء دالة استنادًا إلى طلب المستخدم.
  2. إنشاء المَعلمات: تُنشئ لغة النمذجة الكبيرة قيم المَعلمات التي تتوافق مع مخطّط الدالة.
  3. تنسيق طلب استدعاء الدالة: يُرسِل النموذج اللغوي الكبير عنصرًا من عناصر طلب استدعاء الدالة منظَّمًا في استجابته.
  4. معالجة التطبيق: سيتلقّى تطبيقك هذا الطلب وينفذ الدالة ذات الصلة (يتم تنفيذها في الخطوة التالية).
  5. دمج الردود: في المحادثات التي تتضمّن عدّة أدوار، تتوقّع نموذجة اللغة الكبيرة (LLM) عرض نتيجة الدالة.

في الحالة الحالية لتطبيقك، يتم تنفيذ الخطوات الثلاث الأولى، ولكنك لم تنفِّذ بعد الخطوة 4 أو 5 (معالجة طلبات الدالة)، وسيتم تنفيذها في الخطوة التالية.

التفاصيل الفنية: كيفية تحديد Gemini لحالات استخدام الدوالّ

يتخذ Gemini قرارات ذكية بشأن حالات استخدام الدوالّ استنادًا إلى:

  1. نية المستخدِم: ما إذا كان من الأفضل عرض طلب المستخدِم من خلال دالة
  2. مدى صلة الوظيفة: مدى توافق الدوالّ المتاحة مع المهمة
  3. مدى توفّر المَعلمة: ما إذا كان بإمكانها تحديد قيم المَعلمات بثقة
  4. تعليمات النظام: إرشادات من طلب النظام بشأن استخدام الدالة

من خلال تقديم بيانات واضحة عن الدوالّ وتعليمات النظام، يمكنك إعداد Gemini للتعرّف على طلبات أوصاف الألوان باعتبارها فرصًا لاستدعاء الدالة set_color.

ما هي الخطوات التالية؟

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

تحديد المشاكل وحلّها

مشاكل في تعريف الدالة

إذا واجهت أخطاء في تعريفات الدوالّ:

  • التأكّد من تطابق أسماء المَعلمات وأنواعها مع ما هو متوقّع
  • تأكَّد من أنّ اسم الدالة واضح ووصفي.
  • التأكّد من أنّ وصف الوظيفة يوضّح الغرض منها بدقة

مشاكل طلبات النظام

إذا لم تكن ميزة "المعالجة المحدودة للحدود" تحاول استخدام الدالة:

  • تأكَّد من أنّ طلب النظام يوجّه LLM بوضوح إلى استخدام أداة set_color.
  • تأكَّد من أنّ المثال في طلب النظام يوضّح استخدام الدالة.
  • حاوِل جعل تعليمات استخدام الأداة أكثر وضوحًا.

مشاكل عامة

في حال مواجهة مشاكل أخرى:

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

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

  • تحديد تعريفات الدوالّ لتوسيع إمكانات LLM في تطبيقات Flutter
  • إنشاء مخطّطات للمَعلمات من أجل جمع البيانات المنظَّمة
  • دمج تعريفات الدوالّ مع نموذج Gemini
  • تعديل طلبات النظام لتشجيع استخدام الوظائف
  • فهم كيفية اختيار النماذج اللغوية الكبيرة للدوالّ واستدعائها

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

6. تنفيذ معالجة الأداة

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

ما ستتعرّف عليه في هذه الخطوة

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

فهم مسار استدعاء الدالة

قبل التعمّق في التنفيذ، لنفهم مسار استدعاء الدالة بالكامل:

مراحل البث المباشر

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

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

تنفيذ معالِجات الدوالّ

لنعدِّل ملف lib/services/gemini_tools.dart لإضافة معالِجات لطلبات استدعاء الدوالّ:

lib/services/gemini_tools.dart

import 'package:colorist_ui/colorist_ui.dart';
import 'package:firebase_vertexai/firebase_vertexai.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'gemini_tools.g.dart';

class GeminiTools {
 
GeminiTools(this.ref);

 
final Ref ref;

 
FunctionDeclaration get setColorFuncDecl => FunctionDeclaration(
   
'set_color',
   
'Set the color of the display square based on red, green, and blue values.',
   
parameters: {
     
'red': Schema.number(description: 'Red component value (0.0 - 1.0)'),
     
'green': Schema.number(description: 'Green component value (0.0 - 1.0)'),
     
'blue': Schema.number(description: 'Blue component value (0.0 - 1.0)'),
   
},
 
);

 
List<Tool> get tools => [
   
Tool.functionDeclarations([setColorFuncDecl]),
 
];

 
Map<String, Object?> handleFunctionCall(                           // Add from here
   
String functionName,
   
Map<String, Object?> arguments,
 
) {
   
final logStateNotifier = ref.read(logStateNotifierProvider.notifier);
   
logStateNotifier.logFunctionCall(functionName, arguments);
   
return switch (functionName) {
     
'set_color' => handleSetColor(arguments),
     
_ => handleUnknownFunction(functionName),
   
};
 
}

 
Map<String, Object?> handleSetColor(Map<String, Object?> arguments) {
   
final colorStateNotifier = ref.read(colorStateNotifierProvider.notifier);
   
final red = (arguments['red'] as num).toDouble();
   
final green = (arguments['green'] as num).toDouble();
   
final blue = (arguments['blue'] as num).toDouble();
   
final functionResults = {
     
'success': true,
     
'current_color': colorStateNotifier
         
.updateColor(red: red, green: green, blue: blue)
         
.toLLMContextMap(),
   
};

   
final logStateNotifier = ref.read(logStateNotifierProvider.notifier);
   
logStateNotifier.logFunctionResults(functionResults);
   
return functionResults;
 
}

 
Map<String, Object?> handleUnknownFunction(String functionName) {
   
final logStateNotifier = ref.read(logStateNotifierProvider.notifier);
   
logStateNotifier.logWarning('Unsupported function call $functionName');
   
return {
     
'success': false,
     
'reason': 'Unsupported function call $functionName',
   
};
 
}                                                                  // To here.
}

@riverpod
GeminiTools geminiTools(Ref ref) => GeminiTools(ref);

فهم معالجات الدوالّ

لنلقِ نظرة على ما تفعله معالجات الدوالّ هذه:

  1. handleFunctionCall: نظام توجيه مركزي:
    • تسجِّل طلب الدالة للشفافية في لوحة السجلّ
    • تنقل الطلبات إلى معالِج الطلب المناسب استنادًا إلى اسم الدالة.
    • عرض ردّ منظَّم ليتم إرساله مرة أخرى إلى نموذج اللغة القليلة الكلمات
  2. handleSetColor: معالِج محدّد لوظيفة set_color:
    • استخراج قيم RGB من خريطة الوسيطات
    • تحويلها إلى الأنواع المتوقّعة (الأرقام المزدوجة)
    • تعديل حالة ألوان التطبيق باستخدام colorStateNotifier
    • إنشاء استجابة منظَّمة تتضمّن حالة النجاح ومعلومات اللون الحالية
    • تسجيل نتائج الدالة لتصحيح الأخطاء
  3. handleUnknownFunction: معالج احتياطي للوظائف غير المعروفة التي:
    • تسجيل تحذير بشأن الدالة غير المتوافقة
    • عرض ردّ يفيد بحدوث خطأ في "الشبكة المحلية الكبيرة"

وتعدّ الدالة handleSetColor مهمة بشكل خاص لأنّها تُسدّ الفجوة بين فهم اللغة الطبيعية من خلال نموذج اللغة الكبيرة والتغييرات الملموسة في واجهة المستخدم.

تعديل خدمة محادثات Gemini لمعالجة طلبات الدوالّ والردود

الآن، لنعدِّل ملف lib/services/gemini_chat_service.dart لمعالجة طلبات الدوالّ من ردود النموذج اللغوي الكبير (LLM) وإرسال النتائج مرة أخرى إلى النموذج اللغوي الكبير:

lib/services/gemini_chat_service.dart

import 'dart:async';

import 'package:colorist_ui/colorist_ui.dart';
import 'package:firebase_vertexai/firebase_vertexai.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../providers/gemini.dart';
import 'gemini_tools.dart';                                          // Add this import

part 'gemini_chat_service.g.dart';

class GeminiChatService {
 
GeminiChatService(this.ref);
 
final Ref ref;

 
Future<void> sendMessage(String message) async {
   
final chatSession = await ref.read(chatSessionProvider.future);
   
final chatStateNotifier = ref.read(chatStateNotifierProvider.notifier);
   
final logStateNotifier = ref.read(logStateNotifierProvider.notifier);

   
chatStateNotifier.addUserMessage(message);
   
logStateNotifier.logUserText(message);
   
final llmMessage = chatStateNotifier.createLlmMessage();
   
try {
     
final response = await chatSession.sendMessage(Content.text(message));

     
final responseText = response.text;
     
if (responseText != null) {
       
logStateNotifier.logLlmText(responseText);
       
chatStateNotifier.appendToMessage(llmMessage.id, responseText);
     
}

     
if (response.functionCalls.isNotEmpty) {                       // Add from here
       
final geminiTools = ref.read(geminiToolsProvider);
       
final functionResultResponse = await chatSession.sendMessage(
         
Content.functionResponses([
           
for (final functionCall in response.functionCalls)
             
FunctionResponse(
               
functionCall.name,
               
geminiTools.handleFunctionCall(
                 
functionCall.name,
                 
functionCall.args,
               
),
             
),
         
]),
       
);
       
final responseText = functionResultResponse.text;
       
if (responseText != null) {
         
logStateNotifier.logLlmText(responseText);
         
chatStateNotifier.appendToMessage(llmMessage.id, responseText);
       
}
     
}                                                              // To here.
   
} catch (e, st) {
     
logStateNotifier.logError(e, st: st);
     
chatStateNotifier.appendToMessage(
       
llmMessage.id,
       
"\nI'm sorry, I encountered an error processing your request. "
       
"Please try again.",
     
);
   
} finally {
     
chatStateNotifier.finalizeMessage(llmMessage.id);
   
}
 
}
}

@riverpod
GeminiChatService geminiChatService(Ref ref) => GeminiChatService(ref);

فهم سير عملية التواصل

الإضافة الرئيسية هنا هي المعالجة الكاملة لطلبات الدوالّ والردود:

if (response.functionCalls.isNotEmpty) {
 
final geminiTools = ref.read(geminiToolsProvider);
 
final functionResultResponse = await chatSession.sendMessage(
   
Content.functionResponses([
     
for (final functionCall in response.functionCalls)
       
FunctionResponse(
          functionCall
.name,
          geminiTools
.handleFunctionCall(
            functionCall
.name,
            functionCall
.args,
         
),
       
),
   
]),
 
);
 
final responseText = functionResultResponse.text;
 
if (responseText != null) {
    logStateNotifier
.logLlmText(responseText);
    chatStateNotifier
.appendToMessage(llmMessage.id, responseText);
 
}
}

هذا الرمز:

  1. التحقّق مما إذا كان ردّ LLM يتضمّن أيّ طلبات وظائف
  2. لكلّ استدعاء دالة، يتمّ استدعاء طريقة handleFunctionCall باستخدام اسم الدالة ووسائطها.
  3. تجميع نتائج كلّ استدعاء دالة
  4. إرسال هذه النتائج مرة أخرى إلى نموذج اللغة الكبير باستخدام Content.functionResponses
  5. معالجة استجابة النموذج اللغوي الكبير (LLM) لنتائج الدالة
  6. تعديل واجهة المستخدم لتضمين نص الردّ النهائي

يؤدي ذلك إلى إنشاء مسار رحلة ذهاب وإياب:

  • المستخدم → النموذج اللغوي الكبير: طلب لون
  • LLM → التطبيق: طلبات استدعاء الدوالّ مع المَعلمات
  • التطبيق → المستخدم: يتم عرض لون جديد
  • التطبيق → النموذج اللغوي الكبير (LLM): نتائج الدوالّ
  • النموذج اللغوي الكبير → المستخدم: الرد النهائي الذي يتضمّن نتائج الدالة

إنشاء رمز Riverpod

شغِّل الأمر build runner لإنشاء رمز Riverpod المطلوب:

dart run build_runner build --delete-conflicting-outputs

تنفيذ العملية الكاملة واختبارها

شغِّل تطبيقك الآن:

flutter run -d DEVICE

لقطة شاشة لتطبيق Colorist تعرض ردّ نموذج اللغة الكبيرة (LLM) في Gemini من خلال طلب دالة

جرِّب إدخال أوصاف ألوان مختلفة:

  • "أريد لونًا أحمر داكنًا"
  • "أريد لونًا أزرق سماويًا مهدئًا"
  • "أريد معرفة لون أوراق النعناع الطازجة"
  • "أريد أن أرى لونًا برتقاليًا دافئًا للغروب"
  • "أريد لونًا أرجوانيًا ملكيًا غنيًا"

من المفترض أن يظهر لك الآن ما يلي:

  1. ظهور رسالتك في واجهة المحادثة
  2. ظهور ردّ Gemini في المحادثة
  3. تسجيل طلبات استدعاء الدوالّ في لوحة السجلّ
  4. يتم تسجيل نتائج الدالة فورًا بعد
  5. مستطيل اللون الذي يتم تعديله لعرض اللون الموضَّح
  6. تعديل قيم RGB لعرض مكونات اللون الجديد
  7. ظهور ردّ Gemini النهائي، وغالبًا ما يشير إلى اللون الذي تم ضبطه

تقدّم لوحة السجلّ إحصاءات عن ما يحدث في الكواليس. وسترى ما يلي:

  • طلبات الدالة الدقيقة التي يجريها Gemini
  • المَعلمات التي يتم اختيارها لكل قيمة RGB
  • النتائج التي تعرضها الدالة
  • الردود التي تتضمّن معلومات إضافية من Gemini

مُرسِل إشعارات حالة الألوان

إنّ colorStateNotifier الذي تستخدمه لتعديل الألوان هو جزء من حزمة colorist_ui. وتتولى إدارة ما يلي:

  • اللون الحالي المعروض في واجهة المستخدم
  • سجلّ الألوان (آخر 10 ألوان)
  • إشعارات بتغييرات الحالة في مكونات واجهة المستخدم

عند استدعاء updateColor بقيم RGB جديدة، يتم تنفيذ ما يلي:

  1. تُنشئ عنصرًا جديدًا من النوع ColorData باستخدام القيم المقدَّمة.
  2. تعديل اللون الحالي في حالة التطبيق
  3. تضيف اللون إلى السجلّ
  4. تنشئ تحديثات واجهة المستخدم من خلال إدارة حالة Riverpod

تتتبّع مكونات واجهة المستخدم في حزمة colorist_ui هذه الحالة وتتجدّد تلقائيًا عند تغيُّرها، ما يخلق تجربة استجابة.

فهم معالجة الأخطاء

يتضمّن التنفيذ معالجة فعّالة للأخطاء:

  1. وحدة Try-catch: تُغلِّف جميع تفاعلات النماذج اللغوية الكبيرة لرصد أي استثناءات
  2. تسجيل الأخطاء: لتسجيل الأخطاء في لوحة السجلّ مع تتبُّع تسلسل استدعاء الدوال البرمجية
  3. ملاحظات المستخدمين: تعرِض رسالة خطأ سهلة الفهم في المحادثة.
  4. تنظيف الحالة: يُنهي حالة الرسالة حتى في حال حدوث خطأ

يضمن ذلك بقاء التطبيق ثابتًا وتقديم ملاحظات مناسبة حتى في حال حدوث مشاكل في خدمة النموذج اللغوي الكبير أو تنفيذ الوظائف.

فعالية استدعاء الدوالّ لتحسين تجربة المستخدم

يوضّح ما حقّقته هنا كيف يمكن للغة الآلة الكبيرة إنشاء واجهات طبيعية فعّالة:

  1. واجهة اللغة الطبيعية: يعبّر المستخدمون عن نيتهم بلغة يومية.
  2. التفسير الذكي: تُحوّل النماذج اللغوية الكبيرة الأوصاف المموّهة إلى قيم دقيقة.
  3. المعالجة المباشرة: يتم تعديل واجهة المستخدم استجابةً للغة الطبيعية.
  4. الردود السياقية: توفّر النماذج اللغوية الكبيرة سياقًا للمحادثة حول التغييرات.
  5. انخفاض العبء المعرفي: لا يحتاج المستخدمون إلى فهم قيم RGB أو نظرية الألوان.

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

ما هي الخطوات التالية؟

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

تحديد المشاكل وحلّها

مشاكل في استدعاء الدوالّ

إذا لم تكن Gemini تستدعي دوالّك أو كانت المَعلمات غير صحيحة:

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

مشاكل في استجابة الدوالّ

إذا لم يتم إرسال نتائج الدوالّ بشكل صحيح إلى نموذج اللغة الكبير:

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

مشاكل في شاشة العرض الملوّنة

إذا لم تظهر الألوان بشكل صحيح:

  • تأكَّد من تحويل قيم RGB إلى أعداد مزدوجة بشكلٍ صحيح (قد ترسلها ميزة LLM كأعداد صحيحة).
  • تأكَّد من أنّ القيم ضمن النطاق المتوقّع (0.0 إلى 1.0).
  • تأكَّد من أنّه يتم استدعاء مُعلِم حالة اللون بشكل صحيح.
  • راجِع السجلّ لمعرفة القيم الدقيقة التي يتم تمريرها إلى الدالة.

المشاكل العامة

بالنسبة إلى المشاكل العامة:

  • فحص السجلات بحثًا عن أخطاء أو تحذيرات
  • التحقّق من إمكانية اتصال Vertex AI في Firebase
  • البحث عن أيّ عدم تطابق في النوع في مَعلمات الدالة
  • التأكّد من أنّ جميع الرموز التي أنشأها Riverpod محدّثة

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

  • تنفيذ مسار كامل لاستدعاء الدوال في Flutter
  • إنشاء تواصل كامل بين نموذج اللغة المحوسبة الكبير وتطبيقك
  • معالجة البيانات المنظَّمة من ردود LLM
  • إرسال نتائج الدالة مرة أخرى إلى نموذج اللغة الكبير (LLM) لدمج النتائج في الردود
  • استخدام لوحة السجلّات للاطّلاع على تفاعلات تطبيقات ميزة "البحث الوصفي على شبكة البحث"
  • ربط إدخالات اللغة الطبيعية بتغييرات محدّدة في واجهة المستخدم

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

7. بث الردود لتحسين تجربة المستخدم

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

المحتوى الذي ستتناوله في هذه الخطوة

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

أهمية البث لتطبيقات الذكاء الاصطناعي اللغوي

قبل التنفيذ، لنلقِ نظرة على أهمية بث الردود لتوفير تجارب ممتازة للمستخدمين باستخدام النماذج اللغوية الكبيرة:

تجربة مستخدم محسّنة

توفّر ميزة "بثّ الردود" العديد من المزايا المهمة لتجربة المستخدم:

  1. انخفاض وقت الاستجابة المُلاحظ: يرى المستخدمون ظهور النص على الفور (عادةً في غضون 100 إلى 300 ملي ثانية)، بدلاً من الانتظار لعدة ثوانٍ للحصول على ردّ كامل. ويؤدي هذا الشعور بالسرعة إلى تحسين رضا المستخدم بشكل كبير.
  2. إيقاع المحادثة الطبيعي: يُحاكي ظهور النص تدريجيًا طريقة تواصل البشر، ما يخلق تجربة حوارية أكثر طبيعية.
  3. المعالجة التدريجية للمعلومات: يمكن للمستخدمين بدء معالجة المعلومات فور وصولها، بدلاً من الشعور بالإرهاق بسبب عرض مجموعة كبيرة من النصوص في آنٍ واحد.
  4. إمكانية المقاطعة في وقت مبكر: في التطبيق الكامل، يمكن للمستخدمين مقاطعة نموذج المحادثات الطويلة أو إعادة توجيهه إذا لاحظوا أنّه يسير في اتجاه غير مفيد.
  5. تأكيد مرئي للنشاط: يقدّم نص البث ملاحظات فورية تفيد بأنّ النظام يعمل، ما يقلل من عدم اليقين.

المزايا الفنية

بالإضافة إلى تحسينات تجربة المستخدم، يوفّر البث مزايا فنية:

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

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

إضافة إدارة حالة المحادثة

أولاً، لنضيف مقدّم حالة لتتبُّع ما إذا كان التطبيق يعالج حاليًا استجابة بث. عدِّل ملف lib/services/gemini_chat_service.dart:

lib/services/gemini_chat_service.dart

import 'dart:async';

import 'package:colorist_ui/colorist_ui.dart';
import 'package:firebase_vertexai/firebase_vertexai.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../providers/gemini.dart';
import 'gemini_tools.dart';

part 'gemini_chat_service.g.dart';

final conversationStateProvider = StateProvider(                     // Add from here...
 
(ref) => ConversationState.idle,
);                                                                   // To here.

class GeminiChatService {
 
GeminiChatService(this.ref);
 
final Ref ref;

 
Future<void> sendMessage(String message) async {
   
final chatSession = await ref.read(chatSessionProvider.future);
   
final conversationState = ref.read(conversationStateProvider);   // Add this line
   
final chatStateNotifier = ref.read(chatStateNotifierProvider.notifier);
   
final logStateNotifier = ref.read(logStateNotifierProvider.notifier);

   
if (conversationState == ConversationState.busy) {               // Add from here...
     
logStateNotifier.logWarning(
       
"Can't send a message while a conversation is in progress",
     
);
     
throw Exception(
       
"Can't send a message while a conversation is in progress",
     
);
   
}
   
final conversationStateNotifier = ref.read(
     
conversationStateProvider.notifier,
   
);
   
conversationStateNotifier.state = ConversationState.busy;        // To here.
   
chatStateNotifier.addUserMessage(message);
   
logStateNotifier.logUserText(message);
   
final llmMessage = chatStateNotifier.createLlmMessage();
   
try {                                                            // Modify from here...
     
final responseStream = chatSession.sendMessageStream(
       
Content.text(message),
     
);
     
await for (final block in responseStream) {
       
await _processBlock(block, llmMessage.id);
     
}                                                              // To here.
   
} catch (e, st) {
     
logStateNotifier.logError(e, st: st);
     
chatStateNotifier.appendToMessage(
       
llmMessage.id,
       
"\nI'm sorry, I encountered an error processing your request. "
       
"Please try again.",
     
);
   
} finally {
     
chatStateNotifier.finalizeMessage(llmMessage.id);
     
conversationStateNotifier.state = ConversationState.idle;      // Add this line.
   
}
 
}

 
Future<void> _processBlock(                                        // Add from here...
   
GenerateContentResponse block,
   
String llmMessageId,
 
) async {
   
final chatSession = await ref.read(chatSessionProvider.future);
   
final chatStateNotifier = ref.read(chatStateNotifierProvider.notifier);
   
final logStateNotifier = ref.read(logStateNotifierProvider.notifier);
   
final blockText = block.text;

   
if (blockText != null) {
     
logStateNotifier.logLlmText(blockText);
     
chatStateNotifier.appendToMessage(llmMessageId, blockText);
   
}

   
if (block.functionCalls.isNotEmpty) {
     
final geminiTools = ref.read(geminiToolsProvider);
     
final responseStream = chatSession.sendMessageStream(
       
Content.functionResponses([
         
for (final functionCall in block.functionCalls)
           
FunctionResponse(
             
functionCall.name,
             
geminiTools.handleFunctionCall(
               
functionCall.name,
               
functionCall.args,
             
),
           
),
       
]),
     
);
     
await for (final response in responseStream) {
       
final responseText = response.text;
       
if (responseText != null) {
         
logStateNotifier.logLlmText(responseText);
         
chatStateNotifier.appendToMessage(llmMessageId, responseText);
       
}
     
}
   
}
 
}                                                                  // To here.
}

@riverpod
GeminiChatService geminiChatService(Ref ref) => GeminiChatService(ref);

فهم عملية تنفيذ البث

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

  1. تتبُّع حالة المحادثة:
    • يتتبّع الرمز conversationStateProvider ما إذا كان التطبيق يعالج حاليًا ردًا.
    • تتغيّر الحالة من idle إلى busy أثناء المعالجة، ثم تعود إلى idle
    • ويمنع ذلك حدوث طلبات متزامنة متعددة قد تتعارض مع بعضها.
  2. بدء البث:
    • يعرض sendMessageStream() بثًا من أجزاء الردّ بدلاً من Future مع الردّ الكامل.
    • قد يحتوي كلّ جزء على نص أو طلبات دالات أو كليهما.
  3. المعالجة التدريجية:
    • يعالج await for كل جزء فور وصوله في الوقت الفعلي.
    • يتم إلحاق النص بواجهة المستخدم على الفور، ما يؤدي إلى إنشاء تأثير البث.
    • يتم تنفيذ طلبات دالة فور رصدها
  4. معالجة طلب استدعاء الوظيفة:
    • عند رصد طلب دالة في قطعة، يتم تنفيذه على الفور.
    • يتم إرسال النتائج مرة أخرى إلى نموذج اللغة الكبير من خلال مكالمة بث أخرى.
    • تتم أيضًا معالجة ردّ نموذج اللغة الكبيرة على هذه النتائج بطريقة البث.
  5. معالجة الأخطاء والتنظيف:
    • توفّر try/catch معالجة فعّالة للأخطاء.
    • يضمن الرمز finally إعادة ضبط حالة المحادثة بشكل صحيح.
    • يتم دائمًا إكمال الرسالة، حتى في حال حدوث أخطاء.

يضمن هذا التنفيذ تجربة بث سريعة وموثوقة مع الحفاظ على حالة المحادثة المناسبة.

تعديل الشاشة الرئيسية لربط حالة المحادثة

عدِّل ملف lib/main.dart لنقل حالة المحادثة إلى الشاشة الرئيسية:

lib/main.dart

import 'package:colorist_ui/colorist_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'providers/gemini.dart';
import 'services/gemini_chat_service.dart';

void main() async {
 
runApp(ProviderScope(child: MainApp()));
}

class MainApp extends ConsumerWidget {
 
const MainApp({super.key});

 
@override
 
Widget build(BuildContext context, WidgetRef ref) {
   
final model = ref.watch(geminiModelProvider);
   
final conversationState = ref.watch(conversationStateProvider);  // Add this line

   
return MaterialApp(
     
theme: ThemeData(
       
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
     
),
     
home: model.when(
       
data: (data) => MainScreen(
         
conversationState: conversationState,                      // And this line
         
sendMessage: (text) {
           
ref.read(geminiChatServiceProvider).sendMessage(text);
         
},
       
),
       
loading: () => LoadingScreen(message: 'Initializing Gemini Model'),
       
error: (err, st) => ErrorScreen(error: err),
     
),
   
);
 
}
}

التغيير الرئيسي هنا هو تمرير conversationState إلى التطبيق المصغّر MainScreen. سيستخدم MainScreen (الذي تقدّمه حزمة colorist_ui) هذه الحالة لإيقاف إدخال النص أثناء معالجة الردّ.

ويؤدي ذلك إلى توفير تجربة مستخدم متماسكة يعكس فيها واجهة المستخدم الحالة الحالية للمحادثة.

إنشاء رمز Riverpod

شغِّل الأمر build runner لإنشاء رمز Riverpod المطلوب:

dart run build_runner build --delete-conflicting-outputs

تشغيل الردود التي يتم بثّها واختبارها

شغِّل تطبيقك باتّباع الخطوات التالية:

flutter run -d DEVICE

لقطة شاشة لتطبيق Colorist تعرض ردًّا من نموذج اللغة الكبيرة في Gemini بطريقة البث

جرِّب الآن اختبار سلوك البث باستخدام أوصاف ألوان مختلفة. جرِّب أوصافًا مثل:

  • "أريد رؤية لون الأزرق المخضرّم الداكن للمحيط عند الغسق"
  • "أريد رؤية مرجان حيوي يذكّرني بالزهور الاستوائية"
  • "إنشاء لون أخضر زيتوني خفيف مثل الزي العسكري القديم"

تفاصيل العملية الفنية للبث

لنطّلِع على ما يحدث بالضبط عند بثّ ردّ:

إنشاء الاتصال

عند الاتصال بالرقم sendMessageStream()، يحدث ما يلي:

  1. يُنشئ التطبيق اتصالاً بخدمة Vertex AI.
  2. يتم إرسال طلب المستخدم إلى الخدمة
  3. يبدأ الخادم معالجة الطلب.
  4. يظلّ اتصال البث مفتوحًا وجاهزًا لإرسال الأجزاء.

نقل الأجزاء

أثناء إنشاء Gemini للمحتوى، يتم إرسال أجزاء من خلال البث:

  1. يُرسِل الخادم أجزاء من النص أثناء إنشائها (عادةً ما تكون عبارة عن بضع كلمات أو جمل).
  2. عندما يقرر Gemini إجراء طلب استدعاء دالة، يرسل معلومات طلب الاستدعاء.
  3. قد تتبع استدعاءات الدوالّ أجزاء نصية إضافية.
  4. تستمر عملية البث إلى أن تكتمل عملية إنشاء المحتوى.

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

يعالج تطبيقك كل جزء بشكل تدريجي:

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

اكتمال البث

عند اكتمال عملية الإنشاء:

  1. إغلاق البث من قِبل الخادم
  2. خروج حلقة await for بشكل طبيعي
  3. تم وضع علامة على الرسالة باعتبارها مكتملة
  4. يتم ضبط حالة المحادثة على "غير نشِط" مرة أخرى
  5. يتم تعديل واجهة المستخدم لتعكس الحالة المكتملة

مقارنة بين المحتوى الذي يتم بثّه والمحتوى الذي لا يتم بثّه

لفهم مزايا البث بشكل أفضل، لنقارن بين أسلوب البث وأسلوب عدم البث:

جانب

غير متوفّر للبث

البث

وقت الاستجابة المُلاحظ

لا يظهر للمستخدم أي شيء إلى أن يصبح الردّ كاملاً.

يرى المستخدم الكلمات الأولى في غضون ميلي ثانية

تجربة المستخدم

انتظار طويل متبوعًا بظهور النص بشكل مفاجئ

مظهر النص الطبيعي والمتغيّر

إدارة الحالة

أبسط (الرسائل إما معلّقة أو مكتملة)

أكثر تعقيدًا (يمكن أن تكون الرسائل في حالة بث)

تنفيذ الدالة

لا يحدث إلا بعد اكتمال الاستجابة

تحدث أثناء إنشاء الردّ

مدى تعقيد التنفيذ

سهولة التنفيذ

تتطلّب إدارة حالة إضافية

استعادة الخطأ

الاستجابة الكاملة أو عدم الاستجابة على الإطلاق

قد تظل الردود الجزئية مفيدة

تعقيد الرمز

أقل تعقيدًا

أكثر تعقيدًا بسبب معالجة مصدر البيانات

بالنسبة إلى تطبيق مثل Colorist، تفوق مزايا تجربة المستخدم في البث تعقيد التنفيذ، لا سيما في ما يتعلق بتفسيرات الألوان التي قد يستغرق إنشاؤها عدة ثوانٍ.

أفضل الممارسات المتعلّقة بتجربة المستخدم في البث

عند تنفيذ ميزة البث في تطبيقات معالجة اللغة الضخمة، ننصحك باتّباع أفضل الممارسات التالية:

  1. مؤشرات مرئية واضحة: يجب دائمًا تقديم إشارات مرئية واضحة تميّز بين الرسائل التي يتم بثها والرسائل الكاملة.
  2. حظر الإدخال: يمكنك إيقاف إدخال المستخدم أثناء البث لمنع الطلبات المتعدّدة المتداخلة.
  3. استرداد الأخطاء: تصميم واجهة المستخدم للتعامل مع الاسترداد السلس في حال انقطاع البث
  4. عمليات النقل بين الحالات: تأكَّد من الانتقال السلس بين حالات "غير نشط" و"البث" و"مكتمل".
  5. تصور التقدّم: ننصحك باستخدام صور متحركة أو مؤشرات خفيفة تُظهر أنّه يتمّ إجراء معالجة نشطة.
  6. خيارات الإلغاء: في التطبيق الكامل، وفِّر طرقًا للمستخدمين لإلغاء عمليات الإنشاء الجارية.
  7. دمج نتائج الدوالّ: تصميم واجهة المستخدم لمعالجة نتائج الدوالّ التي تظهر أثناء البث
  8. تحسين الأداء: تقليل عمليات إعادة إنشاء واجهة المستخدم أثناء تعديلات البث السريعة

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

ما هي الخطوات التالية؟

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

تحديد المشاكل وحلّها

مشاكل معالجة البث

في حال مواجهة مشاكل في معالجة البث:

  • الأعراض: الردود الجزئية أو النص غير المتوفّر أو إنهاء البث بشكل مفاجئ
  • الحلّ: التحقّق من اتصال الشبكة والتأكّد من أنّ أنماط async/await صحيحة في الرمز البرمجي
  • التشخيص: راجِع لوحة السجلّات بحثًا عن رسائل خطأ أو تحذيرات متعلّقة بمعالجة البث.
  • الإصلاح: تأكَّد من أنّ جميع عمليات معالجة البث تستخدِم معالجة الأخطاء المناسبة باستخدام وحدات try/catch.

استدعاءات الدوالّ غير متوفّرة

في حال عدم رصد طلبات استدعاء الدوالّ في مصدر البيانات:

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

معالجة الأخطاء العامة

إذا واجهت أي مشاكل أخرى:

  • الخطوة 1: التحقّق من لوحة السجلّ بحثًا عن رسائل الخطأ
  • الخطوة 2: التحقّق من إمكانية اتصال Vertex AI في Firebase
  • الخطوة 3: التأكّد من تحديث كل الرموز التي أنشأها Riverpod
  • الخطوة 4: مراجعة عملية البث بحثًا عن أي عبارات انتظار غير متوفّرة

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

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

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

8. مزامنة سياق النماذج اللغوية الكبيرة

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

المحتوى الذي ستتناوله في هذه الخطوة

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

فهم مزامنة سياق النماذج اللغوية الكبيرة

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

أهمية مزامنة سياق النماذج اللغوية الكبيرة

عندما يتفاعل المستخدمون مع تطبيقك من خلال عناصر واجهة المستخدم (مثل اختيار لون من السجلّ)، لا يمكن لنموذج LLM معرفة ما حدث ما لم تُعلمه بذلك صراحةً. مزامنة سياق النماذج اللغوية الكبيرة:

  1. الحفاظ على السياق: إبقاء نموذج اللغة الكبيرة على دراية بجميع إجراءات المستخدم ذات الصلة
  2. إنشاء اتساق: توفّر تجربة متسقة يُقرّ فيها نموذج اللغة الضخم بتفاعلات واجهة المستخدم
  3. تحسين الذكاء: السماح للنموذج اللغوي الكبير بالردّ بشكل مناسب على جميع إجراءات المستخدم
  4. تحسين تجربة المستخدم: تجعل التطبيق بأكمله أكثر تكاملاً واستجابةً
  5. تقليل الجهد الذي يبذله المستخدم: تُلغي هذه الميزة الحاجة إلى أن يشرح المستخدمون يدويًا إجراءات واجهة المستخدم.

في تطبيق Colorist، عندما يختار المستخدم لونًا من السجلّ، تريد أن يُقرّ Gemini بهذا الإجراء ويُعلِق بذكاء على اللون المحدّد، ما يحافظ على الوهم بأنّه مساعد سلس وواعي.

تعديل خدمة Gemini Chat لإرسال إشعارات اختيار الألوان

أولاً، ستضيف طريقة إلى GeminiChatService لإعلام نموذج "التعلم الآلي للمحتوى" عندما يختار المستخدم لونًا من السجلّ. عدِّل ملف lib/services/gemini_chat_service.dart:

lib/services/gemini_chat_service.dart

import 'dart:async';
import 'dart:convert';                                               // Add this import

import 'package:colorist_ui/colorist_ui.dart';
import 'package:firebase_vertexai/firebase_vertexai.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../providers/gemini.dart';
import 'gemini_tools.dart';

part 'gemini_chat_service.g.dart';

final conversationStateProvider = StateProvider(
 
(ref) => ConversationState.idle,
);

class GeminiChatService {
 
GeminiChatService(this.ref);
 
final Ref ref;

 
Future<void> notifyColorSelection(ColorData color) => sendMessage(  // Add from here...
   
'User selected color from history: ${json.encode(color.toLLMContextMap())}',
 
);                                                                  // To here.

 
Future<void> sendMessage(String message) async {
   
final chatSession = await ref.read(chatSessionProvider.future);
   
final conversationState = ref.read(conversationStateProvider);
   
final chatStateNotifier = ref.read(chatStateNotifierProvider.notifier);
   
final logStateNotifier = ref.read(logStateNotifierProvider.notifier);

   
if (conversationState == ConversationState.busy) {
     
logStateNotifier.logWarning(
       
"Can't send a message while a conversation is in progress",
     
);
     
throw Exception(
       
"Can't send a message while a conversation is in progress",
     
);
   
}
   
final conversationStateNotifier = ref.read(
     
conversationStateProvider.notifier,
   
);
   
conversationStateNotifier.state = ConversationState.busy;
   
chatStateNotifier.addUserMessage(message);
   
logStateNotifier.logUserText(message);
   
final llmMessage = chatStateNotifier.createLlmMessage();
   
try {
     
final responseStream = chatSession.sendMessageStream(
       
Content.text(message),
     
);
     
await for (final block in responseStream) {
       
await _processBlock(block, llmMessage.id);
     
}
   
} catch (e, st) {
     
logStateNotifier.logError(e, st: st);
     
chatStateNotifier.appendToMessage(
       
llmMessage.id,
       
"\nI'm sorry, I encountered an error processing your request. "
       
"Please try again.",
     
);
   
} finally {
     
chatStateNotifier.finalizeMessage(llmMessage.id);
     
conversationStateNotifier.state = ConversationState.idle;
   
}
 
}

 
Future<void> _processBlock(
   
GenerateContentResponse block,
   
String llmMessageId,
 
) async {
   
final chatSession = await ref.read(chatSessionProvider.future);
   
final chatStateNotifier = ref.read(chatStateNotifierProvider.notifier);
   
final logStateNotifier = ref.read(logStateNotifierProvider.notifier);
   
final blockText = block.text;

   
if (blockText != null) {
     
logStateNotifier.logLlmText(blockText);
     
chatStateNotifier.appendToMessage(llmMessageId, blockText);
   
}

   
if (block.functionCalls.isNotEmpty) {
     
final geminiTools = ref.read(geminiToolsProvider);
     
final responseStream = chatSession.sendMessageStream(
       
Content.functionResponses([
         
for (final functionCall in block.functionCalls)
           
FunctionResponse(
             
functionCall.name,
             
geminiTools.handleFunctionCall(
               
functionCall.name,
               
functionCall.args,
             
),
           
),
       
]),
     
);
     
await for (final response in responseStream) {
       
final responseText = response.text;
       
if (responseText != null) {
         
logStateNotifier.logLlmText(responseText);
         
chatStateNotifier.appendToMessage(llmMessageId, responseText);
       
}
     
}
   
}
 
}
}

@riverpod
GeminiChatService geminiChatService(Ref ref) => GeminiChatService(ref);

إضافة المفتاح هي طريقة notifyColorSelection التي:

  1. تأخذ عنصرًا من النوع ColorData يمثّل اللون المحدّد.
  2. ترميزه بتنسيق JSON يمكن تضمينه في رسالة
  3. إرسال رسالة بتنسيق خاص إلى نموذج اللغة الضخمة (LLM) للإشارة إلى اختيار المستخدم
  4. إعادة استخدام طريقة sendMessage الحالية لمعالجة الإشعار

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

تعديل التطبيق الرئيسي لربط إشعارات اختيار الألوان

الآن، عدِّل ملف lib/main.dart لتمرير وظيفة إشعار اختيار اللون إلى الشاشة الرئيسية:

lib/main.dart

import 'package:colorist_ui/colorist_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'providers/gemini.dart';
import 'services/gemini_chat_service.dart';

void main() async {
 
runApp(ProviderScope(child: MainApp()));
}

class MainApp extends ConsumerWidget {
 
const MainApp({super.key});

 
@override
 
Widget build(BuildContext context, WidgetRef ref) {
   
final model = ref.watch(geminiModelProvider);
   
final conversationState = ref.watch(conversationStateProvider);

   
return MaterialApp(
     
theme: ThemeData(
       
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
     
),
     
home: model.when(
       
data: (data) => MainScreen(
         
conversationState: conversationState,
         
notifyColorSelection: (color) {                            // Add from here...
           
ref.read(geminiChatServiceProvider).notifyColorSelection(color);
         
},                                                         // To here.
         
sendMessage: (text) {
           
ref.read(geminiChatServiceProvider).sendMessage(text);
         
},
       
),
       
loading: () => LoadingScreen(message: 'Initializing Gemini Model'),
       
error: (err, st) => ErrorScreen(error: err),
     
),
   
);
 
}
}

التغيير الرئيسي هو إضافة طلب إعادة الاتصال notifyColorSelection الذي يربط حدث واجهة المستخدم (اختيار لون من السجلّ) بنظام إشعارات LLM.

تعديل طلب النظام

الآن، عليك تعديل طلب النظام لتوجيه نموذج اللغة القليلة الكلمات إلى كيفية الردّ على إشعارات اختيار الألوان. عدِّل ملف assets/system_prompt.md:

assets/system_prompt.md

# Colorist System Prompt

You are a color expert assistant integrated into a desktop app called Colorist. Your job is to interpret natural language color descriptions and set the appropriate color values using a specialized tool.

## Your Capabilities

You are knowledgeable about colors, color theory, and how to translate natural language descriptions into specific RGB values. You have access to the following tool:

`set_color` - Sets the RGB values for the color display based on a description

## How to Respond to User Inputs

When users describe a color:

1. First, acknowledge their color description with a brief, friendly response
2. Interpret what RGB values would best represent that color description
3. Use the `set_color` tool to set those values (all values should be between 0.0 and 1.0)
4. After setting the color, provide a brief explanation of your interpretation

Example:
User: "I want a sunset orange"
You: "Sunset orange is a warm, vibrant color that captures the golden-red hues of the setting sun. It combines a strong red component with moderate orange tones."

[Then you would call the set_color tool with approximately: red=1.0, green=0.5, blue=0.25]

After the tool call: "I've set a warm orange with strong red, moderate green, and minimal blue components that is reminiscent of the sun low on the horizon."

## When Descriptions are Unclear

If a color description is ambiguous or unclear, please ask the user clarifying questions, one at a time.

## When Users Select Historical Colors

Sometimes, the user will manually select a color from the history panel. When this happens, you'll receive a notification about this selection that includes details about the color. Acknowledge this selection with a brief response that recognizes what they've done and comments on the selected color.

Example notification:
User: "User selected color from history: {red: 0.2, green: 0.5, blue: 0.8, hexCode: #3380CC}"
You: "I see you've selected an ocean blue from your history. This tranquil blue with a moderate intensity has a calming, professional quality to it. Would you like to explore similar shades or create a contrasting color?"

## Important Guidelines

- Always keep RGB values between 0.0 and 1.0
- Provide thoughtful, knowledgeable responses about colors
- When possible, include color psychology, associations, or interesting facts about colors
- Be conversational and engaging in your responses
- Focus on being helpful and accurate with your color interpretations

الإضافة الرئيسية هي قسم "عندما يختار المستخدمون ألوانًا سابقة"، الذي:

  1. يوضّح مفهوم إشعارات اختيار السجلّ إلى نموذج اللغة المحوسبة الكبير (LLM).
  2. تقديم مثال على شكل هذه الإشعارات
  3. تعرِض هذه السمة مثالاً على ردّ مناسب.
  4. تحديد التوقعات بشأن الردّ على الاختيار والتعليق على اللون

يساعد ذلك النموذج اللغوي الكبير على فهم كيفية الردّ بشكل مناسب على هذه الرسائل الخاصة.

إنشاء رمز Riverpod

شغِّل الأمر build runner لإنشاء رمز Riverpod المطلوب:

dart run build_runner build --delete-conflicting-outputs

تشغيل ميزة "مزامنة سياق النماذج اللغوية الكبيرة" واختبارها

شغِّل تطبيقك باتّباع الخطوات التالية:

flutter run -d DEVICE

لقطة شاشة لتطبيق Colorist تعرض نموذج &quot;التعلم الآلي&quot; في Gemini وهو يستجيب لاختيار من سجلّ الألوان

يتضمّن اختبار مزامنة سياق النماذج اللغوية الكبيرة ما يلي:

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

عليك مراعاة ما يلي:

  1. يظهر اللون المحدّد في الشاشة الرئيسية.
  2. تظهر رسالة مستخدم في المحادثة تشير إلى اختيار اللون.
  3. يردّ النموذج اللغوي الكبير (LLM) من خلال الاعتراف بالاختيار والتعليق على اللون.
  4. أن يبدو التفاعل بأكمله طبيعيًا ومترابطًا

ويؤدي ذلك إلى توفير تجربة سلسة يرصد فيها النموذج اللغوي الكبير الرسائل المباشرة وتفاعلات واجهة المستخدم ويردّ عليها بشكل مناسب.

آلية عمل ميزة "مزامنة سياق النماذج اللغوية الكبيرة"

لنطّلِع على التفاصيل الفنية لآلية عمل هذه المزامنة:

تدفق البيانات

  1. إجراء المستخدِم: ينقر المستخدِم على لون في شريط السجلّ.
  2. حدث واجهة المستخدم: يرصد التطبيق المصغّر MainScreen هذا الاختيار.
  3. تنفيذ معاودة الاتصال: يتم تشغيل دالة معاودة الاتصال notifyColorSelection.
  4. إنشاء الرسالة: يتم إنشاء رسالة بتنسيق خاص باستخدام بيانات الألوان.
  5. معالجة نموذج التعلم الآلي: يتم إرسال الرسالة إلى Gemini الذي يتعرّف على التنسيق.
  6. الردّ السياقي: يردّ Gemini بشكل مناسب استنادًا إلى طلب النظام
  7. تعديل على واجهة المستخدم: يظهر الردّ في المحادثة، ما يمنح تجربة متسقة

تسلسل البيانات

يتمثل أحد الجوانب الرئيسية لهذا النهج في كيفية تسلسل بيانات الألوان:

'User selected color from history: ${json.encode(color.toLLMContextMap())}'

تعمل طريقة toLLMContextMap() (التي تقدّمها حزمة colorist_ui) على تحويل عنصر ColorData إلى خريطة تتضمّن خصائص رئيسية يمكن للنموذج اللغوي الكبير الحجم فهمها. ويشمل ذلك عادةً ما يلي:

  • قيم النموذج اللوني أحمر أخضر أزرق (RGB)
  • تمثيل الرمز السداسي
  • أي اسم أو وصف مرتبط باللون

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

تطبيقات أوسع لمزامنة سياق النماذج اللغوية الكبيرة

يُستخدم نمط إرسال الإشعارات إلى نموذج اللغة الكبيرة (LLM) بشأن أحداث واجهة المستخدم في العديد من التطبيقات الأخرى غير اختيار الألوان:

حالات الاستخدام الأخرى

  1. تغييرات الفلتر: إرسال إشعار إلى نموذج اللغة القليلة المصادر عندما يطبّق المستخدمون فلاتر على البيانات
  2. أحداث التنقّل: إبلاغ نموذج التعلم الآلي للغة (LLM) عندما ينتقل المستخدِمون إلى أقسام مختلفة
  3. تغييرات الاختيار: تعديل نموذج ملاءمة اللغة عندما يختار المستخدمون عناصر من القوائم أو الشبكات
  4. تعديلات الإعدادات المفضّلة: إبلاغ نموذج اللغة الضخم (LLM) عندما يغيّر المستخدمون الإعدادات أو الإعدادات المفضّلة
  5. تلاعب البيانات: إرسال إشعار إلى "المسؤول عن إدارة الموافقة" عندما يضيف المستخدمون بيانات أو يعدّلونها أو يحذفونها

في كلتا الحالتَين، يبقى النمط كما هو:

  1. رصد حدث واجهة المستخدم
  2. تسلسل البيانات ذات الصلة
  3. إرسال إشعار بتنسيق خاص إلى "المسؤول عن إدارة المحتوى"
  4. توجيه النموذج اللغوي الكبير (LLM) للردّ بشكل مناسب من خلال طلب النظام

أفضل الممارسات لمزامنة سياق نموذج التعلم الآلي (LLM)

استنادًا إلى عملية التنفيذ، إليك بعض أفضل الممارسات لمزامنة سياق نموذج "التعلم الآلي للغة" (LLM) الفعّالة:

1. اعتماد تنسيق موحَّد

استخدِم تنسيقًا ثابتًا للإشعارات حتى تتمكّن ميزة "المعالجة المحدودة للبيانات" من التعرّف عليها بسهولة:

"User [action] [object]: [structured data]"

2. سياق غني

يجب تضمين تفاصيل كافية في الإشعارات ليتمكّن النموذج اللغوي الكبير من الردّ بذكاء. بالنسبة إلى الألوان، يعني ذلك قيم RGB والرموز السداسية العشرية وأيّ سمات أخرى ذات صلة.

3- تعليمات واضحة

قدِّم تعليمات واضحة في طلب النظام حول كيفية التعامل مع الإشعارات، ويُفضَّل أن تكون مصحوبة بأمثلة.

4. الدمج الطبيعي

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

5- إشعار انتقائي

لا تُعلِم نموذج اللغة الكبيرة إلا بالإجراءات ذات الصلة بالمحادثة. لا يلزم إرسال كل أحداث واجهة المستخدم.

تحديد المشاكل وحلّها

المشاكل المتعلّقة بالإشعارات

إذا لم يستجِب نموذج اللغة الكبيرة بشكل صحيح لخيارات الألوان:

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

إدارة السياق

إذا بدا أنّ نموذج "التعلم الآلي للترجمة" فقد السياق:

  • التأكّد من الحفاظ على جلسة المحادثة بشكلٍ سليم
  • التأكّد من انتقال حالات المحادثة بشكلٍ صحيح
  • التأكّد من إرسال الإشعارات من خلال جلسة المحادثة نفسها

المشاكل العامة

بالنسبة إلى المشاكل العامة:

  • فحص السجلات بحثًا عن أخطاء أو تحذيرات
  • التحقّق من إمكانية اتصال Vertex AI في Firebase
  • البحث عن أيّ عدم تطابق في النوع في مَعلمات الدالة
  • التأكّد من أنّ جميع الرموز التي أنشأها Riverpod محدّثة

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

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

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

9. تهانينا!

لقد أكملت بنجاح دورة Colorist codelab. 🎉

المحتوى الذي أنشأته

لقد أنشأت تطبيق Flutter وظيفيًا بالكامل يدمج Gemini API من Google لتفسير أوصاف الألوان باللغة الطبيعية. يمكن لتطبيقك الآن تنفيذ ما يلي:

  • معالجة أوصاف باللغة الطبيعية، مثل "برتقالي غروب الشمس" أو "أزرق عميق للمحيط"
  • استخدام Gemini لترجمة هذه الأوصاف بذكاء إلى قيم RGB
  • عرض الألوان المترجَمة في الوقت الفعلي مع بث الردود
  • التعامل مع تفاعلات المستخدمين من خلال عناصر المحادثة وواجهة المستخدم
  • الحفاظ على الوعي السياقي في جميع طرق التفاعل المختلفة

الخطوة التالية

بعد أن اطّلعت على أساسيات دمج Gemini مع Flutter، إليك بعض الطرق لمواصلة رحلتك:

تحسين تطبيق Colorist

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

استكشاف المزيد من ميزات Gemini

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

تطبيق هذه الأنماط على نطاقات أخرى

  • تحليل المستندات: إنشاء تطبيقات يمكنها فهم المستندات وتحليلها
  • المساعدة في الكتابة الإبداعية: إنشاء أدوات كتابة باستخدام اقتراحات مستندة إلى الذكاء الاصطناعي (AI) على مستوى اللغة
  • المعالجة الآلية للمهام: تصميم تطبيقات تترجم اللغة الطبيعية إلى مهام مبرمَجة
  • التطبيقات المستندة إلى المعرفة: إنشاء أنظمة خبراء في مجالات معيّنة

الموارد

في ما يلي بعض المراجع القيّمة لمواصلة التعلّم:

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

الدورة التدريبية والدليل الإرشادي لكتابة الطلبات

المنتدى

سلسلة Observable Flutter Agentic

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

في الحلقة 60، انضم إلى "كريج" و"أندرو" مرة أخرى أثناء توسيع نطاق تطبيق codelab من خلال إضافة إمكانات جديدة ومحاولة جعل النماذج اللغوية الكبيرة تلتزم بالتعليمات.

في الحلقة 61، ينضم إلى "كريج" "كريس سيلز" لتحليل عناوين الأخبار وإنشاء صور مقابلة لها.

الملاحظات

يسرّنا معرفة تجربتك في هذا الدليل التعليمي حول البرمجة. يُرجى إرسال ملاحظاتك من خلال:

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