একটি জেমিনি চালিত ফ্লটার অ্যাপ তৈরি করুন, একটি জেমিনি চালিত ফ্লটার অ্যাপ তৈরি করুন

১. জেমিনি দ্বারা চালিত একটি ফ্লাটার অ্যাপ তৈরি করুন।

আপনি যা তৈরি করবেন

এই কোডল্যাবে, আপনি কালারিস্ট (Colorist) তৈরি করবেন – এটি একটি ইন্টারেক্টিভ ফ্লাটার অ্যাপ্লিকেশন যা জেমিনি এপিআই (Gemini API)-এর ক্ষমতা সরাসরি আপনার ফ্লাটার অ্যাপে নিয়ে আসে। আপনি কি কখনো ব্যবহারকারীদের স্বাভাবিক ভাষার মাধ্যমে আপনার অ্যাপ নিয়ন্ত্রণ করার সুযোগ দিতে চেয়েছেন, কিন্তু কোথা থেকে শুরু করবেন তা জানতেন না? এই কোডল্যাবটি আপনাকে দেখাবে কীভাবে তা করতে হয়।

কালারিস্ট ব্যবহারকারীদের স্বাভাবিক ভাষায় রঙের বর্ণনা দেওয়ার সুযোগ দেয় (যেমন "সূর্যাস্তের কমলা" বা "গভীর সমুদ্রের নীল"), এবং অ্যাপটি:

  • গুগলের জেমিনি এপিআই ব্যবহার করে এই বিবরণগুলি প্রক্রিয়া করে।
  • বর্ণনাগুলোকে সুনির্দিষ্ট RGB রঙের মানে রূপান্তর করে।
  • স্ক্রিনে রিয়েল-টাইমে রঙ প্রদর্শন করে।
  • রঙের প্রযুক্তিগত বিবরণ এবং রঙটি সম্পর্কে আকর্ষণীয় প্রেক্ষাপট প্রদান করে।
  • সম্প্রতি তৈরি হওয়া রঙগুলোর ইতিহাস সংরক্ষণ করে।

কালারিস্ট অ্যাপের স্ক্রিনশট, যেখানে রঙিন ডিসপ্লে এবং চ্যাট ইন্টারফেস দেখা যাচ্ছে।

অ্যাপটিতে একটি স্প্লিট-স্ক্রিন ইন্টারফেস রয়েছে, যার একপাশে একটি রঙিন ডিসপ্লে এলাকা ও একটি ইন্টারেক্টিভ চ্যাট সিস্টেম এবং অপরপাশে একটি বিস্তারিত লগ প্যানেল আছে, যা এলএলএম-এর সরাসরি ইন্টারঅ্যাকশনগুলো দেখায়। এই লগটি আপনাকে আরও ভালোভাবে বুঝতে সাহায্য করে যে, একটি এলএলএম ইন্টিগ্রেশন আড়ালে আসলে কীভাবে কাজ করে।

ফ্লাটার ডেভেলপারদের জন্য এটি কেন গুরুত্বপূর্ণ

এলএলএম (LLM) ব্যবহারকারীদের অ্যাপ্লিকেশনের সাথে মিথস্ক্রিয়ার পদ্ধতিতে বৈপ্লবিক পরিবর্তন আনছে, কিন্তু মোবাইল এবং ডেস্কটপ অ্যাপে এগুলোকে কার্যকরভাবে একীভূত করা কিছু স্বতন্ত্র চ্যালেঞ্জ তৈরি করে। এই কোডল্যাবটি আপনাকে এমন কিছু ব্যবহারিক প্যাটার্ন শেখাবে যা কেবল গতানুগতিক এপিআই (API) কলের বাইরেও কাজ করে।

আপনার শেখার যাত্রা

এই কোডল্যাবটি আপনাকে ধাপে ধাপে কালারিস্ট তৈরি করার প্রক্রিয়াটি দেখাবে:

  1. প্রজেক্ট সেটআপ - আপনি একটি বেসিক ফ্লাটার অ্যাপ স্ট্রাকচার এবং colorist_ui প্যাকেজ দিয়ে শুরু করবেন।
  2. বেসিক জেমিনি ইন্টিগ্রেশন - আপনার অ্যাপকে ফায়ারবেস এআই লজিকের সাথে সংযুক্ত করুন এবং এলএলএম কমিউনিকেশন বাস্তবায়ন করুন।
  3. কার্যকরী নির্দেশনা - এমন একটি সিস্টেম নির্দেশনা তৈরি করুন যা এলএলএম-কে রঙের বর্ণনা বুঝতে পথ দেখাবে।
  4. ফাংশন ঘোষণা - আপনার অ্যাপ্লিকেশনে রং নির্ধারণ করার জন্য LLM যে টুলগুলো ব্যবহার করতে পারে, সেগুলো সংজ্ঞায়িত করুন।
  5. টুল হ্যান্ডলিং - LLM থেকে ফাংশন কলগুলো প্রসেস করুন এবং সেগুলোকে আপনার অ্যাপের স্টেটের সাথে সংযুক্ত করুন।
  6. স্ট্রিমিং প্রতিক্রিয়া - রিয়েল-টাইম স্ট্রিমিং এলএলএম প্রতিক্রিয়ার মাধ্যমে ব্যবহারকারীর অভিজ্ঞতা উন্নত করুন
  7. এলএলএম কনটেক্সট সিঙ্ক্রোনাইজেশন - ব্যবহারকারীর কার্যকলাপ সম্পর্কে এলএলএম-কে অবহিত করে একটি সুসংহত অভিজ্ঞতা তৈরি করুন।

আপনি যা শিখবেন

  • ফ্লাটার অ্যাপ্লিকেশনের জন্য ফায়ারবেস এআই লজিক কনফিগার করুন
  • এলএলএম আচরণকে নির্দেশিত করার জন্য কার্যকর সিস্টেম নির্দেশিকা তৈরি করুন।
  • স্বাভাবিক ভাষা এবং অ্যাপের বৈশিষ্ট্যগুলির মধ্যে সংযোগ স্থাপনকারী ফাংশন ঘোষণাগুলি বাস্তবায়ন করুন।
  • প্রতিক্রিয়াশীল ব্যবহারকারীর অভিজ্ঞতার জন্য স্ট্রিমিং প্রতিক্রিয়া প্রক্রিয়া করুন
  • UI ইভেন্ট এবং LLM-এর মধ্যে অবস্থা সিঙ্ক্রোনাইজ করুন
  • রিভারপড ব্যবহার করে এলএলএম কথোপকথনের অবস্থা পরিচালনা করুন
  • LLM-চালিত অ্যাপ্লিকেশনগুলিতে ত্রুটিগুলি সুন্দরভাবে পরিচালনা করুন

কোড প্রিভিউ: আপনি যা বাস্তবায়ন করবেন তার একটি ঝলক

আপনার অ্যাপে LLM-কে রং নির্ধারণ করতে দেওয়ার জন্য আপনি যে ফাংশন ডিক্লারেশনটি তৈরি করবেন, তার একটি ঝলক এখানে দেওয়া হলো:

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)'),
  },
);

এই কোডল্যাবটির একটি ভিডিও ওভারভিউ

Observable Flutter এপিসোড #59-এ ক্রেইগ ল্যাবেঞ্জ এবং অ্যান্ড্রু ব্রগডনের এই কোডল্যাব আলোচনাটি দেখুন:

পূর্বশর্ত

এই কোডল্যাব থেকে সর্বাধিক সুবিধা পেতে আপনার নিম্নলিখিত বিষয়গুলো থাকা উচিত:

  • ফ্লাটার ডেভেলপমেন্টের অভিজ্ঞতা - ফ্লাটারের মৌলিক বিষয় এবং ডার্ট সিনট্যাক্স সম্পর্কে পরিচিতি
  • অ্যাসিঙ্ক্রোনাস প্রোগ্রামিং জ্ঞান - ফিউচার, async/await, এবং স্ট্রিম সম্পর্কে ধারণা
  • ফায়ারবেস অ্যাকাউন্ট - ফায়ারবেস সেট আপ করার জন্য আপনার একটি গুগল অ্যাকাউন্ট লাগবে।

চলুন আপনার প্রথম এলএলএম-চালিত ফ্লাটার অ্যাপ তৈরি করা শুরু করা যাক!

২. প্রজেক্ট সেটআপ এবং ইকো সার্ভিস

এই প্রথম ধাপে, আপনি প্রজেক্টের কাঠামো তৈরি করবেন এবং একটি ইকো সার্ভিস ইমপ্লিমেন্ট করবেন, যা পরবর্তীতে জেমিনি এপিআই ইন্টিগ্রেশন দ্বারা প্রতিস্থাপিত হবে। এর মাধ্যমে অ্যাপ্লিকেশনটির আর্কিটেকচার প্রতিষ্ঠিত হয় এবং এলএলএম কলের জটিলতা যোগ করার আগে আপনার ইউআই (UI) সঠিকভাবে কাজ করছে কিনা তা নিশ্চিত করা হয়।

এই ধাপে আপনি যা শিখবেন

  • প্রয়োজনীয় ডিপেন্ডেন্সি সহ একটি ফ্লাটার প্রজেক্ট সেট আপ করা
  • UI কম্পোনেন্টগুলির জন্য colorist_ui প্যাকেজ নিয়ে কাজ করা
  • একটি ইকো মেসেজ সার্ভিস বাস্তবায়ন করা এবং এটিকে UI-এর সাথে সংযুক্ত করা।

একটি নতুন ফ্লাটার প্রজেক্ট তৈরি করুন

নিম্নলিখিত কমান্ড ব্যবহার করে একটি নতুন ফ্লাটার প্রজেক্ট তৈরি করে শুরু করুন:

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

-e ফ্ল্যাগটি নির্দেশ করে যে আপনি ডিফল্ট counter অ্যাপ ছাড়া একটি খালি প্রজেক্ট চান। অ্যাপটি ডেস্কটপ, মোবাইল এবং ওয়েবে কাজ করার জন্য ডিজাইন করা হয়েছে। তবে, flutterfire বর্তমানে লিনাক্স সমর্থন করে না।

নির্ভরতা যোগ করুন

আপনার প্রজেক্ট ডিরেক্টরিতে যান এবং প্রয়োজনীয় ডিপেন্ডেন্সিগুলো যোগ করুন:

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 : একটি কাস্টম প্যাকেজ যা কালারিস্ট অ্যাপের জন্য UI উপাদানগুলো সরবরাহ করে।
  • 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.9.2

dependencies:
  flutter:
    sdk: flutter
  colorist_ui: ^0.3.0
  flutter_riverpod: ^3.0.0
  riverpod_annotation: ^3.0.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^6.0.0
  build_runner: ^2.7.1
  riverpod_generator: ^3.0.0
  riverpod_lint: ^3.0.0
  json_serializable: ^6.11.1

flutter:
  uses-material-design: true

বিশ্লেষণ বিকল্পগুলি কনফিগার করুন

আপনার প্রোজেক্টের রুটে থাকা analysis_options.yaml ফাইলে custom_lint যোগ করুন:

include: package:flutter_lints/flutter.yaml

analyzer:
  plugins:
    - custom_lint

এই কনফিগারেশনটি কোডের মান বজায় রাখতে রিভারপড-এর নিজস্ব লিন্টগুলো সক্রিয় করে।

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(chatStateProvider.notifier);
    final logStateNotifier = ref.read(logStateProvider.notifier);

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

এটি এমন একটি ফ্লাটার অ্যাপ তৈরি করে যা একটি ইকো সার্ভিস প্রয়োগ করে, যা ব্যবহারকারীর বার্তা ফেরত দেওয়ার মাধ্যমে একটি এলএলএম (LLM)-এর আচরণ অনুকরণ করে।

স্থাপত্য বোঝা

চলুন, colorist অ্যাপটির গঠনপ্রণালী বুঝতে এক মিনিট সময় নিই:

colorist_ui প্যাকেজ

colorist_ui প্যাকেজটি পূর্ব-নির্মিত UI উপাদান এবং অবস্থা ব্যবস্থাপনা সরঞ্জাম সরবরাহ করে:

  1. MainScreen : প্রধান UI উপাদান যা প্রদর্শন করে:
    • ডেস্কটপে একটি স্প্লিট-স্ক্রিন লেআউট (ইন্টারঅ্যাকশন এরিয়া এবং লগ প্যানেল)
    • মোবাইলে একটি ট্যাবযুক্ত ইন্টারফেস
    • রঙিন ডিসপ্লে, চ্যাট ইন্টারফেস এবং ইতিহাসের থাম্বনেইল
  2. অবস্থা ব্যবস্থাপনা : অ্যাপটি একাধিক অবস্থা নোটিফায়ার ব্যবহার করে:
    • ChatStateNotifier : চ্যাট বার্তাগুলো পরিচালনা করে
    • ColorStateNotifier : বর্তমান রঙ এবং ইতিহাস পরিচালনা করে
    • LogStateNotifier : ডিবাগিংয়ের জন্য লগ এন্ট্রিগুলো পরিচালনা করে।
  3. বার্তা পরিচালনা : অ্যাপটি বিভিন্ন অবস্থা সহ একটি বার্তা মডেল ব্যবহার করে:
    • ব্যবহারকারীর বার্তা : ব্যবহারকারী কর্তৃক প্রবেশ করানো হয়েছে
    • এলএলএম বার্তা : এলএলএম দ্বারা (অথবা আপাতত আপনার ইকো পরিষেবা দ্বারা) তৈরি।
    • MessageState : LLM বার্তাগুলি সম্পূর্ণ হয়েছে নাকি এখনও আসছে তা ট্র্যাক করে।

অ্যাপ্লিকেশন আর্কিটেকচার

অ্যাপটি নিম্নলিখিত স্থাপত্য অনুসরণ করে:

  1. UI লেয়ার : colorist_ui প্যাকেজ দ্বারা সরবরাহকৃত
  2. স্টেট ম্যানেজমেন্ট : রিঅ্যাক্টিভ স্টেট ম্যানেজমেন্টের জন্য রিভারপড ব্যবহার করে।
  3. সার্ভিস লেয়ার : বর্তমানে এতে আপনার সিম্পল ইকো সার্ভিস রয়েছে, এটি জেমিনি চ্যাট সার্ভিস দ্বারা প্রতিস্থাপিত হবে।
  4. এলএলএম অন্তর্ভুক্তি : পরবর্তী ধাপে যোগ করা হবে

এই পৃথকীকরণ আপনাকে এলএলএম ইন্টিগ্রেশন বাস্তবায়নের উপর মনোযোগ দিতে সাহায্য করে, কারণ ইউআই উপাদানগুলোর ব্যবস্থা আগে থেকেই করা থাকে।

অ্যাপটি চালান

নিম্নলিখিত কমান্ডটি দিয়ে অ্যাপটি চালান:

flutter run -d DEVICE

DEVICE জায়গায় আপনার কাঙ্ক্ষিত ডিভাইসটির নাম লিখুন, যেমন macos , windows , chrome বা একটি ডিভাইস আইডি।

কালারিস্ট অ্যাপের স্ক্রিনশট যেখানে ইকো সার্ভিস মার্কডাউন রেন্ডার করছে তা দেখানো হচ্ছে।

এখন আপনি কালারিস্ট অ্যাপটি দেখতে পাবেন, যেখানে থাকবে:

  1. ডিফল্ট রঙ সহ একটি রঙিন প্রদর্শন এলাকা
  2. একটি চ্যাট ইন্টারফেস যেখানে আপনি বার্তা টাইপ করতে পারেন
  3. একটি লগ প্যানেল যা চ্যাটের কথোপকথনগুলো দেখাচ্ছে।

"আমি একটি গাঢ় নীল রঙ চাই"-এর মতো একটি বার্তা টাইপ করে সেন্ড চাপুন। ইকো সার্ভিসটি কেবল আপনার বার্তাটি পুনরাবৃত্তি করবে। পরবর্তী ধাপগুলিতে, আপনি ফায়ারবেস এআই লজিক ব্যবহার করে এটিকে প্রকৃত রঙের ব্যাখ্যা দিয়ে প্রতিস্থাপন করবেন।

এরপর কী?

পরবর্তী ধাপে, আপনি আপনার ইকো সার্ভিসকে জেমিনি চ্যাট সার্ভিস দিয়ে প্রতিস্থাপন করতে ফায়ারবেস কনফিগার করবেন এবং বেসিক জেমিনি এপিআই ইন্টিগ্রেশন প্রয়োগ করবেন। এর ফলে অ্যাপটি রঙের বিবরণ বুঝতে পারবে এবং বুদ্ধিদীপ্ত প্রতিক্রিয়া প্রদান করতে পারবে।

সমস্যা সমাধান

UI প্যাকেজ সমস্যা

colorist_ui প্যাকেজটি নিয়ে যদি কোনো সমস্যা হয়:

  • নিশ্চিত করুন যে আপনি সর্বশেষ সংস্করণটি ব্যবহার করছেন।
  • যাচাই করুন যে আপনি ডিপেন্ডেন্সিটি সঠিকভাবে যোগ করেছেন।
  • প্যাকেজের কোনো সাংঘর্ষিক সংস্করণ আছে কিনা তা পরীক্ষা করুন।

বিল্ড ত্রুটি

যদি আপনি বিল্ড ত্রুটি দেখতে পান:

  • নিশ্চিত করুন যে আপনার সিস্টেমে সর্বশেষ স্থিতিশীল চ্যানেল ফ্লাটার এসডিকে (Flutter SDK) ইনস্টল করা আছে।
  • প্রথমে flutter clean এবং তারপর flutter pub get চালান।
  • নির্দিষ্ট ত্রুটির বার্তাগুলির জন্য কনসোল আউটপুট পরীক্ষা করুন।

শেখা মূল ধারণাগুলো

  • প্রয়োজনীয় ডিপেন্ডেন্সি সহ একটি ফ্লাটার প্রজেক্ট সেট আপ করা
  • অ্যাপ্লিকেশনটির স্থাপত্য এবং উপাদানগুলির দায়িত্ব বোঝা
  • একটি সাধারণ পরিষেবা বাস্তবায়ন করা যা একটি এলএলএম-এর আচরণ অনুকরণ করে।
  • সার্ভিসটিকে UI কম্পোনেন্টগুলোর সাথে সংযুক্ত করা
  • স্টেট ম্যানেজমেন্টের জন্য রিভারপড ব্যবহার করা

৩. বেসিক জেমিনি চ্যাট ইন্টিগ্রেশন

এই ধাপে, আপনি আগের ধাপের ইকো সার্ভিসটিকে ফায়ারবেস এআই লজিক ব্যবহার করে জেমিনি এপিআই ইন্টিগ্রেশন দ্বারা প্রতিস্থাপন করবেন। আপনি ফায়ারবেস কনফিগার করবেন, প্রয়োজনীয় প্রোভাইডারগুলো সেট আপ করবেন এবং একটি বেসিক চ্যাট সার্ভিস ইমপ্লিমেন্ট করবেন যা জেমিনি এপিআই-এর সাথে যোগাযোগ করে।

এই ধাপে আপনি যা শিখবেন

  • ফ্লাটার অ্যাপ্লিকেশনে ফায়ারবেস সেট আপ করা
  • জেমিনি অ্যাক্সেসের জন্য ফায়ারবেস এআই লজিক কনফিগার করা
  • Firebase এবং Gemini পরিষেবাগুলির জন্য Riverpod প্রোভাইডার তৈরি করা
  • জেমিনি এপিআই ব্যবহার করে একটি প্রাথমিক চ্যাট পরিষেবা বাস্তবায়ন করা
  • অ্যাসিঙ্ক্রোনাস এপিআই প্রতিক্রিয়া এবং ত্রুটির অবস্থা পরিচালনা করা

ফায়ারবেস সেট আপ করুন

প্রথমে, আপনাকে আপনার ফ্লাটার প্রজেক্টের জন্য ফায়ারবেস সেট আপ করতে হবে। এর জন্য একটি ফায়ারবেস প্রজেক্ট তৈরি করতে হবে, তাতে আপনার অ্যাপটি যুক্ত করতে হবে এবং প্রয়োজনীয় ফায়ারবেস এআই লজিক সেটিংস কনফিগার করতে হবে।

একটি ফায়ারবেস প্রজেক্ট তৈরি করুন

  1. ফায়ারবেস কনসোলে যান এবং আপনার গুগল অ্যাকাউন্ট দিয়ে সাইন ইন করুন।
  2. একটি Firebase প্রজেক্ট তৈরি করতে ক্লিক করুন অথবা একটি বিদ্যমান প্রজেক্ট নির্বাচন করুন।
  3. আপনার প্রজেক্ট তৈরি করতে সেটআপ উইজার্ডটি অনুসরণ করুন।

আপনার Firebase প্রোজেক্টে Firebase AI Logic সেট আপ করুন

  1. Firebase কনসোলে আপনার প্রজেক্টে যান।
  2. বাম পাশের সাইডবারে AI নির্বাচন করুন।
  3. AI ড্রপ-ডাউন মেনু থেকে AI Logic নির্বাচন করুন।
  4. Firebase AI Logic কার্ডে, Get Started নির্বাচন করুন।
  5. আপনার প্রোজেক্টের জন্য জেমিনি ডেভেলপার এপিআই (Gemini Developer API) সক্রিয় করতে নির্দেশাবলী অনুসরণ করুন।

FlutterFire CLI ইনস্টল করুন

FlutterFire CLI ফ্লাটার অ্যাপে Firebase সেটআপকে সহজ করে তোলে:

dart pub global activate flutterfire_cli

আপনার ফ্লাটার অ্যাপে ফায়ারবেস যোগ করুন

  1. আপনার প্রজেক্টে Firebase core এবং Firebase AI Logic প্যাকেজগুলো যোগ করুন:
flutter pub add firebase_core firebase_ai
  1. FlutterFire কনফিগারেশন কমান্ডটি চালান:
flutterfire configure

এই কমান্ডটি যা করবে:

  • আপনাকে এইমাত্র তৈরি করা ফায়ারবেস প্রজেক্টটি নির্বাচন করতে বলা হচ্ছে।
  • আপনার ফ্লাটার অ্যাপ(গুলি) ফায়ারবেসে নিবন্ধন করুন
  • আপনার প্রোজেক্ট কনফিগারেশন দিয়ে একটি firebase_options.dart ফাইল তৈরি করুন।

এই কমান্ডটি আপনার নির্বাচিত প্ল্যাটফর্মগুলো (iOS, Android, macOS, Windows, web) স্বয়ংক্রিয়ভাবে শনাক্ত করবে এবং সেগুলোকে যথাযথভাবে কনফিগার করবে।

প্ল্যাটফর্ম-নির্দিষ্ট কনফিগারেশন

ফায়ারবেসের জন্য ফ্লাটারের ডিফল্ট ভার্সনের চেয়ে ন্যূনতম উচ্চতর ভার্সন প্রয়োজন। ফায়ারবেস এআই লজিক সার্ভারগুলোর সাথে যোগাযোগের জন্য এটির নেটওয়ার্ক অ্যাক্সেসও প্রয়োজন।

ম্যাকওএস অনুমতি কনফিগার করুন

macOS-এর জন্য, আপনার অ্যাপের এনটাইটেলমেন্টে নেটওয়ার্ক অ্যাক্সেস চালু করতে হবে:

  1. macos/Runner/DebugProfile.entitlements খুলুন এবং যোগ করুন:

macos/Runner/DebugProfile.entitlements

<key>com.apple.security.network.client</key>
<true/>
  1. এছাড়াও macos/Runner/Release.entitlements খুলুন এবং একই এন্ট্রিটি যোগ করুন।

iOS সেটিংস কনফিগার করুন

iOS-এর জন্য, ios/Podfile এর শীর্ষে সর্বনিম্ন সংস্করণটি আপডেট করুন:

ios/Podfile

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

জেমিনি মডেল প্রদানকারী তৈরি করুন

এখন আপনি Firebase এবং Gemini-এর জন্য Riverpod প্রোভাইডার তৈরি করবেন। lib/providers/gemini.dart একটি নতুন ফাইল তৈরি করুন:

lib/providers/gemini.dart

import 'dart:async';

import 'package:firebase_ai/firebase_ai.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../firebase_options.dart';

part 'gemini.g.dart';

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

@Riverpod(keepAlive: true)
Future<GenerativeModel> geminiModel(Ref ref) async {
  await ref.watch(firebaseAppProvider.future);

  final model = FirebaseAI.googleAI().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 চালান, তখন রিভারপড কোড জেনারেটরগুলো এই প্রোভাইডারগুলো তৈরি করে। এই কোডটি আপডেট করা প্রোভাইডার প্যাটার্নসহ রিভারপড ৩-এর অ্যানোটেশন-ভিত্তিক পদ্ধতি ব্যবহার করে।

  1. firebaseAppProvider : আপনার প্রোজেক্ট কনফিগারেশন দিয়ে Firebase চালু করে।
  2. geminiModelProvider : একটি জেমিনি জেনারেটিভ মডেল ইনস্ট্যান্স তৈরি করে।
  3. chatSessionProvider : জেমিনি মডেলের সাথে একটি চ্যাট সেশন তৈরি ও রক্ষণাবেক্ষণ করে।

চ্যাট সেশনের keepAlive: true অ্যানোটেশনটি নিশ্চিত করে যে এটি অ্যাপের জীবনচক্র জুড়ে টিকে থাকে এবং কথোপকথনের প্রাসঙ্গিকতা বজায় রাখে।

জেমিনি চ্যাট পরিষেবা বাস্তবায়ন করুন

চ্যাট পরিষেবাটি বাস্তবায়ন করতে 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_ai/firebase_ai.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(chatStateProvider.notifier);
    final logStateNotifier = ref.read(logStateProvider.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(keepAlive: true)
GeminiChatService geminiChatService(Ref ref) => GeminiChatService(ref);

এই পরিষেবা:

  1. ব্যবহারকারীর বার্তা গ্রহণ করে এবং সেগুলো জেমিনি এপিআই-তে পাঠায়।
  2. মডেলের প্রতিক্রিয়া দিয়ে চ্যাট ইন্টারফেস আপডেট করে।
  3. এলএলএম-এর প্রকৃত কার্যপ্রবাহ সহজে বোঝার জন্য সমস্ত যোগাযোগ নথিভুক্ত করা হয়।
  4. যথাযথ ব্যবহারকারীর মতামতের মাধ্যমে ত্রুটিগুলি সমাধান করে।

দ্রষ্টব্য: এই পর্যায়ে লগ উইন্ডোটি দেখতে প্রায় চ্যাট উইন্ডোর মতোই হবে। আপনি যখন ফাংশন কল এবং তারপর স্ট্রিমিং রেসপন্স যুক্ত করবেন, তখন লগটি আরও আকর্ষণীয় হয়ে উঠবে।

রিভারপড কোড তৈরি করুন

প্রয়োজনীয় রিভারপড কোড তৈরি করতে বিল্ড রানার কমান্ডটি চালান:

dart run build_runner build --delete-conflicting-outputs

এটি রিভারপডের কার্যকারিতার জন্য প্রয়োজনীয় .g.dart ফাইলগুলো তৈরি করবে।

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';

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. ইকো সার্ভিসকে জেমিনি এপিআই ভিত্তিক চ্যাট সার্ভিস দিয়ে প্রতিস্থাপন করা
  2. রিভারপডের AsyncValue প্যাটার্নের when মেথড ব্যবহার করে লোডিং এবং এরর স্ক্রিন যোগ করা।
  3. sendMessage কলব্যাকের মাধ্যমে আপনার নতুন চ্যাট পরিষেবার সাথে UI সংযোগ করা

অ্যাপটি চালান

নিম্নলিখিত কমান্ডটি দিয়ে অ্যাপটি চালান:

flutter run -d DEVICE

DEVICE জায়গায় আপনার কাঙ্ক্ষিত ডিভাইসটির নাম লিখুন, যেমন macos , windows , chrome বা একটি ডিভাইস আইডি।

কালারিস্ট অ্যাপের স্ক্রিনশট, যেখানে জেমিনি এলএলএম একটি উজ্জ্বল হলুদ রঙের অনুরোধের উত্তর দিচ্ছেন।

এখন আপনি যখন কোনো বার্তা টাইপ করবেন, সেটি জেমিনি এপিআই-তে পাঠানো হবে এবং আপনি প্রতিধ্বনির (echo) পরিবর্তে এলএলএম (LLM) থেকে একটি প্রতিক্রিয়া পাবেন। লগ প্যানেলটি এপিআই-এর সাথে হওয়া কার্যকলাপগুলো দেখাবে।

এলএলএম যোগাযোগ বোঝা

জেমিনি এপিআই (Gemini API)-এর সাথে যোগাযোগ করার সময় কী ঘটে, তা বুঝতে একটু সময় নেওয়া যাক:

যোগাযোগের প্রবাহ

  1. ব্যবহারকারীর ইনপুট : ব্যবহারকারী চ্যাট ইন্টারফেসে টেক্সট প্রবেশ করান।
  2. অনুরোধের বিন্যাস : অ্যাপটি জেমিনি এপিআই-এর জন্য টেক্সটটিকে একটি Content অবজেক্ট হিসেবে বিন্যাস করে।
  3. এপিআই যোগাযোগ : টেক্সটটি ফায়ারবেস এআই লজিকের মাধ্যমে জেমিনি এপিআই-তে পাঠানো হয়।
  4. এলএলএম প্রসেসিং : জেমিনি মডেলটি টেক্সট প্রসেস করে এবং একটি প্রতিক্রিয়া তৈরি করে।
  5. প্রতিক্রিয়া পরিচালনা : অ্যাপটি প্রতিক্রিয়া গ্রহণ করে এবং UI আপডেট করে।
  6. লগিং : স্বচ্ছতার জন্য সমস্ত যোগাযোগ লগ করা হয়।

চ্যাট সেশন এবং কথোপকথনের প্রেক্ষাপট

জেমিনি চ্যাট সেশন মেসেজগুলোর মধ্যে প্রাসঙ্গিকতা বজায় রাখে, যা কথোপকথনমূলক আদান-প্রদানের সুযোগ করে দেয়। এর মানে হলো, এলএলএম বর্তমান সেশনের পূর্ববর্তী আলাপচারিতা "মনে রাখে", যা আরও সুসংহত কথোপকথন সম্ভব করে তোলে।

আপনার চ্যাট সেশন প্রোভাইডারে থাকা keepAlive: true অ্যানোটেশনটি নিশ্চিত করে যে এই কনটেক্সটটি অ্যাপটির জীবনচক্র জুড়ে বজায় থাকে। LLM-এর সাথে একটি স্বাভাবিক কথোপকথনের ধারা বজায় রাখার জন্য এই স্থায়ী কনটেক্সটটি অত্যন্ত গুরুত্বপূর্ণ।

এরপর কী?

এই পর্যায়ে, আপনি জেমিনি এপিআই-কে যেকোনো কিছু জিজ্ঞাসা করতে পারেন, কারণ এটি কী উত্তর দেবে তার উপর কোনো বিধিনিষেধ নেই। উদাহরণস্বরূপ, আপনি এটিকে 'ওয়ার্স অফ দ্য রোজেস'-এর একটি সারাংশ জিজ্ঞাসা করতে পারেন, যা আপনার কালার অ্যাপের উদ্দেশ্যের সাথে সম্পর্কিত নয়।

পরবর্তী ধাপে, আপনি জেমিনিকে রঙের বিবরণ আরও কার্যকরভাবে ব্যাখ্যা করতে নির্দেশনা দেওয়ার জন্য একটি সিস্টেম প্রম্পট তৈরি করবেন। এর মাধ্যমে দেখানো হবে কীভাবে অ্যাপ্লিকেশন-নির্দিষ্ট প্রয়োজন অনুসারে একটি এলএলএম-এর আচরণ কাস্টমাইজ করতে হয় এবং এর সক্ষমতাগুলোকে আপনার অ্যাপের ডোমেইনে কেন্দ্রীভূত করতে হয়।

সমস্যা সমাধান

ফায়ারবেস কনফিগারেশন সমস্যা

ফায়ারবেস ইনিশিয়ালাইজেশনে কোনো ত্রুটি দেখা দিলে:

  • আপনার firebase_options.dart ফাইলটি সঠিকভাবে তৈরি হয়েছে কিনা তা নিশ্চিত করুন।
  • Firebase AI Logic অ্যাক্সেসের জন্য আপনি Blaze প্ল্যানে আপগ্রেড করেছেন কিনা তা যাচাই করুন।

এপিআই অ্যাক্সেস ত্রুটি

জেমিনি এপিআই অ্যাক্সেস করতে গিয়ে যদি কোনো ত্রুটি পান:

  • আপনার ফায়ারবেস প্রজেক্টে বিলিং সঠিকভাবে সেট আপ করা আছে কিনা তা নিশ্চিত করুন।
  • আপনার Firebase প্রজেক্টে Firebase AI Logic এবং Cloud AI API সক্রিয় করা আছে কিনা তা যাচাই করুন।
  • আপনার নেটওয়ার্ক সংযোগ এবং ফায়ারওয়াল সেটিংস পরীক্ষা করুন
  • মডেলের নাম ( gemini-2.0-flash ) সঠিক এবং উপলব্ধ আছে কিনা তা যাচাই করুন।

কথোপকথনের প্রেক্ষাপট সংক্রান্ত সমস্যা

যদি আপনি লক্ষ্য করেন যে জেমিনি চ্যাটের পূর্ববর্তী প্রসঙ্গ মনে রাখতে পারছে না:

  • নিশ্চিত করুন যে chatSession ফাংশনটি @Riverpod(keepAlive: true) দিয়ে অ্যানোটেট করা আছে।
  • সমস্ত বার্তা আদান-প্রদানের জন্য আপনি একই চ্যাট সেশন পুনরায় ব্যবহার করছেন কিনা তা যাচাই করুন।
  • বার্তা পাঠানোর আগে চ্যাট সেশনটি সঠিকভাবে চালু হয়েছে কিনা তা যাচাই করুন।

প্ল্যাটফর্ম-নির্দিষ্ট সমস্যা

প্ল্যাটফর্ম-নির্দিষ্ট সমস্যাগুলির জন্য:

  • iOS/macOS: সঠিক এনটাইটেলমেন্ট সেট করা আছে এবং ন্যূনতম সংস্করণ কনফিগার করা আছে কিনা তা নিশ্চিত করুন।
  • অ্যান্ড্রয়েড: ন্যূনতম SDK সংস্করণটি সঠিকভাবে সেট করা আছে কিনা তা যাচাই করুন।
  • কনসোলে প্ল্যাটফর্ম-নির্দিষ্ট ত্রুটির বার্তাগুলি পরীক্ষা করুন।

শেখা মূল ধারণাগুলো

  • ফ্লাটার অ্যাপ্লিকেশনে ফায়ারবেস সেট আপ করা
  • জেমিনিতে অ্যাক্সেসের জন্য ফায়ারবেস এআই লজিক কনফিগার করা হচ্ছে
  • অ্যাসিঙ্ক্রোনাস পরিষেবাগুলির জন্য রিভারপড প্রোভাইডার তৈরি করা
  • একটি চ্যাট পরিষেবা বাস্তবায়ন করা যা একজন এলএলএম-এর সাথে যোগাযোগ করে
  • অ্যাসিঙ্ক্রোনাস এপিআই স্টেট (লোডিং, এরর, ডেটা) পরিচালনা করা
  • এলএলএম যোগাযোগ প্রবাহ এবং চ্যাট সেশন বোঝা

৪. রঙের বর্ণনা দেওয়ার জন্য কার্যকর নির্দেশনা

এই ধাপে, আপনি একটি সিস্টেম প্রম্পট তৈরি ও প্রয়োগ করবেন যা জেমিনিকে রঙের বিবরণ ব্যাখ্যা করতে নির্দেশনা দেবে। আপনার কোড পরিবর্তন না করেই নির্দিষ্ট কাজের জন্য এলএলএম-এর আচরণ কাস্টমাইজ করার একটি শক্তিশালী উপায় হলো সিস্টেম প্রম্পট।

এই ধাপে আপনি যা শিখবেন

  • এলএলএম আবেদনপত্রে সিস্টেম প্রম্পট এবং তাদের গুরুত্ব বোঝা
  • ডোমেন-নির্দিষ্ট কাজের জন্য কার্যকর নির্দেশিকা তৈরি করা
  • ফ্লাটার অ্যাপে সিস্টেম প্রম্পট লোড করা এবং ব্যবহার করা
  • এলএলএম শিক্ষার্থীকে সামঞ্জস্যপূর্ণ বিন্যাসে উত্তর প্রদানে নির্দেশনা প্রদান
  • সিস্টেম প্রম্পটগুলো কীভাবে LLM-এর আচরণকে প্রভাবিত করে তা পরীক্ষা করা হচ্ছে

সিস্টেম প্রম্পট বোঝা

বাস্তবায়নে যাওয়ার আগে, চলুন জেনে নিই সিস্টেম প্রম্পট কী এবং কেন এগুলো গুরুত্বপূর্ণ:

সিস্টেম প্রম্পট বলতে কী বোঝায়?

সিস্টেম প্রম্পট হলো একটি এলএলএম-কে দেওয়া এক বিশেষ ধরনের নির্দেশনা, যা তার প্রতিক্রিয়ার জন্য প্রেক্ষাপট, আচরণের নির্দেশিকা এবং প্রত্যাশা নির্ধারণ করে। ব্যবহারকারীর বার্তার থেকে ভিন্ন, সিস্টেম প্রম্পটগুলো:

  • এলএলএম-এর ভূমিকা ও ব্যক্তিত্ব প্রতিষ্ঠা করুন
  • বিশেষায়িত জ্ঞান বা সক্ষমতা সংজ্ঞায়িত করুন।
  • ফরম্যাটিং নির্দেশাবলী প্রদান করুন
  • প্রতিক্রিয়ার উপর সীমাবদ্ধতা আরোপ করুন
  • বিভিন্ন পরিস্থিতি কীভাবে সামাল দিতে হয় তা বর্ণনা করুন।

সিস্টেম প্রম্পটকে এলএলএম-কে তার 'কাজের বিবরণ' দেওয়ার মতো করে ভাবুন — এটি মডেলকে বলে দেয় যে কথোপকথন জুড়ে তাকে কীভাবে আচরণ করতে হবে।

সিস্টেম প্রম্পট কেন গুরুত্বপূর্ণ

সামঞ্জস্যপূর্ণ ও কার্যকর এলএলএম মিথস্ক্রিয়া তৈরির জন্য সিস্টেম প্রম্পট অত্যন্ত গুরুত্বপূর্ণ, কারণ এগুলো:

  1. সামঞ্জস্য নিশ্চিত করুন : মডেলটিকে একটি সামঞ্জস্যপূর্ণ বিন্যাসে প্রতিক্রিয়া জানাতে নির্দেশনা দিন।
  2. প্রাসঙ্গিকতা উন্নত করুন : মডেলটিকে আপনার নির্দিষ্ট ডোমেনের (আপনার ক্ষেত্রে, রঙ) উপর কেন্দ্রীভূত করুন।
  3. সীমা নির্ধারণ করুন : মডেলটি কী করবে এবং কী করবে না তা সংজ্ঞায়িত করুন।
  4. ব্যবহারকারীর অভিজ্ঞতা উন্নত করুন : আরও স্বাভাবিক ও সহায়ক ইন্টারঅ্যাকশন প্যাটার্ন তৈরি করুন
  5. পরবর্তী প্রক্রিয়াকরণ হ্রাস করুন : এমন বিন্যাসে প্রতিক্রিয়া পান যা বিশ্লেষণ বা প্রদর্শন করা সহজ।

আপনার কালারিস্ট অ্যাপের জন্য, রঙের বিবরণ ধারাবাহিকভাবে ব্যাখ্যা করতে এবং একটি নির্দিষ্ট ফরম্যাটে RGB মান প্রদান করতে 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 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. ভূমিকার সংজ্ঞা : এলএলএম-কে 'রঙ বিশেষজ্ঞ সহকারী' হিসেবে প্রতিষ্ঠা করে।
  2. কাজের বিবরণ : রঙের বিবরণকে RGB মানে রূপান্তর করাই হলো প্রধান কাজ।
  3. প্রতিক্রিয়া বিন্যাস : সামঞ্জস্য রক্ষার জন্য RGB মানগুলি ঠিক কীভাবে বিন্যাস করা উচিত তা নির্দিষ্ট করে।
  4. উদাহরণ বিনিময় : প্রত্যাশিত মিথস্ক্রিয়ার ধরনের একটি সুনির্দিষ্ট উদাহরণ প্রদান করে
  5. প্রান্তিক পরিস্থিতি পরিচালনা : অস্পষ্ট বিবরণ কীভাবে পরিচালনা করতে হবে তার নির্দেশনা দেয়।
  6. সীমাবদ্ধতা ও নির্দেশিকা : RGB মান 0.0 এবং 1.0-এর মধ্যে রাখার মতো সীমা নির্ধারণ করে।

এই কাঠামোগত পদ্ধতিটি নিশ্চিত করে যে LLM-এর প্রতিক্রিয়াগুলি সামঞ্জস্যপূর্ণ, তথ্যপূর্ণ এবং এমনভাবে বিন্যস্ত হবে, যাতে আপনি প্রোগ্রামগতভাবে RGB মানগুলি বের করতে চাইলে তা সহজে বিশ্লেষণ করতে পারেন।

pubspec.yaml আপডেট করুন

এখন, আপনার pubspec.yaml নিচের অংশটি আপডেট করে assets ডিরেক্টরিটি অন্তর্ভুক্ত করুন:

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:riverpod_annotation/riverpod_annotation.dart';

part 'system_prompt.g.dart';

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

এই প্রোভাইডারটি রানটাইমে প্রম্পট ফাইলটি পড়ার জন্য ফ্লাটারের অ্যাসেট লোডিং সিস্টেম ব্যবহার করে।

জেমিনি মডেল সরবরাহকারীকে আপডেট করুন

এখন আপনার lib/providers/gemini.dart ফাইলটি পরিবর্তন করে সিস্টেম প্রম্পট অন্তর্ভুক্ত করুন:

lib/providers/gemini.dart

import 'dart:async';

import 'package:firebase_ai/firebase_ai.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

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

part 'gemini.g.dart';

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

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

  final model = FirebaseAI.googleAI().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) যোগ করা। এটি জেমিনিকে বলে দেয় যে এই চ্যাট সেশনের সমস্ত ইন্টারঅ্যাকশনের জন্য আপনার নির্দেশাবলীকে সিস্টেম প্রম্পট হিসেবে ব্যবহার করতে হবে।

রিভারপড কোড তৈরি করুন

প্রয়োজনীয় রিভারপড কোড তৈরি করতে বিল্ড রানার কমান্ডটি চালান:

dart run build_runner build --delete-conflicting-outputs

অ্যাপ্লিকেশনটি চালান এবং পরীক্ষা করুন।

এখন আপনার অ্যাপ্লিকেশনটি চালান:

flutter run -d DEVICE

কালারিস্ট অ্যাপের স্ক্রিনশট, যেখানে জেমিনি এলএলএম একটি রঙ নির্বাচন অ্যাপের জন্য তার চরিত্রের ভঙ্গিতে প্রতিক্রিয়া জানাচ্ছেন।

বিভিন্ন রঙের বিবরণ দিয়ে এটি পরীক্ষা করে দেখুন:

  • আমি আকাশী নীল রঙ চাই।
  • আমাকে গাঢ় সবুজ রঙ দাও।
  • একটি উজ্জ্বল সূর্যাস্তের কমলা রঙ তৈরি করুন।
  • আমি তাজা ল্যাভেন্ডারের মতো রঙ চাই।
  • আমাকে গভীর সমুদ্রের নীলের মতো কিছু দেখাও।

আপনি লক্ষ্য করবেন যে, জেমিনি এখন রংগুলো সম্পর্কে কথোপকথনমূলক ব্যাখ্যার পাশাপাশি সামঞ্জস্যপূর্ণভাবে বিন্যস্ত RGB মানও প্রদান করে। সিস্টেম প্রম্পটটি কার্যকরভাবে LLM-কে আপনার প্রয়োজনীয় প্রতিক্রিয়াগুলো প্রদান করতে পরিচালিত করেছে।

এছাড়াও রঙের প্রসঙ্গের বাইরে অন্য কোনো বিষয়বস্তু সম্পর্কে জিজ্ঞাসা করে দেখুন। যেমন, ‘ওয়ার্স অফ দ্য রোজেস’-এর প্রধান কারণগুলো। আপনি আগের ধাপ থেকে একটি পার্থক্য লক্ষ্য করবেন।

বিশেষায়িত কাজের জন্য দ্রুত প্রকৌশলের গুরুত্ব

সিস্টেম প্রম্পট হলো একাধারে শিল্প ও বিজ্ঞান। এগুলো এলএলএম ইন্টিগ্রেশনের একটি অত্যন্ত গুরুত্বপূর্ণ অংশ, যা আপনার নির্দিষ্ট অ্যাপ্লিকেশনের জন্য মডেলটি কতটা উপযোগী হবে, তা ব্যাপকভাবে প্রভাবিত করতে পারে। আপনি এখানে যা করেছেন তা হলো এক ধরনের প্রম্পট ইঞ্জিনিয়ারিং—অর্থাৎ, আপনার অ্যাপ্লিকেশনের প্রয়োজন অনুসারে মডেলটিকে কাজ করানোর জন্য নির্দেশাবলীকে বিশেষভাবে তৈরি করা।

কার্যকরী প্রম্পট ইঞ্জিনিয়ারিংয়ের সাথে জড়িত বিষয়গুলো হলো:

  1. ভূমিকার সুস্পষ্ট সংজ্ঞা : এলএলএম-এর উদ্দেশ্য কী তা প্রতিষ্ঠা করা
  2. সুস্পষ্ট নির্দেশাবলী : এলএলএম ঠিক কীভাবে প্রতিক্রিয়া জানাবে তার বিশদ বিবরণ।
  3. বাস্তব উদাহরণ : ভালো প্রতিক্রিয়াগুলো কেমন হয় তা শুধু বলার পরিবর্তে দেখানো
  4. প্রান্তিক পরিস্থিতি পরিচালনা : অস্পষ্ট পরিস্থিতি কীভাবে মোকাবেলা করতে হবে সে বিষয়ে এলএলএম-কে নির্দেশনা প্রদান।
  5. বিন্যাস সংক্রান্ত নির্দেশাবলী : উত্তরগুলো যেন সামঞ্জস্যপূর্ণ ও ব্যবহারযোগ্যভাবে বিন্যস্ত থাকে তা নিশ্চিত করা।

আপনার তৈরি করা সিস্টেম প্রম্পটটি জেমিনির সাধারণ ক্ষমতাগুলোকে একটি বিশেষায়িত রঙ ব্যাখ্যা সহায়কে রূপান্তরিত করে, যা আপনার অ্যাপ্লিকেশনের প্রয়োজন অনুসারে বিশেষভাবে বিন্যস্ত প্রতিক্রিয়া প্রদান করে। এটি একটি শক্তিশালী প্যাটার্ন যা আপনি বিভিন্ন ক্ষেত্র ও কাজে প্রয়োগ করতে পারেন।

এরপর কী?

পরবর্তী ধাপে, আপনি ফাংশন ডিক্লারেশন যোগ করে এই ভিত্তির ওপর কাজ করবেন, যা LLM-কে শুধু RGB ভ্যালু সাজেস্ট করতেই নয়, বরং সরাসরি রঙ সেট করার জন্য আপনার অ্যাপের ফাংশন কল করতেও সক্ষম করে। এটি দেখায় যে কীভাবে LLM স্বাভাবিক ভাষা এবং অ্যাপ্লিকেশনের সুনির্দিষ্ট ফিচারের মধ্যেকার ব্যবধান কমিয়ে আনতে পারে।

সমস্যা সমাধান

অ্যাসেট লোডিং সমস্যা

সিস্টেম প্রম্পট লোড করতে ত্রুটি দেখা দিলে:

  • আপনার pubspec.yaml অ্যাসেটস ডিরেক্টরি সঠিকভাবে তালিকাভুক্ত আছে কিনা তা যাচাই করুন।
  • rootBundle.loadString() -এর পাথটি আপনার ফাইলের অবস্থানের সাথে মেলে কিনা তা যাচাই করুন।
  • অ্যাসেট বান্ডেল রিফ্রেশ করতে প্রথমে flutter clean এবং তারপর flutter pub get চালান।

অসামঞ্জস্যপূর্ণ প্রতিক্রিয়া

যদি এলএলএম আপনার ফরম্যাট নির্দেশাবলী ধারাবাহিকভাবে অনুসরণ না করে:

  • সিস্টেম প্রম্পটে ফরম্যাটের প্রয়োজনীয়তাগুলো আরও সুস্পষ্ট করার চেষ্টা করুন।
  • প্রত্যাশিত প্যাটার্নটি দেখানোর জন্য আরও উদাহরণ যোগ করুন।
  • আপনি যে ফরম্যাটটি অনুরোধ করছেন তা যেন মডেলটির জন্য উপযুক্ত হয়, তা নিশ্চিত করুন।

এপিআই রেট লিমিটিং

যদি আপনি রেট লিমিটিং সম্পর্কিত ত্রুটির সম্মুখীন হন:

  • মনে রাখবেন যে Firebase AI Logic পরিষেবা ব্যবহারের সীমাবদ্ধতা রয়েছে।
  • এক্সপোনেনশিয়াল ব্যাকঅফ সহ রিট্রাই লজিক প্রয়োগ করার কথা বিবেচনা করুন।
  • কোটা সংক্রান্ত কোনো সমস্যা আছে কিনা তা জানতে আপনার ফায়ারবেস কনসোল চেক করুন।

শেখা মূল ধারণাগুলো

  • এলএলএম আবেদনপত্রে সিস্টেম প্রম্পটের ভূমিকা ও গুরুত্ব বোঝা
  • স্পষ্ট নির্দেশনা, উদাহরণ এবং সীমাবদ্ধতা সহ কার্যকর প্রম্পট তৈরি করা
  • ফ্লাটার অ্যাপ্লিকেশনে সিস্টেম প্রম্পট লোড এবং ব্যবহার করা
  • ডোমেন-নির্দিষ্ট কাজের জন্য এলএলএম আচরণকে নির্দেশিত করা
  • এলএলএম প্রতিক্রিয়াগুলিকে আকার দিতে প্রম্পট ইঞ্জিনিয়ারিং ব্যবহার করা

এই ধাপে দেখানো হয়েছে কিভাবে আপনি আপনার কোড পরিবর্তন না করেই, শুধুমাত্র সিস্টেম প্রম্পটে স্পষ্ট নির্দেশনা প্রদানের মাধ্যমে LLM-এর আচরণে উল্লেখযোগ্য কাস্টমাইজেশন করতে পারেন।

৫. এলএলএম টুলগুলির জন্য ফাংশন ঘোষণা

এই ধাপে, আপনি ফাংশন ডিক্লারেশন প্রয়োগ করার মাধ্যমে আপনার অ্যাপে জেমিনিকে সক্রিয় করার কাজ শুরু করবেন। এই শক্তিশালী বৈশিষ্ট্যটি এলএলএম-কে শুধু আরজিবি মান প্রস্তাব করতেই নয়, বরং বিশেষ টুল কলের মাধ্যমে আপনার অ্যাপের ইউআই-তে তা সেট করতেও সক্ষম করে। তবে, ফ্লাটার অ্যাপে এলএলএম অনুরোধগুলো কার্যকর হতে দেখার জন্য পরবর্তী ধাপটির প্রয়োজন হবে।

এই ধাপে আপনি যা শিখবেন

  • ফ্লাটার অ্যাপ্লিকেশনের জন্য LLM ফাংশন কলিং এবং এর সুবিধাগুলো বোঝা
  • জেমিনির জন্য স্কিমা-ভিত্তিক ফাংশন ঘোষণা সংজ্ঞায়িত করা
  • আপনার জেমিনি মডেলের সাথে ফাংশন ডিক্লারেশন একীভূত করা
  • টুলের সক্ষমতা ব্যবহার করার জন্য সিস্টেম প্রম্পট আপডেট করা হচ্ছে।

ফাংশন কলিং বোঝা

ফাংশন ডিক্লারেশন প্রয়োগ করার আগে, চলুন জেনে নিই এগুলো কী এবং কেন এগুলো মূল্যবান:

ফাংশন কলিং বলতে কী বোঝায়?

ফাংশন কলিং (কখনও কখনও "টুল ব্যবহার" বলা হয়) এমন একটি সক্ষমতা যা একজন এলএলএম-কে নিম্নলিখিত কাজগুলো করতে দেয়:

  1. কখন কোনো ব্যবহারকারীর অনুরোধ একটি নির্দিষ্ট ফাংশন আহ্বান করার মাধ্যমে উপকৃত হবে তা শনাক্ত করুন।
  2. ঐ ফাংশনের জন্য প্রয়োজনীয় প্যারামিটারগুলো দিয়ে একটি স্ট্রাকচার্ড JSON অবজেক্ট তৈরি করুন।
  3. আপনার অ্যাপ্লিকেশনটিকে ওই প্যারামিটারগুলো দিয়ে ফাংশনটি সম্পাদন করতে দিন।
  4. ফাংশনের ফলাফল গ্রহণ করুন এবং এটিকে এর প্রতিক্রিয়ার সাথে অন্তর্ভুক্ত করুন।

এলএলএম শুধু কী করতে হবে তা বর্ণনা করার পরিবর্তে, ফাংশন কলিং আপনার অ্যাপ্লিকেশনে সুনির্দিষ্ট পদক্ষেপ গ্রহণ করার ক্ষমতা দেয়।

ফ্লাটার অ্যাপের জন্য ফাংশন কলিং কেন গুরুত্বপূর্ণ

ফাংশন কলিং স্বাভাবিক ভাষা এবং অ্যাপ্লিকেশন বৈশিষ্ট্যগুলির মধ্যে একটি শক্তিশালী সংযোগ স্থাপন করে:

  1. সরাসরি পদক্ষেপ : ব্যবহারকারীরা স্বাভাবিক ভাষায় তাদের চাহিদা বর্ণনা করতে পারেন এবং অ্যাপটি সুনির্দিষ্ট পদক্ষেপের মাধ্যমে সাড়া দেয়।
  2. কাঠামোগত আউটপুট : এলএলএম এমন টেক্সটের পরিবর্তে পরিচ্ছন্ন ও কাঠামোগত ডেটা তৈরি করে, যেগুলোর পার্সিং প্রয়োজন হয়।
  3. জটিল কার্যক্রম : LLM-কে বাহ্যিক ডেটা অ্যাক্সেস করতে, গণনা সম্পাদন করতে, বা অ্যাপ্লিকেশনের অবস্থা পরিবর্তন করতে সক্ষম করে।
  4. উন্নত ব্যবহারকারীর অভিজ্ঞতা : কথোপকথন এবং কার্যকারিতার মধ্যে নির্বিঘ্ন সমন্বয় তৈরি করে

আপনার কালারিস্ট অ্যাপে, ফাংশন কলিংয়ের মাধ্যমে ব্যবহারকারীরা "আমি একটি ফরেস্ট গ্রিন চাই" বললেই, টেক্সট থেকে RGB ভ্যালু পার্স না করেই UI তাৎক্ষণিকভাবে সেই রঙে আপডেট হয়ে যায়।

ফাংশন ঘোষণা সংজ্ঞায়িত করুন

আপনার ফাংশন ডিক্লারেশনগুলো সংজ্ঞায়িত করতে lib/services/gemini_tools.dart একটি নতুন ফাইল তৈরি করুন:

lib/services/gemini_tools.dart

import 'package:firebase_ai/firebase_ai.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(keepAlive: true)
GeminiTools geminiTools(Ref ref) => GeminiTools(ref);

ফাংশন ঘোষণা বোঝা

চলুন এই কোডটি কী করে তা বিশ্লেষণ করা যাক:

  1. ফাংশনের নামকরণ : এর উদ্দেশ্য স্পষ্টভাবে বোঝানোর জন্য আপনার ফাংশনের নাম set_color রাখুন।
  2. কার্যাবলীর বিবরণ : আপনি একটি সুস্পষ্ট বিবরণ প্রদান করবেন যা এলএলএম-কে বুঝতে সাহায্য করবে কখন এটি ব্যবহার করতে হবে।
  3. প্যারামিটার সংজ্ঞা : আপনি নিজস্ব বিবরণ সহ কাঠামোগত প্যারামিটার নির্ধারণ করেন:
    • red : RGB-এর লাল উপাদান, যা 0.0 এবং 1.0-এর মধ্যে একটি সংখ্যা হিসাবে নির্দিষ্ট করা হয়।
    • green : RGB-এর সবুজ উপাদান, যা 0.0 এবং 1.0-এর মধ্যে একটি সংখ্যা হিসাবে নির্দিষ্ট করা হয়।
    • blue : RGB-এর নীল উপাদান, যা 0.0 এবং 1.0-এর মধ্যে একটি সংখ্যা হিসাবে নির্দিষ্ট করা হয়।
  4. স্কিমা প্রকারভেদ : এগুলি যে সাংখ্যিক মান, তা বোঝাতে আপনি Schema.number() ব্যবহার করেন।
  5. টুলস সংগ্রহ : আপনি আপনার ফাংশন ঘোষণা সম্বলিত টুলসের একটি তালিকা তৈরি করেন।

এই কাঠামোগত পদ্ধতি জেমিনি এলএলএম-কে বুঝতে সাহায্য করে:

  • কখন এই ফাংশনটি কল করা উচিত
  • এটিকে কী কী প্যারামিটার সরবরাহ করতে হবে
  • সেই প্যারামিটারগুলোর ক্ষেত্রে কী কী সীমাবদ্ধতা প্রযোজ্য (যেমন মানের পরিসর)?

জেমিনি মডেল সরবরাহকারীকে আপডেট করুন

এখন, জেমিনি মডেল ইনিশিয়ালাইজ করার সময় ফাংশন ডিক্লারেশনগুলো অন্তর্ভুক্ত করতে আপনার lib/providers/gemini.dart ফাইলটি পরিবর্তন করুন:

lib/providers/gemini.dart

import 'dart:async';

import 'package:firebase_ai/firebase_ai.dart';
import 'package:firebase_core/firebase_core.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(keepAlive: true)
Future<FirebaseApp> firebaseApp(Ref ref) =>
    Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);

@Riverpod(keepAlive: true)
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 = FirebaseAI.googleAI().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 প্যারামিটারটি যোগ করা। এর ফলে, জেমিনি জানতে পারে যে কোন কোন ফাংশন কল করার জন্য উপলব্ধ আছে।

সিস্টেম প্রম্পট আপডেট করুন

এখন আপনাকে নতুন set_color টুলটি ব্যবহার করার জন্য 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.

## 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. সংশোধিত উদাহরণ : আপনি দেখিয়েছেন কীভাবে প্রতিক্রিয়ায় ফরম্যাট করা টেক্সটের পরিবর্তে একটি টুল কল অন্তর্ভুক্ত করা উচিত।
  4. ফরম্যাটিংয়ের আবশ্যকতা দূর করা হয়েছে : যেহেতু আপনি স্ট্রাকচার্ড ফাংশন কল ব্যবহার করছেন, তাই আপনার আর কোনো নির্দিষ্ট টেক্সট ফরম্যাটের প্রয়োজন নেই।

এই আপডেট করা প্রম্পটটি এলএলএম-কে শুধু টেক্সট আকারে আরজিবি মান প্রদানের পরিবর্তে ফাংশন কলিং ব্যবহার করতে নির্দেশ দেয়।

রিভারপড কোড তৈরি করুন

প্রয়োজনীয় রিভারপড কোড তৈরি করতে বিল্ড রানার কমান্ডটি চালান:

dart run build_runner build --delete-conflicting-outputs

অ্যাপ্লিকেশনটি চালান

এই পর্যায়ে, জেমিনি এমন কন্টেন্ট তৈরি করবে যা ফাংশন কলিং ব্যবহার করার চেষ্টা করে, কিন্তু আপনি এখনও ফাংশন কলগুলোর জন্য হ্যান্ডলার ইমপ্লিমেন্ট করেননি। যখন আপনি অ্যাপটি রান করে কোনো রঙের বর্ণনা দেবেন, তখন দেখবেন জেমিনি এমনভাবে সাড়া দিচ্ছে যেন এটি কোনো টুল চালু করেছে, কিন্তু পরবর্তী ধাপের আগে আপনি UI-তে কোনো রঙের পরিবর্তন দেখতে পাবেন না।

আপনার অ্যাপটি চালান:

flutter run -d DEVICE

কালারিস্ট অ্যাপের স্ক্রিনশট যেখানে জেমিনি এলএলএম আংশিক প্রতিক্রিয়া জানাচ্ছে।

'গভীর সমুদ্রের নীল' বা 'বনের সবুজ'-এর মতো কোনো রঙের বর্ণনা দিয়ে দেখুন এবং প্রতিক্রিয়াগুলো পর্যবেক্ষণ করুন। এলএলএম (LLM) উপরে সংজ্ঞায়িত ফাংশনগুলোকে কল করার চেষ্টা করছে, কিন্তু আপনার কোড এখনও ফাংশন কলগুলো শনাক্ত করতে পারছে না।

ফাংশন কলিং প্রক্রিয়া

চলুন জেনে নেওয়া যাক, মিথুন রাশি ফাংশন কলিং ব্যবহার করলে কী ঘটে:

  1. ফাংশন নির্বাচন : ব্যবহারকারীর অনুরোধের ভিত্তিতে কোনো ফাংশন কল সহায়ক হবে কিনা, তা এলএলএম (LLM) সিদ্ধান্ত নেয়।
  2. প্যারামিটার তৈরি : এলএলএম এমন প্যারামিটার মান তৈরি করে যা ফাংশনের স্কিমার সাথে সামঞ্জস্যপূর্ণ।
  3. ফাংশন কল ফরম্যাট : LLM তার প্রতিক্রিয়ায় একটি স্ট্রাকচার্ড ফাংশন কল অবজেক্ট পাঠায়।
  4. অ্যাপ্লিকেশন হ্যান্ডলিং : আপনার অ্যাপ এই কলটি গ্রহণ করবে এবং প্রাসঙ্গিক ফাংশনটি (যা পরবর্তী ধাপে প্রয়োগ করা হয়েছে) কার্যকর করবে।
  5. প্রতিক্রিয়া একত্রীকরণ : একাধিক পালাবিশিষ্ট কথোপকথনে, LLM ফাংশনটির ফলাফল ফেরত পাওয়ার প্রত্যাশা করে।

আপনার অ্যাপের বর্তমান অবস্থায় প্রথম তিনটি ধাপ সম্পন্ন হচ্ছে, কিন্তু আপনি এখনো ৪ বা ৫ নম্বর ধাপটি (ফাংশন কলগুলো পরিচালনা করা) বাস্তবায়ন করেননি, যা আপনি পরবর্তী ধাপে করবেন।

প্রযুক্তিগত বিবরণ: মিথুন রাশি কীভাবে ফাংশন ব্যবহার করার সিদ্ধান্ত নেয়

মিথুন রাশি নিম্নলিখিত বিষয়গুলির উপর ভিত্তি করে কখন ফাংশন ব্যবহার করতে হবে সে সম্পর্কে বুদ্ধিদীপ্ত সিদ্ধান্ত নেয়:

  1. ব্যবহারকারীর অভিপ্রায় : ব্যবহারকারীর অনুরোধটি কোনো ফাংশনের মাধ্যমে সবচেয়ে ভালোভাবে পূরণ করা যাবে কিনা
  2. ফাংশনের প্রাসঙ্গিকতা : উপলব্ধ ফাংশনগুলো কাজের সাথে কতটা ভালোভাবে মেলে।
  3. প্যারামিটার প্রাপ্যতা : এটি আত্মবিশ্বাসের সাথে প্যারামিটার মান নির্ধারণ করতে পারে কিনা
  4. সিস্টেম নির্দেশাবলী : ফাংশন ব্যবহার সম্পর্কে আপনার সিস্টেম প্রম্পট থেকে প্রাপ্ত নির্দেশনা

সুস্পষ্ট ফাংশন ডিক্লারেশন এবং সিস্টেম নির্দেশনা প্রদানের মাধ্যমে, আপনি জেমিনিকে এমনভাবে সেট আপ করেছেন যাতে এটি রঙের বিবরণ সংক্রান্ত অনুরোধগুলোকে set_color ফাংশনটি কল করার সুযোগ হিসেবে শনাক্ত করতে পারে।

এরপর কী?

পরবর্তী ধাপে, আপনি জেমিনি থেকে আসা ফাংশন কলগুলোর জন্য হ্যান্ডলার প্রয়োগ করবেন। এর মাধ্যমে প্রক্রিয়াটি সম্পূর্ণ হবে, যা এলএলএম-এর ফাংশন কলের মাধ্যমে ব্যবহারকারীর বর্ণনাকে ইউআই-তে প্রকৃত রঙের পরিবর্তন ঘটাতে সক্ষম করবে।

সমস্যা সমাধান

ফাংশন ঘোষণার সমস্যা

ফাংশন ডিক্লারেশনে কোনো ত্রুটি দেখা দিলে:

  • প্যারামিটারের নাম এবং টাইপ প্রত্যাশিত মানের সাথে মিলছে কিনা তা যাচাই করুন।
  • ফাংশনের নামটি স্পষ্ট এবং বর্ণনামূলক কিনা তা যাচাই করুন।
  • নিশ্চিত করুন যে ফাংশনের বিবরণটি এর উদ্দেশ্য সঠিকভাবে ব্যাখ্যা করে।

সিস্টেম প্রম্পট সমস্যা

যদি এলএলএম ফাংশনটি ব্যবহার করার চেষ্টা না করে:

  • যাচাই করুন যে আপনার সিস্টেম প্রম্পট LLM-কে set_color টুলটি ব্যবহার করার জন্য স্পষ্টভাবে নির্দেশ দিচ্ছে।
  • সিস্টেম প্রম্পটে থাকা উদাহরণটি ফাংশনের ব্যবহার প্রদর্শন করে কিনা তা যাচাই করুন।
  • টুলটি ব্যবহারের নির্দেশনা আরও সুস্পষ্ট করার চেষ্টা করুন।

সাধারণ বিষয়গুলি

যদি আপনি অন্য কোনো সমস্যার সম্মুখীন হন:

  • ফাংশন ডিক্লারেশন সম্পর্কিত কোনো ত্রুটির জন্য কনসোল চেক করুন।
  • টুলগুলো মডেলে সঠিকভাবে পাঠানো হয়েছে কিনা তা যাচাই করুন।
  • রিভারপড দ্বারা তৈরি সমস্ত কোড হালনাগাদ আছে কিনা তা নিশ্চিত করুন।

শেখা মূল ধারণাগুলো

  • ফ্লাটার অ্যাপে LLM-এর সক্ষমতা বাড়ানোর জন্য ফাংশন ডিক্লারেশন সংজ্ঞায়িত করা
  • কাঠামোগত ডেটা সংগ্রহের জন্য প্যারামিটার স্কিমা তৈরি করা
  • জেমিনি মডেলের সাথে ফাংশন ঘোষণা একীভূত করা
  • সিস্টেম আপডেট করার মাধ্যমে ফাংশন ব্যবহারে উৎসাহিত করা হয়।
  • এলএলএম কীভাবে ফাংশন নির্বাচন ও আহ্বান করে তা বোঝা

এই ধাপে দেখানো হয়েছে কীভাবে এলএলএম (LLM) স্বাভাবিক ভাষার ইনপুট এবং কাঠামোগত ফাংশন কলের মধ্যেকার ব্যবধান পূরণ করতে পারে, যা কথোপকথন এবং অ্যাপ্লিকেশনের বৈশিষ্ট্যগুলির মধ্যে নির্বিঘ্ন একীকরণের ভিত্তি স্থাপন করে।

৬. টুল হ্যান্ডলিং বাস্তবায়ন

এই ধাপে, আপনি জেমিনি থেকে আসা ফাংশন কলগুলোর জন্য হ্যান্ডলার প্রয়োগ করবেন। এর মাধ্যমে স্বাভাবিক ভাষার ইনপুট এবং অ্যাপ্লিকেশনের সুনির্দিষ্ট ফিচারগুলোর মধ্যে যোগাযোগের চক্রটি সম্পূর্ণ হয়, যা এলএলএম-কে ব্যবহারকারীর বর্ণনার উপর ভিত্তি করে সরাসরি আপনার ইউআই নিয়ন্ত্রণ করার সুযোগ দেয়।

এই ধাপে আপনি যা শিখবেন

  • এলএলএম অ্যাপ্লিকেশনগুলিতে সম্পূর্ণ ফাংশন কলিং পাইপলাইন বোঝা
  • একটি ফ্লাটার অ্যাপ্লিকেশনে জেমিনি থেকে ফাংশন কল প্রসেস করা
  • অ্যাপ্লিকেশন স্টেট পরিবর্তনকারী ফাংশন হ্যান্ডলার বাস্তবায়ন করা
  • ফাংশনের প্রতিক্রিয়াগুলি পরিচালনা করা এবং LLM-এ ফলাফল ফেরত পাঠানো
  • LLM এবং UI-এর মধ্যে একটি সম্পূর্ণ যোগাযোগ ব্যবস্থা তৈরি করা
  • স্বচ্ছতার জন্য ফাংশন কল এবং প্রতিক্রিয়া লগ করা

ফাংশন কলিং পাইপলাইন বোঝা

বাস্তবায়নে যাওয়ার আগে, চলুন সম্পূর্ণ ফাংশন কলিং পাইপলাইনটি বুঝে নিই:

প্রান্ত থেকে প্রান্ত পর্যন্ত প্রবাহ

  1. ব্যবহারকারীর ইনপুট : ব্যবহারকারী স্বাভাবিক ভাষায় একটি রঙের বর্ণনা দেবেন (যেমন, "ফরেস্ট গ্রিন")।
  2. LLM প্রক্রিয়াকরণ : জেমিনি বর্ণনাটি বিশ্লেষণ করে set_color ফাংশনটি কল করার সিদ্ধান্ত নেয়।
  3. ফাংশন কল তৈরি : জেমিনি প্যারামিটার (লাল, সবুজ, নীল মান) সহ একটি কাঠামোগত JSON তৈরি করে।
  4. ফাংশন কল গ্রহণ : আপনার অ্যাপ জেমিনি থেকে এই কাঠামোগত ডেটা গ্রহণ করে।
  5. ফাংশন সম্পাদন : আপনার অ্যাপ প্রদত্ত প্যারামিটারসহ ফাংশনটি সম্পাদন করে।
  6. অবস্থা হালনাগাদ : এই ফাংশনটি আপনার অ্যাপের অবস্থা হালনাগাদ করে (প্রদর্শিত রঙ পরিবর্তন করে)।
  7. প্রতিক্রিয়া তৈরি : আপনার ফাংশনটি LLM-এ ফলাফল ফেরত পাঠায়।
  8. প্রতিক্রিয়া অন্তর্ভুক্তি : এলএলএম এই ফলাফলগুলোকে তার চূড়ান্ত প্রতিক্রিয়ার মধ্যে অন্তর্ভুক্ত করে।
  9. UI আপডেট : আপনার UI অবস্থার পরিবর্তনে সাড়া দিয়ে নতুন রঙ প্রদর্শন করে।

সঠিক এলএলএম ইন্টিগ্রেশনের জন্য সম্পূর্ণ যোগাযোগ চক্রটি অপরিহার্য। যখন একটি এলএলএম কোনো ফাংশন কল করে, তখন এটি কেবল অনুরোধ পাঠিয়েই চলে যায় না। বরং, এটি আপনার অ্যাপ্লিকেশনটির ফাংশনটি সম্পাদন করে ফলাফল ফেরত দেওয়ার জন্য অপেক্ষা করে। এরপর এলএলএম এই ফলাফলগুলো ব্যবহার করে তার চূড়ান্ত প্রতিক্রিয়া তৈরি করে, যা গৃহীত পদক্ষেপগুলোকে স্বীকৃতি দিয়ে একটি স্বাভাবিক কথোপকথনের প্রবাহ সৃষ্টি করে।

ফাংশন হ্যান্ডলার বাস্তবায়ন করুন

ফাংশন কলের জন্য হ্যান্ডলার যোগ করতে আপনার lib/services/gemini_tools.dart ফাইলটি আপডেট করুন:

lib/services/gemini_tools.dart

import 'package:colorist_ui/colorist_ui.dart';
import 'package:firebase_ai/firebase_ai.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(logStateProvider.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(colorStateProvider.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(logStateProvider.notifier);
    logStateNotifier.logFunctionResults(functionResults);
    return functionResults;
  }

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

@Riverpod(keepAlive: true)
GeminiTools geminiTools(Ref ref) => GeminiTools(ref);

ফাংশন হ্যান্ডলারগুলি বোঝা

চলুন এই ফাংশন হ্যান্ডলারগুলো কী কাজ করে তা বিশদভাবে আলোচনা করা যাক:

  1. handleFunctionCall : একটি কেন্দ্রীয় ডিসপ্যাচার যা:
    • স্বচ্ছতার জন্য লগ প্যানেলে ফাংশন কলটি লগ করে।
    • ফাংশনের নামের উপর ভিত্তি করে উপযুক্ত হ্যান্ডলারে রুট করা হয়।
    • একটি কাঠামোগত প্রতিক্রিয়া প্রদান করে যা এলএলএম-এ ফেরত পাঠানো হবে।
  2. handleSetColor : আপনার set_color ফাংশনের জন্য নির্দিষ্ট হ্যান্ডলার যা:
    • আর্গুমেন্ট ম্যাপ থেকে RGB মান বের করে।
    • সেগুলোকে প্রত্যাশিত টাইপে (ডাবল) রূপান্তর করে।
    • colorStateNotifier ব্যবহার করে অ্যাপ্লিকেশনটির রঙের অবস্থা আপডেট করে।
    • সফলতার অবস্থা এবং বর্তমান রঙের তথ্য সহ একটি কাঠামোগত প্রতিক্রিয়া তৈরি করে।
    • ডিবাগিংয়ের জন্য ফাংশনের ফলাফল লগ করে।
  3. handleUnknownFunction : অজানা ফাংশনগুলির জন্য একটি ফলব্যাক হ্যান্ডলার যা:
    • অসমর্থিত ফাংশন সম্পর্কে একটি সতর্কবার্তা লগ করে।
    • LLM-কে একটি ত্রুটিপূর্ণ প্রতিক্রিয়া ফেরত দেয়।

handleSetColor ফাংশনটি বিশেষভাবে গুরুত্বপূর্ণ, কারণ এটি LLM-এর স্বাভাবিক ভাষা বোঝার ক্ষমতা এবং সুনির্দিষ্ট UI পরিবর্তনের মধ্যেকার ব্যবধান পূরণ করে।

ফাংশন কল এবং প্রতিক্রিয়া প্রক্রিয়া করার জন্য জেমিনি চ্যাট পরিষেবা আপডেট করুন।

এখন, LLM রেসপন্স থেকে ফাংশন কলগুলো প্রসেস করতে এবং ফলাফলগুলো LLM-এ ফেরত পাঠাতে 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_ai/firebase_ai.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(chatStateProvider.notifier);
    final logStateNotifier = ref.read(logStateProvider.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(keepAlive: true)
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 ব্যবহার করে এই ফলাফলগুলো LLM-এ ফেরত পাঠায়।
  5. ফাংশনের ফলাফলের প্রতি LLM-এর প্রতিক্রিয়া প্রক্রিয়া করে।
  6. চূড়ান্ত প্রতিক্রিয়া টেক্সট দিয়ে UI আপডেট করে।

এটি একটি চক্রাকার প্রবাহ তৈরি করে:

  • ব্যবহারকারী → এলএলএম: একটি রঙের জন্য অনুরোধ করেন
  • LLM → App: প্যারামিটার সহ ফাংশন কল
  • অ্যাপ → ব্যবহারকারী: নতুন রঙ প্রদর্শিত হয়েছে
  • অ্যাপ → এলএলএম: ফাংশনের ফলাফল
  • এলএলএম → ব্যবহারকারী: ফাংশনের ফলাফল অন্তর্ভুক্ত করে চূড়ান্ত প্রতিক্রিয়া

রিভারপড কোড তৈরি করুন

প্রয়োজনীয় রিভারপড কোড তৈরি করতে বিল্ড রানার কমান্ডটি চালান:

dart run build_runner build --delete-conflicting-outputs

সম্পূর্ণ প্রবাহটি চালান এবং পরীক্ষা করুন।

এখন আপনার অ্যাপ্লিকেশনটি চালান:

flutter run -d DEVICE

কালারিস্ট অ্যাপের স্ক্রিনশট যেখানে দেখা যাচ্ছে জেমিনি এলএলএম একটি ফাংশন কলের মাধ্যমে সাড়া দিচ্ছে।

বিভিন্ন রঙের বিবরণ লিখে চেষ্টা করুন:

  • আমি গাঢ় টকটকে লাল রঙ চাই।
  • আমাকে একটি প্রশান্তিদায়ক আকাশী নীল দেখাও।
  • আমাকে তাজা পুদিনা পাতার মতো রঙ দাও।
  • আমি একটি উষ্ণ কমলা রঙের সূর্যাস্ত দেখতে চাই।
  • এটিকে একটি গাঢ় রাজকীয় বেগুনি রঙ দিন।

এখন আপনি দেখবেন:

  1. আপনার বার্তাটি চ্যাট ইন্টারফেসে প্রদর্শিত হচ্ছে
  2. চ্যাটে জেমিনির প্রতিক্রিয়া দেখা যাচ্ছে
  3. লগ প্যানেলে ফাংশন কলগুলো লগ করা হচ্ছে
  4. ফাংশনের ফলাফল অবিলম্বে লগ করা হচ্ছে
  5. বর্ণিত রঙটি প্রদর্শন করার জন্য রঙিন আয়তক্ষেত্রটি আপডেট হচ্ছে।
  6. নতুন রঙের উপাদানগুলো দেখানোর জন্য RGB মানগুলো আপডেট করা হচ্ছে।
  7. মিথুনের চূড়ান্ত প্রতিক্রিয়া প্রকাশিত হচ্ছে, প্রায়শই নির্ধারিত রঙটি নিয়ে মন্তব্য করা হচ্ছে।

লগ প্যানেলটি পর্দার আড়ালে কী ঘটছে সে সম্পর্কে ধারণা দেয়। আপনি দেখতে পাবেন:

  • জেমিনি ঠিক যে ফাংশন কলগুলো করছে
  • প্রতিটি RGB মানের জন্য এটি যে প্যারামিটারগুলো বেছে নিচ্ছে
  • আপনার ফাংশনটি যে ফলাফলগুলো ফেরত দিচ্ছে
  • জেমিনি থেকে প্রাপ্ত ফলো-আপ প্রতিক্রিয়া

রঙের অবস্থা জানানোর যন্ত্র

রঙ আপডেট করার জন্য আপনি যে colorStateNotifier ব্যবহার করছেন, তা colorist_ui প্যাকেজের একটি অংশ। এটি নিম্নলিখিত বিষয়গুলো পরিচালনা করে:

  • UI-তে প্রদর্শিত বর্তমান রঙ
  • রঙের ইতিহাস (শেষ ১০টি রঙ)
  • UI উপাদানগুলির অবস্থা পরিবর্তনের বিজ্ঞপ্তি

যখন আপনি নতুন RGB মান দিয়ে updateColor কল করেন, তখন এটি:

  1. প্রদত্ত মানগুলো দিয়ে একটি নতুন ColorData অবজেক্ট তৈরি করে।
  2. অ্যাপের অবস্থায় বর্তমান রঙ আপডেট করে।
  3. ইতিহাসে রঙ যোগ করে
  4. রিভারপডের স্টেট ম্যানেজমেন্টের মাধ্যমে UI আপডেট ট্রিগার করে।

colorist_ui প্যাকেজের UI কম্পোনেন্টগুলো এই স্টেট পর্যবেক্ষণ করে এবং এর পরিবর্তনে স্বয়ংক্রিয়ভাবে আপডেট হয়, যা একটি রিঅ্যাক্টিভ অভিজ্ঞতা তৈরি করে।

ত্রুটি পরিচালনা বোঝা

আপনার বাস্তবায়নে শক্তিশালী ত্রুটি ব্যবস্থাপনা অন্তর্ভুক্ত রয়েছে:

  1. ট্রাই-ক্যাচ ব্লক : যেকোনো ব্যতিক্রম ধরার জন্য সমস্ত LLM ইন্টারঅ্যাকশনকে এর মধ্যে রাখা হয়।
  2. ত্রুটি লগিং : লগ প্যানেলে স্ট্যাক ট্রেস সহ ত্রুটিগুলো রেকর্ড করে।
  3. ব্যবহারকারীর প্রতিক্রিয়া : চ্যাটে একটি সহজবোধ্য ত্রুটি বার্তা প্রদান করে।
  4. অবস্থা পরিষ্করণ : ত্রুটি ঘটলেও বার্তার অবস্থা চূড়ান্ত করে।

এর ফলে, LLM পরিষেবা বা ফাংশন সম্পাদনে কোনো সমস্যা দেখা দিলেও অ্যাপটি স্থিতিশীল থাকে এবং যথাযথ প্রতিক্রিয়া প্রদান করে।

ব্যবহারকারীর অভিজ্ঞতার জন্য ফাংশন কলিংয়ের শক্তি

আপনি এখানে যা সম্পন্ন করেছেন তা দেখায় যে কীভাবে এলএলএম শক্তিশালী স্বাভাবিক ইন্টারফেস তৈরি করতে পারে:

  1. স্বাভাবিক ভাষার ইন্টারফেস : ব্যবহারকারীরা দৈনন্দিন ভাষায় তাদের অভিপ্রায় প্রকাশ করেন।
  2. বুদ্ধিদীপ্ত ব্যাখ্যা : এলএলএম অস্পষ্ট বর্ণনাকে সুনির্দিষ্ট মানে রূপান্তরিত করে।
  3. সরাসরি ম্যানিপুলেশন : স্বাভাবিক ভাষার প্রতিক্রিয়ায় UI আপডেট হয়।
  4. প্রাসঙ্গিক প্রতিক্রিয়া : এলএলএম পরিবর্তনগুলো সম্পর্কে কথোপকথনমূলক প্রেক্ষাপট প্রদান করে।
  5. কম মানসিক চাপ : ব্যবহারকারীদের RGB মান বা রঙের তত্ত্ব বোঝার প্রয়োজন নেই।

স্বাভাবিক ভাষা এবং UI ক্রিয়াকলাপের মধ্যে সংযোগ স্থাপনের জন্য LLM ফাংশন কলিং ব্যবহারের এই পদ্ধতিটি রঙ নির্বাচন ছাড়াও আরও অগণিত ক্ষেত্রে প্রসারিত করা যেতে পারে।

এরপর কী?

পরবর্তী ধাপে, আপনি স্ট্রিমিং রেসপন্স প্রয়োগ করে ব্যবহারকারীর অভিজ্ঞতা উন্নত করবেন। সম্পূর্ণ রেসপন্সের জন্য অপেক্ষা না করে, আপনি টেক্সটের অংশ এবং ফাংশন কলগুলো পাওয়ার সাথে সাথেই প্রসেস করবেন, যা একটি আরও বেশি রেসপন্সিভ এবং আকর্ষণীয় অ্যাপ্লিকেশন তৈরি করবে।

সমস্যা সমাধান

ফাংশন কল সমস্যা

যদি জেমিনি আপনার ফাংশনগুলো কল না করে অথবা প্যারামিটারগুলো ভুল থাকে:

  • আপনার ফাংশন ডিক্লারেশনটি সিস্টেম প্রম্পটে বর্ণিত বিবরণের সাথে মেলে কিনা তা যাচাই করুন।
  • প্যারামিটারের নাম এবং টাইপ সামঞ্জস্যপূর্ণ কিনা তা যাচাই করুন।
  • নিশ্চিত করুন যে আপনার সিস্টেম প্রম্পট এলএলএম-কে টুলটি ব্যবহার করার জন্য স্পষ্টভাবে নির্দেশ দেয়।
  • আপনার হ্যান্ডলারের ফাংশন নামটি ডিক্লারেশনে যা আছে তার সাথে হুবহু মেলে কিনা তা যাচাই করুন।
  • ফাংশন কল সম্পর্কে বিস্তারিত তথ্যের জন্য লগ প্যানেলটি পরীক্ষা করুন।

ফাংশন প্রতিক্রিয়া সমস্যা

যদি ফাংশনের ফলাফল LLM-এ সঠিকভাবে ফেরত পাঠানো না হয়:

  • যাচাই করুন যে আপনার ফাংশনটি একটি সঠিকভাবে ফরম্যাট করা Map রিটার্ন করে।
  • Content.functionResponses সঠিকভাবে তৈরি হচ্ছে কিনা তা যাচাই করুন।
  • ফাংশন প্রতিক্রিয়া সম্পর্কিত লগে কোনো ত্রুটি আছে কিনা তা অনুসন্ধান করুন।
  • উত্তর দেওয়ার জন্য আপনি একই চ্যাট সেশন ব্যবহার করছেন কিনা তা নিশ্চিত করুন।

রঙ প্রদর্শনে সমস্যা

যদি রংগুলো সঠিকভাবে প্রদর্শিত না হয়:

  • নিশ্চিত করুন যে RGB মানগুলি সঠিকভাবে ডাবল-এ রূপান্তরিত হয়েছে (LLM সেগুলিকে ইন্টিজার হিসাবে পাঠাতে পারে)।
  • মানগুলো প্রত্যাশিত সীমার (০.০ থেকে ১.০) মধ্যে আছে কিনা তা যাচাই করুন।
  • কালার স্টেট নোটিফায়ারটি সঠিকভাবে কল করা হচ্ছে কিনা তা পরীক্ষা করুন।
  • ফাংশনে পাঠানো সঠিক মানগুলো জানতে লগটি পরীক্ষা করুন।

সাধারণ সমস্যা

সাধারণ বিষয়গুলির জন্য:

  • ত্রুটি বা সতর্কতার জন্য লগগুলি পরীক্ষা করুন।
  • ফায়ারবেস এআই লজিক সংযোগ যাচাই করুন
  • ফাংশন প্যারামিটারগুলিতে কোন ধরণের অমিল আছে কিনা তা পরীক্ষা করুন।
  • রিভারপড দ্বারা তৈরি সমস্ত কোড হালনাগাদ আছে কিনা তা নিশ্চিত করুন।

শেখা মূল ধারণাগুলো

  • ফ্লুটারে একটি সম্পূর্ণ ফাংশন কলিং পাইপলাইন বাস্তবায়ন করা
  • এলএলএম এবং আপনার আবেদনের মধ্যে পূর্ণাঙ্গ যোগাযোগ স্থাপন করা
  • এলএলএম প্রতিক্রিয়া থেকে কাঠামোগত ডেটা প্রক্রিয়াকরণ
  • প্রতিক্রিয়াগুলিতে অন্তর্ভুক্ত করার জন্য ফাংশনের ফলাফল LLM-এ ফেরত পাঠানো হচ্ছে
  • এলএলএম-আবেদন সংক্রান্ত মিথস্ক্রিয়া সম্পর্কে স্বচ্ছতা অর্জনের জন্য লগ প্যানেল ব্যবহার করা
  • স্বাভাবিক ভাষার ইনপুটকে সুনির্দিষ্ট UI পরিবর্তনের সাথে সংযুক্ত করা

এই ধাপটি সম্পন্ন হওয়ার সাথে সাথে, আপনার অ্যাপটি এখন এলএলএম ইন্টিগ্রেশনের অন্যতম শক্তিশালী একটি প্যাটার্ন প্রদর্শন করছে: স্বাভাবিক ভাষার ইনপুটগুলোকে সুনির্দিষ্ট UI অ্যাকশনে রূপান্তরিত করা এবং একই সাথে এই অ্যাকশনগুলোকে স্বীকৃতি দিয়ে একটি সুসংগত কথোপকথন বজায় রাখা। এটি একটি স্বজ্ঞাত ও কথোপকথনমূলক ইন্টারফেস তৈরি করে, যা ব্যবহারকারীদের কাছে জাদুকরী মনে হয়।

৭. উন্নততর ইউএক্স-এর জন্য প্রতিক্রিয়াগুলির স্ট্রিমিং

এই ধাপে, আপনি জেমিনি থেকে স্ট্রিমিং রেসপন্স প্রয়োগ করে ব্যবহারকারীর অভিজ্ঞতা উন্নত করবেন। সম্পূর্ণ রেসপন্স তৈরি হওয়ার জন্য অপেক্ষা করার পরিবর্তে, আপনি টেক্সটের অংশ এবং ফাংশন কলগুলো পাওয়ার সাথে সাথেই প্রসেস করবেন, যা একটি আরও রেসপন্সিভ এবং আকর্ষণীয় অ্যাপ্লিকেশন তৈরি করবে।

এই ধাপে আপনি যা যা আলোচনা করবেন

  • এলএলএম-ভিত্তিক আবেদনপত্রের জন্য স্ট্রিমিং-এর গুরুত্ব
  • ফ্লাটার অ্যাপ্লিকেশনে স্ট্রিমিং এলএলএম প্রতিক্রিয়া বাস্তবায়ন করা
  • এপিআই থেকে আসা আংশিক পাঠ্য খণ্ডগুলি প্রক্রিয়াকরণ করা হচ্ছে
  • বার্তার দ্বন্দ্ব এড়াতে কথোপকথনের অবস্থা পরিচালনা করা
  • স্ট্রিমিং প্রতিক্রিয়াগুলিতে ফাংশন কল পরিচালনা করা
  • চলমান প্রতিক্রিয়াগুলির জন্য ভিজ্যুয়াল নির্দেশক তৈরি করা

এলএলএম আবেদনের ক্ষেত্রে স্ট্রিমিং কেন গুরুত্বপূর্ণ

বাস্তবায়নের আগে, চলুন জেনে নেওয়া যাক কেন এলএলএম (LLM) ব্যবহার করে চমৎকার ব্যবহারকারী অভিজ্ঞতা তৈরির জন্য স্ট্রিমিং রেসপন্স অত্যন্ত গুরুত্বপূর্ণ:

উন্নত ব্যবহারকারীর অভিজ্ঞতা

স্ট্রিমিং প্রতিক্রিয়া ব্যবহারকারীর অভিজ্ঞতার ক্ষেত্রে বেশ কিছু গুরুত্বপূর্ণ সুবিধা প্রদান করে:

  1. বিলম্বের অনুভূতি হ্রাস : ব্যবহারকারীরা একটি সম্পূর্ণ প্রতিক্রিয়ার জন্য কয়েক সেকেন্ড অপেক্ষা না করে, সাথে সাথেই (সাধারণত ১০০-৩০০ মিলিসেকেন্ডের মধ্যে) লেখাটি দেখতে পান। এই তাৎক্ষণিকতার অনুভূতি ব্যবহারকারীর সন্তুষ্টি ব্যাপকভাবে বৃদ্ধি করে।
  2. স্বাভাবিক কথোপকথনের ছন্দ : লেখার ক্রমান্বয়ে প্রকাশ মানুষের যোগাযোগের পদ্ধতিকে অনুকরণ করে, যা আরও স্বাভাবিক কথোপকথনের অভিজ্ঞতা তৈরি করে।
  3. পর্যায়ক্রমিক তথ্য প্রক্রিয়াকরণ : ব্যবহারকারীরা একবারে বিশাল পরিমাণ লেখা দেখে অভিভূত না হয়ে, তথ্য আসার সাথে সাথেই তা প্রক্রিয়াকরণ শুরু করতে পারেন।
  4. শুরুতেই বাধা দেওয়ার সুযোগ : একটি পূর্ণাঙ্গ অ্যাপ্লিকেশনের ক্ষেত্রে, ব্যবহারকারীরা যদি দেখেন যে এলএলএম (LLM) কোনো অপ্রয়োজনীয় দিকে যাচ্ছে, তাহলে তাঁরা এটিকে বাধা দিতে বা এর গতিপথ পরিবর্তন করে দিতে পারেন।
  5. কার্যক্রমের চাক্ষুষ নিশ্চিতকরণ : চলমান লেখাটি সিস্টেমটি কাজ করছে তার তাৎক্ষণিক প্রতিক্রিয়া প্রদান করে, যা অনিশ্চয়তা হ্রাস করে।

প্রযুক্তিগত সুবিধা

ইউএক্স (UX) উন্নতির পাশাপাশি, স্ট্রিমিং প্রযুক্তিগত সুবিধাও প্রদান করে:

  1. ফাংশনের আগাম সম্পাদন : সম্পূর্ণ প্রতিক্রিয়ার জন্য অপেক্ষা না করে, স্ট্রিমে ফাংশন কলগুলো উপস্থিত হওয়ার সাথে সাথেই তা শনাক্ত ও সম্পাদন করা যায়।
  2. পর্যায়ক্রমিক UI আপডেট : নতুন তথ্য আসার সাথে সাথে আপনি আপনার UI পর্যায়ক্রমে আপডেট করতে পারেন, যা আরও গতিশীল অভিজ্ঞতা তৈরি করে।
  3. কথোপকথনের অবস্থা ব্যবস্থাপনা : স্ট্রিমিং প্রতিক্রিয়া কখন সম্পন্ন হয়েছে এবং কখন তা এখনও চলছে সে সম্পর্কে স্পষ্ট সংকেত প্রদান করে, যা উন্নততর অবস্থা ব্যবস্থাপনায় সহায়তা করে।
  4. টাইমআউটের ঝুঁকি হ্রাস : নন-স্ট্রিমিং রেসপন্সের ক্ষেত্রে, দীর্ঘ সময় ধরে চলা জেনারেশনের কারণে কানেকশন টাইমআউটের ঝুঁকি থাকে। স্ট্রিমিং দ্রুত কানেকশন স্থাপন করে এবং তা বজায় রাখে।

আপনার কালারিস্ট অ্যাপে স্ট্রিমিং প্রয়োগ করার অর্থ হলো, ব্যবহারকারীরা টেক্সট প্রতিক্রিয়া এবং রঙের পরিবর্তন উভয়ই আরও দ্রুত দেখতে পাবেন, যা একটি উল্লেখযোগ্যভাবে আরও প্রতিক্রিয়াশীল অভিজ্ঞতা তৈরি করবে।

কথোপকথনের অবস্থা ব্যবস্থাপনা যোগ করুন

প্রথমে, অ্যাপটি বর্তমানে কোনো স্ট্রিমিং রেসপন্স পরিচালনা করছে কিনা তা ট্র্যাক করার জন্য একটি স্টেট প্রোভাইডার যোগ করা যাক। আপনার 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_ai/firebase_ai.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';

class ConversationStateNotifier extends Notifier<ConversationState> {  // Add from here...
  @override
  ConversationState build() => ConversationState.idle;

  void busy() {
    state = ConversationState.busy;
  }

  void idle() {
    state = ConversationState.idle;
  }
}

final conversationStateProvider =
    NotifierProvider<ConversationStateNotifier, ConversationState>(
      ConversationStateNotifier.new,
    );                                                                 // 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(chatStateProvider.notifier);
    final logStateNotifier = ref.read(logStateProvider.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.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.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(chatStateProvider.notifier);
    final logStateNotifier = ref.read(logStateProvider.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(keepAlive: true)
GeminiChatService geminiChatService(Ref ref) => GeminiChatService(ref);

স্ট্রিমিং বাস্তবায়ন বোঝা

চলুন এই কোডটি কী করে তা বিশ্লেষণ করা যাক:

  1. কথোপকথনের অবস্থা পর্যবেক্ষণ :
    • একটি conversationStateProvider ট্র্যাক করে যে অ্যাপটি বর্তমানে কোনো প্রতিক্রিয়া প্রক্রিয়া করছে কিনা।
    • প্রসেসিং চলাকালীন অবস্থাটি idle থেকে busy হয়, এবং তারপর আবার idle ফিরে আসে।
    • এটি একই সাথে একাধিক অনুরোধের মধ্যে সংঘাত প্রতিরোধ করে।
  2. স্ট্রিম প্রারম্ভিকীকরণ :
    • sendMessageStream() সম্পূর্ণ প্রতিক্রিয়া সহ একটি Future এর পরিবর্তে প্রতিক্রিয়ার খণ্ডাংশগুলির একটি Stream ফেরত দেয়।
    • প্রতিটি খণ্ডে টেক্সট, ফাংশন কল অথবা উভয়ই থাকতে পারে।
  3. প্রগতিশীল প্রক্রিয়াকরণ :
    • রিয়েল-টাইমে প্রতিটি খণ্ড আসার সাথে সাথে প্রক্রিয়া করার await for
    • টেক্সটটি তাৎক্ষণিকভাবে UI-তে যুক্ত হয়ে যায়, যা একটি স্ট্রিমিং এফেক্ট তৈরি করে।
    • ফাংশন কলগুলো শনাক্ত হওয়ার সাথে সাথেই সম্পাদিত হয়।
  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),
      ),
    );
  }
}

এখানে মূল পরিবর্তনটি হলো MainScreen উইজেটে conversationState পাস করা। MainScreen (যা colorist_ui প্যাকেজ দ্বারা সরবরাহকৃত) একটি প্রতিক্রিয়া প্রক্রিয়া করার সময় টেক্সট ইনপুট নিষ্ক্রিয় করতে এই স্টেটটি ব্যবহার করবে।

এর ফলে একটি সুসংহত ব্যবহারকারী অভিজ্ঞতা তৈরি হয়, যেখানে ইউআই (UI) কথোপকথনের বর্তমান অবস্থাকে প্রতিফলিত করে।

রিভারপড কোড তৈরি করুন

প্রয়োজনীয় রিভারপড কোড তৈরি করতে বিল্ড রানার কমান্ডটি চালান:

dart run build_runner build --delete-conflicting-outputs

স্ট্রিমিং প্রতিক্রিয়াগুলি চালান এবং পরীক্ষা করুন

আপনার অ্যাপ্লিকেশনটি চালান:

flutter run -d DEVICE

কালারিস্ট অ্যাপের স্ক্রিনশট, যেখানে জেমিনি এলএলএম স্ট্রিম পদ্ধতিতে সাড়া দিচ্ছে।

এখন বিভিন্ন রঙের বিবরণ দিয়ে স্ট্রিমিং আচরণ পরীক্ষা করে দেখুন। এই ধরনের বিবরণ ব্যবহার করে দেখুন:

  • গোধূলি বেলায় সমুদ্রের গভীর নীল রঙ আমাকে দেখাও।
  • আমি এমন একটি উজ্জ্বল প্রবাল রঙ দেখতে চাই যা আমাকে গ্রীষ্মমণ্ডলীয় ফুলের কথা মনে করিয়ে দেয়।
  • পুরোনো সেনা পোশাকের মতো একটি অনুজ্জ্বল জলপাই সবুজ রঙ তৈরি করুন।

স্ট্রিমিংয়ের প্রযুক্তিগত প্রবাহের বিস্তারিত বিবরণ

একটি প্রতিক্রিয়া স্ট্রিম করার সময় ঠিক কী ঘটে, চলুন তা খতিয়ে দেখি:

সংযোগ স্থাপন

যখন আপনি sendMessageStream() কল করেন, তখন নিম্নলিখিত ঘটনাটি ঘটে:

  1. অ্যাপটি Firebase AI Logic পরিষেবার সাথে একটি সংযোগ স্থাপন করে।
  2. ব্যবহারকারীর অনুরোধটি পরিষেবাতে পাঠানো হয়।
  3. সার্ভার অনুরোধটি প্রক্রিয়া করা শুরু করে।
  4. স্ট্রিম সংযোগটি খোলা থাকে, খণ্ডাংশ প্রেরণের জন্য প্রস্তুত।

খণ্ড সংক্রমণ

জেমিনি যখন কন্টেন্ট তৈরি করে, তখন তার খণ্ডাংশগুলো স্ট্রিমের মাধ্যমে পাঠানো হয়:

  1. সার্ভারটি তৈরি হওয়ার সাথে সাথেই টেক্সটের অংশগুলো পাঠিয়ে দেয় (সাধারণত কয়েকটি শব্দ বা বাক্য)।
  2. যখন জেমিনি কোনো ফাংশন কল করার সিদ্ধান্ত নেয়, তখন এটি ফাংশন কলের তথ্য পাঠিয়ে দেয়।
  3. ফাংশন কলের পরে অতিরিক্ত টেক্সট খণ্ড থাকতে পারে।
  4. প্রজন্ম সম্পূর্ণ না হওয়া পর্যন্ত এই ধারা চলতে থাকে।

প্রগতিশীল প্রক্রিয়াকরণ

আপনার অ্যাপ প্রতিটি অংশকে পর্যায়ক্রমে প্রক্রিয়া করে:

  1. প্রতিটি পাঠ্যাংশ বিদ্যমান প্রতিক্রিয়ার সাথে যুক্ত করা হয়।
  2. ফাংশন কলগুলো শনাক্ত হওয়ার সাথে সাথেই সম্পাদিত হয়।
  3. টেক্সট এবং ফাংশন উভয় ফলাফলের সাথে UI রিয়েল-টাইমে আপডেট হয়।
  4. প্রতিক্রিয়াটি এখনও প্রবাহিত হচ্ছে তা দেখানোর জন্য অবস্থাটি ট্র্যাক করা হচ্ছে।

স্ট্রিম সমাপ্তি

যখন প্রজন্মটি সম্পূর্ণ হয়:

  1. সার্ভার কর্তৃক স্ট্রিমটি বন্ধ করে দেওয়া হয়েছে।
  2. আপনার await for লুপটি স্বাভাবিকভাবেই শেষ হয়ে যায়।
  3. বার্তাটি সম্পূর্ণ হিসেবে চিহ্নিত করা হয়েছে।
  4. কথোপকথনের অবস্থা আবার নিষ্ক্রিয় অবস্থায় ফিরে এসেছে।
  5. সম্পন্ন অবস্থা প্রতিফলিত করতে UI আপডেট হয়।

স্ট্রিমিং বনাম নন-স্ট্রিমিং তুলনা

স্ট্রিমিংয়ের সুবিধাগুলো আরও ভালোভাবে বোঝার জন্য, চলুন স্ট্রিমিং এবং নন-স্ট্রিমিং পদ্ধতিগুলোর মধ্যে তুলনা করা যাক:

দিক

নন-স্ট্রিমিং

স্ট্রিমিং

অনুভূত বিলম্ব

সম্পূর্ণ প্রতিক্রিয়া প্রস্তুত না হওয়া পর্যন্ত ব্যবহারকারী কিছুই দেখতে পান না।

ব্যবহারকারী কয়েক মিলিসেকেন্ডের মধ্যে প্রথম শব্দগুলো দেখতে পান।

ব্যবহারকারীর অভিজ্ঞতা

দীর্ঘ অপেক্ষার পর হঠাৎ মেসেজ এলো।

স্বাভাবিক, প্রগতিশীল পাঠ্য চেহারা

রাষ্ট্রীয় ব্যবস্থাপনা

আরও সরল (বার্তাগুলো হয় অপেক্ষমান অথবা সম্পূর্ণ)

আরও জটিল (বার্তাগুলো স্ট্রিমিং অবস্থায় থাকতে পারে)

ফাংশন সম্পাদন

সম্পূর্ণ প্রতিক্রিয়ার পরেই ঘটে

প্রতিক্রিয়া তৈরির সময় ঘটে

বাস্তবায়নের জটিলতা

বাস্তবায়ন করা সহজ

অতিরিক্ত রাষ্ট্রীয় ব্যবস্থাপনার প্রয়োজন

ত্রুটি পুনরুদ্ধার

হয়-না হয় প্রতিক্রিয়া

আংশিক প্রতিক্রিয়া এখনও কার্যকর হতে পারে।

কোডের জটিলতা

কম জটিল

স্ট্রিম হ্যান্ডলিংয়ের কারণে আরও জটিল

কালারিস্টের মতো অ্যাপ্লিকেশনের ক্ষেত্রে, স্ট্রিমিংয়ের ইউএক্স সুবিধাগুলো এর বাস্তবায়নগত জটিলতাকে ছাপিয়ে যায়, বিশেষ করে রঙের ব্যাখ্যার ক্ষেত্রে যা তৈরি হতে কয়েক সেকেন্ড সময় নিতে পারে।

স্ট্রিমিং ইউএক্স-এর জন্য সেরা অনুশীলন

আপনার নিজের এলএলএম অ্যাপ্লিকেশনগুলিতে স্ট্রিমিং প্রয়োগ করার সময়, এই সর্বোত্তম অনুশীলনগুলি বিবেচনা করুন:

  1. সুস্পষ্ট দৃশ্যমান নির্দেশক : চলমান বার্তা এবং সম্পূর্ণ বার্তার মধ্যে পার্থক্য বোঝানোর জন্য সর্বদা সুস্পষ্ট দৃশ্যমান সংকেত প্রদান করুন।
  2. ইনপুট ব্লকিং : স্ট্রিমিং চলাকালীন একাধিক ওভারল্যাপিং অনুরোধ প্রতিরোধ করতে ব্যবহারকারীর ইনপুট নিষ্ক্রিয় করুন।
  3. ত্রুটি পুনরুদ্ধার : স্ট্রিমিং বাধাগ্রস্ত হলে সুষ্ঠুভাবে পুনরুদ্ধারের জন্য আপনার UI ডিজাইন করুন।
  4. অবস্থার পরিবর্তন : নিষ্ক্রিয়, স্ট্রিমিং এবং সম্পূর্ণ অবস্থার মধ্যে মসৃণ পরিবর্তন নিশ্চিত করুন।
  5. অগ্রগতির দৃশ্যমানতা : সক্রিয় প্রক্রিয়া দেখানোর জন্য সূক্ষ্ম অ্যানিমেশন বা সূচক বিবেচনা করুন।
  6. বাতিল করার বিকল্প : একটি সম্পূর্ণ অ্যাপে, ব্যবহারকারীদের চলমান জেনারেশন বাতিল করার উপায় প্রদান করুন।
  7. ফাংশন ফলাফলের একীকরণ : কার্যপ্রবাহের মাঝপথে ফাংশন ফলাফল প্রদর্শিত হওয়ার বিষয়টি সামলানোর জন্য আপনার UI ডিজাইন করুন।
  8. পারফরম্যান্স অপ্টিমাইজেশন : দ্রুত স্ট্রিম আপডেটের সময় UI পুনর্নির্মাণ কমানো।

colorist_ui প্যাকেজটি আপনার জন্য এই সেরা অনুশীলনগুলির অনেকগুলোই বাস্তবায়ন করে, কিন্তু যেকোনো স্ট্রিমিং LLM বাস্তবায়নের ক্ষেত্রেই এগুলি গুরুত্বপূর্ণ বিবেচ্য বিষয়।

এরপর কী?

পরবর্তী ধাপে, ব্যবহারকারীরা হিস্ট্রি থেকে রঙ নির্বাচন করলে জেমিনিকে অবহিত করার মাধ্যমে আপনি এলএলএম সিঙ্ক্রোনাইজেশন বাস্তবায়ন করবেন। এর ফলে একটি আরও সুসংহত অভিজ্ঞতা তৈরি হবে, যেখানে এলএলএম অ্যাপ্লিকেশন স্টেটে ব্যবহারকারীর করা পরিবর্তন সম্পর্কে অবগত থাকবে।

সমস্যা সমাধান

স্ট্রিম প্রক্রিয়াকরণ সমস্যা

স্ট্রিম প্রসেসিং-এ সমস্যা দেখা দিলে:

  • লক্ষণ : আংশিক প্রতিক্রিয়া, লেখা অনুপস্থিত থাকা, অথবা স্ট্রিম হঠাৎ বন্ধ হয়ে যাওয়া
  • সমাধান : নেটওয়ার্ক সংযোগ পরীক্ষা করুন এবং আপনার কোডে সঠিক async/await প্যাটার্ন নিশ্চিত করুন।
  • নির্ণয় : স্ট্রিম প্রসেসিং সম্পর্কিত ত্রুটির বার্তা বা সতর্কতার জন্য লগ প্যানেলটি পরীক্ষা করুন।
  • সমাধান : নিশ্চিত করুন যেন সমস্ত স্ট্রিম প্রসেসিং-এ try / catch ব্লক ব্যবহার করে যথাযথ ত্রুটি ব্যবস্থাপনা করা হয়।

অনুপস্থিত ফাংশন কল

যদি স্ট্রিমে ফাংশন কল শনাক্ত না হয়:

  • লক্ষণ : লেখা দেখা যায় কিন্তু রং আপডেট হয় না, অথবা লগে কোনো ফাংশন কল দেখা যায় না।
  • সমাধান : ফাংশন কল ব্যবহার সম্পর্কে সিস্টেম প্রম্পটের নির্দেশাবলী যাচাই করুন।
  • নির্ণয় : ফাংশন কলগুলি গৃহীত হচ্ছে কিনা তা দেখতে লগ প্যানেলটি পরীক্ষা করুন।
  • সমাধান : LLM-কে set_color টুলটি ব্যবহার করার জন্য আরও স্পষ্টভাবে নির্দেশ দিতে আপনার সিস্টেম প্রম্পটটি সামঞ্জস্য করুন।

সাধারণ ত্রুটি পরিচালনা

অন্য যেকোনো সমস্যার জন্য:

  • ধাপ ১ : ত্রুটির বার্তার জন্য লগ প্যানেলটি দেখুন।
  • ধাপ ২ : ফায়ারবেস এআই লজিক সংযোগ যাচাই করুন
  • ধাপ ৩ : নিশ্চিত করুন যে Riverpod দ্বারা তৈরি সমস্ত কোড হালনাগাদ আছে।
  • ধাপ ৪ : স্ট্রিমিং ইমপ্লিমেন্টেশনে কোনো await স্টেটমেন্ট অনুপস্থিত আছে কিনা তা পর্যালোচনা করুন।

শেখা মূল ধারণাগুলো

  • আরও রেসপন্সিভ ইউএক্স-এর জন্য জেমিনি এপিআই ব্যবহার করে স্ট্রিমিং রেসপন্স বাস্তবায়ন করা হচ্ছে।
  • স্ট্রিমিং ইন্টারঅ্যাকশন সঠিকভাবে পরিচালনা করার জন্য কথোপকথনের অবস্থা ব্যবস্থাপনা করা।
  • রিয়েল-টাইম টেক্সট এবং ফাংশন কলগুলো আসার সাথে সাথে সেগুলোর প্রসেসিং করা হচ্ছে।
  • স্ট্রিমিং চলাকালীন পর্যায়ক্রমে আপডেট হওয়া রেসপন্সিভ UI তৈরি করা।
  • সঠিক অ্যাসিঙ্ক প্যাটার্ন ব্যবহার করে সমান্তরাল স্ট্রিম পরিচালনা করা
  • স্ট্রিমিং প্রতিক্রিয়ার সময় উপযুক্ত ভিজ্যুয়াল প্রতিক্রিয়া প্রদান করা

স্ট্রিমিং প্রয়োগ করার মাধ্যমে, আপনি আপনার কালারিস্ট অ্যাপের ব্যবহারকারীর অভিজ্ঞতা উল্লেখযোগ্যভাবে উন্নত করেছেন, যা একটি আরও প্রতিক্রিয়াশীল ও আকর্ষক ইন্টারফেস তৈরি করেছে এবং যা সত্যিকারের কথোপকথনমূলক অনুভূতি দেয়।

৮. এলএলএম প্রসঙ্গ সিঙ্ক্রোনাইজেশন

এই বোনাস ধাপে, ব্যবহারকারীরা হিস্ট্রি থেকে রঙ নির্বাচন করলে জেমিনিকে অবহিত করার মাধ্যমে আপনি এলএলএম কনটেক্সট সিনক্রোনাইজেশন বাস্তবায়ন করবেন। এটি একটি আরও সুসংহত অভিজ্ঞতা তৈরি করে, যেখানে এলএলএম শুধুমাত্র ব্যবহারকারীর সুস্পষ্ট বার্তাগুলোই নয়, বরং ইন্টারফেসে তার কার্যকলাপ সম্পর্কেও অবগত থাকে।

এই ধাপে আপনি যা যা আলোচনা করবেন

  • আপনার UI এবং LLM-এর মধ্যে LLM কনটেক্সট সিঙ্ক্রোনাইজেশন তৈরি করা
  • UI ইভেন্টগুলোকে এমন একটি প্রেক্ষাপটে ক্রমানুসারে সাজানো যা LLM বুঝতে পারে
  • ব্যবহারকারীর কার্যকলাপের উপর ভিত্তি করে কথোপকথনের প্রসঙ্গ আপডেট করা
  • বিভিন্ন মিথস্ক্রিয়া পদ্ধতি জুড়ে একটি সামঞ্জস্যপূর্ণ অভিজ্ঞতা তৈরি করা
  • সুস্পষ্ট চ্যাট বার্তার বাইরে এলএলএম প্রসঙ্গ সচেতনতা বৃদ্ধি করা

এলএলএম প্রেক্ষাপট সিঙ্ক্রোনাইজেশন বোঝা

প্রচলিত চ্যাটবটগুলো কেবল ব্যবহারকারীর সুস্পষ্ট বার্তারই উত্তর দেয়, ফলে ব্যবহারকারীরা যখন অন্য কোনো উপায়ে অ্যাপটির সাথে মিথস্ক্রিয়া করে, তখন একটি সংযোগহীনতা তৈরি হয়। এলএলএম কনটেক্সট সিনক্রোনাইজেশন এই সীমাবদ্ধতাটি দূর করে:

এলএলএম প্রেক্ষাপট সিঙ্ক্রোনাইজেশন কেন গুরুত্বপূর্ণ

যখন ব্যবহারকারীরা UI এলিমেন্টের মাধ্যমে আপনার অ্যাপের সাথে ইন্টারঅ্যাক্ট করে (যেমন হিস্ট্রি থেকে একটি রঙ নির্বাচন করা), তখন কী ঘটেছে তা LLM-এর জানার কোনো উপায় থাকে না, যদি না আপনি স্পষ্টভাবে তাকে জানান। LLM কনটেক্সট সিনক্রোনাইজেশন:

  1. প্রাসঙ্গিকতা বজায় রাখে : ব্যবহারকারীর সমস্ত প্রাসঙ্গিক কার্যকলাপ সম্পর্কে এলএলএম-কে অবহিত রাখে।
  2. সামঞ্জস্য তৈরি করে : একটি সুসংহত অভিজ্ঞতা প্রদান করে যেখানে LLM, UI ইন্টারঅ্যাকশনকে স্বীকৃতি দেয়।
  3. বুদ্ধিমত্তা বৃদ্ধি করে : এলএলএম-কে ব্যবহারকারীর সকল কার্যকলাপের প্রতি যথাযথভাবে সাড়া দিতে সক্ষম করে।
  4. ব্যবহারকারীর অভিজ্ঞতা উন্নত করে : পুরো অ্যাপ্লিকেশনটিকে আরও সমন্বিত এবং প্রতিক্রিয়াশীল করে তোলে।
  5. ব্যবহারকারীর শ্রম কমায় : ব্যবহারকারীদের তাদের UI কার্যকলাপ ম্যানুয়ালি ব্যাখ্যা করার প্রয়োজনীয়তা দূর করে।

আপনার কালারিস্ট অ্যাপে, যখন কোনো ব্যবহারকারী হিস্ট্রি থেকে একটি রঙ নির্বাচন করেন, তখন আপনি চাইবেন যে জেমিনি যেন এই কাজটি স্বীকার করে এবং নির্বাচিত রঙটি সম্পর্কে বুদ্ধিমত্তার সাথে মন্তব্য করে, যা একটি নির্বিঘ্ন ও সচেতন সহকারীর আবহ বজায় রাখবে।

রঙ নির্বাচনের বিজ্ঞপ্তি পেতে জেমিনি চ্যাট পরিষেবা আপডেট করুন।

প্রথমে, ব্যবহারকারী হিস্ট্রি থেকে কোনো রঙ নির্বাচন করলে LLM-কে জানানোর জন্য আপনাকে 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_ai/firebase_ai.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';

class ConversationStateNotifier extends Notifier<ConversationState> {
  @override
  ConversationState build() => ConversationState.idle;

  void busy() {
    state = ConversationState.busy;
  }

  void idle() {
    state = ConversationState.idle;
  }
}

final conversationStateProvider =
    NotifierProvider<ConversationStateNotifier, ConversationState>(
      ConversationStateNotifier.new,
    );

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(chatStateProvider.notifier);
    final logStateNotifier = ref.read(logStateProvider.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.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.idle();
    }
  }

  Future<void> _processBlock(
    GenerateContentResponse block,
    String llmMessageId,
  ) async {
    final chatSession = await ref.read(chatSessionProvider.future);
    final chatStateNotifier = ref.read(chatStateProvider.notifier);
    final logStateNotifier = ref.read(logStateProvider.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(keepAlive: true)
GeminiChatService geminiChatService(Ref ref) => GeminiChatService(ref);

মূল সংযোজনটি হলো notifyColorSelection মেথড, যা:

  1. নির্বাচিত রঙকে প্রতিনিধিত্বকারী একটি ColorData অবজেক্ট গ্রহণ করে।
  2. এটিকে একটি JSON ফরম্যাটে এনকোড করে যা একটি বার্তায় অন্তর্ভুক্ত করা যায়।
  3. ব্যবহারকারীর নির্বাচন নির্দেশ করে এলএলএম-এর কাছে একটি বিশেষ বিন্যাসের বার্তা পাঠায়।
  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 কলব্যাকটি যোগ করা, যা UI ইভেন্টটিকে (হিস্ট্রি থেকে একটি রঙ নির্বাচন করা) LLM নোটিফিকেশন সিস্টেমের সাথে সংযুক্ত করে।

সিস্টেম প্রম্পট আপডেট করুন

এখন, রঙ নির্বাচনের নোটিফিকেশনে কীভাবে সাড়া দিতে হবে, সে বিষয়ে 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. এলএলএম-কে হিস্ট্রি সিলেকশন নোটিফিকেশনের ধারণা ব্যাখ্যা করে।
  2. এই নোটিফিকেশনগুলো দেখতে কেমন হয় তার একটি উদাহরণ দেওয়া হলো।
  3. একটি উপযুক্ত প্রতিক্রিয়ার উদাহরণ দেখানো হয়েছে
  4. নির্বাচনকে স্বীকৃতি দেওয়া এবং রঙ সম্পর্কে মন্তব্য করার বিষয়ে প্রত্যাশা নির্ধারণ করে।

এটি এলএলএম-কে এই বিশেষ বার্তাগুলোর যথাযথভাবে উত্তর দিতে বুঝতে সাহায্য করে।

রিভারপড কোড তৈরি করুন

প্রয়োজনীয় রিভারপড কোড তৈরি করতে বিল্ড রানার কমান্ডটি চালান:

dart run build_runner build --delete-conflicting-outputs

এলএলএম কনটেক্সট সিঙ্ক্রোনাইজেশন চালান এবং পরীক্ষা করুন

আপনার অ্যাপ্লিকেশনটি চালান:

flutter run -d DEVICE

কালারিস্ট অ্যাপের স্ক্রিনশট, যেখানে কালার হিস্ট্রি থেকে একটি সিলেকশনের প্রতিক্রিয়ায় জেমিনি এলএলএম-কে দেখানো হচ্ছে।

এলএলএম কনটেক্সট সিঙ্ক্রোনাইজেশন পরীক্ষা করার জন্য নিম্নলিখিত বিষয়গুলো অন্তর্ভুক্ত:

  1. প্রথমে, চ্যাটে বর্ণনা করে কয়েকটি রঙ তৈরি করুন।
    • আমাকে একটি উজ্জ্বল বেগুনি দেখাও।
    • আমি গাঢ় সবুজ রঙ চাই।
    • আমাকে উজ্জ্বল লাল দাও।
  2. এরপর, হিস্ট্রি স্ট্রিপে থাকা রঙিন থাম্বনেইলগুলোর মধ্যে একটিতে ক্লিক করুন।

আপনার লক্ষ্য করা উচিত:

  1. নির্বাচিত রঙটি মূল ডিসপ্লেতে প্রদর্শিত হয়।
  2. চ্যাটে ব্যবহারকারীর একটি বার্তা প্রদর্শিত হয়, যা রঙ নির্বাচনের বিষয়টি নির্দেশ করে।
  3. এলএলএম নির্বাচনটিকে স্বীকার করে এবং রঙটি সম্পর্কে মন্তব্য করে প্রতিক্রিয়া জানায়।
  4. পুরো আলাপচারিতাটি স্বাভাবিক এবং সুসংহত মনে হয়।

এর ফলে একটি নির্বিঘ্ন অভিজ্ঞতা তৈরি হয়, যেখানে এলএলএম সরাসরি বার্তা এবং ইউআই ইন্টারঅ্যাকশন উভয় সম্পর্কেই অবগত থাকেন এবং যথাযথভাবে সাড়া দেন।

এলএলএম কনটেক্সট সিঙ্ক্রোনাইজেশন কীভাবে কাজ করে

চলুন এই সিঙ্ক্রোনাইজেশনটি কীভাবে কাজ করে তার প্রযুক্তিগত বিবরণ জেনে নেওয়া যাক:

ডেটা প্রবাহ

  1. ব্যবহারকারীর কার্যকলাপ : ব্যবহারকারী হিস্ট্রি স্ট্রিপে একটি রঙে ক্লিক করেন।
  2. UI ইভেন্ট : MainScreen উইজেট এই নির্বাচনটি শনাক্ত করে।
  3. কলব্যাক সম্পাদন : notifyColorSelection কলব্যাকটি ট্রিগার হয়।
  4. বার্তা তৈরি : রঙের তথ্য দিয়ে একটি বিশেষ ফরম্যাটের বার্তা তৈরি করা হয়।
  5. এলএলএম প্রক্রিয়াকরণ : বার্তাটি জেমিনিতে পাঠানো হয়, যা ফরম্যাটটি শনাক্ত করে।
  6. প্রাসঙ্গিক প্রতিক্রিয়া : জেমিনি সিস্টেমের নির্দেশ অনুযায়ী যথাযথভাবে সাড়া দেয়।
  7. UI আপডেট : উত্তরটি চ্যাটে দেখা যায়, যা একটি সুসংহত অভিজ্ঞতা তৈরি করে।

ডেটা সিরিয়ালাইজেশন

এই পদ্ধতির একটি মূল দিক হলো আপনি কীভাবে রঙের ডেটা ক্রমিকীকরণ করেন:

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

colorist_ui প্যাকেজের toLLMContextMap() মেথডটি একটি ColorData অবজেক্টকে এমন একটি ম্যাপে রূপান্তর করে, যাতে LLM বুঝতে পারে এমন কী প্রোপার্টিগুলো থাকে। এতে সাধারণত অন্তর্ভুক্ত থাকে:

  • আরজিবি মান (লাল, সবুজ, নীল)
  • হেক্স কোড উপস্থাপনা
  • রঙের সাথে সম্পর্কিত যেকোনো নাম বা বিবরণ

এই ডেটা সামঞ্জস্যপূর্ণভাবে বিন্যাস করে এবং বার্তায় অন্তর্ভুক্ত করার মাধ্যমে, আপনি নিশ্চিত করেন যে যথাযথভাবে প্রতিক্রিয়া জানানোর জন্য এলএলএম-এর কাছে প্রয়োজনীয় সমস্ত তথ্য রয়েছে।

এলএলএম প্রসঙ্গ সিঙ্ক্রোনাইজেশনের ব্যাপকতর প্রয়োগ

UI ইভেন্ট সম্পর্কে LLM-কে অবহিত করার এই পদ্ধতির প্রয়োগ শুধু রঙ নির্বাচন ছাড়াও আরও অনেক ক্ষেত্রে রয়েছে:

অন্যান্য ব্যবহারের ক্ষেত্র

  1. ফিল্টার পরিবর্তন : ব্যবহারকারীরা ডেটাতে ফিল্টার প্রয়োগ করলে LLM-কে অবহিত করুন।
  2. নেভিগেশন ইভেন্ট : ব্যবহারকারীরা যখন বিভিন্ন বিভাগে নেভিগেট করেন তখন LLM-কে অবহিত করুন।
  3. নির্বাচন পরিবর্তন : ব্যবহারকারীরা তালিকা বা গ্রিড থেকে আইটেম নির্বাচন করলে LLM আপডেট করুন।
  4. পছন্দের হালনাগাদ : ব্যবহারকারীরা যখন সেটিংস বা পছন্দ পরিবর্তন করেন তখন LLM-কে জানান।
  5. ডেটা পরিবর্তন : ব্যবহারকারীরা ডেটা যোগ, সম্পাদনা বা মুছে ফেললে LLM-কে অবহিত করুন।

প্রতিটি ক্ষেত্রেই ধরণটি একই থাকে:

  1. UI ইভেন্ট সনাক্ত করুন
  2. প্রাসঙ্গিক ডেটা ক্রমানুসারে সাজান
  3. এলএলএম-কে একটি বিশেষ বিন্যাসে বিজ্ঞপ্তি পাঠান।
  4. সিস্টেম প্রম্পটের মাধ্যমে এলএলএম-কে যথাযথভাবে উত্তর দিতে নির্দেশনা দিন।

এলএলএম কনটেক্সট সিঙ্ক্রোনাইজেশনের জন্য সর্বোত্তম অনুশীলন

আপনার বাস্তবায়নের উপর ভিত্তি করে, কার্যকর এলএলএম কনটেক্সট সিনক্রোনাইজেশনের জন্য এখানে কিছু সর্বোত্তম অনুশীলন দেওয়া হলো:

১. সামঞ্জস্যপূর্ণ বিন্যাস

বিজ্ঞপ্তিগুলির জন্য একটি সামঞ্জস্যপূর্ণ বিন্যাস ব্যবহার করুন যাতে এলএলএম সহজেই সেগুলি শনাক্ত করতে পারেন:

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

২. সমৃদ্ধ প্রেক্ষাপট

এলএলএম যাতে বুদ্ধিমত্তার সাথে সাড়া দিতে পারে, সেজন্য নোটিফিকেশনে যথেষ্ট বিস্তারিত তথ্য অন্তর্ভুক্ত করুন। রঙের ক্ষেত্রে, এর অর্থ হলো আরজিবি (RGB) মান, হেক্স কোড এবং অন্য যেকোনো প্রাসঙ্গিক বৈশিষ্ট্য।

৩. স্পষ্ট নির্দেশাবলী

নোটিফিকেশনগুলো কীভাবে পরিচালনা করতে হবে সে সম্পর্কে সিস্টেম প্রম্পটে সুস্পষ্ট নির্দেশনা দিন, সম্ভব হলে উদাহরণসহ।

৪. প্রাকৃতিক একীকরণ

নোটিফিকেশনগুলো এমনভাবে ডিজাইন করুন যাতে সেগুলো কথোপকথনের মধ্যে স্বাভাবিকভাবে মিশে যায়, প্রযুক্তিগত বাধা হিসেবে নয়।

৫. নির্বাচনী বিজ্ঞপ্তি

শুধুমাত্র আলোচনার সাথে প্রাসঙ্গিক কাজগুলো সম্পর্কেই এলএলএম-কে অবহিত করুন। প্রতিটি ইউআই ইভেন্ট জানানোর প্রয়োজন নেই।

সমস্যা সমাধান

বিজ্ঞপ্তি সংক্রান্ত সমস্যা

যদি এলএলএম রঙ নির্বাচনে সঠিকভাবে সাড়া না দেয়:

  • যাচাই করুন যে নোটিফিকেশন বার্তার ফরম্যাটটি সিস্টেম প্রম্পটে বর্ণিত ফরম্যাটের সাথে মেলে কিনা।
  • রঙের ডেটা সঠিকভাবে সিরিয়ালাইজ করা হচ্ছে কিনা তা যাচাই করুন।
  • নির্বাচনগুলি পরিচালনা করার জন্য সিস্টেম প্রম্পটে স্পষ্ট নির্দেশাবলী আছে কিনা তা নিশ্চিত করুন।
  • নোটিফিকেশন পাঠানোর সময় চ্যাট সার্ভিসে কোনো ত্রুটি আছে কিনা তা খতিয়ে দেখুন।

প্রসঙ্গ ব্যবস্থাপনা

যদি এলএলএম তার প্রাসঙ্গিকতা হারায় বলে মনে হয়:

  • চ্যাট সেশনটি সঠিকভাবে বজায় রাখা হচ্ছে কিনা তা পরীক্ষা করুন।
  • যাচাই করুন যে কথোপকথনের অবস্থা সঠিকভাবে পরিবর্তিত হচ্ছে।
  • নিশ্চিত করুন যে নোটিফিকেশনগুলো একই চ্যাট সেশনের মাধ্যমে পাঠানো হচ্ছে।

সাধারণ সমস্যা

সাধারণ বিষয়গুলির জন্য:

  • ত্রুটি বা সতর্কতার জন্য লগগুলি পরীক্ষা করুন।
  • ফায়ারবেস এআই লজিক সংযোগ যাচাই করুন
  • ফাংশন প্যারামিটারগুলিতে কোন ধরণের অমিল আছে কিনা তা পরীক্ষা করুন।
  • রিভারপড দ্বারা তৈরি সমস্ত কোড হালনাগাদ আছে কিনা তা নিশ্চিত করুন।

শেখা মূল ধারণাগুলো

  • UI এবং LLM-এর মধ্যে LLM কনটেক্সট সিঙ্ক্রোনাইজেশন তৈরি করা
  • UI ইভেন্টগুলোকে LLM-বান্ধব প্রেক্ষাপটে ক্রমানুসারে সাজানো
  • বিভিন্ন মিথস্ক্রিয়া প্যাটার্নের জন্য LLM আচরণকে নির্দেশিত করা
  • বার্তা এবং বার্তাবিহীন মিথস্ক্রিয়া জুড়ে একটি সুসংহত অভিজ্ঞতা তৈরি করা
  • বৃহত্তর প্রয়োগের অবস্থা সম্পর্কে এলএলএম-এর সচেতনতা বৃদ্ধি করা

এলএলএম কনটেক্সট সিনক্রোনাইজেশন প্রয়োগ করার মাধ্যমে, আপনি একটি সত্যিকারের সমন্বিত অভিজ্ঞতা তৈরি করেছেন যেখানে এলএলএম-কে শুধুমাত্র একটি টেক্সট জেনারেটর না হয়ে, একজন সচেতন ও প্রতিক্রিয়াশীল সহকারী হিসেবে মনে হয়। আরও স্বাভাবিক ও স্বজ্ঞাত এআই-চালিত ইন্টারফেস তৈরি করতে এই পদ্ধতিটি অগণিত অন্যান্য অ্যাপ্লিকেশনেও প্রয়োগ করা যেতে পারে।

৯. অভিনন্দন!

আপনি সফলভাবে কালারিস্ট কোডল্যাবটি সম্পন্ন করেছেন! 🎉

আপনি যা তৈরি করেছেন

আপনি একটি সম্পূর্ণ কার্যকরী ফ্লাটার অ্যাপ্লিকেশন তৈরি করেছেন যা স্বাভাবিক ভাষার রঙের বর্ণনা ব্যাখ্যা করার জন্য গুগলের জেমিনি এপিআই (Gemini API) সংহত করে। আপনার অ্যাপটি এখন যা করতে পারে:

  • 'সূর্যাস্তের কমলা' বা 'গভীর সমুদ্রের নীল'-এর মতো স্বাভাবিক ভাষার বর্ণনা প্রক্রিয়া করুন।
  • এই বর্ণনাগুলিকে বুদ্ধিমত্তার সাথে RGB মানে অনুবাদ করতে Gemini ব্যবহার করুন।
  • স্ট্রিমিং প্রতিক্রিয়ার মাধ্যমে রিয়েল-টাইমে ব্যাখ্যা করা রঙগুলো প্রদর্শন করুন।
  • চ্যাট এবং UI উপাদান উভয়ের মাধ্যমেই ব্যবহারকারীর মিথস্ক্রিয়া পরিচালনা করুন
  • বিভিন্ন মিথস্ক্রিয়া পদ্ধতি জুড়ে প্রাসঙ্গিক সচেতনতা বজায় রাখুন

এখান থেকে কোথায় যাওয়া যায়

এখন যেহেতু আপনি ফ্লাটারের সাথে জেমিনি ইন্টিগ্রেট করার প্রাথমিক বিষয়গুলো আয়ত্ত করে ফেলেছেন, আপনার এই যাত্রা অব্যাহত রাখার জন্য এখানে কিছু উপায় দেওয়া হলো:

আপনার কালারিস্ট অ্যাপটি উন্নত করুন

  • রঙের প্যালেট : পরিপূরক বা মানানসই রঙের স্কিম তৈরি করার কার্যকারিতা যোগ করুন
  • ভয়েস ইনপুট : রঙের মৌখিক বর্ণনার জন্য স্পিচ রিকগনিশন একীভূত করুন।
  • ইতিহাস ব্যবস্থাপনা : রঙের সেটগুলির নামকরণ, বিন্যাস এবং রপ্তানি করার জন্য বিকল্প যোগ করুন
  • কাস্টম প্রম্পটিং : ব্যবহারকারীদের সিস্টেম প্রম্পট কাস্টমাইজ করার জন্য একটি ইন্টারফেস তৈরি করুন।
  • উন্নত বিশ্লেষণ : কোন বর্ণনাগুলো সবচেয়ে ভালো কাজ করে বা সমস্যা সৃষ্টি করে তা ট্র্যাক করুন।

মিথুন রাশির আরও বৈশিষ্ট্য অন্বেষণ করুন

  • মাল্টিমোডাল ইনপুট : ছবি থেকে রঙ বের করতে ইমেজ ইনপুট যোগ করুন
  • কন্টেন্ট তৈরি : বর্ণনা বা গল্পের মতো রঙ-সম্পর্কিত কন্টেন্ট তৈরি করতে জেমিনি ব্যবহার করুন।
  • ফাংশন কলিং-এর উন্নতি : একাধিক ফাংশন ব্যবহার করে আরও জটিল টুল ইন্টিগ্রেশন তৈরি করুন
  • নিরাপত্তা সেটিংস : বিভিন্ন নিরাপত্তা সেটিংস এবং প্রতিক্রিয়ার উপর সেগুলোর প্রভাব সম্পর্কে জানুন।

এই নিদর্শনগুলি অন্যান্য ডোমেনে প্রয়োগ করুন

  • নথি বিশ্লেষণ : এমন অ্যাপ তৈরি করুন যা নথি বুঝতে ও বিশ্লেষণ করতে পারে।
  • সৃজনশীল লেখা সহায়তা : এলএলএম-এর পরামর্শে লেখার দক্ষতা গড়ে তুলুন
  • টাস্ক অটোমেশন : এমন অ্যাপ ডিজাইন করুন যা স্বাভাবিক ভাষাকে স্বয়ংক্রিয় কাজে রূপান্তরিত করে।
  • জ্ঞান-ভিত্তিক অ্যাপ্লিকেশন : নির্দিষ্ট ডোমেনে বিশেষজ্ঞ সিস্টেম তৈরি করুন

সম্পদ

আপনার শিক্ষা অব্যাহত রাখার জন্য এখানে কিছু মূল্যবান উৎস দেওয়া হলো:

সরকারি নথিপত্র

প্রম্পটিং কোর্স এবং গাইড

সম্প্রদায়

পর্যবেক্ষণযোগ্য ফ্লাটার এজেন্টিক সিরিজ

এপিসোড #৫৯-এ, ক্রেইগ ল্যাবেঞ্জ এবং অ্যান্ড্রু ব্রগডেন এই কোডল্যাবটি বিশ্লেষণ করেছেন এবং অ্যাপ বিল্ডের আকর্ষণীয় অংশগুলো তুলে ধরেছেন।

৬০তম পর্বে আবারও ক্রেইগ এবং অ্যান্ড্রুর সাথে যোগ দিন, যেখানে তারা নতুন সক্ষমতা যোগ করে কোডল্যাব অ্যাপটিকে আরও উন্নত করছেন এবং এলএলএমদের নির্দেশমতো কাজ করাতে লড়াই করছেন।

৬১তম পর্বে, ক্রেইগের সাথে যোগ দিয়েছেন ক্রিস সেলস, যিনি সংবাদের শিরোনাম বিশ্লেষণের একটি নতুন দৃষ্টিভঙ্গি তুলে ধরেন এবং এর সাথে সঙ্গতিপূর্ণ চিত্র তৈরি করেন।

প্রতিক্রিয়া

এই কোডল্যাবটি নিয়ে আপনার অভিজ্ঞতা সম্পর্কে আমরা জানতে আগ্রহী! অনুগ্রহ করে নিম্নলিখিত মাধ্যমে আপনার মতামত জানান:

এই কোডল্যাবটি সম্পন্ন করার জন্য আপনাকে ধন্যবাদ, এবং আমরা আশা করি আপনি ফ্লাটার ও এআই-এর সংযোগস্থলে থাকা উত্তেজনাপূর্ণ সম্ভাবনাগুলো অন্বেষণ করা চালিয়ে যাবেন!