স্ট্রাকচার্ড আউটপুট জেনারেট করুন

আরও প্রসেস করার জন্য, Gemini Nano থেকে পাওয়া উত্তর JSON-এর মতো নির্দিষ্ট ফর্ম্যাটে পার্স করতে হলে, সরাসরি মডেল অ্যাক্সেস সহ Structured Output API ব্যবহার করুন।

Structured Output API-এর মাধ্যমে, আপনি Kotlin ক্লাস এবং অ্যানোটেশন ব্যবহার করে টার্গেট আউটপুট স্ট্রাকচার সংজ্ঞায়িত করেন। ডাইরেক্ট মডেল অ্যাক্সেস তারপর আপনার Kotlin অবজেক্টের ফর্মে একটি উত্তর ফেরত দেয়।

স্ট্রাকচার্ড আউটপুট তৈরি করা বিশেষ করে নিম্নলিখিত টাস্কের ক্ষেত্রে উপযোগী:

  • এন্টিটি এক্সট্র্যাকশন: স্ট্রাকচার্ড নয় এমন টেক্সট থেকে স্ট্রাকচার্ড ফিল্ড (যেমন, ইভেন্টের নাম, তারিখ, লোকেশন) এক্সট্র্যাক্ট করা।
  • শ্রেণীবিভাগ: ইনপুট টেক্সটকে পূর্বনির্ধারিত বিভাগে ভাগ করা।
  • ডেটা সিরিয়ালাইজেশন: ব্যবহারকারীর অসংগঠিত ইনপুটকে ডেটাবেস স্টোরেজ বা API কলের জন্য উপযুক্ত ফর্ম্যাটে পরিবর্তন করা।

পূর্বশর্ত

ডিভাইসে Structured Output API উপলভ্য কিনা তা যাচাই করতে, isStructuredOutputFeatureAvailable() API ব্যবহার করুন। ডিভাইসে Structured Output API উপলভ্য থাকলে API true রিটার্ন করে, অন্যথায় false রিটার্ন করে।

suspend fun isStructuredOutputFeatureAvailable(): Boolean

এছাড়াও, Structured Output API-এর নিম্নলিখিত প্রয়োজনীয়তা আছে:

  • Android API লেভেল ২৬ বা তার পরবর্তী ভার্সন (minSdk ২৬)
  • KSP প্লাগ-ইন ভার্সন 2.3.6 বা তার পরের যেকোনও ভার্সন

সীমাবদ্ধতা

স্ট্রাকচার্ড আউটপুট API-এর নিম্নলিখিত সীমাবদ্ধতা রয়েছে:

  • শুধুমাত্র Kotlin-এ কাজ করে।
  • ProGuard আপনার অ্যানোটেট করা ক্লাস পার্স করার সময় বাধা সৃষ্টি করতে পারে। পার্সিং করার সময় সমস্যা হলে, ProGuard থেকে বাদ দিতে আপনার নিয়ম রাখুন বিকল্পে অ্যানোটেট করা ক্লাস যোগ করুন, যেমন:
# Keep classes used by structured output for deserialization for release builds.
-keep class com.google.mlkit.genai.demo.kotlin.Plant { *; }

প্রোজেক্ট কনফিগার করুন

Structured Output API ব্যবহার শুরু করতে, এই ধাপগুলি অনুসরণ করুন:

  1. আপনি আগে থেকে না করে থাকলে, অ্যাপ-লেভেল build.gradle.kts (বা build.gradle) ফাইলে com.google.mlkit:genai-prompt ডিপেন্ডেন্সি যোগ করুন।

  2. আপনার প্রোজেক্ট-লেভেল build.gradle.kts ফাইলে KSP প্লাগ-ইন যোগ করুন। আপনার Kotlin ভার্সনের সাথে মানানসই KSP প্লাগ-ইন ভার্সন ব্যবহার করুন; আমরা KSP ভার্সন 2.3.6 বা তার পরবর্তী যেকোনও ভার্সন ব্যবহার করার সাজেশন দিই।

    dependencies {
        ...
        classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:2.3.6"
    }
    
  3. আপনার অ্যাপ-লেভেল build.gradle.kts ফাইলে স্ট্রাকচার্ড কম্পাইলার ডিপেন্ডেন্সি যোগ করুন:

    dependencies {
        ...
        ksp("com.google.mlkit:genai-schema-compiler:1.0.0-alpha1")
    }
    

আউটপুট স্ট্রাকচার নির্দিষ্ট করুন

Kotlin ডেটা ক্লাস ব্যবহার করে আপনি মডেল থেকে যে ডেটা ফেরত পেতে চান তার স্ট্রাকচার নির্ধারণ করুন। আউটপুট স্ট্রাকচার নির্ধারণ করার জন্য দুটি প্রধান অ্যানোটেশন রয়েছে:

  • স্ট্রাকচার্ড আউটপুটের জন্য ক্লাসকে টার্গেট হিসেবে সংজ্ঞায়িত করতে @Generable অ্যানোটেশন ব্যবহার করুন।
  • মডেলের আউটপুটকে গাইড করে এমন বিবরণ এবং সীমাবদ্ধতা প্রদান করতে ক্লাস প্রপার্টিতে @Guide অ্যানোটেশন ব্যবহার করুন।

উদ্ভিদ সংক্রান্ত তথ্য এক্সট্র্যাক্ট করার জন্য নিম্নলিখিত উদাহরণে একটি স্ট্রাকচার সংজ্ঞায়িত করা হয়েছে:

import com.google.mlkit.genai.schema.annotations.Generable
import com.google.mlkit.genai.schema.annotations.Guide

@Generable
data class PlantList(
    @Guide(description = "The list of plants found", minItems = 1, maxItems = 5)
    val plants: List<Plant>
)

@Generable("Information about a plant species")
data class Plant(
    @Guide(description = "The common name of the plant")
    val commonName: String,
    
    @Guide(description = "The full latin scientific name of the plant")
    val scientificName: String,
    
    @Guide(
        description = "The maximum height of the plant in centimeters.",
        minimum = 1.0,
        maximum = 10000.0
    )
    val maxHeightCm: Int,
    
    @Guide(description = "Whether the plant is poisonous or not")
    val isPoisonous: Boolean?,
    
    @Guide(
        description = "The primary continent where this plant is native to",
        enumValues = ["Africa", "Antarctica", "Asia", "Australia", "Europe", "North America", "South America"]
    )
    val nativeContinent: String
)

যেসব ধরন ও সীমাবদ্ধতা কাজ করে

@Generable অ্যানোটেটেড ক্লাসের মধ্যে নিম্নলিখিত ধরনগুলি কাজ করে, এর সাথে সংশ্লিষ্ট @Guide কনস্ট্রেন্টও কাজ করে:

ধরন বিবরণ সমর্থিত @Guide সীমাবদ্ধতা
String টেক্সটের জন্য। description, enumValues
Double / Float ফ্লোটিং-পয়েন্ট সংখ্যার জন্য। description, minimum, maximum
Int / Long পূর্ণ সংখ্যার জন্য। description, minimum, maximum
Boolean সত্য/মিথ্যা ভ্যালুর জন্য। description
List<T> কাজ করে এমন ধরনের তালিকা বা নেস্টেড @Generable ক্লাসের জন্য। description, minItems, maxItems
List<String> Stringটি ভ্যালুর তালিকার জন্য। description, enumValues, minItems, maxItems
@Generable ক্লাস নেস্টেড স্ট্রাকচার্ড অবজেক্টের জন্য। description

স্ট্রাকচার্ড কন্টেন্ট জেনারেট করুন

স্ট্রাকচার্ড আউটপুটের অনুরোধ করতে, আপনার স্ট্যান্ডার্ড প্রম্পট র‍্যাপ করতে এবং টার্গেট আউটপুট ক্লাস নির্দিষ্ট করতে generateTypedContentRequest হেল্পার ফাংশন ব্যবহার করুন।

// 1. Initialize your GenerativeModel as usual
val generativeModel = Generation.getClient()

// 2. Prepare the prompt text
val promptText = "List some common plants found in California."
val baseRequest = GenerateContentRequest.Builder(TextPart(promptText)).build()

// 3. Create the typed request, specifying the target class (e.g., PlantList)
val typedRequest = generateTypedContentRequest(
    generateContentRequest = baseRequest,
    outputClass = PlantList::class
)

// 4. Run the inference
try {
    val typedResponse = generativeModel.generateContent(typedRequest)
    
    // 5. Access the parsed object
    // The response candidates contain the parsed object of type T (PlantList in this case)
    val plantList: PlantList? = typedResponse.candidates.firstOrNull()?.response
    
    if (plantList != null) {
        // Process the structured data
        for (plant in plantList.plants) {
            Log.d("StructuredOutput", "Found plant: ${plant.commonName} (${plant.scientificName})")
        }
    } else {
        Log.e("StructuredOutput", "Failed to parse response into the desired structure.")
        
        // Inspect finish reason for details
        val finishReason = typedResponse.candidates.firstOrNull()?.finishReason
        Log.d("StructuredOutput", "Finish reason: $finishReason")
    }
} catch (e: GenAiException) {
    // Handle API errors
    when (e.errorCode) {
        GenAiException.STRUCTURED_OUTPUT_INVALID_CLASS -> {
            Log.e("StructuredOutput", "The class structure is not supported.")
        }
        GenAiException.STRUCTURED_OUTPUT_INVALID_VALUE -> {
            Log.e("StructuredOutput", "The model generated values that violate the schema constraints.")
        }
        else -> {
            Log.e("StructuredOutput", "API error: ${e.message}")
        }
    }
}

শেষ হওয়ার কারণ ও সমস্যা ম্যানেজ করা

Structured Output API ব্যবহার করার সময়, API-এর মাধ্যমে সম্ভাব্য ব্যতিক্রমগুলি আপনাকে ম্যানেজ করতে হবে এবং পার্স করা উত্তর ফাঁকা থাকলে, উত্তর ক্যান্ডিডেটে finishReason প্রপার্টি চেক করতে হবে।

finishReason ভ্যালু

finishReason প্রপার্টিতে নিম্নলিখিত মানগুলির মধ্যে যেকোনও একটি থাকতে পারে:

  • TypedFinishReason.STOP: মডেলটি সফলভাবে জেনারেট করা শেষ করেছে এবং আউটপুট স্কিমার সাথে মিলে গেছে।
  • TypedFinishReason.MAX_TOKENS: মডেলটি বন্ধ হয়ে গেছে কারণ এটি টোকেন সীমায় পৌঁছে গেছে। আউটপুট অসম্পূর্ণ হতে পারে।
  • TypedFinishReason.PARSE_CLASS_ERROR: মডেলটি জেনারেশন সম্পূর্ণ করেছে, কিন্তু ফলাফল JSON টার্গেট Kotlin ক্লাসে পার্স করা যায়নি।
  • TypedFinishReason.STRUCTURE_NOT_ANNOTATED: টার্গেট ক্লাস বা তার নেস্টেড ক্লাসে প্রয়োজনীয় @Generable অ্যানোটেশন নেই।
  • TypedFinishReason.STRUCTURE_VALUES_INVALID: জেনারেট করা ভ্যালু @Guide অ্যানোটেশনে সংজ্ঞায়িত সীমাবদ্ধতা লঙ্ঘন করেছে (যেমন, ভ্যালু রেঞ্জের বাইরে, তালিকার সাইজ সীমার বাইরে)।
  • TypedFinishReason.OTHER: অন্য কারণে জেনারেশন বন্ধ করা হয়েছে।

ব্যতিক্রম

স্ট্রাকচার্ড আউটপুট API নিম্নলিখিত ত্রুটি কোড সহ GenAiException দেখাতে পারে:

  • GenAiException.STRUCTURED_OUTPUT_INVALID_CLASS (-104): অ্যানোটেট করা ক্লাসের গঠন সঠিক নয় অথবা এতে কাজ করে না এমন ধরন রয়েছে। এটি সাধারণত ডেভেলপমেন্ট-টাইম কনফিগারেশন সংক্রান্ত সমস্যা। আপনার @Generable ডেটা ক্লাস ডেফিনিশন পর্যালোচনা করে দেখুন যে সব প্রপার্টি টাইপ কাজ করছে কিনা এবং কোনও সার্কুলার ডিপেন্ডেন্সি নেই কিনা।
  • GenAiException.STRUCTURED_OUTPUT_INVALID_VALUE (-105): মডেলের মাধ্যমে জেনারেট করা ভ্যালু সঠিক নয় অথবা কনস্ট্রেন্ট যাচাইকরণে ব্যর্থ হয়েছে। এটি একটি রানটাইম সমস্যা। আপনি যদি প্রায়ই এই সমস্যার সম্মুখীন হন, তাহলে নিম্নলিখিত সমাধানগুলি বিবেচনা করুন:
    • মডেলকে আরও কঠোরভাবে নির্দেশ দিতে আপনার প্রম্পট নির্দেশাবলী রিফাইন করা হচ্ছে।
    • আপনার @Guide অ্যানোটেশনে সীমাবদ্ধতা (যেমন সর্বনিম্ন, সর্বোচ্চ বা তালিকার সাইজের সীমা) শিথিল করা, যদি সেগুলি মডেলের ক্ষমতার জন্য খুব বেশি সীমাবদ্ধ হয়।
    • আপনার অ্যাপে ফলব্যাক স্ট্র্যাটেজি প্রয়োগ করা, যেমন অনুরোধ আবার করা বা ডিফল্ট স্ট্যাটাস দেখানো।

টোকেন গণনা করুন

আপনার স্ট্রাকচার্ড প্রম্পট ইনপুট টোকেন সীমার মধ্যে আছে কিনা তা চেক করতে, countTokens() পদ্ধতি ব্যবহার করে টোকেন কাউন্ট হিসাব করুন।

যেহেতু স্ট্রাকচার্ড আউটপুট সংক্রান্ত অনুরোধের ক্ষেত্রে মডেলকে স্কিমা স্ট্রাকচার সম্পর্কে নির্দেশ দিতে হয়, তাই শুধু র প্রম্পট টেক্সটে (GenerateContentRequest ইনস্ট্যান্স ব্যবহার করে) টোকেন গণনা করা সঠিক নয়। সঠিক টোকেন কাউন্ট পেতে, আপনাকে সম্পূর্ণ GenerateTypedContentRequest ইনস্ট্যান্স পাস করতে হবে, যার মধ্যে আপনার টার্গেট ক্লাস ও স্কিমা কনফিগারেশন অন্তর্ভুক্ত থাকে, countTokens() পদ্ধতিতে:

suspend fun <T : Any> countTokens(request: GenerateTypedContentRequest<T>): CountTokensResponse