Gemini की मदद से काम करने वाला Flutter ऐप्लिकेशन बनाना

Gemini की मदद से काम करने वाला Flutter ऐप्लिकेशन बनाना

इस कोडलैब (कोड बनाना सीखने के लिए ट्यूटोरियल) के बारे में जानकारी

subjectपिछली बार अप्रैल 7, 2025 को अपडेट किया गया
account_circleBrett Morgan ने लिखा

1. Gemini की मदद से काम करने वाला Flutter ऐप्लिकेशन बनाना

आपको क्या बनाना है

इस कोडलैब में, आपको Colorist बनाना होगा. यह एक इंटरैक्टिव Flutter ऐप्लिकेशन है, जो Gemini API की सुविधाओं को सीधे आपके Flutter ऐप्लिकेशन में जोड़ता है. क्या आपको कभी उपयोगकर्ताओं को अपने ऐप्लिकेशन को सामान्य भाषा से कंट्रोल करने की सुविधा देनी थी, लेकिन आपको नहीं पता था कि कहां से शुरू करें? इस कोडलैब में इसका तरीका बताया गया है.

Colorist की मदद से, उपयोगकर्ता रंगों के बारे में सामान्य भाषा में बता सकते हैं. जैसे, "सूर्यास्त का नारंगी रंग" या "गहरे नीले रंग का ओशन". साथ ही, ऐप्लिकेशन:

  • Google के Gemini API का इस्तेमाल करके, इन ब्यौरों को प्रोसेस करता है
  • जानकारी को सटीक आरजीबी कलर वैल्यू में बदलता है
  • स्क्रीन पर रंग को रीयल-टाइम में दिखाता है
  • रंग के बारे में तकनीकी जानकारी और दिलचस्प जानकारी देता है
  • हाल ही में जनरेट किए गए कलर का इतिहास बनाए रखता है

Colorist ऐप्लिकेशन का स्क्रीनशॉट, जिसमें रंग डिसप्ले और चैट इंटरफ़ेस दिख रहा है

इस ऐप्लिकेशन में स्प्लिट-स्क्रीन इंटरफ़ेस है. इसमें एक तरफ़ कलर डिसप्ले एरिया और इंटरैक्टिव चैट सिस्टम है. वहीं, दूसरी तरफ़ एलएलएम के रॉ इंटरैक्शन दिखाने वाला ज़्यादा जानकारी वाला लॉग पैनल है. इस लॉग की मदद से, यह बेहतर तरीके से समझा जा सकता है कि एलएलएम इंटिग्रेशन, अंदरूनी तौर पर कैसे काम करता है.

Flutter डेवलपर के लिए यह जानकारी क्यों ज़रूरी है

एलएलएम, उपयोगकर्ताओं के ऐप्लिकेशन के साथ इंटरैक्ट करने के तरीके में क्रांति ला रहे हैं. हालांकि, उन्हें मोबाइल और डेस्कटॉप ऐप्लिकेशन में असरदार तरीके से इंटिग्रेट करने में खास चुनौतियां आती हैं. इस कोडलैब में, आपको एपीआई कॉल के अलावा, काम के पैटर्न के बारे में बताया गया है.

सीखने की आपकी यात्रा

इस कोडलैब में, Colorist को सिलसिलेवार तरीके से बनाने की प्रोसेस के बारे में बताया गया है:

  1. प्रोजेक्ट सेटअप करना - आपको Flutter ऐप्लिकेशन के बुनियादी स्ट्रक्चर और colorist_ui पैकेज से शुरुआत करनी होगी
  2. Gemini का बुनियादी इंटिग्रेशन - अपने ऐप्लिकेशन को Firebase में Vertex AI से कनेक्ट करें और एलएलएम के साथ आसानी से कम्यूनिकेट करने की सुविधा लागू करें
  3. असरदार प्रॉम्प्ट - सिस्टम प्रॉम्प्ट बनाएं, जो रंग की जानकारी को समझने के लिए एलएलएम को गाइड करे
  4. फ़ंक्शन के एलान - उन टूल के बारे में बताएं जिनका इस्तेमाल LLM, आपके ऐप्लिकेशन में रंग सेट करने के लिए कर सकता है
  5. टूल मैनेज करना - LLM से फ़ंक्शन कॉल प्रोसेस करना और उन्हें आपके ऐप्लिकेशन की स्थिति से कनेक्ट करना
  6. जवाबों को स्ट्रीम करना - रीयल-टाइम में एलएलएम के जवाबों को स्ट्रीम करके, उपयोगकर्ता अनुभव को बेहतर बनाना
  7. एलएलएम कॉन्टेक्स्ट सिंक करना - उपयोगकर्ता की कार्रवाइयों के बारे में एलएलएम को बताकर, बेहतर अनुभव दें

आपको क्या सीखने को मिलेगा

  • Flutter ऐप्लिकेशन के लिए, Firebase में Vertex AI को कॉन्फ़िगर करना
  • एलएलएम के व्यवहार को निर्देश देने के लिए, असरदार सिस्टम प्रॉम्प्ट बनाएं
  • फ़ंक्शन के एलान लागू करें, जो नैचुरल लैंग्वेज और ऐप्लिकेशन की सुविधाओं को जोड़ते हैं
  • उपयोगकर्ता को बेहतर अनुभव देने के लिए, स्ट्रीमिंग के जवाबों को प्रोसेस करना
  • यूज़र इंटरफ़ेस (यूआई) इवेंट और एलएलएम के बीच स्टेटस सिंक करना
  • Riverpod का इस्तेमाल करके, एलएलएम की बातचीत की स्थिति मैनेज करना
  • एलएलएम की मदद से काम करने वाले ऐप्लिकेशन में गड़बड़ियों को आसानी से मैनेज करना

कोड की झलक: इससे आपको पता चलता है कि आपको क्या लागू करना है

यहां फ़ंक्शन के एलान की झलक दी गई है. इसे आपको अपने ऐप्लिकेशन में 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)'),
  },
);

ज़रूरी शर्तें

इस कोडलैब का ज़्यादा से ज़्यादा फ़ायदा पाने के लिए, आपके पास ये चीज़ें होनी चाहिए:

  • Flutter डेवलपमेंट का अनुभव - Flutter की बुनियादी बातों और Dart सिंटैक्स के बारे में जानकारी
  • एसिंक्रोनस प्रोग्रामिंग के बारे में जानकारी - फ़्यूचर्स, async/await, और स्ट्रीम के बारे में जानकारी
  • Firebase खाता - Firebase सेट अप करने के लिए, आपके पास Google खाता होना चाहिए
  • बिलिंग की सुविधा चालू किया गया Firebase प्रोजेक्ट - Firebase में Vertex AI के लिए, बिलिंग खाते की ज़रूरत होती है

आइए, एलएलएम की मदद से काम करने वाला अपना पहला Flutter ऐप्लिकेशन बनाना शुरू करते हैं!

2. प्रोजेक्ट सेटअप और इको सेवा

पहले चरण में, आपको प्रोजेक्ट का स्ट्रक्चर सेट अप करना होगा और एक आसान इको सेवा लागू करनी होगी. बाद में, इसे Gemini API इंटिग्रेशन से बदल दिया जाएगा. इससे ऐप्लिकेशन का आर्किटेक्चर तय होता है. साथ ही, LLM कॉल की जटिलता को जोड़ने से पहले, यह पक्का किया जाता है कि आपका यूज़र इंटरफ़ेस सही तरीके से काम कर रहा है.

इस चरण में आपको क्या सीखने को मिलेगा

  • ज़रूरी डिपेंडेंसी के साथ Flutter प्रोजेक्ट सेट अप करना
  • यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट के लिए colorist_ui पैकेज के साथ काम करना
  • इको मैसेज सेवा लागू करना और उसे यूज़र इंटरफ़ेस (यूआई) से कनेक्ट करना

कीमत तय करने के बारे में अहम जानकारी

नया Flutter प्रोजेक्ट बनाना

इस कमांड का इस्तेमाल करके, नया Flutter प्रोजेक्ट बनाकर शुरू करें:

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

-e फ़्लैग से पता चलता है कि आपको डिफ़ॉल्ट counter ऐप्लिकेशन के बिना खाली प्रोजेक्ट चाहिए. इस ऐप्लिकेशन को डेस्कटॉप, मोबाइल, और वेब पर काम करने के लिए डिज़ाइन किया गया है. हालांकि, फ़िलहाल flutterfire पर Linux काम नहीं करता.

डिपेंडेंसी जोड़ें

अपनी प्रोजेक्ट डायरेक्ट्री पर जाएं और ज़रूरी डिपेंडेंसी जोड़ें:

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

इससे ये मुख्य पैकेज जुड़ जाएंगे:

  • colorist_ui: Colorist ऐप्लिकेशन के लिए यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट उपलब्ध कराने वाला कस्टम पैकेज
  • flutter_riverpod और riverpod_annotation: स्टेट मैनेजमेंट के लिए
  • logging: स्ट्रक्चर्ड लॉगिंग के लिए
  • कोड जनरेट करने और उसे लिंट करने के लिए, डेवलपमेंट डिपेंडेंसी

आपका pubspec.yaml कुछ ऐसा दिखेगा:

pubspec.yaml

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

environment:
  sdk: ^3.7.2

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

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

flutter:
  uses-material-design: true

विश्लेषण के विकल्प कॉन्फ़िगर करना

अपने प्रोजेक्ट के रूट में मौजूद analysis_options.yaml फ़ाइल में custom_lint जोड़ें:

include: package:flutter_lints/flutter.yaml

analyzer:
  plugins:
    - custom_lint

इस कॉन्फ़िगरेशन से, Riverpod के हिसाब से लिंट की सुविधा चालू होती है. इससे कोड की क्वालिटी बनाए रखने में मदद मिलती है.

main.dart फ़ाइल लागू करना

lib/main.dart के कॉन्टेंट की जगह, यह कॉन्टेंट डालें:

lib/main.dart

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

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

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

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

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

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

इससे, Flutter ऐप्लिकेशन सेट अप हो जाता है. साथ ही, एक आसान इको सेवा लागू होती है, जो उपयोगकर्ता के मैसेज को वापस करके एलएलएम के व्यवहार की नकल करती है.

आर्किटेक्चर को समझना

colorist ऐप्लिकेशन के आर्किटेक्चर को समझने के लिए, कुछ समय निकालें:

colorist_ui पैकेज

colorist_ui पैकेज में, पहले से बने यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट और स्टेटस मैनेजमेंट टूल मिलते हैं:

  1. MainScreen: मुख्य यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट, जो ये दिखाता है:
    • डेस्कटॉप पर स्प्लिट-स्क्रीन लेआउट (इंटरैक्शन एरिया और लॉग पैनल)
    • मोबाइल पर टैब वाला इंटरफ़ेस
    • रंगीन डिसप्ले, चैट इंटरफ़ेस, और इतिहास के थंबनेल
  2. स्टेटस मैनेजमेंट: ऐप्लिकेशन, स्टेटस की सूचना देने वाले कई टूल का इस्तेमाल करता है:
    • ChatStateNotifier: चैट मैसेज मैनेज करता है
    • ColorStateNotifier: यह मौजूदा रंग और उसके इतिहास को मैनेज करता है
    • LogStateNotifier: डीबग करने के लिए लॉग एंट्री मैनेज करता है
  3. मैसेज हैंडल करना: यह ऐप्लिकेशन, अलग-अलग स्थितियों वाले मैसेज मॉडल का इस्तेमाल करता है:
    • उपयोगकर्ता के मैसेज: उपयोगकर्ता ने डाला है
    • एलएलएम मैसेज: एलएलएम (या फ़िलहाल आपकी इको सेवा) से जनरेट किए गए
    • MessageState: इससे पता चलता है कि एलएलएम मैसेज पूरे हो गए हैं या अब भी स्ट्रीम हो रहे हैं

ऐप्लिकेशन का आर्किटेक्चर

ऐप्लिकेशन इस आर्किटेक्चर का इस्तेमाल करता है:

  1. यूज़र इंटरफ़ेस लेयर: इसे colorist_ui पैकेज उपलब्ध कराता है
  2. स्टेट मैनेजमेंट: रिऐक्टिव स्टेट मैनेजमेंट के लिए, Riverpod का इस्तेमाल करता है
  3. सर्विस लेयर: फ़िलहाल, इसमें आपकी सामान्य इको सेवा शामिल है. इसे Gemini Chat की सेवा से बदल दिया जाएगा
  4. एलएलएम इंटिग्रेशन: इसे बाद के चरणों में जोड़ा जाएगा

इस अलगाव की मदद से, LLM इंटिग्रेशन को लागू करने पर फ़ोकस किया जा सकता है. इस दौरान, यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट का ध्यान पहले से ही रखा जाता है.

ऐप्लिकेशन चलाना

इस कमांड की मदद से ऐप्लिकेशन चलाएं:

flutter run -d DEVICE

DEVICE को अपने टारगेट डिवाइस से बदलें. जैसे, macos, windows, chrome या डिवाइस आईडी.

Colorist ऐप्लिकेशन का स्क्रीनशॉट, जिसमें मार्कडाउन को रेंडर करने वाली इको सेवा दिखाई गई है

अब आपको Colorist ऐप्लिकेशन दिखेगा, जिसमें ये चीज़ें होंगी:

  1. डिफ़ॉल्ट रंग वाला कलर डिसप्ले एरिया
  2. चैट इंटरफ़ेस, जहां मैसेज टाइप किए जा सकते हैं
  3. चैट इंटरैक्शन दिखाने वाला लॉग पैनल

"मुझे गहरे नीले रंग का बैकग्राउंड चाहिए" जैसा कोई मैसेज लिखें और भेजें पर टैप करें. इस सेवा की मदद से, आपके मैसेज को दोहराया जाएगा. बाद के चरणों में, आपको Firebase में Vertex AI के ज़रिए Gemini API का इस्तेमाल करके, रंग के सही अनुमान से इसे बदलना होगा.

आगे क्या करना है?

अगले चरण में, आपको Firebase को कॉन्फ़िगर करना होगा और Gemini Chat की सेवा के साथ अपनी इको सेवा को बदलने के लिए, Gemini API का बुनियादी इंटिग्रेशन लागू करना होगा. इससे ऐप्लिकेशन, रंगों के ब्यौरे को समझ पाएगा और बेहतर जवाब दे पाएगा.

समस्या का हल

यूज़र इंटरफ़ेस (यूआई) पैकेज से जुड़ी समस्याएं

अगर आपको colorist_ui पैकेज से जुड़ी समस्याएं आती हैं, तो:

  • पक्का करें कि आपने ऐप्लिकेशन का नया वर्शन इंस्टॉल किया हो
  • पुष्टि करें कि आपने डिपेंडेंसी सही तरीके से जोड़ी है
  • पैकेज के ऐसे वर्शन देखें जो एक-दूसरे से मेल नहीं खाते

बिल्ड से जुड़ी गड़बड़ियां

अगर आपको बिल्ड से जुड़ी गड़बड़ियां दिखती हैं, तो:

  • पक्का करें कि आपने Flutter SDK टूल का नया और स्टेबल वर्शन इंस्टॉल किया हो
  • flutter clean के बाद flutter pub get चलाएं
  • गड़बड़ी के खास मैसेज के लिए, कंसोल आउटपुट देखना

सीखे गए मुख्य कॉन्सेप्ट

  • ज़रूरी डिपेंडेंसी के साथ Flutter प्रोजेक्ट सेट अप करना
  • ऐप्लिकेशन के आर्किटेक्चर और कॉम्पोनेंट की ज़िम्मेदारियों को समझना
  • एलएलएम के व्यवहार की नकल करने वाली आसान सेवा लागू करना
  • सेवा को यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट से कनेक्ट करना
  • स्टेट मैनेजमेंट के लिए Riverpod का इस्तेमाल करना

3. Gemini Chat का बुनियादी इंटिग्रेशन

इस चरण में, आपको पिछले चरण की गूंज सेवा को Firebase में Vertex AI का इस्तेमाल करके, Gemini API इंटिग्रेशन से बदलना होगा. आपको Firebase को कॉन्फ़िगर करना होगा, ज़रूरी सेवा देने वाली कंपनियों को सेट अप करना होगा, और Gemini API के साथ काम करने वाली बुनियादी चैट सेवा लागू करनी होगी.

इस चरण में आपको क्या सीखने को मिलेगा

  • Flutter ऐप्लिकेशन में Firebase सेट अप करना
  • Gemini का ऐक्सेस पाने के लिए, Firebase में Vertex AI को कॉन्फ़िगर करना
  • Firebase और Gemini सेवाओं के लिए Riverpod प्रोवाइडर बनाना
  • Gemini API की मदद से, बुनियादी चैट सेवा लागू करना
  • एसिंक्रोनस एपीआई रिस्पॉन्स और गड़बड़ी की स्थितियों को हैंडल करना

Firebase सेट अप करना

सबसे पहले, आपको अपने Flutter प्रोजेक्ट के लिए Firebase सेट अप करना होगा. इसके लिए, आपको Firebase प्रोजेक्ट बनाना होगा, उसमें अपना ऐप्लिकेशन जोड़ना होगा, और Vertex AI की ज़रूरी सेटिंग कॉन्फ़िगर करनी होंगी.

Firebase प्रोजेक्ट बनाना

  1. Firebase कंसोल पर जाएं और अपने Google खाते से साइन इन करें.
  2. Firebase प्रोजेक्ट बनाएं पर क्लिक करें या कोई मौजूदा प्रोजेक्ट चुनें.
  3. अपना प्रोजेक्ट बनाने के लिए, सेटअप विज़र्ड का पालन करें.
  4. प्रोजेक्ट बनाने के बाद, Vertex AI की सेवाएं ऐक्सेस करने के लिए, आपको Blaze प्लान (पे-ऐज़-यू-गो) में अपग्रेड करना होगा. Firebase कंसोल में सबसे नीचे बाईं ओर मौजूद, अपग्रेड करें बटन पर क्लिक करें.

अपने Firebase प्रोजेक्ट में Vertex AI सेट अप करना

  1. Firebase कंसोल में, अपने प्रोजेक्ट पर जाएं.
  2. बाईं ओर मौजूद साइडबार में, AI को चुनें.
  3. Firebase में Vertex AI कार्ड में, शुरू करें चुनें.
  4. अपने प्रोजेक्ट के लिए, Firebase API में Vertex AI को चालू करने के लिए निर्देशों का पालन करें.

FlutterFire सीएलआई इंस्टॉल करना

FlutterFire CLI, Flutter ऐप्लिकेशन में Firebase सेटअप करने की प्रोसेस को आसान बनाता है:

dart pub global activate flutterfire_cli

अपने Flutter ऐप्लिकेशन में Firebase जोड़ना

  1. अपने प्रोजेक्ट में Firebase कोर और Vertex AI पैकेज जोड़ें:
flutter pub add firebase_core firebase_vertexai
  1. FlutterFire कॉन्फ़िगरेशन कमांड चलाएं:
flutterfire configure

इस निर्देश से:

  • आपसे वह Firebase प्रोजेक्ट चुनने के लिए कहा जाएगा जिसे आपने अभी बनाया है
  • Firebase के साथ अपने Flutter ऐप्लिकेशन रजिस्टर करना
  • अपने प्रोजेक्ट कॉन्फ़िगरेशन के साथ firebase_options.dart फ़ाइल जनरेट करना

यह कमांड, आपके चुने गए प्लैटफ़ॉर्म (iOS, Android, macOS, Windows, वेब) का अपने-आप पता लगा लेगा और उन्हें सही तरीके से कॉन्फ़िगर कर देगा.

प्लैटफ़ॉर्म के हिसाब से कॉन्फ़िगरेशन

Firebase के लिए, Flutter के डिफ़ॉल्ट वर्शन से ज़्यादा वर्शन की ज़रूरत होती है. Firebase सर्वर में Vertex AI से बातचीत करने के लिए, नेटवर्क ऐक्सेस की भी ज़रूरत होती है.

macOS डिवाइसों के लिए अनुमतियां कॉन्फ़िगर करना

macOS के लिए, आपको अपने ऐप्लिकेशन के एनटाइटलमेंट में नेटवर्क ऐक्सेस की सुविधा चालू करनी होगी:

  1. macos/Runner/DebugProfile.entitlements खोलें और जोड़ें:

macos/Runner/DebugProfile.entitlements

<key>com.apple.security.network.client</key>
<true/>
  1. macos/Runner/Release.entitlements को भी खोलें और उसी एंट्री को जोड़ें.
  2. macos/Podfile के सबसे ऊपर, macOS का कम से कम वर्शन अपडेट करें:

macos/Podfile

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

iOS की अनुमतियां कॉन्फ़िगर करना

iOS के लिए, ios/Podfile में सबसे ऊपर मौजूद मिनिमम वर्शन को अपडेट करें:

ios/Podfile

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

Android की सेटिंग कॉन्फ़िगर करना

Android के लिए, android/app/build.gradle.kts को अपडेट करें:

android/app/build.gradle.kts

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

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

Gemini मॉडल की सेवा देने वाली कंपनियां बनाना

अब आपको Firebase और Gemini के लिए, Riverpod के प्रोवाइडर बनाने होंगे. नई फ़ाइल बनाने के लिए lib/providers/gemini.dart:

lib/providers/gemini.dart

import 'dart:async';

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

import '../firebase_options.dart';

part 'gemini.g.dart';

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

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

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

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

इस फ़ाइल में, तीन मुख्य सेवा देने वाली कंपनियों के बारे में बताया गया है. ये प्रोवाइडर तब जनरेट होते हैं, जब Riverpod कोड जनरेटर की मदद से dart run build_runner को चलाया जाता है.

  1. firebaseAppProvider: आपके प्रोजेक्ट कॉन्फ़िगरेशन की मदद से Firebase को शुरू करता है
  2. geminiModelProvider: Gemini का जनरेटिव मॉडल इंस्टेंस बनाता है
  3. chatSessionProvider: Gemini मॉडल के साथ चैट सेशन बनाता है और उसे मैनेज करता है

चैट सेशन पर keepAlive: true एनोटेशन लगाने से, यह पक्का होता है कि वह ऐप्लिकेशन के लाइफ़साइकल के दौरान बना रहे. इससे बातचीत का कॉन्टेक्स्ट भी बना रहता है.

Gemini Chat की सेवा लागू करना

चैट सेवा लागू करने के लिए, एक नई फ़ाइल lib/services/gemini_chat_service.dart बनाएं:

lib/services/gemini_chat_service.dart

import 'dart:async';

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

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

part 'gemini_chat_service.g.dart';

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

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

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

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

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

इस सेवा की मदद से:

  1. उपयोगकर्ता के मैसेज स्वीकार करता है और उन्हें Gemini API को भेजता है
  2. मॉडल से मिले जवाबों के साथ चैट इंटरफ़ेस को अपडेट करता है
  3. असल LLM फ़्लो को आसानी से समझने के लिए, सभी कम्यूनिकेशन को लॉग करता है
  4. उपयोगकर्ता के सुझाव, शिकायत या राय के हिसाब से गड़बड़ियों को ठीक करना

ध्यान दें: इस समय लॉग विंडो, चैट विंडो से मिलती-जुलती दिखेगी. फ़ंक्शन कॉल और उसके बाद स्ट्रीमिंग रिस्पॉन्स जोड़ने के बाद, लॉग ज़्यादा दिलचस्प हो जाएगा.

Riverpod कोड जनरेट करना

ज़रूरी Riverpod कोड जनरेट करने के लिए, 'बिल्ड रनर' कमांड चलाएं:

dart run build_runner build --delete-conflicting-outputs

इससे .g.dart फ़ाइलें बन जाएंगी, जिनकी ज़रूरत Riverpod को काम करने के लिए होती है.

main.dart फ़ाइल अपडेट करना

Gemini की नई चैट सेवा का इस्तेमाल करने के लिए, अपनी 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. Gemini API पर आधारित चैट सेवा की मदद से, गूगल वॉइस असिस्टेंट की इको सेवा को बदलना
  2. when तरीके के साथ Riverpod के AsyncValue पैटर्न का इस्तेमाल करके, लोडिंग और गड़बड़ी वाली स्क्रीन जोड़ना
  3. sendMessage कॉलबैक की मदद से, यूज़र इंटरफ़ेस (यूआई) को अपनी नई चैट सेवा से कनेक्ट करना

ऐप्लिकेशन चलाना

इस कमांड की मदद से ऐप्लिकेशन चलाएं:

flutter run -d DEVICE

DEVICE को अपने टारगेट डिवाइस से बदलें. जैसे, macos, windows, chrome या डिवाइस आईडी.

Colorist ऐप्लिकेशन का स्क्रीनशॉट, जिसमें Gemini LLM को धूप में चमकते हुए पीले रंग के लिए अनुरोध करते हुए दिखाया गया है

अब कोई मैसेज टाइप करने पर, वह Gemini API को भेज दिया जाएगा. साथ ही, आपको गूंजने वाली आवाज़ के बजाय एलएलएम से जवाब मिलेगा. लॉग पैनल में, एपीआई के साथ हुए इंटरैक्शन दिखेंगे.

एलएलएम के साथ कम्यूनिकेशन को समझना

Gemini API के साथ इंटरैक्ट करने पर क्या होता है, यह समझने के लिए थोड़ा समय दें:

कम्यूनिकेशन फ़्लो

  1. उपयोगकर्ता का इनपुट: उपयोगकर्ता, चैट इंटरफ़ेस में टेक्स्ट डालता है
  2. रिक्वेस्ट फ़ॉर्मैटिंग: ऐप्लिकेशन, Gemini API के लिए टेक्स्ट को Content ऑब्जेक्ट के तौर पर फ़ॉर्मैट करता है
  3. एपीआई कम्यूनिकेशन: टेक्स्ट को Firebase में Vertex AI के ज़रिए Gemini API को भेजा जाता है
  4. एलएलएम प्रोसेसिंग: Gemini मॉडल, टेक्स्ट को प्रोसेस करता है और जवाब जनरेट करता है
  5. जवाब मैनेज करना: ऐप्लिकेशन को जवाब मिलता है और वह यूज़र इंटरफ़ेस (यूआई) को अपडेट करता है
  6. लॉगिंग: पारदर्शिता के लिए, सभी बातचीत को लॉग किया जाता है

चैट सेशन और बातचीत का कॉन्टेक्स्ट

Gemini चैट सेशन, मैसेज के बीच के कॉन्टेक्स्ट को बनाए रखता है. इससे बातचीत के दौरान इंटरैक्शन करने में मदद मिलती है. इसका मतलब है कि एलएलएम, मौजूदा सेशन में हुई पिछली बातचीत को "याद रखता" है. इससे, ज़्यादा बेहतर बातचीत की सुविधा मिलती है.

चैट सेशन की सेवा देने वाली कंपनी पर keepAlive: true एनोटेशन से यह पक्का होता है कि यह कॉन्टेक्स्ट, ऐप्लिकेशन के लाइफ़साइकल के दौरान बना रहे. एलएलएम के साथ बातचीत के सामान्य फ़्लो को बनाए रखने के लिए, यह कॉन्टेक्स्ट बनाए रखना ज़रूरी है.

आगे क्या करना है?

फ़िलहाल, Gemini API से कुछ भी पूछा जा सकता है. इस पर कोई पाबंदी नहीं है कि वह किस तरह के सवालों के जवाब देगा. उदाहरण के लिए, आपके पास यह पूछने का विकल्प है कि'गुलाबों की लड़ाई' के बारे में खास जानकारी क्या है. यह जानकारी, आपके कलर ऐप्लिकेशन के मकसद से जुड़ी नहीं है.

अगले चरण में, आपको एक सिस्टम प्रॉम्प्ट बनाना होगा. इससे Gemini को रंगों के ब्यौरे को ज़्यादा असरदार तरीके से समझने में मदद मिलेगी. इस वीडियो में, ऐप्लिकेशन की ज़रूरतों के हिसाब से एलएलएम के व्यवहार को पसंद के मुताबिक बनाने और उसकी सुविधाओं को आपके ऐप्लिकेशन के डोमेन पर फ़ोकस करने का तरीका बताया गया है.

समस्या का हल

Firebase कॉन्फ़िगरेशन से जुड़ी समस्याएं

अगर आपको Firebase को शुरू करने में गड़बड़ियां आ रही हैं, तो:

  • पक्का करें कि आपकी firebase_options.dart फ़ाइल सही तरीके से जनरेट की गई हो
  • पुष्टि करें कि आपने Vertex AI का ऐक्सेस पाने के लिए, Blaze प्लान पर अपग्रेड कर लिया है

एपीआई ऐक्सेस करने से जुड़ी गड़बड़ियां

अगर आपको Gemini API को ऐक्सेस करने में गड़बड़ियां मिलती हैं, तो:

  • पुष्टि करें कि आपके Firebase प्रोजेक्ट पर बिलिंग सही तरीके से सेट अप की गई है
  • देखें कि आपके Firebase प्रोजेक्ट में Vertex AI और Cloud AI API चालू हैं या नहीं
  • अपनी इंटरनेट कनेक्टिविटी और फ़ायरवॉल की सेटिंग देखें
  • पुष्टि करें कि मॉडल का नाम (gemini-2.0-flash) सही और उपलब्ध हो

बातचीत के संदर्भ से जुड़ी समस्याएं

अगर आपको लगता है कि Gemini, चैट के पिछले कॉन्टेक्स्ट को याद नहीं रखता है, तो:

  • पुष्टि करें कि chatSession फ़ंक्शन को @Riverpod(keepAlive: true) के साथ एनोटेट किया गया है
  • देखें कि मैसेज एक्सचेंज करने के लिए, एक ही चैट सेशन का इस्तेमाल किया जा रहा है या नहीं
  • मैसेज भेजने से पहले, पुष्टि करें कि चैट सेशन सही तरीके से शुरू हुआ है

प्लैटफ़ॉर्म से जुड़ी समस्याएं

प्लैटफ़ॉर्म से जुड़ी समस्याओं के लिए:

  • iOS/macOS: पक्का करें कि सही एनटाइटलमेंट सेट हों और ज़रूरी वर्शन कॉन्फ़िगर किए गए हों
  • Android: पुष्टि करें कि SDK टूल का कम से कम वर्शन सही तरीके से सेट किया गया हो
  • कंसोल में, प्लैटफ़ॉर्म के हिसाब से गड़बड़ी के मैसेज देखना

सीखे गए मुख्य कॉन्सेप्ट

  • Flutter ऐप्लिकेशन में Firebase सेट अप करना
  • Gemini का ऐक्सेस पाने के लिए, Firebase में Vertex AI को कॉन्फ़िगर करना
  • एसिंक्रोनस सेवाओं के लिए Riverpod प्रोवाइडर बनाना
  • LLM के साथ काम करने वाली चैट सेवा लागू करना
  • एपीआई के एसिंक्रोनस स्टेटस (लोड हो रहा है, गड़बड़ी, डेटा) को हैंडल करना
  • LLM कम्यूनिकेशन फ़्लो और चैट सेशन को समझना

4. रंगों की जानकारी के लिए असरदार प्रॉम्प्ट

इस चरण में, आपको एक सिस्टम प्रॉम्प्ट बनाना और लागू करना होगा. इससे Gemini को रंगों के ब्यौरे को समझने में मदद मिलेगी. सिस्टम प्रॉम्प्ट, कोड में बदलाव किए बिना खास टास्क के लिए एलएलएम के व्यवहार को पसंद के मुताबिक बनाने का एक बेहतरीन तरीका है.

इस चरण में आपको क्या सीखने को मिलेगा

  • एलएलएम ऐप्लिकेशन में सिस्टम प्रॉम्प्ट और उनकी अहमियत को समझना
  • डोमेन के हिसाब से टास्क के लिए असरदार प्रॉम्प्ट बनाना
  • Flutter ऐप्लिकेशन में सिस्टम प्रॉम्प्ट लोड करना और उनका इस्तेमाल करना
  • एलएलएम को एक जैसे फ़ॉर्मैट में जवाब देने के लिए निर्देश देना
  • यह जांच करना कि सिस्टम के प्रॉम्प्ट से एलएलएम के काम करने के तरीके पर क्या असर पड़ता है

सिस्टम के प्रॉम्प्ट को समझना

लागू करने के बारे में जानने से पहले, यह समझ लें कि सिस्टम प्रॉम्प्ट क्या होते हैं और ये क्यों ज़रूरी हैं:

सिस्टम प्रॉम्प्ट क्या होते हैं?

सिस्टम प्रॉम्प्ट, एलएलएम को दिया जाने वाला एक खास तरह का निर्देश है. इससे जवाबों के लिए संदर्भ, व्यवहार के दिशा-निर्देश, और उम्मीदें तय होती हैं. उपयोगकर्ता के मैसेज के उलट, सिस्टम के प्रॉम्प्ट:

  • एलएलएम की भूमिका और व्यक्तित्व तय करना
  • खास जानकारी या क्षमताओं के बारे में बताएं
  • फ़ॉर्मैटिंग के निर्देश देना
  • जवाबों पर पाबंदियां सेट करना
  • अलग-अलग स्थितियों को हैंडल करने का तरीका बताएं

सिस्टम प्रॉम्प्ट को एलएलएम की "नौकरी की जानकारी" के तौर पर देखें. इससे मॉडल को यह पता चलता है कि बातचीत के दौरान उसे कैसे व्यवहार करना है.

सिस्टम प्रॉम्प्ट क्यों मायने रखते हैं

सिस्टम प्रॉम्प्ट, एलएलएम के साथ लगातार और काम के इंटरैक्शन बनाने के लिए ज़रूरी हैं, क्योंकि:

  1. एक जैसा अनुभव यानी कंसिस्टेंसी बनाए रखना: मॉडल को एक जैसे फ़ॉर्मैट में जवाब देने के लिए गाइड करें
  2. प्रासंगिकता को बेहतर बनाना: मॉडल को अपने खास डोमेन (आपके मामले में, रंग) पर फ़ोकस करें
  3. सीमाएं तय करना: तय करें कि मॉडल को क्या करना चाहिए और क्या नहीं करना चाहिए
  4. उपयोगकर्ता अनुभव को बेहतर बनाना: इंटरैक्शन का ज़्यादा स्वाभाविक और मददगार पैटर्न बनाएं
  5. पोस्ट-प्रोसेसिंग कम करना: जवाबों को ऐसे फ़ॉर्मैट में पाएं जिन्हें आसानी से पार्स या दिखाया जा सके

Colorist ऐप्लिकेशन के लिए, आपको 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. टास्क के बारे में जानकारी: इस फ़ील्ड में, मुख्य टास्क के बारे में जानकारी दी जाती है. जैसे, रंग की जानकारी को आरजीबी वैल्यू में बदलना
  3. रिस्पॉन्स फ़ॉर्मैट: इससे पता चलता है कि आरजीबी वैल्यू को एक जैसा रखने के लिए, उन्हें कैसे फ़ॉर्मैट किया जाना चाहिए
  4. एक्सचेंज का उदाहरण: यह इंटरैक्शन के अनुमानित पैटर्न का एक उदाहरण देता है
  5. ऐसे मामले जिनमें सामान्य निर्देश काम नहीं करते: इसमें, ऐसे मामलों में क्या करना है जिनमें सामान्य निर्देश काम नहीं करते
  6. सीमाएं और दिशा-निर्देश: ये सीमाएं तय करते हैं, जैसे कि आरजीबी वैल्यू को 0.0 और 1.0 के बीच रखना

इस स्ट्रक्चर्ड तरीके से यह पक्का किया जाता है कि एलएलएम के जवाब एक जैसे और जानकारी देने वाले हों. साथ ही, उन्हें इस तरह से फ़ॉर्मैट किया गया हो कि प्रोग्राम के हिसाब से RGB वैल्यू निकालने पर, उन्हें आसानी से पार्स किया जा सके.

pubspec.yaml अपडेट करना

अब एसेट डायरेक्ट्री को शामिल करने के लिए, अपने pubspec.yaml के नीचे मौजूद जानकारी को अपडेट करें:

pubspec.yaml

flutter:
  uses-material-design: true

  assets:
    - assets/

ऐसेट बंडल को रीफ़्रेश करने के लिए, flutter pub get चलाएं.

सिस्टम प्रॉम्प्ट प्रोवाइडर बनाना

सिस्टम प्रॉम्प्ट लोड करने के लिए, एक नई फ़ाइल lib/providers/system_prompt.dart बनाएं:

lib/providers/system_prompt.dart

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

part 'system_prompt.g.dart';

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

यह प्रोवाइडर, रनटाइम पर प्रॉम्प्ट फ़ाइल को पढ़ने के लिए, Flutter के एसेट लोडिंग सिस्टम का इस्तेमाल करता है.

Gemini मॉडल उपलब्ध कराने वाली कंपनी को अपडेट करना

अब सिस्टम प्रॉम्प्ट को शामिल करने के लिए, अपनी lib/providers/gemini.dart फ़ाइल में बदलाव करें:

lib/providers/gemini.dart

import 'dart:async';

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

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

part 'gemini.g.dart';

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

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

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

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

जनरेटिव मॉडल बनाते समय, systemInstruction: Content.system(systemPrompt) जोड़ना ही मुख्य बदलाव है. इससे Gemini को यह निर्देश मिलता है कि इस चैट सेशन में सभी इंटरैक्शन के लिए, आपके निर्देशों को सिस्टम प्रॉम्प्ट के तौर पर इस्तेमाल किया जाए.

Riverpod कोड जनरेट करना

ज़रूरी Riverpod कोड जनरेट करने के लिए, 'बिल्ड रनर' कमांड चलाएं:

dart run build_runner build --delete-conflicting-outputs

ऐप्लिकेशन को चलाना और उसकी जांच करना

अब अपना ऐप्लिकेशन चलाएं:

flutter run -d DEVICE

Colorist ऐप्लिकेशन का स्क्रीनशॉट, जिसमें रंग चुनने वाले ऐप्लिकेशन के लिए, Gemini LLM के जवाब में कैरेक्टर का इस्तेमाल किया गया है

अलग-अलग रंगों की जानकारी के साथ इसे आज़माकर देखें:

  • "मुझे स्काई ब्लू रंग का चाहिए"
  • "मुझे फ़ॉरेस्ट ग्रीन रंग दिखाओ"
  • "चटक नारंगी रंग बनाना"
  • "मुझे लैवेंडर का रंग चाहिए"
  • "मुझे डीप ओशन ब्लू जैसा कोई रंग दिखाओ"

आपको पता चलेगा कि Gemini अब रंगों के बारे में बातचीत वाली जानकारी के साथ-साथ, आरजीबी वैल्यू को एक जैसा फ़ॉर्मैट करके जवाब देती है. सिस्टम प्रॉम्प्ट की मदद से, एलएलएम को आपकी ज़रूरत के मुताबिक जवाब देने के लिए बेहतर तरीके से निर्देश दिए गए हैं.

रंगों के अलावा, दूसरे विषयों के बारे में भी इससे पूछें. उदाहरण के लिए, गुलाब के युद्ध की मुख्य वजहें बताएं. आपको पिछले चरण से अंतर दिखेगा.

खास टास्क के लिए, प्रॉम्प्ट इंजीनियरिंग की अहमियत

सिस्टम प्रॉम्प्ट, कला और विज्ञान, दोनों हैं. ये एलएलएम इंटिग्रेशन का अहम हिस्सा हैं. इनसे इस बात पर काफ़ी असर पड़ सकता है कि आपके ऐप्लिकेशन के लिए मॉडल कितना काम का है. आपने यहां प्रॉम्प्ट इंजीनियरिंग का इस्तेमाल किया है. इसमें, निर्देशों में बदलाव करके मॉडल को इस तरह से तैयार किया जाता है कि वह आपके ऐप्लिकेशन की ज़रूरतों के हिसाब से काम करे.

प्रॉम्प्ट इंजीनियरिंग में ये चीज़ें शामिल हैं:

  1. रोल की साफ़ तौर पर परिभाषा: एलएलएम का मकसद क्या है, यह तय करना
  2. साफ़ तौर पर दिए गए निर्देश: इनमें यह बताया जाता है कि एलएलएम को किस तरह जवाब देना चाहिए
  3. असल उदाहरण: अच्छे जवाबों के बारे में बताने के बजाय, उन्हें दिखाना
  4. एज केस मैनेजमेंट: एलएलएम को अस्पष्ट स्थितियों से निपटने का तरीका बताना
  5. फ़ॉर्मैट से जुड़ी खास जानकारी: यह पक्का करना कि जवाबों को एक जैसा और इस्तेमाल किया जा सकने वाला बनाया गया हो

आपने जो सिस्टम प्रॉम्प्ट बनाया है वह Gemini की सामान्य सुविधाओं को, रंगों के बारे में जानकारी देने वाली विशेष असिस्टेंट में बदल देता है. यह असिस्टेंट, आपके ऐप्लिकेशन की ज़रूरतों के हिसाब से फ़ॉर्मैट किए गए जवाब देती है. यह एक ऐसा बेहतरीन पैटर्न है जिसे कई अलग-अलग डोमेन और टास्क पर लागू किया जा सकता है.

आगे क्या करना है?

अगले चरण में, फ़ंक्शन के एलान जोड़कर इस फ़ाउंडेशन को बेहतर बनाया जाएगा. इससे LLM, RGB वैल्यू का सुझाव देने के साथ-साथ, सीधे तौर पर रंग सेट करने के लिए आपके ऐप्लिकेशन में फ़ंक्शन को कॉल कर पाएगा. इससे पता चलता है कि एलएलएम, सामान्य भाषा और ऐप्लिकेशन की खास सुविधाओं के बीच के अंतर को कैसे कम कर सकते हैं.

समस्या का हल

एसेट लोड करने से जुड़ी समस्याएं

अगर आपको सिस्टम प्रॉम्प्ट लोड करने में गड़बड़ियां आ रही हैं, तो:

  • पुष्टि करें कि आपके pubspec.yaml में ऐसेट डायरेक्ट्री की सही जानकारी दी गई हो
  • देखें कि rootBundle.loadString() में दिया गया पाथ, आपकी फ़ाइल की जगह से मेल खाता है या नहीं
  • एसेट बंडल को रीफ़्रेश करने के लिए, पहले flutter clean और फिर flutter pub get चलाएं

अलग-अलग जवाब

अगर LLM, फ़ॉर्मैट के लिए दिए गए निर्देशों का लगातार पालन नहीं कर रहा है, तो:

  • सिस्टम प्रॉम्प्ट में, फ़ॉर्मैट की ज़रूरी शर्तों को ज़्यादा साफ़ तौर पर बताएं
  • अनुमानित पैटर्न दिखाने के लिए ज़्यादा उदाहरण जोड़ें
  • पक्का करें कि आपने मॉडल के लिए सही फ़ॉर्मैट का अनुरोध किया हो

एपीआई के लिए अनुरोध की संख्या सीमित करना

अगर आपको दर सीमित करने से जुड़ी गड़बड़ियां मिलती हैं, तो:

  • ध्यान रखें कि Vertex AI सेवा के इस्तेमाल की सीमाएं हैं
  • एक्सपोनेंशियल बैकऑफ़ के साथ, फिर से कोशिश करने का लॉजिक लागू करें (पाठक के लिए एक गतिविधि के तौर पर छोड़ा गया है)
  • कोटा से जुड़ी किसी भी समस्या के लिए, अपने Firebase कंसोल पर जाएं

सीखे गए मुख्य कॉन्सेप्ट

  • एलएलएम ऐप्लिकेशन में सिस्टम प्रॉम्प्ट की भूमिका और अहमियत को समझना
  • साफ़ निर्देशों, उदाहरणों, और सीमाओं के साथ असरदार प्रॉम्प्ट बनाना
  • Flutter ऐप्लिकेशन में सिस्टम प्रॉम्प्ट लोड करना और उनका इस्तेमाल करना
  • डोमेन के हिसाब से टास्क के लिए, एलएलएम के व्यवहार को निर्देश देना
  • एलएलएम के जवाबों को बेहतर बनाने के लिए, प्रॉम्प्ट इंजीनियरिंग का इस्तेमाल करना

इस चरण में बताया गया है कि अपने कोड में बदलाव किए बिना, एलएलएम के व्यवहार को ज़रूरत के मुताबिक कैसे बनाया जा सकता है. इसके लिए, सिस्टम प्रॉम्प्ट में साफ़ निर्देश देने होंगे.

5. LLM टूल के लिए फ़ंक्शन के एलान

इस चरण में, फ़ंक्शन के एलान लागू करके, Gemini को अपने ऐप्लिकेशन में कार्रवाई करने की अनुमति दी जाएगी. इस बेहतरीन सुविधा की मदद से, एलएलएम न सिर्फ़ आरजीबी वैल्यू का सुझाव देता है, बल्कि खास टूल कॉल की मदद से उन्हें आपके ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में सेट भी करता है. हालांकि, Flutter ऐप्लिकेशन में एलएलएम के अनुरोधों को देखने के लिए, आपको अगले चरण को पूरा करना होगा.

इस चरण में आपको क्या सीखने को मिलेगा

  • एलएलएम फ़ंक्शन कॉलिंग और Flutter ऐप्लिकेशन के लिए इसके फ़ायदों को समझना
  • Gemini के लिए, स्कीमा पर आधारित फ़ंक्शन के एलान तय करना
  • अपने Gemini मॉडल में फ़ंक्शन के एलान को इंटिग्रेट करना
  • टूल की सुविधाओं का इस्तेमाल करने के लिए, सिस्टम प्रॉम्प्ट को अपडेट करना

फ़ंक्शन कॉल करने की सुविधा को समझना

फ़ंक्शन के एलान लागू करने से पहले, यह समझ लें कि ये क्या हैं और ये काम के क्यों हैं:

फ़ंक्शन कॉलिंग क्या है?

फ़ंक्शन कॉलिंग (इसे कभी-कभी "टूल का इस्तेमाल" भी कहा जाता है) एक ऐसी सुविधा है जिसकी मदद से एलएलएम:

  1. यह पता लगाना कि उपयोगकर्ता के अनुरोध को पूरा करने के लिए, किसी खास फ़ंक्शन को ट्रिगर करने से क्या फ़ायदा होगा
  2. उस फ़ंक्शन के लिए ज़रूरी पैरामीटर के साथ स्ट्रक्चर्ड JSON ऑब्जेक्ट जनरेट करना
  3. अपने ऐप्लिकेशन को उन पैरामीटर के साथ फ़ंक्शन को लागू करने दें
  4. फ़ंक्शन का नतीजा पाना और उसे जवाब में शामिल करना

एलएलएम सिर्फ़ यह बताने के बजाय कि क्या करना है, फ़ंक्शन कॉल करने से एलएलएम को आपके ऐप्लिकेशन में खास कार्रवाइयां ट्रिगर करने की सुविधा मिलती है.

Flutter ऐप्लिकेशन के लिए फ़ंक्शन कॉल करना क्यों ज़रूरी है

फ़ंक्शन कॉल करने से, सामान्य भाषा और ऐप्लिकेशन की सुविधाओं के बीच एक बेहतरीन कनेक्शन बनता है:

  1. डायरेक्ट ऐक्शन: उपयोगकर्ता सामान्य भाषा में बता सकते हैं कि उन्हें क्या चाहिए. इसके बाद, ऐप्लिकेशन उनसे जुड़ी कार्रवाइयों के साथ जवाब देता है
  2. स्ट्रक्चर्ड आउटपुट: एलएलएम, पार्स किए जाने वाले टेक्स्ट के बजाय, साफ़ और स्ट्रक्चर्ड डेटा बनाता है
  3. जटिल ऑपरेशन: एलएलएम को बाहरी डेटा ऐक्सेस करने, हिसाब लगाने या ऐप्लिकेशन की स्थिति में बदलाव करने की अनुमति देता है
  4. बेहतर उपयोगकर्ता अनुभव: इससे बातचीत और फ़ंक्शन के बीच आसानी से इंटिग्रेशन होता है

आपके Colorist ऐप्लिकेशन में, फ़ंक्शन कॉल करने की सुविधा की मदद से उपयोगकर्ता, "मुझे फ़ॉरेस्ट ग्रीन चाहिए" कह सकते हैं. इसके बाद, टेक्स्ट से RGB वैल्यू को पार्स किए बिना, यूज़र इंटरफ़ेस (यूआई) तुरंत उस रंग में अपडेट हो जाता है.

फ़ंक्शन के एलान तय करना

फ़ंक्शन के एलान तय करने के लिए, एक नई फ़ाइल lib/services/gemini_tools.dart बनाएं:

lib/services/gemini_tools.dart

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

part 'gemini_tools.g.dart';

class GeminiTools {
 
GeminiTools(this.ref);

 
final Ref ref;

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

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

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

फ़ंक्शन के एलान को समझना

चलिए, इस कोड के बारे में ज़्यादा जानते हैं:

  1. फ़ंक्शन का नाम: अपने फ़ंक्शन set_color का नाम रखें, ताकि उसके मकसद के बारे में साफ़ तौर पर पता चल सके
  2. फ़ंक्शन का ब्यौरा: इसमें फ़ंक्शन के बारे में साफ़ तौर पर जानकारी दी जाती है, ताकि एलएलएम को यह समझने में मदद मिल सके कि फ़ंक्शन का इस्तेमाल कब करना है
  3. पैरामीटर की परिभाषाएं: स्ट्रक्चर्ड पैरामीटर को उनकी जानकारी के साथ तय किया जाता है:
    • red: आरजीबी के लाल रंग का घटक, जिसे 0.0 से 1.0 के बीच की संख्या के तौर पर दिखाया जाता है
    • green: आरजीबी के हरे रंग का कॉम्पोनेंट, जिसे 0.0 से 1.0 के बीच की संख्या के तौर पर दिखाया जाता है
    • blue: आरजीबी के नीले रंग का कॉम्पोनेंट, जिसे 0.0 से 1.0 के बीच की संख्या के तौर पर दिखाया जाता है
  4. स्कीमा टाइप: Schema.number() का इस्तेमाल करके, यह दिखाया जाता है कि ये संख्यात्मक वैल्यू हैं
  5. टूल कलेक्शन: इसमें, फ़ंक्शन के एलान वाले टूल की सूची बनाई जाती है

इस स्ट्रक्चर्ड तरीके से, Gemini LLM को इन चीज़ों को समझने में मदद मिलती है:

  • इस फ़ंक्शन को कब कॉल करना चाहिए
  • उसे कौनसे पैरामीटर देने होंगे
  • उन पैरामीटर पर कौनसी पाबंदियां लागू होती हैं (जैसे, वैल्यू की सीमा)

Gemini मॉडल उपलब्ध कराने वाली कंपनी को अपडेट करना

अब, Gemini मॉडल को शुरू करते समय फ़ंक्शन के एलान शामिल करने के लिए, अपनी lib/providers/gemini.dart फ़ाइल में बदलाव करें:

lib/providers/gemini.dart

import 'dart:async';

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

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

part 'gemini.g.dart';

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

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

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

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

जनरेटिव मॉडल बनाते समय, tools: geminiTools.tools पैरामीटर जोड़ना एक अहम बदलाव है. इससे Gemini को उन फ़ंक्शन के बारे में पता चलता है जिन्हें कॉल किया जा सकता है.

सिस्टम प्रॉम्प्ट अपडेट करना

अब आपको अपने सिस्टम प्रॉम्प्ट में बदलाव करना होगा, ताकि LLM को नए set_color टूल का इस्तेमाल करने के बारे में निर्देश दिया जा सके. assets/system_prompt.md अपडेट करें:

assets/system_prompt.md

# Colorist System Prompt

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

## Your Capabilities

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

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

## How to Respond to User Inputs

When users describe a color:

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

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

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

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

## When Descriptions are Unclear

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

## Important Guidelines

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

सिस्टम प्रॉम्प्ट में ये मुख्य बदलाव हुए हैं:

  1. टूल के बारे में जानकारी: फ़ॉर्मैट की गई आरजीबी वैल्यू के बजाय, अब एलएलएम को set_color टूल के बारे में बताया जाता है
  2. बदली गई प्रोसेस: आपने तीसरे चरण को "जवाब में वैल्यू फ़ॉर्मैट करें" से बदलकर "वैल्यू सेट करने के लिए टूल का इस्तेमाल करें" कर दिया है
  3. अपडेट किया गया उदाहरण: इसमें दिखाया गया है कि फ़ॉर्मैट किए गए टेक्स्ट के बजाय, जवाब में टूल कॉल को कैसे शामिल किया जाना चाहिए
  4. फ़ॉर्मैटिंग की ज़रूरी शर्त हटा दी गई है: स्ट्रक्चर्ड फ़ंक्शन कॉल का इस्तेमाल करने पर, अब आपको किसी खास टेक्स्ट फ़ॉर्मैट की ज़रूरत नहीं है

इस अपडेट किए गए प्रॉम्प्ट से एलएलएम को, टेक्स्ट फ़ॉर्म में RGB वैल्यू देने के बजाय, फ़ंक्शन कॉलिंग का इस्तेमाल करने का निर्देश मिलता है.

Riverpod कोड जनरेट करना

ज़रूरी Riverpod कोड जनरेट करने के लिए, 'बिल्ड रनर' कमांड चलाएं:

dart run build_runner build --delete-conflicting-outputs

ऐप्लिकेशन चलाना

इस स्थिति में, Gemini ऐसा कॉन्टेंट जनरेट करेगा जो फ़ंक्शन कॉल का इस्तेमाल करने की कोशिश करता है. हालांकि, आपने फ़ंक्शन कॉल के लिए अब तक हैंडलर लागू नहीं किए हैं. ऐप्लिकेशन को चलाकर किसी रंग के बारे में बताने पर, आपको Gemini का ऐसा जवाब दिखेगा जैसे उसने कोई टूल चालू किया हो. हालांकि, अगले चरण तक आपको यूज़र इंटरफ़ेस (यूआई) में रंग में कोई बदलाव नहीं दिखेगा.

अपना ऐप्लिकेशन चलाएं:

flutter run -d DEVICE

Colorist ऐप्लिकेशन का स्क्रीनशॉट, जिसमें Gemini LLM का कुछ हिस्सा दिख रहा है

"गहरे नीले रंग" या "हरे रंग" जैसे किसी रंग के बारे में बताकर देखें कि आपको क्या नतीजे मिलते हैं. एलएलएम, ऊपर बताए गए फ़ंक्शन को कॉल करने की कोशिश कर रहा है. हालांकि, आपका कोड फ़िलहाल फ़ंक्शन कॉल का पता नहीं लगा रहा है.

फ़ंक्शन कॉल करने की प्रोसेस

आइए, यह समझते हैं कि फ़ंक्शन कॉल करने पर Gemini क्या करता है:

  1. फ़ंक्शन चुनना: एलएलएम यह तय करता है कि उपयोगकर्ता के अनुरोध के आधार पर, कोई फ़ंक्शन कॉल मददगार होगा या नहीं
  2. पैरामीटर जनरेशन: एलएलएम, फ़ंक्शन के स्कीमा के हिसाब से पैरामीटर वैल्यू जनरेट करता है
  3. फ़ंक्शन कॉल फ़ॉर्मैट: एलएलएम, अपने जवाब में स्ट्रक्चर्ड फ़ंक्शन कॉल ऑब्जेक्ट भेजता है
  4. ऐप्लिकेशन को मैनेज करना: आपके ऐप्लिकेशन को यह कॉल मिलेगा और वह काम का फ़ंक्शन लागू करेगा (अगले चरण में लागू किया गया)
  5. जवाब का इंटिग्रेशन: कई चरणों वाली बातचीत में, एलएलएम को फ़ंक्शन का नतीजा दिखना चाहिए

आपके ऐप्लिकेशन की मौजूदा स्थिति में, पहले तीन चरण पूरे हो रहे हैं. हालांकि, आपने अब तक चौथा या पांचवां चरण (फ़ंक्शन कॉल को मैनेज करना) लागू नहीं किया है. इसे अगले चरण में लागू किया जाएगा.

तकनीकी जानकारी: Gemini यह कैसे तय करता है कि फ़ंक्शन का इस्तेमाल कब करना है

Gemini, फ़ंक्शन इस्तेमाल करने के समय के बारे में बेहतर फ़ैसले लेता है. ये फ़ैसले इनके आधार पर लिए जाते हैं:

  1. उपयोगकर्ता का इंटेंट: क्या उपयोगकर्ता के अनुरोध को किसी फ़ंक्शन से सबसे अच्छा तरीके से पूरा किया जा सकता है
  2. फ़ंक्शन का काम के होने का स्तर: उपलब्ध फ़ंक्शन, टास्क से कितने हद तक मेल खाते हैं
  3. पैरामीटर की उपलब्धता: क्या यह पैरामीटर की वैल्यू का सटीक तरीके से पता लगा सकता है
  4. सिस्टम के निर्देश: फ़ंक्शन के इस्तेमाल के बारे में, सिस्टम से मिलने वाले निर्देश

फ़ंक्शन के बारे में साफ़ तौर पर जानकारी देने और सिस्टम के निर्देशों की मदद से, आपने Gemini को कलर डिस्क्रिप्शन के अनुरोधों को set_color फ़ंक्शन को कॉल करने के अवसरों के तौर पर पहचानने के लिए सेट अप किया है.

आगे क्या करना है?

अगले चरण में, आपको Gemini से आने वाले फ़ंक्शन कॉल के लिए हैंडलर लागू करने होंगे. इससे यह प्रोसेस पूरी हो जाएगी. साथ ही, उपयोगकर्ता के ब्यौरे से, LLM के फ़ंक्शन कॉल की मदद से, यूज़र इंटरफ़ेस (यूआई) में रंग में असल बदलाव ट्रिगर हो सकेंगे.

समस्या का हल

फ़ंक्शन के एलान से जुड़ी समस्याएं

अगर आपको फ़ंक्शन के एलान से जुड़ी गड़बड़ियां मिलती हैं, तो:

  • देखें कि पैरामीटर के नाम और टाइप, उम्मीद के मुताबिक हों
  • पुष्टि करें कि फ़ंक्शन का नाम साफ़ तौर पर दिख रहा हो और उसमें जानकारी दी गई हो
  • पक्का करें कि फ़ंक्शन के ब्यौरे में, उसके मकसद के बारे में सही जानकारी दी गई हो

सिस्टम प्रॉम्प्ट से जुड़ी समस्याएं

अगर एलएलएम, फ़ंक्शन का इस्तेमाल नहीं कर रहा है, तो:

  • पुष्टि करें कि आपके सिस्टम प्रॉम्प्ट में, LLM को set_color टूल का इस्तेमाल करने का साफ़ तौर पर निर्देश दिया गया हो
  • देखें कि सिस्टम प्रॉम्प्ट में दिए गए उदाहरण में, फ़ंक्शन के इस्तेमाल के बारे में बताया गया हो
  • टूल इस्तेमाल करने के निर्देशों को ज़्यादा साफ़ तौर पर लिखें

आम तौर पर आने वाली समस्याएं

अगर आपको कोई और समस्या आती है, तो:

  • फ़ंक्शन के एलान से जुड़ी गड़बड़ियों के लिए कंसोल देखें
  • पुष्टि करें कि टूल, मॉडल को सही तरीके से पास किए गए हैं
  • पक्का करें कि Riverpod से जनरेट किया गया सारा कोड अप-टू-डेट हो

सीखे गए मुख्य कॉन्सेप्ट

  • Flutter ऐप्लिकेशन में एलएलएम की सुविधाओं को बढ़ाने के लिए, फ़ंक्शन के एलान तय करना
  • स्ट्रक्चर्ड डेटा इकट्ठा करने के लिए पैरामीटर स्कीमा बनाना
  • फ़ंक्शन के एलान को Gemini मॉडल के साथ इंटिग्रेट करना
  • फ़ंक्शन के इस्तेमाल को बढ़ावा देने के लिए, सिस्टम के प्रॉम्प्ट अपडेट करना
  • यह समझना कि एलएलएम, फ़ंक्शन को कैसे चुनते और कॉल करते हैं

इस चरण में दिखाया गया है कि एलएलएम, सामान्य भाषा के इनपुट और स्ट्रक्चर्ड फ़ंक्शन कॉल के बीच के अंतर को कैसे कम कर सकते हैं. इससे बातचीत और ऐप्लिकेशन की सुविधाओं के बीच आसानी से इंटिग्रेशन किया जा सकता है.

6. टूल को मैनेज करने की सुविधा लागू करना

इस चरण में, आपको Gemini से आने वाले फ़ंक्शन कॉल के लिए हैंडलर लागू करने होंगे. इससे, सामान्य भाषा के इनपुट और ऐप्लिकेशन की खास सुविधाओं के बीच कम्यूनिकेशन का चक्र पूरा हो जाता है. इससे एलएलएम, उपयोगकर्ता के ब्यौरे के आधार पर सीधे आपके यूआई में बदलाव कर सकता है.

इस चरण में आपको क्या सीखने को मिलेगा

  • एलएलएम ऐप्लिकेशन में, फ़ंक्शन कॉल करने की पूरी पाइपलाइन को समझना
  • Flutter ऐप्लिकेशन में, Gemini से फ़ंक्शन कॉल प्रोसेस करना
  • ऐप्लिकेशन की स्थिति में बदलाव करने वाले फ़ंक्शन हैंडलर लागू करना
  • फ़ंक्शन के रिस्पॉन्स मैनेज करना और एलएलएम को नतीजे दिखाना
  • LLM और यूज़र इंटरफ़ेस (यूआई) के बीच पूरी तरह से कम्यूनिकेशन फ़्लो बनाना
  • पारदर्शिता के लिए, फ़ंक्शन कॉल और रिस्पॉन्स को लॉग करना

फ़ंक्शन कॉलिंग पाइपलाइन को समझना

लागू करने की प्रोसेस शुरू करने से पहले, फ़ंक्शन कॉल करने की पूरी पाइपलाइन को समझते हैं:

एंड-टू-एंड फ़्लो

  1. उपयोगकर्ता का इनपुट: उपयोगकर्ता किसी रंग के बारे में सामान्य भाषा में बताता है (उदाहरण के लिए, "फ़ॉरेस्ट ग्रीन")
  2. एलएलएम प्रोसेसिंग: Gemini, ब्यौरे का विश्लेषण करता है और set_color फ़ंक्शन को कॉल करने का फ़ैसला करता है
  3. फ़ंक्शन कॉल जनरेशन: Gemini, पैरामीटर (लाल, हरी, नीली वैल्यू) के साथ स्ट्रक्चर्ड JSON बनाता है
  4. फ़ंक्शन कॉल रिसेप्शन: आपके ऐप्लिकेशन को यह स्ट्रक्चर्ड डेटा, Gemini से मिलता है
  5. फ़ंक्शन को लागू करना: आपका ऐप्लिकेशन, दिए गए पैरामीटर के साथ फ़ंक्शन को लागू करता है
  6. स्टेटस अपडेट: यह फ़ंक्शन आपके ऐप्लिकेशन की स्थिति को अपडेट करता है. इसके लिए, डिसप्ले किए गए रंग में बदलाव किया जाता है
  7. जवाब जनरेट करना: आपका फ़ंक्शन, एलएलएम को नतीजे दिखाता है
  8. जवाब में शामिल करना: एलएलएम इन नतीजों को अपने फ़ाइनल जवाब में शामिल करता है
  9. यूज़र इंटरफ़ेस (यूआई) अपडेट: आपका यूज़र इंटरफ़ेस (यूआई), स्टेटस में हुए बदलाव के हिसाब से, नया रंग दिखाता है

एलएलएम को सही तरीके से इंटिग्रेट करने के लिए, पूरी बातचीत की प्रक्रिया ज़रूरी है. जब कोई एलएलएम किसी फ़ंक्शन को कॉल करता है, तो वह अनुरोध भेजकर आगे नहीं बढ़ता. इसके बजाय, यह आपके ऐप्लिकेशन के फ़ंक्शन को लागू करने और नतीजे दिखाने का इंतज़ार करता है. इसके बाद, एलएलएम इन नतीजों का इस्तेमाल करके अपना फ़ाइनल जवाब तैयार करता है. साथ ही, वह बातचीत का ऐसा फ़्लो बनाता है जो आपकी की गई कार्रवाइयों को स्वीकार करता है.

फ़ंक्शन हैंडलर लागू करना

फ़ंक्शन कॉल के लिए हैंडलर जोड़ने के लिए, आपकी lib/services/gemini_tools.dart फ़ाइल को अपडेट करते हैं:

lib/services/gemini_tools.dart

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

part 'gemini_tools.g.dart';

class GeminiTools {
 
GeminiTools(this.ref);

 
final Ref ref;

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

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

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

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

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

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

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

फ़ंक्शन हैंडलर को समझना

आइए, इन फ़ंक्शन हैंडलर के काम करने के तरीके के बारे में जानें:

  1. handleFunctionCall: एक सेंट्रल डिस्पैचर, जो:
    • लॉग पैनल में पारदर्शिता के लिए फ़ंक्शन कॉल को लॉग करता है
    • फ़ंक्शन के नाम के आधार पर, सही हैंडलर पर रूट करता है
    • एक स्ट्रक्चर्ड रिस्पॉन्स दिखाता है, जिसे LLM को वापस भेजा जाएगा
  2. handleSetColor: आपके set_color फ़ंक्शन के लिए खास हैंडलर, जो:
    • आर्ग्युमेंट मैप से आरजीबी वैल्यू निकालता है
    • उन्हें उम्मीद के मुताबिक टाइप (डबल) में बदलता है
    • colorStateNotifier का इस्तेमाल करके, ऐप्लिकेशन के कलर स्टेटस को अपडेट करता है
    • सही स्थिति और मौजूदा रंग की जानकारी के साथ स्ट्रक्चर्ड रिस्पॉन्स बनाता है
    • डीबग करने के लिए, फ़ंक्शन के नतीजों को लॉग करता है
  3. handleUnknownFunction: ऐसे फ़ंक्शन के लिए फ़ॉलबैक हैंडलर जो:
    • काम न करने वाले फ़ंक्शन के बारे में चेतावनी को लॉग करता है
    • LLM को गड़बड़ी का जवाब देता है

handleSetColor फ़ंक्शन काफ़ी अहम है, क्योंकि यह एलएलएम की सामान्य भाषा को समझने की सुविधा और यूज़र इंटरफ़ेस (यूआई) में किए गए बदलावों के बीच के अंतर को कम करता है.

फ़ंक्शन कॉल और जवाबों को प्रोसेस करने के लिए, Gemini Chat की सेवा को अपडेट करना

अब, एलएलएम के जवाबों से फ़ंक्शन कॉल को प्रोसेस करने और नतीजों को एलएलएम को वापस भेजने के लिए, lib/services/gemini_chat_service.dart फ़ाइल को अपडेट करें:

lib/services/gemini_chat_service.dart

import 'dart:async';

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

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

part 'gemini_chat_service.g.dart';

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

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

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

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

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

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

बातचीत के फ़्लो को समझना

यहां फ़ंक्शन कॉल और उनके जवाबों को पूरी तरह से मैनेज करने की सुविधा जोड़ी गई है:

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

यह कोड:

  1. यह जांचता है कि LLM के जवाब में कोई फ़ंक्शन कॉल है या नहीं
  2. हर फ़ंक्शन कॉल के लिए, फ़ंक्शन के नाम और आर्ग्युमेंट के साथ आपके handleFunctionCall तरीके को लागू करता है
  3. हर फ़ंक्शन कॉल के नतीजे इकट्ठा करता है
  4. Content.functionResponses का इस्तेमाल करके, इन नतीजों को एलएलएम को वापस भेजता है
  5. फ़ंक्शन के नतीजों के लिए एलएलएम के जवाब को प्रोसेस करता है
  6. यूज़र इंटरफ़ेस (यूआई) को जवाब के फ़ाइनल टेक्स्ट के साथ अपडेट करता है

इससे राउंड ट्रिप फ़्लो बनता है:

  • उपयोगकर्ता → एलएलएम: रंग का अनुरोध करता है
  • LLM → ऐप्लिकेशन: पैरामीटर के साथ फ़ंक्शन कॉल
  • ऐप्लिकेशन → उपयोगकर्ता: नया रंग दिखाया गया
  • ऐप्लिकेशन → एलएलएम: फ़ंक्शन के नतीजे
  • एलएलएम → उपयोगकर्ता: फ़ंक्शन के नतीजों को शामिल करके दिया गया फ़ाइनल रिस्पॉन्स

Riverpod कोड जनरेट करना

ज़रूरी Riverpod कोड जनरेट करने के लिए, 'बिल्ड रनर' कमांड चलाएं:

dart run build_runner build --delete-conflicting-outputs

पूरे फ़्लो को चलाना और उसकी जांच करना

अब अपना ऐप्लिकेशन चलाएं:

flutter run -d DEVICE

Colorist ऐप्लिकेशन का स्क्रीनशॉट, जिसमें फ़ंक्शन कॉल के साथ जवाब देने वाले Gemini LLM को दिखाया गया है

अलग-अलग रंगों के ब्यौरे डालकर देखें:

  • "मुझे गहरे लाल रंग का जूता चाहिए"
  • "मुझे शांत करने वाला स्काई ब्लू रंग दिखाओ"
  • "मुझे पुदीने की ताज़ी पत्तियों का रंग बताओ"
  • "मुझे नारंगी रंग का वॉलपेपर चाहिए"
  • "इसे गहरे रॉयल पर्पल में बदलें"

अब आपको यह दिखेगा:

  1. चैट इंटरफ़ेस में दिख रहा आपका मैसेज
  2. चैट में दिख रहा Gemini का जवाब
  3. लॉग पैनल में लॉग किए जा रहे फ़ंक्शन कॉल
  4. फ़ंक्शन के नतीजे तुरंत लॉग किए जा रहे हैं
  5. रंग के बारे में बताए गए रंग को दिखाने के लिए, रंग का रेक्टैंगल अपडेट हो रहा है
  6. नए रंग के कॉम्पोनेंट दिखाने के लिए, आरजीबी वैल्यू अपडेट की जा रही हैं
  7. Gemini का आखिरी जवाब, जिसमें अक्सर सेट किए गए रंग के बारे में बताया जाता है

लॉग पैनल से यह जानकारी मिलती है कि पर्दे के पीछे क्या हो रहा है. आपको ये चीज़ें दिखेंगी:

  • Gemini के ज़रिए किए जा रहे फ़ंक्शन कॉल
  • हर RGB वैल्यू के लिए चुने गए पैरामीटर
  • आपका फ़ंक्शन जो नतीजे दिखा रहा है
  • Gemini से मिले फ़ॉलो-अप जवाब

रंग की स्थिति बताने वाला नोटिफ़ायर

रंगों को अपडेट करने के लिए इस्तेमाल किया जा रहा colorStateNotifier, colorist_ui पैकेज का हिस्सा है. इसकी मदद से, ये काम किए जा सकते हैं:

  • यूज़र इंटरफ़ेस (यूआई) में दिखाया गया मौजूदा रंग
  • रंग का इतिहास (पिछले 10 रंग)
  • यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट की स्थिति में हुए बदलावों की सूचना

नई आरजीबी वैल्यू के साथ updateColor को कॉल करने पर, यह:

  1. दी गई वैल्यू के साथ नया ColorData ऑब्जेक्ट बनाता है
  2. ऐप्लिकेशन की स्थिति में मौजूदा रंग को अपडेट करता है
  3. इतिहास में रंग जोड़ता है
  4. Riverpod के स्टेट मैनेजमेंट की मदद से, यूज़र इंटरफ़ेस (यूआई) के अपडेट को ट्रिगर करता है

colorist_ui पैकेज में मौजूद यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट, इस स्थिति को देखते हैं और बदलाव होने पर अपने-आप अपडेट हो जाते हैं. इससे, यूज़र इंटरफ़ेस (यूआई) में बदलाव होने पर, उसे तुरंत अपडेट किया जा सकता है.

गड़बड़ी ठीक करने की सुविधा को समझना

आपके लागू किए गए तरीके में, गड़बड़ी को ठीक करने की बेहतर सुविधा शामिल है:

  1. Try-catch ब्लॉक: किसी भी अपवाद को पकड़ने के लिए, सभी एलएलएम इंटरैक्शन को रैप करता है
  2. गड़बड़ी को लॉग करना: स्टैक ट्रेस की मदद से, लॉग पैनल में गड़बड़ियों को रिकॉर्ड करता है
  3. उपयोगकर्ता का सुझाव, शिकायत या राय: Chat में गड़बड़ी का आसान मैसेज दिखाता है
  4. स्टेट को क्लीनअप करना: गड़बड़ी होने पर भी, मैसेज की स्थिति को फ़ाइनल कर देता है

इससे यह पक्का होता है कि ऐप्लिकेशन स्थिर रहे और LLM सेवा या फ़ंक्शन के लागू होने में समस्या होने पर भी सही सुझाव या राय दे सके.

उपयोगकर्ता अनुभव के लिए फ़ंक्शन कॉल करने की सुविधा

यहां आपने जो किया है उससे पता चलता है कि एलएलएम, बेहतरीन नेचुरल इंटरफ़ेस कैसे बना सकते हैं:

  1. सामान्य भाषा का इंटरफ़ेस: उपयोगकर्ता अपनी सामान्य भाषा में अपनी ज़रूरत बताते हैं
  2. स्मार्ट तरीके से जानकारी का विश्लेषण करना: एलएलएम, अस्पष्ट जानकारी को सटीक वैल्यू में बदल देता है
  3. यूज़र इंटरफ़ेस (यूआई) में सीधे तौर पर बदलाव करना: यूज़र इंटरफ़ेस (यूआई) सामान्य भाषा के हिसाब से अपडेट होता है
  4. कॉन्टेक्स्ट के हिसाब से जवाब: एलएलएम, बदलावों के बारे में बातचीत के कॉन्टेक्स्ट में जवाब देता है
  5. कम संज्ञानात्मक लोड: उपयोगकर्ताओं को आरजीबी वैल्यू या रंग सिद्धांत को समझने की ज़रूरत नहीं होती

नैचुरल लैंग्वेज और यूज़र इंटरफ़ेस (यूआई) ऐक्शन को जोड़ने के लिए, एलएलएम फ़ंक्शन कॉलिंग का इस्तेमाल करने के इस पैटर्न को रंग चुनने के अलावा, अनगिनत अन्य डोमेन में भी इस्तेमाल किया जा सकता है.

आगे क्या करना है?

अगले चरण में, स्ट्रीमिंग जवाबों को लागू करके, उपयोगकर्ता अनुभव को बेहतर बनाया जा सकता है. पूरे जवाब का इंतज़ार करने के बजाय, टेक्स्ट के हिस्सों और फ़ंक्शन कॉल को मिलने के साथ ही प्रोसेस किया जाएगा. इससे, ज़्यादा रिस्पॉन्सिव और दिलचस्प ऐप्लिकेशन बनेगा.

समस्या का हल

फ़ंक्शन कॉल से जुड़ी समस्याएं

अगर Gemini आपके फ़ंक्शन को कॉल नहीं कर रहा है या पैरामीटर गलत हैं, तो:

  • पुष्टि करें कि फ़ंक्शन के एलान में दी गई जानकारी, सिस्टम प्रॉम्प्ट में दी गई जानकारी से मेल खाती हो
  • देखें कि पैरामीटर के नाम और टाइप एक जैसे हों
  • पक्का करें कि आपके सिस्टम प्रॉम्प्ट में, LLM को टूल का इस्तेमाल करने का निर्देश साफ़ तौर पर दिया गया हो
  • पुष्टि करें कि आपके हैंडलर में फ़ंक्शन का नाम, एलान में दिए गए नाम से पूरी तरह मेल खाता हो
  • फ़ंक्शन कॉल के बारे में ज़्यादा जानकारी के लिए, लॉग पैनल देखें

फ़ंक्शन के जवाब से जुड़ी समस्याएं

अगर फ़ंक्शन के नतीजे एलएलएम को ठीक से नहीं भेजे जा रहे हैं, तो:

  • देखें कि आपका फ़ंक्शन सही फ़ॉर्मैट में मैप दिखाता है या नहीं
  • पुष्टि करें कि Content.functionResponses सही तरीके से बनाया जा रहा है
  • फ़ंक्शन के जवाबों से जुड़े लॉग में कोई गड़बड़ी देखें
  • पक्का करें कि जवाब देने के लिए, उसी चैट सेशन का इस्तेमाल किया जा रहा हो

रंगों के डिसप्ले से जुड़ी समस्याएं

अगर रंग सही से नहीं दिख रहे हैं, तो:

  • पक्का करें कि आरजीबी वैल्यू को डबल में सही तरीके से बदला गया हो. ऐसा हो सकता है कि एलएलएम उन्हें पूर्णांक के तौर पर भेजे
  • पुष्टि करें कि वैल्यू, उम्मीद के मुताबिक रेंज (0.0 से 1.0) में हों
  • देखें कि कलर स्टेटस नोटिफ़ायर को सही तरीके से कॉल किया जा रहा है या नहीं
  • फ़ंक्शन में भेजी जा रही सटीक वैल्यू के लिए लॉग की जांच करें

सामान्य समस्याएं

सामान्य समस्याओं के लिए:

  • गड़बड़ियों या चेतावनियों के लिए लॉग की जांच करना
  • Firebase कनेक्शन में Vertex AI की पुष्टि करना
  • फ़ंक्शन पैरामीटर में किसी भी तरह के मैच न होने की जांच करना
  • पक्का करें कि Riverpod से जनरेट किया गया सारा कोड अप-टू-डेट हो

सीखे गए मुख्य कॉन्सेप्ट

  • Flutter में फ़ंक्शन कॉल करने की पूरी पाइपलाइन लागू करना
  • एलएलएम और आपके ऐप्लिकेशन के बीच पूरी तरह से कम्यूनिकेशन करना
  • एलएलएम के जवाबों से स्ट्रक्चर्ड डेटा प्रोसेस करना
  • जवाबों में शामिल करने के लिए, फ़ंक्शन के नतीजों को एलएलएम को वापस भेजना
  • लॉग पैनल का इस्तेमाल करके, LLM-ऐप्लिकेशन इंटरैक्शन की जानकारी पाना
  • नैचुरल लैंग्वेज इनपुट को यूज़र इंटरफ़ेस में किए गए बदलावों से जोड़ना

इस चरण को पूरा करने के बाद, आपका ऐप्लिकेशन अब एलएलएम इंटिग्रेशन के लिए सबसे बेहतरीन पैटर्न में से एक दिखाता है: सामान्य भाषा के इनपुट को यूज़र इंटरफ़ेस (यूआई) की सटीक कार्रवाइयों में बदलना. साथ ही, इन कार्रवाइयों को स्वीकार करने वाली बातचीत को जारी रखना. इससे एक आसान और बातचीत वाला इंटरफ़ेस बनता है, जो उपयोगकर्ताओं को जादुई लगता है.

7. बेहतर UX के लिए जवाब स्ट्रीम करना

इस चरण में, Gemini से स्ट्रीम किए जा रहे जवाबों को लागू करके, उपयोगकर्ता अनुभव को बेहतर बनाया जा सकता है. पूरे जवाब के जनरेट होने का इंतज़ार करने के बजाय, टेक्स्ट के हिस्सों और फ़ंक्शन कॉल को मिलने के साथ ही प्रोसेस किया जाएगा. इससे, ज़्यादा रिस्पॉन्सिव और दिलचस्प ऐप्लिकेशन बनेगा.

इस चरण में आपको क्या जानकारी मिलेगी

  • एलएलएम की मदद से काम करने वाले ऐप्लिकेशन के लिए स्ट्रीमिंग की अहमियत
  • Flutter ऐप्लिकेशन में स्ट्रीमिंग एलएलएम के जवाब लागू करना
  • एपीआई से मिलने वाले टेक्स्ट के कुछ हिस्सों को प्रोसेस करना
  • मैसेज के अंतर को रोकने के लिए, बातचीत की स्थिति मैनेज करना
  • स्ट्रीमिंग रिस्पॉन्स में फ़ंक्शन कॉल मैनेज करना
  • जवाबों के लिए विज़ुअल इंडिकेटर बनाना

एलएलएम के आवेदनों के लिए स्ट्रीमिंग क्यों ज़रूरी है

इसे लागू करने से पहले, यह समझ लें कि एलएलएम की मदद से बेहतर उपयोगकर्ता अनुभव देने के लिए, स्ट्रीमिंग जवाब क्यों ज़रूरी हैं:

उपयोगकर्ताओं को बेहतर अनुभव

जवाबों को स्ट्रीम करने से, उपयोगकर्ता अनुभव को बेहतर बनाने में कई फ़ायदे मिलते हैं:

  1. इंतज़ार का समय कम होना: उपयोगकर्ताओं को पूरा जवाब पाने के लिए कई सेकंड इंतज़ार करने के बजाय, टेक्स्ट तुरंत दिखने लगता है. आम तौर पर, यह 100 से 300 मिलीसेकंड के अंदर दिखने लगता है. तुरंत जवाब मिलने की यह धारणा, उपयोगकर्ता की संतुष्टि को काफ़ी बढ़ाती है.
  2. बातचीत की स्वाभाविक लय: टेक्स्ट धीरे-धीरे दिखने से, यह एहसास होता है कि कोई व्यक्ति बातचीत कर रहा है. इससे, बातचीत का अनुभव ज़्यादा स्वाभाविक बनता है.
  3. जानकारी को धीरे-धीरे प्रोसेस करना: उपयोगकर्ता, जानकारी मिलने के साथ ही उसे प्रोसेस करना शुरू कर सकते हैं. इससे उन्हें एक साथ बहुत ज़्यादा टेक्स्ट का सामना नहीं करना पड़ता.
  4. शुरुआत में ही रुकने का विकल्प: अगर उपयोगकर्ताओं को लगता है कि एलएलएम का इस्तेमाल किसी काम के नहीं है, तो वे उसे बीच में रोक सकते हैं या किसी दूसरे ऐप्लिकेशन पर रीडायरेक्ट कर सकते हैं.
  5. गतिविधि की विज़ुअल पुष्टि: स्ट्रीमिंग टेक्स्ट से तुरंत यह पता चलता है कि सिस्टम काम कर रहा है. इससे, उपयोगकर्ताओं को किसी तरह की परेशानी नहीं होती.

तकनीकी फ़ायदे

यूज़र एक्सपीरियंस को बेहतर बनाने के अलावा, स्ट्रीमिंग से तकनीकी तौर पर भी ये फ़ायदे मिलते हैं:

  1. फ़ंक्शन को जल्दी से लागू करना: फ़ंक्शन कॉल, स्ट्रीम में दिखने के साथ ही पहचाने और लागू किए जा सकते हैं. इसके लिए, पूरे जवाब का इंतज़ार करने की ज़रूरत नहीं होती.
  2. यूज़र इंटरफ़ेस (यूआई) में धीरे-धीरे होने वाले अपडेट: नई जानकारी आने पर, अपने यूज़र इंटरफ़ेस (यूआई) को धीरे-धीरे अपडेट किया जा सकता है. इससे, आपको ज़्यादा डाइनैमिक अनुभव मिलता है.
  3. बातचीत की स्थिति मैनेज करना: स्ट्रीमिंग से यह साफ़ तौर पर पता चलता है कि जवाब कब पूरे हो गए हैं और कब अभी भी जवाब दिए जा रहे हैं. इससे, स्टेटस को बेहतर तरीके से मैनेज किया जा सकता है.
  4. टाइम आउट के जोखिम कम हो जाते हैं: नॉन-स्ट्रीमिंग रिस्पॉन्स के साथ, लंबे समय तक चलने वाली जनरेशन से कनेक्शन टाइम आउट होने का खतरा होता है. स्ट्रीमिंग से, कनेक्शन जल्दी से जुड़ता है और बना रहता है.

आपके Colorist ऐप्लिकेशन के लिए, स्ट्रीमिंग लागू करने का मतलब है कि उपयोगकर्ताओं को टेक्स्ट के जवाब और रंग में होने वाले बदलाव, तुरंत दिखेंगे. इससे उन्हें बेहतर अनुभव मिलेगा.

बातचीत की स्थिति मैनेज करने की सुविधा जोड़ना

सबसे पहले, एक स्टेटस प्रोवाइडर जोड़ें, ताकि यह ट्रैक किया जा सके कि ऐप्लिकेशन फ़िलहाल स्ट्रीमिंग रिस्पॉन्स को मैनेज कर रहा है या नहीं. अपनी lib/services/gemini_chat_service.dart फ़ाइल अपडेट करें:

lib/services/gemini_chat_service.dart

import 'dart:async';

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

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

part 'gemini_chat_service.g.dart';

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

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

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

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

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

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

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

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

स्ट्रीमिंग की सुविधा को लागू करने के बारे में जानकारी

चलिए, इस कोड के बारे में ज़्यादा जानते हैं:

  1. बातचीत की स्थिति ट्रैक करना:
    • conversationStateProvider से यह पता चलता है कि ऐप्लिकेशन फ़िलहाल कोई जवाब प्रोसेस कर रहा है या नहीं
    • प्रोसेस के दौरान, स्टेटस idlebusy में बदलता है और फिर idle पर वापस आ जाता है
    • इससे एक साथ कई अनुरोध होने से रोका जा सकता है, जो आपस में मेल नहीं खाते
  2. स्ट्रीम शुरू करना:
    • sendMessageStream(), पूरे जवाब के साथ फ़्यूचर के बजाय, जवाब के हिस्सों की स्ट्रीम दिखाता है
    • हर चंक में टेक्स्ट, फ़ंक्शन कॉल या दोनों शामिल हो सकते हैं
  3. प्रगतिशील प्रोसेसिंग:
    • await for, रीयल-टाइम में मिलने वाले हर चंक को प्रोसेस करता है
    • टेक्स्ट, यूज़र इंटरफ़ेस (यूआई) में तुरंत जुड़ जाता है, जिससे स्ट्रीमिंग इफ़ेक्ट बनता है
    • फ़ंक्शन कॉल का पता चलने के साथ ही, उन्हें लागू कर दिया जाता है
  4. फ़ंक्शन कॉल मैनेज करना:
    • जब किसी चंक में फ़ंक्शन कॉल का पता चलता है, तो उसे तुरंत लागू कर दिया जाता है
    • नतीजे, स्ट्रीमिंग कॉल के ज़रिए एलएलएम को वापस भेजे जाते हैं
    • इन नतीजों के लिए एलएलएम का जवाब भी स्ट्रीमिंग के तरीके से प्रोसेस किया जाता है
  5. गड़बड़ी ठीक करना और डेटा हटाना:
    • try/catch, गड़बड़ी को मैनेज करने की बेहतर सुविधा देता है
    • finally ब्लॉक से यह पक्का होता है कि बातचीत की स्थिति सही तरीके से रीसेट हो गई है
    • गड़बड़ियां होने पर भी मैसेज हमेशा भेज दिया जाता है

इस सुविधा को लागू करने से, बातचीत की सही स्थिति को बनाए रखते हुए, रिस्पॉन्सिव और भरोसेमंद स्ट्रीमिंग का अनुभव मिलता है.

बातचीत की स्थिति को कनेक्ट करने के लिए, मुख्य स्क्रीन को अपडेट करना

बातचीत की स्थिति को मुख्य स्क्रीन पर भेजने के लिए, अपनी lib/main.dart फ़ाइल में बदलाव करें:

lib/main.dart

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

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

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

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

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

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

यहां मुख्य बदलाव यह है कि conversationState को MainScreen विजेट को पास किया जा रहा है. MainScreen (colorist_ui पैकेज से मिला) इस स्टेटस का इस्तेमाल करके, जवाब प्रोसेस होने के दौरान टेक्स्ट इनपुट को बंद कर देगा.

इससे उपयोगकर्ता को बेहतर अनुभव मिलता है. इसमें यूज़र इंटरफ़ेस (यूआई), बातचीत की मौजूदा स्थिति को दिखाता है.

Riverpod कोड जनरेट करना

ज़रूरी Riverpod कोड जनरेट करने के लिए, 'बिल्ड रनर' कमांड चलाएं:

dart run build_runner build --delete-conflicting-outputs

स्ट्रीमिंग रिस्पॉन्स चलाना और उनकी जांच करना

अपना ऐप्लिकेशन चलाएं:

flutter run -d DEVICE

Colorist ऐप्लिकेशन का स्क्रीनशॉट, जिसमें Gemini LLM के जवाब को स्ट्रीमिंग फ़ॉर्मैट में दिखाया गया है

अब अलग-अलग रंगों के ब्यौरे के साथ, स्ट्रीमिंग के व्यवहार की जांच करें. इनमें से कोई जानकारी दें:

  • "मुझे शाम के समय, समुद्र का गहरा टिएल रंग दिखाओ"
  • "मुझे ऐसा चमकीला मूंगा दिखाओ जो मुझे ट्रॉपिकल फूलों की याद दिलाए"
  • "पुराने फ़ैटीज़ की तरह मटमैट जैतूनी हरा रंग बनाएं"

स्ट्रीमिंग के तकनीकी फ़्लो के बारे में पूरी जानकारी

आइए, देखें कि जवाब स्ट्रीम करने पर क्या होता है:

कनेक्शन सेट अप करना

sendMessageStream() बोलने पर, ये काम होते हैं:

  1. ऐप्लिकेशन, Vertex AI सेवा से कनेक्ट होता है
  2. उपयोगकर्ता का अनुरोध, सेवा को भेजा जाता है
  3. सर्वर, अनुरोध को प्रोसेस करना शुरू कर देता है
  4. स्ट्रीम कनेक्शन खुला रहता है, ताकि चंक भेजे जा सकें

चंक ट्रांसमिशन

Gemini के कॉन्टेंट जनरेट करने के दौरान, स्ट्रीम के ज़रिए चंक भेजे जाते हैं:

  1. सर्वर, जनरेट होने के साथ ही टेक्स्ट के हिस्से भेजता है. आम तौर पर, ये कुछ शब्द या वाक्य होते हैं
  2. जब Gemini फ़ंक्शन कॉल करने का फ़ैसला करता है, तो वह फ़ंक्शन कॉल की जानकारी भेजता है
  3. फ़ंक्शन कॉल के बाद, टेक्स्ट के अन्य हिस्से दिख सकते हैं
  4. वीडियो जनरेट होने तक स्ट्रीमिंग जारी रहती है

प्रोग्रेसिव प्रोसेसिंग

आपका ऐप्लिकेशन हर चंक को क्रम से प्रोसेस करता है:

  1. हर टेक्स्ट चंक को मौजूदा जवाब में जोड़ दिया जाता है
  2. फ़ंक्शन कॉल का पता चलने के साथ ही, उन्हें लागू कर दिया जाता है
  3. यूज़र इंटरफ़ेस (यूआई), टेक्स्ट और फ़ंक्शन के नतीजों के साथ रीयल-टाइम में अपडेट होता है
  4. जवाब अब भी स्ट्रीम हो रहा है, यह दिखाने के लिए स्टेटस को ट्रैक किया जाता है

स्ट्रीम खत्म होने की सूचना

जनरेट होने के बाद:

  1. सर्वर ने स्ट्रीम बंद कर दी है
  2. आपका await for लूप अपने-आप बंद हो जाता है
  3. मैसेज पर 'पूरा हो गया' का निशान लगाया गया
  4. बातचीत की स्थिति को फिर से 'कुछ समय से इस्तेमाल में नहीं है' पर सेट किया जाता है
  5. पूरा होने की स्थिति दिखाने के लिए, यूज़र इंटरफ़ेस (यूआई) अपडेट हो जाता है

स्ट्रीमिंग और नॉन-स्ट्रीमिंग की तुलना

स्ट्रीमिंग के फ़ायदों को बेहतर तरीके से समझने के लिए, स्ट्रीमिंग और नॉन-स्ट्रीमिंग के तरीकों की तुलना करते हैं:

पक्ष

नॉन-स्ट्रीमिंग

स्ट्रीमिंग

इंतज़ार का अनुमानित समय

जब तक पूरा जवाब तैयार नहीं हो जाता, तब तक उपयोगकर्ता को कुछ नहीं दिखता

उपयोगकर्ता को पहले शब्द मिलिसेकंड में दिखते हैं

उपयोगकर्ता अनुभव

लंबे इंतज़ार के बाद अचानक टेक्स्ट दिखना

टेक्स्ट का नैचुरल और प्रोग्रेसिव तरीके से दिखना

स्टेटस मैनेजमेंट

आसान (मैसेज या तो भेजे नहीं गए हैं या भेजे जा चुके हैं)

ज़्यादा जटिल (मैसेज स्ट्रीमिंग की स्थिति में हो सकते हैं)

फ़ंक्शन को लागू करना

यह सिर्फ़ पूरा जवाब मिलने के बाद होता है

जवाब जनरेट करने के दौरान होता है

लागू करने में आने वाली समस्याएं

लागू करने में आसान

इसके लिए, स्टेटस को अलग से मैनेज करना ज़रूरी है

गड़बड़ी ठीक करना

'सभी या कुछ भी नहीं' जवाब

अधूरे जवाब भी काम के हो सकते हैं

कोड की जटिलता

कम जटिल

स्ट्रीम मैनेज करने की वजह से ज़्यादा मुश्किल

Colorist जैसे ऐप्लिकेशन के लिए, स्ट्रीमिंग के यूज़र एक्सपीरियंस (यूएक्स) के फ़ायदे, लागू करने की जटिलता से ज़्यादा होते हैं. खास तौर पर, रंगों के विश्लेषण के लिए, जनरेट होने में कई सेकंड लग सकते हैं.

स्ट्रीमिंग के यूज़र एक्सपीरियंस के लिए सबसे सही तरीके

अपने एलएलएम ऐप्लिकेशन में स्ट्रीमिंग लागू करते समय, इन सबसे सही तरीकों को ध्यान में रखें:

  1. साफ़ तौर पर दिखने वाले विज़ुअल इंडिकेटर: हमेशा ऐसे विज़ुअल दिए जाने चाहिए जिनसे यह पता चल सके कि मैसेज स्ट्रीम किया जा रहा है या पूरा हो चुका है
  2. इनपुट ब्लॉक करना: स्ट्रीमिंग के दौरान उपयोगकर्ता के इनपुट को बंद करना, ताकि एक साथ कई अनुरोध न किए जा सकें
  3. गड़बड़ी ठीक करना: स्ट्रीमिंग में रुकावट आने पर, उसे ठीक करने के लिए अपना यूज़र इंटरफ़ेस (यूआई) डिज़ाइन करें
  4. स्टेटस ट्रांज़िशन: यह पक्का करें कि इंतज़ार में, स्ट्रीमिंग में, और पूरा होने की स्थितियों के बीच ट्रांज़िशन आसानी से हो
  5. प्रगति को विज़ुअलाइज़ करना: प्रोसेस के दौरान दिखने वाले छोटे ऐनिमेशन या इंडिकेटर का इस्तेमाल करें
  6. रद्द करने के विकल्प: ऐप्लिकेशन के पूरी तरह से काम करने वाले वर्शन में, उपयोगकर्ताओं को जनरेशन की प्रोसेस को रद्द करने के तरीके उपलब्ध कराएं
  7. फ़ंक्शन के नतीजे का इंटिग्रेशन: लाइव स्ट्रीम के बीच में दिखने वाले फ़ंक्शन के नतीजों को मैनेज करने के लिए, अपना यूज़र इंटरफ़ेस डिज़ाइन करें
  8. परफ़ॉर्मेंस को ऑप्टिमाइज़ करना: स्ट्रीम में तेज़ी से होने वाले अपडेट के दौरान, यूज़र इंटरफ़ेस (यूआई) को फिर से बनाने की प्रोसेस को कम करना

colorist_ui पैकेज, इनमें से कई सबसे सही तरीकों को आपके लिए लागू करता है. हालांकि, स्ट्रीमिंग एलएलएम को लागू करने के लिए, इन बातों का ध्यान रखना ज़रूरी है.

आगे क्या करना है?

अगले चरण में, आपको एलएलएम सिंक करने की सुविधा लागू करनी होगी. इसके लिए, जब उपयोगकर्ता इतिहास से रंग चुनेंगे, तब Gemini को सूचना देनी होगी. इससे, उपयोगकर्ता को बेहतर अनुभव मिलेगा. इसमें एलएलएम को ऐप्लिकेशन की स्थिति में, उपयोगकर्ता से किए गए बदलावों की जानकारी होगी.

समस्या का हल

स्ट्रीम प्रोसेस करने से जुड़ी समस्याएं

अगर आपको स्ट्रीम प्रोसेस करने में समस्याएं आ रही हैं, तो:

  • लक्षण: कुछ ही जवाब मिलना, टेक्स्ट न दिखना या स्ट्रीम अचानक बंद होना
  • समाधान: नेटवर्क कनेक्टिविटी की जांच करें और पक्का करें कि आपके कोड में सही async/await पैटर्न हों
  • गड़बड़ी का पता लगाना: स्ट्रीम प्रोसेस करने से जुड़ी गड़बड़ी के मैसेज या चेतावनियों के लिए, लॉग पैनल देखें
  • ठीक करें: पक्का करें कि स्ट्रीम प्रोसेसिंग के लिए, try/catch ब्लॉक के साथ गड़बड़ी को ठीक करने का सही तरीका इस्तेमाल किया जा रहा हो

फ़ंक्शन कॉल मौजूद नहीं हैं

अगर स्ट्रीम में फ़ंक्शन कॉल का पता नहीं चल रहा है, तो:

  • लक्षण: टेक्स्ट दिखता है, लेकिन रंग अपडेट नहीं होते या लॉग में कोई फ़ंक्शन कॉल नहीं दिखता
  • समाधान: फ़ंक्शन कॉल इस्तेमाल करने के बारे में सिस्टम प्रॉम्प्ट के निर्देशों की पुष्टि करें
  • गड़बड़ी का पता लगाना: लॉग पैनल देखकर पता लगाएं कि फ़ंक्शन कॉल मिल रहे हैं या नहीं
  • ठीक करें: अपने सिस्टम प्रॉम्प्ट में बदलाव करें, ताकि LLM को set_color टूल का इस्तेमाल करने का निर्देश साफ़ तौर पर दिया जा सके

गड़बड़ी को मैनेज करने का सामान्य तरीका

किसी भी अन्य समस्या के लिए:

  • पहला चरण: गड़बड़ी के मैसेज के लिए, लॉग पैनल देखें
  • दूसरा चरण: Firebase कनेक्शन में Vertex AI की पुष्टि करना
  • तीसरा चरण: पक्का करें कि Riverpod से जनरेट किया गया सारा कोड अप-टू-डेट हो
  • चौथा चरण: स्ट्रीमिंग लागू करने के तरीके की समीक्षा करें और देखें कि कहीं कोई await स्टेटमेंट तो छूट न गया हो

सीखे गए मुख्य कॉन्सेप्ट

  • बेहतर यूज़र एक्सपीरियंस (UX) के लिए, Gemini API की मदद से स्ट्रीमिंग रिस्पॉन्स लागू करना
  • स्ट्रीमिंग इंटरैक्शन को सही तरीके से मैनेज करने के लिए, बातचीत की स्थिति मैनेज करना
  • रीयल-टाइम में मैसेज और फ़ंक्शन कॉल आने पर उन्हें प्रोसेस करना
  • स्ट्रीमिंग के दौरान धीरे-धीरे अपडेट होने वाले रिस्पॉन्सिव यूज़र इंटरफ़ेस (यूआई) बनाना
  • एक साथ चल रही स्ट्रीम को सही तरीके से सिंक करने के पैटर्न
  • जवाबों को स्ट्रीम करते समय, सही विज़ुअल फ़ीडबैक देना

स्ट्रीमिंग की सुविधा लागू करके, आपने Colorist ऐप्लिकेशन के उपयोगकर्ता अनुभव को बेहतर बनाया है. साथ ही, आपने एक ऐसा इंटरफ़ेस बनाया है जो ज़्यादा रिस्पॉन्सिव और दिलचस्प है. इससे उपयोगकर्ताओं को बातचीत करने जैसा अनुभव मिलता है.

8. एलएलएम कॉन्टेक्स्ट सिंक करना

इस बोनस चरण में, उपयोगकर्ता इतिहास से रंग चुनने पर Gemini को सूचना देकर, एलएलएम कॉन्टेक्स्ट सिंक करने की सुविधा लागू की जाएगी. इससे, उपयोगकर्ताओं को बेहतर अनुभव मिलता है. इसमें LLM, इंटरफ़ेस में उपयोगकर्ता की कार्रवाइयों के बारे में जानता है, न कि सिर्फ़ उनके अश्लील मैसेज के बारे में.

इस चरण में आपको क्या जानकारी मिलेगी

  • अपने यूज़र इंटरफ़ेस (यूआई) और एलएलएम के बीच एलएलएम कॉन्टेक्स्ट सिंक करने की सुविधा बनाना
  • यूज़र इंटरफ़ेस (यूआई) इवेंट को ऐसे कॉन्टेक्स्ट में सीरियलाइज़ करना जिसे एलएलएम समझ सके
  • उपयोगकर्ता की कार्रवाइयों के आधार पर बातचीत का कॉन्टेक्स्ट अपडेट करना
  • अलग-अलग इंटरैक्शन के तरीकों के लिए एक जैसा अनुभव देना
  • अश्लील चैट मैसेज के अलावा, एलएलएम के कॉन्टेक्स्ट के बारे में जानकारी देने की सुविधा को बेहतर बनाना

एलएलएम कॉन्टेक्स्ट सिंक करने की सुविधा के बारे में जानकारी

पारंपरिक चैटबॉट सिर्फ़ उपयोगकर्ता के साफ़ तौर पर पूछे गए सवालों का जवाब देते हैं. इससे, जब उपयोगकर्ता किसी दूसरे तरीके से ऐप्लिकेशन से इंटरैक्ट करते हैं, तो उन्हें चैटबॉट से जवाब नहीं मिलता. एलएलएम कॉन्टेक्स्ट सिंक करने की सुविधा से, इस समस्या को हल किया जा सकता है:

एलएलएम कॉन्टेक्स्ट सिंक करना क्यों ज़रूरी है

जब उपयोगकर्ता यूज़र इंटरफ़ेस (यूआई) एलिमेंट (जैसे, इतिहास से कोई रंग चुनना) के ज़रिए आपके ऐप्लिकेशन के साथ इंटरैक्ट करते हैं, तो एलएलएम को यह पता नहीं चलता कि क्या हुआ है. ऐसा तब तक नहीं होगा, जब तक आप उसे साफ़ तौर पर नहीं बताते. एलएलएम कॉन्टेक्स्ट सिंक करना:

  1. कॉन्टेक्स्ट बनाए रखता है: उपयोगकर्ता की सभी ज़रूरी कार्रवाइयों के बारे में एलएलएम को जानकारी देता है
  2. एक जैसा अनुभव देता है: इससे एक जैसा अनुभव मिलता है, जिसमें एलएलएम, यूज़र इंटरफ़ेस (यूआई) इंटरैक्शन को स्वीकार करता है
  3. इंटेलिजेंस को बेहतर बनाता है: इससे एलएलएम, उपयोगकर्ता की सभी कार्रवाइयों का सही जवाब दे पाता है
  4. उपयोगकर्ता अनुभव को बेहतर बनाता है: इससे पूरे ऐप्लिकेशन को ज़्यादा इंटिग्रेट और रिस्पॉन्सिव महसूस होता है
  5. उपयोगकर्ता की मेहनत कम होती है: इससे उपयोगकर्ताओं को अपने यूज़र इंटरफ़ेस (यूआई) की कार्रवाइयों के बारे में मैन्युअल तरीके से बताने की ज़रूरत नहीं पड़ती

आपके Colorist ऐप्लिकेशन में, जब कोई उपयोगकर्ता इतिहास से कोई रंग चुनता है, तो आपको Gemini से इस कार्रवाई की पुष्टि करने के साथ-साथ, चुने गए रंग के बारे में स्मार्ट तरीके से टिप्पणी करने की सुविधा चाहिए. इससे, उपयोगकर्ता को यह एहसास होगा कि आपका ऐप्लिकेशन, एक बेहतर और समझदार सहायक की तरह काम कर रहा है.

रंग चुनने से जुड़ी सूचनाएं पाने के लिए, Gemini Chat की सेवा को अपडेट करना

सबसे पहले, आपको GeminiChatService में एक तरीका जोड़ना होगा, ताकि जब कोई उपयोगकर्ता इतिहास से कोई रंग चुनता है, तो LLM को इसकी सूचना दी जा सके. अपनी lib/services/gemini_chat_service.dart फ़ाइल अपडेट करें:

lib/services/gemini_chat_service.dart

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

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

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

part 'gemini_chat_service.g.dart';

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

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

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

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

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

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

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

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

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

इसमें notifyColorSelection तरीका जोड़ा गया है, जो:

  1. चुने गए रंग को दिखाने वाला ColorData ऑब्जेक्ट लेता है
  2. इसे JSON फ़ॉर्मैट में एन्कोड करता है, ताकि इसे मैसेज में शामिल किया जा सके
  3. उपयोगकर्ता के चुने गए विकल्प के बारे में बताने के लिए, LLM को खास तौर पर फ़ॉर्मैट किया गया मैसेज भेजता है
  4. सूचना को मैनेज करने के लिए, मौजूदा sendMessage तरीके का फिर से इस्तेमाल करता है

इस तरीके से, मैसेज मैनेज करने के लिए इस्तेमाल किए जा रहे मौजूदा इन्फ़्रास्ट्रक्चर का इस्तेमाल करके, डुप्लीकेट मैसेज से बचा जा सकता है.

रंग चुनने की सूचनाएं कनेक्ट करने के लिए, मुख्य ऐप्लिकेशन को अपडेट करना

अब, रंग चुनने की सूचना देने वाले फ़ंक्शन को मुख्य स्क्रीन पर भेजने के लिए, अपनी lib/main.dart फ़ाइल में बदलाव करें:

lib/main.dart

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

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

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

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

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

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

मुख्य बदलाव notifyColorSelection कॉलबैक जोड़ना है, जो यूज़र इंटरफ़ेस (इतिहास से कोई रंग चुनना) इवेंट को एलएलएम सूचना सिस्टम से जोड़ता है.

सिस्टम प्रॉम्प्ट अपडेट करना

अब आपको अपने सिस्टम प्रॉम्प्ट को अपडेट करना होगा, ताकि LLM को रंग चुनने से जुड़ी सूचनाओं का जवाब देने का तरीका बताया जा सके. अपनी assets/system_prompt.md फ़ाइल में बदलाव करें:

assets/system_prompt.md

# Colorist System Prompt

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

## Your Capabilities

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

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

## How to Respond to User Inputs

When users describe a color:

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

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

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

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

## When Descriptions are Unclear

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

## When Users Select Historical Colors

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

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

## Important Guidelines

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

इसमें "जब उपयोगकर्ता पुराने रंग चुनते हैं" सेक्शन जोड़ा गया है. इस सेक्शन में:

  1. एलएलएम को, इतिहास चुनने से जुड़ी सूचनाओं के कॉन्सेप्ट के बारे में बताता है
  2. इन सूचनाओं के दिखने का उदाहरण देता है
  3. सही जवाब का उदाहरण दिखाता है
  4. चुने गए रंग की पुष्टि करने और उस पर टिप्पणी करने के लिए उम्मीदें सेट करता है

इससे एलएलएम को यह समझने में मदद मिलती है कि इन खास मैसेज का सही जवाब कैसे दिया जाए.

Riverpod कोड जनरेट करना

ज़रूरी Riverpod कोड जनरेट करने के लिए, 'बिल्ड रनर' कमांड चलाएं:

dart run build_runner build --delete-conflicting-outputs

एलएलएम कॉन्टेक्स्ट सिंक करने की सुविधा को चलाना और उसकी जांच करना

अपना ऐप्लिकेशन चलाएं:

flutter run -d DEVICE

Colorist ऐप्लिकेशन का स्क्रीनशॉट, जिसमें कलर के इतिहास से चुने गए रंग के हिसाब से Gemini LLM का जवाब दिख रहा है

एलएलएम कॉन्टेक्स्ट सिंक्रोनाइज़ेशन की जांच करने के लिए:

  1. सबसे पहले, चैट में रंगों के बारे में बताकर कुछ रंग जनरेट करें
    • "मुझे ज़्यादा चमकीला बैंगनी रंग दिखाओ"
    • "मुझे फ़ॉरेस्ट ग्रीन रंग चाहिए"
    • "मुझे ज़्यादा लाल रंग दिखाओ"
  2. इसके बाद, इतिहास स्ट्रिप में मौजूद कलर वाले किसी थंबनेल पर क्लिक करें

आपको इन बातों का ध्यान रखना चाहिए:

  1. चुना गया रंग मुख्य डिसप्ले में दिखता है
  2. चैट में उपयोगकर्ता का मैसेज दिखता है, जिसमें चुने गए रंग की जानकारी होती है
  3. LLM, चुने गए विकल्प की पुष्टि करके और रंग के बारे में टिप्पणी करके जवाब देता है
  4. पूरा इंटरैक्शन स्वाभाविक और एक जैसा लगता है

इससे उपयोगकर्ता को बेहतर अनुभव मिलता है. एलएलएम, डायरेक्ट मैसेज और यूज़र इंटरफ़ेस (यूआई) इंटरैक्शन, दोनों के बारे में जानता है और उनका सही जवाब देता है.

एलएलएम कॉन्टेक्स्ट सिंक करने की सुविधा कैसे काम करती है

आइए, सिंक करने की प्रोसेस के बारे में तकनीकी जानकारी देखें:

डेटा फ़्लो

  1. उपयोगकर्ता की कार्रवाई: उपयोगकर्ता, इतिहास स्ट्रिप में किसी रंग पर क्लिक करता है
  2. यूज़र इंटरफ़ेस (यूआई) इवेंट: MainScreen विजेट इस विकल्प का पता लगाता है
  3. कॉलबैक लागू करना: notifyColorSelection कॉलबैक ट्रिगर हो जाता है
  4. मैसेज बनाना: कलर डेटा की मदद से, खास फ़ॉर्मैट में मैसेज बनाया जाता है
  5. LLM प्रोसेसिंग: मैसेज को Gemini पर भेजा जाता है, जो फ़ॉर्मैट को पहचानता है
  6. स्थिति के हिसाब से जवाब: Gemini, सिस्टम के प्रॉम्प्ट के आधार पर सही जवाब देता है
  7. यूज़र इंटरफ़ेस (यूआई) में बदलाव: जवाब, चैट में दिखता है. इससे आपको बेहतर अनुभव मिलता है

डेटा को क्रम से लगाना

इस तरीके का एक अहम पहलू यह है कि कलर डेटा को सीरियलाइज़ कैसे किया जाता है:

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

toLLMContextMap() तरीका (colorist_ui पैकेज से दिया गया), ColorData ऑब्जेक्ट को ऐसे मैप में बदल देता है जिसमें ऐसी मुख्य प्रॉपर्टी होती हैं जिन्हें एलएलएम समझ सकता है. आम तौर पर, इसमें ये चीज़ें शामिल होती हैं:

  • आरजीबी वैल्यू (लाल, हरा, नीला)
  • हेक्स कोड का प्रतिनिधित्व
  • रंग से जुड़ा कोई नाम या ब्यौरा

इस डेटा को लगातार फ़ॉर्मैट करके मैसेज में शामिल करने से, यह पक्का किया जा सकता है कि एलएलएम के पास सही जवाब देने के लिए ज़रूरी जानकारी हो.

एलएलएम कॉन्टेक्स्ट सिंक्रोनाइज़ेशन के ज़्यादा बड़े ऐप्लिकेशन

यूज़र इंटरफ़ेस (यूआई) इवेंट के बारे में एलएलएम को सूचना देने के इस पैटर्न का इस्तेमाल, रंग चुनने के अलावा कई कामों के लिए किया जा सकता है:

इस्तेमाल के अन्य उदाहरण

  1. फ़िल्टर में बदलाव: जब उपयोगकर्ता डेटा पर फ़िल्टर लागू करते हैं, तब एलएलएम को सूचना दें
  2. नेविगेशन इवेंट: जब उपयोगकर्ता अलग-अलग सेक्शन पर नेविगेट करते हैं, तब एलएलएम को इसकी जानकारी देना
  3. चुने गए आइटम में बदलाव: जब उपयोगकर्ता सूचियों या ग्रिड से आइटम चुनते हैं, तो एलएलएम को अपडेट करें
  4. प्राथमिकता से जुड़े अपडेट: जब उपयोगकर्ता सेटिंग या प्राथमिकताएं बदलते हैं, तब एलएलएम को बताएं
  5. डेटा में बदलाव करना: जब उपयोगकर्ता डेटा जोड़ते हैं, उसमें बदलाव करते हैं या उसे मिटाते हैं, तब एलएलएम को सूचना दें

हर मामले में, पैटर्न एक जैसा ही रहता है:

  1. यूज़र इंटरफ़ेस (यूआई) इवेंट का पता लगाना
  2. काम के डेटा को सीरियलाइज़ करना
  3. LLM को खास फ़ॉर्मैट में सूचना भेजना
  4. सिस्टम प्रॉम्प्ट की मदद से, एलएलएम को सही जवाब देने के लिए गाइड करना

एलएलएम कॉन्टेक्स्ट सिंक करने के सबसे सही तरीके

एलएलएम कॉन्टेक्स्ट सिंक्रोनाइज़ेशन को असरदार बनाने के लिए, यहां कुछ सबसे सही तरीके दिए गए हैं:

1. एक ही तरह का फ़ॉर्मैट इस्तेमाल करना

सूचनाओं के लिए एक जैसे फ़ॉर्मैट का इस्तेमाल करें, ताकि एलएलएम उन्हें आसानी से पहचान सके:

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

2. रिच कॉन्टेक्स्ट

सूचनाओं में ज़रूरत के मुताबिक जानकारी शामिल करें, ताकि एलएलएम बेहतर जवाब दे सके. रंगों के लिए, इसका मतलब आरजीबी वैल्यू, हेक्स कोड, और काम की अन्य प्रॉपर्टी है.

3. साफ़ तौर पर निर्देश

सिस्टम प्रॉम्प्ट में, सूचनाओं को मैनेज करने के तरीके के बारे में साफ़ तौर पर निर्देश दें. साथ ही, उदाहरण भी दें.

4. नैचुरल इंटिग्रेशन

सूचनाओं को इस तरह डिज़ाइन करें कि वे बातचीत में रुकावट न डालें.

5. चुनिंदा सूचनाएं

एलएलएम को सिर्फ़ उन कार्रवाइयों के बारे में सूचना दें जो बातचीत के लिए काम की हों. हर यूज़र इंटरफ़ेस (यूआई) इवेंट को भेजने की ज़रूरत नहीं होती.

समस्या का हल

सूचना से जुड़ी समस्याएं

अगर LLM, रंग चुनने के लिए सही तरीके से काम नहीं कर रहा है, तो:

  • देखें कि सूचना मैसेज का फ़ॉर्मैट, सिस्टम प्रॉम्प्ट में बताए गए फ़ॉर्मैट से मेल खाता हो
  • पुष्टि करें कि रंग का डेटा सही तरीके से क्रम में लगाया जा रहा है
  • पक्का करें कि सिस्टम प्रॉम्प्ट में, विकल्पों को मैनेज करने के लिए साफ़ निर्देश दिए गए हों
  • सूचनाएं भेजते समय, चैट सेवा में कोई गड़बड़ी न हो

पिछली बातचीत से जुड़ा डेटा मैनेज करना

अगर एलएलएम का कॉन्टेक्स्ट हट जाता है, तो:

  • देखें कि चैट सेशन को सही तरीके से मैनेज किया जा रहा है या नहीं
  • पुष्टि करना कि बातचीत की स्थितियां सही तरीके से ट्रांज़िशन करती हैं
  • पक्का करें कि सूचनाएं उसी चैट सेशन से भेजी जा रही हों

सामान्य समस्याएं

सामान्य समस्याओं के लिए:

  • गड़बड़ियों या चेतावनियों के लिए लॉग की जांच करना
  • Firebase कनेक्शन में Vertex AI की पुष्टि करना
  • फ़ंक्शन पैरामीटर में किसी भी तरह के मैच न होने की जांच करना
  • पक्का करें कि Riverpod से जनरेट किया गया सारा कोड अप-टू-डेट हो

सीखे गए मुख्य कॉन्सेप्ट

  • यूज़र इंटरफ़ेस (यूआई) और एलएलएम के बीच एलएलएम कॉन्टेक्स्ट सिंक करने की सुविधा बनाना
  • यूज़र इंटरफ़ेस (यूआई) इवेंट को एलएलएम के हिसाब से कॉन्टेक्स्ट में सीरियलाइज़ करना
  • अलग-अलग इंटरैक्शन पैटर्न के लिए एलएलएम के व्यवहार को निर्देशित करना
  • मैसेज और मैसेज के अलावा अन्य इंटरैक्शन के लिए एक जैसा अनुभव देना
  • ऐप्लिकेशन की पूरी स्थिति के बारे में LLM की जागरूकता बढ़ाना

एलएलएम के कॉन्टेक्स्ट सिंक्रोनाइज़ेशन को लागू करके, आपने एक ऐसा बेहतरीन अनुभव बनाया है जिसमें एलएलएम, टेक्स्ट जनरेटर के बजाय, एक जागरूक और जवाब देने वाली सहायक की तरह काम करता है. इस पैटर्न को अनगिनत अन्य ऐप्लिकेशन पर लागू किया जा सकता है, ताकि एआई (AI) की मदद से बनाए गए इंटरफ़ेस ज़्यादा सहज और आसान बन सकें.

9. बधाई हो!

आपने कलरिस्ट कोडलैब को पूरा कर लिया है! 🎉

आपने क्या बनाया है

आपने एक ऐसा Flutter ऐप्लिकेशन बनाया है जो पूरी तरह से काम करता है. यह ऐप्लिकेशन, रंगों के बारे में सामान्य भाषा में दी गई जानकारी को समझने के लिए, Google के Gemini API को इंटिग्रेट करता है. आपका ऐप्लिकेशन अब ये काम कर सकता है:

  • "सनसेट ऑरेंज" या "डीप ओशन ब्लू" जैसी सामान्य भाषा में दी गई जानकारी को प्रोसेस करना
  • इन ब्यौरों को आरजीबी वैल्यू में बदलने के लिए, Gemini का इस्तेमाल करना
  • स्ट्रीमिंग के जवाबों के साथ, अनुवाद किए गए रंगों को रीयल-टाइम में दिखाना
  • चैट और यूज़र इंटरफ़ेस (यूआई) एलिमेंट, दोनों के ज़रिए उपयोगकर्ता के इंटरैक्शन को मैनेज करना
  • अलग-अलग इंटरैक्शन के तरीकों के हिसाब से, संदर्भ के हिसाब से जानकारी देना

यहां से कहां जाएं

अब आपने Gemini को Flutter के साथ इंटिग्रेट करने की बुनियादी बातें जान ली हैं. आगे बढ़ने के लिए, यहां कुछ तरीके दिए गए हैं:

Colorist ऐप्लिकेशन को बेहतर बनाना

  • कलर पैलेट: साथ में इस्तेमाल किए जा सकने वाले या मैच करने वाले कलर स्कीम जनरेट करने की सुविधा जोड़ें
  • बोलकर फ़ोन को निर्देश देना: रंगों के बारे में बोलकर जानकारी देने के लिए, बोली पहचानने की सुविधा को इंटिग्रेट करना
  • इतिहास मैनेज करना: कलर सेट को नाम देने, व्यवस्थित करने, और एक्सपोर्ट करने के विकल्प जोड़ना
  • पसंद के मुताबिक प्रॉम्प्ट: उपयोगकर्ताओं के लिए ऐसा इंटरफ़ेस बनाएं जिससे वे सिस्टम प्रॉम्प्ट को पसंद के मुताबिक बना सकें
  • बेहतर आंकड़े: ट्रैक करें कि कौनसे ब्यौरे सबसे अच्छा काम करते हैं या कौनसे ब्यौरे से समस्याएं आती हैं

Gemini की ज़्यादा सुविधाओं के बारे में जानें

  • मल्टीमोडल इनपुट: फ़ोटो से रंग निकालने के लिए, इमेज इनपुट जोड़ें
  • कॉन्टेंट जनरेशन: रंग से जुड़ा कॉन्टेंट जनरेट करने के लिए, Gemini का इस्तेमाल करें. जैसे, जानकारी या कहानियां
  • फ़ंक्शन कॉल करने की सुविधा में सुधार: एक से ज़्यादा फ़ंक्शन के साथ, टूल के ज़्यादा जटिल इंटिग्रेशन बनाएं
  • सुरक्षा सेटिंग: सुरक्षा से जुड़ी अलग-अलग सेटिंग और जवाबों पर उनके असर के बारे में जानें

इन पैटर्न को दूसरे डोमेन पर लागू करना

  • दस्तावेज़ का विश्लेषण: ऐसे ऐप्लिकेशन बनाएं जो दस्तावेज़ों को समझ सकें और उनका विश्लेषण कर सकें
  • क्रिएटिव तरीके से लिखने में मदद करने वाली सुविधा: एलएलएम की मदद से, लिखने के लिए टूल बनाएं
  • टास्क ऑटोमेशन: ऐसे ऐप्लिकेशन डिज़ाइन करना जो नैचुरल लैंग्वेज को ऑटोमेट किए गए टास्क में बदलते हैं
  • नॉलेज-आधारित ऐप्लिकेशन: खास डोमेन में विशेषज्ञ सिस्टम बनाएं

संसाधन

ज़्यादा जानने के लिए, यहां कुछ ज़रूरी संसाधन दिए गए हैं:

आधिकारिक दस्तावेज़

प्रॉम्प्ट करने वाला कोर्स और गाइड

कम्यूनिटी

सुझाव/राय दें या शिकायत करें

हमें यह जानकर खुशी होगी कि इस कोडलैब का इस्तेमाल करने का आपका अनुभव कैसा रहा! कृपया इन तरीकों से सुझाव, शिकायत या राय दें:

इस कोडलैब को पूरा करने के लिए धन्यवाद. हमें उम्मीद है कि आप Flutter और एआई के बीच की दिलचस्प संभावनाओं को एक्सप्लोर करना जारी रखेंगे!