Conversation হলো একটি উচ্চ-স্তরের এপিআই, যা এলএলএম-এর সাথে একটি একক, স্টেটফুল কথোপকথনের প্রতিনিধিত্ব করে এবং এটি অধিকাংশ ব্যবহারকারীর জন্য প্রস্তাবিত প্রবেশপথ। এটি অভ্যন্তরীণভাবে একটি Session পরিচালনা করে এবং জটিল ডেটা প্রক্রিয়াকরণের কাজগুলো সামলায়। এই কাজগুলোর মধ্যে রয়েছে প্রাথমিক কনটেক্সট বজায় রাখা, টুল ডেফিনিশন পরিচালনা করা, মাল্টিমোডাল ডেটার প্রিপ্রসেসিং করা এবং ভূমিকা-ভিত্তিক মেসেজ ফরম্যাটিং সহ জিনজা প্রম্পট টেমপ্লেট প্রয়োগ করা।
কথোপকথন এপিআই কর্মপ্রবাহ
কনভারসেশন এপিআই ব্যবহারের সাধারণ জীবনচক্রটি হলো:
- একটি
Engineতৈরি করুন : মডেল পাথ এবং কনফিগারেশন দিয়ে একটি এককEngineচালু করুন। এটি একটি হেভিওয়েট অবজেক্ট যা মডেলের ওয়েটগুলো ধারণ করে। - একটি
Conversationতৈরি করুন : এক বা একাধিক লাইটওয়েটConversationঅবজেক্ট তৈরি করতেEngineব্যবহার করুন। - বার্তা পাঠান : LLM-এ বার্তা পাঠাতে এবং উত্তর গ্রহণ করতে
Conversationঅবজেক্টের মেথডগুলো ব্যবহার করুন, যা কার্যকরভাবে একটি চ্যাটের মতো মিথস্ক্রিয়া সক্ষম করে।
নিচে মেসেজ পাঠানোর এবং মডেল রেসপন্স পাওয়ার সবচেয়ে সহজ উপায়টি দেওয়া হলো। বেশিরভাগ ক্ষেত্রে ব্যবহারের জন্য এটিই সুপারিশ করা হয়। এটি জেমিনি চ্যাট এপিআই-এর অনুরূপ।
-
SendMessage: একটি ব্লকিং কল যা ব্যবহারকারীর ইনপুট গ্রহণ করে এবং সম্পূর্ণ মডেল প্রতিক্রিয়া ফেরত দেয়। -
SendMessageAsync: একটি নন-ব্লকিং কল যা মডেলের প্রতিক্রিয়া কলব্যাকের মাধ্যমে টোকেন-বাই-টোকেন স্ট্রিম করে ফেরত পাঠায়।
এখানে উদাহরণ কোড স্নিপেট দেওয়া হল:
শুধুমাত্র টেক্সট কন্টেন্ট
#include "runtime/engine/engine.h"
// ...
// 1. Define model assets and engine settings.
auto model_assets = ModelAssets::Create(model_path);
CHECK_OK(model_assets);
auto engine_settings = EngineSettings::CreateDefault(
model_assets,
/*backend=*/litert::lm::Backend::CPU);
// 2. Create the main Engine object.
absl::StatusOr<std::unique_ptr<Engine>> engine = Engine::CreateEngine(engine_settings);
CHECK_OK(engine);
// 3. Create a Conversation
auto conversation_config = ConversationConfig::CreateDefault(**engine);
CHECK_OK(conversation_config)
absl::StatusOr<std::unique_ptr<Conversation>> conversation = Conversation::Create(**engine, *conversation_config);
CHECK_OK(conversation);
// 4. Send message to the LLM with blocking call.
absl::StatusOr<Message> model_message = (*conversation)->SendMessage(
JsonMessage{
{"role", "user"},
{"content", "What is the tallest building in the world?"}
});
CHECK_OK(model_message);
// 5. Print the model message.
std::cout << *model_message << std::endl;
// 6. Send message to the LLM with asynchronous call
// where CreatePrintMessageCallback is a users implemented callback that would
// process the message once a chunk of message output is received.
std::stringstream captured_output;
(*conversation)->SendMessageAsync(
JsonMessage{
{"role", "user"},
{"content", "What is the tallest building in the world?"}
},
CreatePrintMessageCallback(std::stringstream& captured_output)
);
// Wait until asynchronous finish or timeout.
*engine->WaitUntilDone(absl::Seconds(10));
উদাহরণ CreatePrintMessageCallback
absl::AnyInvocable<void(absl::StatusOr<Message>)> CreatePrintMessageCallback(
std::stringstream& captured_output) {
return [&captured_output](absl::StatusOr<Message> message) {
if (!message.ok()) {
std::cout << message.status().message() << std::endl;
return;
}
if (auto json_message = std::get_if<JsonMessage>(&(*message))) {
if (json_message->is_null()) {
std::cout << std::endl << std::flush;
return;
}
ABSL_CHECK_OK(PrintJsonMessage(*json_message, captured_output,
/*streaming=*/true));
}
};
}
absl::Status PrintJsonMessage(const JsonMessage& message,
std::stringstream& captured_output,
bool streaming = false) {
if (message["content"].is_array()) {
for (const auto& content : message["content"]) {
if (content["type"] == "text") {
captured_output << content["text"].get<std::string>();
std::cout << content["text"].get<std::string>();
}
}
if (!streaming) {
captured_output << std::endl << std::flush;
std::cout << std::endl << std::flush;
} else {
captured_output << std::flush;
std::cout << std::flush;
}
} else if (message["content"]["text"].is_string()) {
if (!streaming) {
captured_output << message["content"]["text"].get<std::string>()
<< std::endl
<< std::flush;
std::cout << message["content"]["text"].get<std::string>() << std::endl
<< std::flush;
} else {
captured_output << message["content"]["text"].get<std::string>()
<< std::flush;
std::cout << message["content"]["text"].get<std::string>() << std::flush;
}
} else {
return absl::InvalidArgumentError("Invalid message: " + message.dump());
}
return absl::OkStatus();
}
মাল্টিমোডাল ডেটা বিষয়বস্তু
// To use multimodality, the engine must be created with vision and audio
// backend depending on the multimodality to be used
auto engine_settings = EngineSettings::CreateDefault(
model_assets,
/*backend=*/litert::lm::Backend::CPU,
/*vision_backend*/litert::lm::Backend::GPU,
/*audio_backend*/litert::lm::Backend::CPU,
);
// The same steps to create Engine and Conversation as above...
// Send message to the LLM with image data.
absl::StatusOr<Message> model_message = (*conversation)->SendMessage(
JsonMessage{
{"role", "user"},
{"content", { // Now content must be an array.
{
{"type", "text"}, {"text", "Describe the following image: "}
},
{
{"type", "image"}, {"path", "/file/path/to/image.jpg"}
}
}},
});
CHECK_OK(model_message);
// Print the model message.
std::cout << *model_message << std::endl;
// Send message to the LLM with audio data.
model_message = (*conversation)->SendMessage(
JsonMessage{
{"role", "user"},
{"content", { // Now content must be an array.
{
{"type", "text"}, {"text", "Transcribe the audio: "}
},
{
{"type", "audio"}, {"path", "/file/path/to/audio.wav"}
}
}},
});
CHECK_OK(model_message);
// Print the model message.
std::cout << *model_message << std::endl;
// The content can include multiple image or audio data.
model_message = (*conversation)->SendMessage(
JsonMessage{
{"role", "user"},
{"content", { // Now content must be an array.
{
{"type", "text"}, {"text", "First briefly describe the two images "}
},
{
{"type", "image"}, {"path", "/file/path/to/image1.jpg"}
},
{
{"type", "text"}, {"text", "and "}
},
{
{"type", "image"}, {"path", "/file/path/to/image2.jpg"}
},
{
{"type", "text"}, {"text", " then transcribe the content in the audio"}
},
{
{"type", "audio"}, {"path", "/file/path/to/audio.wav"}
}
}},
});
CHECK_OK(model_message);
// Print the model message.
std::cout << *model_message << std::endl;
টুলসের সাথে কথোপকথন ব্যবহার করুন
কনভারসেশন এপিআই-এর সাথে টুলের বিস্তারিত ব্যবহারের জন্য অ্যাডভান্সড ইউসেজ দেখুন।
কথোপকথনের উপাদানসমূহ
সেশনে ডেটা পাঠানোর আগে, Session পরিচালনা এবং জটিল ডেটা প্রক্রিয়াকরণের জন্য ব্যবহারকারীদের একটি প্রতিনিধি হিসেবে Conversation বিবেচনা করা যেতে পারে।
ইনপুট/আউটপুট প্রকার
কনভারসেশন এপিআই-এর মূল ইনপুট এবং আউটপুট ফরম্যাট হলো Message । বর্তমানে, এটি JsonMessage হিসেবে প্রয়োগ করা হয়েছে, যা ordered_json এর একটি টাইপ অ্যালিয়াস; ordered_json হলো একটি নমনীয় নেস্টেড কী-ভ্যালু ডেটা স্ট্রাকচার।
Conversation এপিআই একটি সাধারণ চ্যাট অভিজ্ঞতার অনুকরণে মেসেজ আদান-প্রদানের ভিত্তিতে কাজ করে। Message -এর এই নমনীয়তা ব্যবহারকারীদের নির্দিষ্ট প্রম্পট টেমপ্লেট বা এলএলএম মডেলের প্রয়োজন অনুযায়ী যেকোনো ফিল্ড অন্তর্ভুক্ত করার সুযোগ দেয়, যা LiteRT-LM-কে বিভিন্ন ধরনের মডেল সমর্থন করতে সক্ষম করে।
যদিও কোনো একক কঠোর মানদণ্ড নেই, বেশিরভাগ প্রম্পট টেমপ্লেট এবং মডেল আশা করে যে Message জেমিনি এপিআই কন্টেন্ট (Gemini API Content) বা ওপেনএআই মেসেজ (OpenAI Message) কাঠামোতে ব্যবহৃত নিয়মাবলীর অনুরূপ নিয়ম অনুসরণ করবে।
Message অবশ্যই role উল্লেখ থাকতে হবে, যা থেকে বোঝা যাবে বার্তাটি কে পাঠিয়েছেন। content একটি সাধারণ টেক্সট স্ট্রিং-এর মতোও হতে পারে।
{
"role": "model", // Represent who the message is sent from.
"content": "Hello World!" // Naive text only content.
}
মাল্টিমোডাল ডেটা ইনপুটের ক্ষেত্রে, content হলো part -এর একটি তালিকা। আবার, part কোনো পূর্বনির্ধারিত ডেটা স্ট্রাকচার নয়, বরং এটি একটি অর্ডারড কী-ভ্যালু পেয়ার ডেটা টাইপ । নির্দিষ্ট ফিল্ডগুলো নির্ভর করে প্রম্পট টেমপ্লেট এবং মডেল কী প্রত্যাশা করে তার উপর।
{
"role": "user",
"content": [ // Multimodal content.
// Now the content is composed of parts
{
"type": "text",
"text": "Describe the image in details: "
},
{
"type": "image",
"path": "/path/to/image.jpg"
}
]
}
মাল্টিমোডাল part জন্য, আমরা নিম্নলিখিত ফরম্যাটটি সমর্থন করি যা data_utils.h দ্বারা পরিচালিত হয়।
{
"type": "text",
"text": "this is a text"
}
{
"type": "image",
"path": "/path/to/image.jpg"
}
{
"type": "image",
"blob": "base64 encoded image bytes as string",
}
{
"type": "audio",
"path": "/path/to/audio.wav"
}
{
"type": "audio",
"blob": "base64 encoded audio bytes as string",
}
প্রম্পট টেমপ্লেট
বিভিন্ন মডেলের জন্য নমনীয়তা বজায় রাখতে, PromptTemplate-কে Minja- এর একটি পাতলা র্যাপার হিসেবে প্রয়োগ করা হয়েছে। Minja হলো Jinja টেমপ্লেট ইঞ্জিনের একটি C++ সংস্করণ, যা JSON ইনপুট প্রক্রিয়াকরণ করে ফরম্যাট করা প্রম্পট তৈরি করে।
জিনজা টেমপ্লেট ইঞ্জিন হলো এলএলএম প্রম্পট টেমপ্লেটের জন্য বহুল ব্যবহৃত একটি ফরম্যাট। নিচে এর কয়েকটি উদাহরণ দেওয়া হলো:
জিনজা টেমপ্লেট ইঞ্জিনের ফরম্যাটটি অবশ্যই ইনস্ট্রাকশন-টিউনড মডেলের প্রত্যাশিত কাঠামোর সাথে হুবহু মিলতে হবে। সাধারণত, মডেলের সঠিক ব্যবহার নিশ্চিত করার জন্য মডেল রিলিজগুলোতে স্ট্যান্ডার্ড জিনজা টেমপ্লেট অন্তর্ভুক্ত থাকে।
মডেলটি যে জিনজা টেমপ্লেট ব্যবহার করে, তা মডেল ফাইলের মেটাডেটা থেকে পাওয়া যাবে।
দ্রষ্টব্য: ভুল ফরম্যাটিংয়ের কারণে প্রম্পটে সামান্য পরিবর্তনও মডেলের উল্লেখযোগ্য অবনতি ঘটাতে পারে। যেমনটি "প্রম্পট ডিজাইনে অপ্রয়োজনীয় বৈশিষ্ট্যের প্রতি ল্যাঙ্গুয়েজ মডেলের সংবেদনশীলতা পরিমাপ করা অথবা: আমি কীভাবে প্রম্পট ফরম্যাটিং নিয়ে চিন্তা করতে শিখলাম" শীর্ষক প্রতিবেদনে উল্লেখ করা হয়েছে।
ভূমিকা
Preface কথোপকথনের প্রাথমিক প্রেক্ষাপট তৈরি করে। এতে প্রাথমিক বার্তা, টুলের সংজ্ঞা এবং আলোচনা শুরু করার জন্য এলএলএম-এর প্রয়োজনীয় অন্য যেকোনো পটভূমিমূলক তথ্য অন্তর্ভুক্ত থাকতে পারে। এর মাধ্যমে Gemini API system instruction এবং Gemini API Tools অনুরূপ কার্যকারিতা সাধিত হয়।
ভূমিকাতে নিম্নলিখিত ক্ষেত্রগুলি রয়েছে
messagesহলো ভূমিকার বার্তা। এই বার্তাগুলো কথোপকথনের প্রাথমিক প্রেক্ষাপট তৈরি করেছে। উদাহরণস্বরূপ, বার্তাগুলো হতে পারে কথোপকথনের ইতিহাস, প্রম্পট ইঞ্জিনিয়ারিং সিস্টেমের নির্দেশাবলী, কয়েকটি খণ্ডচিত্রের উদাহরণ ইত্যাদি।toolsসেই টুলগুলো যা মডেলটি কথোপকথনে ব্যবহার করতে পারে। টুলসগুলোর ফরম্যাটও নির্দিষ্ট নয়, তবে এটি বেশিরভাগ ক্ষেত্রেGemini API FunctionDeclaration) অনুসরণ করে।extra_contextপ্রেক্ষাপট যা মডেলগুলোকে কথোপকথন শুরু করার জন্য প্রয়োজনীয় প্রেক্ষাপট তথ্য কাস্টমাইজ করার প্রসারণযোগ্যতা বজায় রাখে। উদাহরণস্বরূপ,- থিংকিং মোডযুক্ত মডেলগুলির জন্য
enable_thinking, যেমন Qwen3 বা SmolLM3-3B ।
- থিংকিং মোডযুক্ত মডেলগুলির জন্য
প্রাথমিক সিস্টেম নির্দেশনা, টুলস প্রদান এবং থিঙ্কিং মোড নিষ্ক্রিয় করার জন্য একটি উদাহরণমূলক ভূমিকা।
Preface preface = JsonPreface({
.messages = {
{"role", "system"},
{"content", {"You are a model that can do function calling."}}
},
.tools = {
{
{"name", "get_weather"},
{"description", "Returns the weather for a given location."},
{"parameters", {
{"type", "object"},
{"properties", {
{"location", {
{"type", "string"},
{"description", "The location to get the weather for."}
}}
}},
{"required", {"location"}}
}}
},
{
{"name", "get_stock_price"},
{"description", "Returns the stock price for a given stock symbol."},
{"parameters", {
{"type", "object"},
{"properties", {
{"stock_symbol", {
{"type", "string"},
{"description", "The stock symbol to get the price for."}
}}
}},
{"required", {"stock_symbol"}}
}}
}
},
.extra_context = {
{"enable_thinking": false}
}
});
ইতিহাস
কথোপকথনটি সেশনের মধ্যেকার সমস্ত বার্তা আদান-প্রদানের একটি তালিকা সংরক্ষণ করে। এই ইতিহাসটি প্রম্পট টেমপ্লেট রেন্ডারিংয়ের জন্য অত্যন্ত গুরুত্বপূর্ণ, কারণ জিনজা প্রম্পট টেমপ্লেটটি সাধারণত এলএলএম-এর জন্য সঠিক প্রম্পট তৈরি করতে সম্পূর্ণ কথোপকথনের ইতিহাসের প্রয়োজন হয়।
তবে, LiteRT-LM সেশনটি স্টেটফুল, অর্থাৎ এটি ইনপুটগুলোকে পর্যায়ক্রমে প্রসেস করে। এই ব্যবধানটি পূরণ করতে, কনভারসেশন প্রয়োজনীয় ইনক্রিমেন্টাল প্রম্পটটি তৈরি করার জন্য প্রম্পট টেমপ্লেটটিকে দুইবার রেন্ডার করে: একবার পূর্ববর্তী টার্ন পর্যন্ত হিস্ট্রি সহ, এবং আরেকবার বর্তমান মেসেজটি অন্তর্ভুক্ত করে। এই দুটি রেন্ডার করা প্রম্পট তুলনা করে, এটি সেশনে পাঠানোর জন্য নতুন অংশটি বের করে নেয়।
কথোপকথন কনফিগারেশন
একটি Conversation ইনস্ট্যান্স শুরু করার জন্য ConversationConfig ব্যবহার করা হয়। আপনি কয়েকটি উপায়ে এই কনফিগারেশনটি তৈরি করতে পারেন:
-
Engineথেকে: এই পদ্ধতিটি ইঞ্জিনের সাথে যুক্ত ডিফল্টSessionConfigব্যবহার করে। - একটি নির্দিষ্ট
SessionConfigথেকে: এর মাধ্যমে সেশন সেটিংসের উপর আরও সূক্ষ্ম নিয়ন্ত্রণ রাখা যায়।
সেশন সেটিংস ছাড়াও, আপনি ConversationConfig মধ্যে Conversation আচরণ আরও কাস্টমাইজ করতে পারেন। এর মধ্যে রয়েছে:
-
Prefaceপ্রদান। - ডিফল্ট
PromptTemplateওভাররাইট করা হচ্ছে। - ডিফল্ট
DataProcessorConfigওভাররাইট করা হচ্ছে।
এই ওভাররাইটগুলো সূক্ষ্মভাবে টিউন করা মডেলগুলোর জন্য বিশেষভাবে উপযোগী, যেগুলোর জন্য মূল মডেলের চেয়ে ভিন্ন কনফিগারেশন বা প্রম্পট টেমপ্লেটের প্রয়োজন হতে পারে।
মেসেজকলব্যাক
MessageCallback হলো সেই কলব্যাক ফাংশন যা ব্যবহারকারীদের অ্যাসিঙ্ক্রোনাস SendMessageAsync মেথড ব্যবহার করার সময় ইমপ্লিমেন্ট করতে হয়।
কলব্যাক সিগনেচারটি হলো absl::AnyInvocable<void(absl::StatusOr<Message>)> । এই ফাংশনটি নিম্নলিখিত শর্তে ট্রিগার হয়:
- যখন মডেল থেকে
Messageএকটি নতুন অংশ পাওয়া যায়। - LiteRT-LM-এর বার্তা প্রক্রিয়াকরণের সময় যদি কোনো ত্রুটি ঘটে।
- LLM-এর ইনফারেন্স সম্পন্ন হলে, রেসপন্সের সমাপ্তি বোঝাতে একটি খালি
Message(যেমন,JsonMessage()) সহ কলব্যাকটি ট্রিগার করা হয়।
একটি উদাহরণ বাস্তবায়নের জন্য ধাপ ৬-এর অ্যাসিঙ্ক্রোনাস কলটি দেখুন।
দ্রষ্টব্য: কলব্যাক দ্বারা প্রাপ্ত Message মডেলের আউটপুটের শুধুমাত্র সর্বশেষ অংশটি থাকে, সম্পূর্ণ মেসেজ হিস্ট্রি নয়।
উদাহরণস্বরূপ, যদি একটি ব্লকিং SendMessage কল থেকে প্রত্যাশিত সম্পূর্ণ মডেল প্রতিক্রিয়াটি হয়:
{
"role": "model",
"content": [
"type": "text",
"text": "Hello World!"
]
}
SendMessageAsync এর কলব্যাকটি একাধিকবার আহ্বান করা হতে পারে, প্রতিবার পাঠ্যের একটি পরবর্তী অংশ সহ:
// 1st Message
{
"role": "model",
"content": [
"type": "text",
"text": "He"
]
}
// 2nd Message
{
"role": "model",
"content": [
"type": "text",
"text": "llo"
]
}
// 3rd Message
{
"role": "model",
"content": [
"type": "text",
"text": " Wo"
]
}
// 4th Message
{
"role": "model",
"content": [
"type": "text",
"text": "rl"
]
}
// 5th Message
{
"role": "model",
"content": [
"type": "text",
"text": "d!"
]
}
অ্যাসিঙ্ক্রোনাস স্ট্রিম চলাকালীন সম্পূর্ণ প্রতিক্রিয়ার প্রয়োজন হলে, এই খণ্ডগুলো সংগ্রহ করার দায়িত্ব বাস্তবায়নকারীর। বিকল্পভাবে, অ্যাসিঙ্ক্রোনাস কলটি সম্পূর্ণ হয়ে গেলে সম্পূর্ণ প্রতিক্রিয়াটি History শেষ এন্ট্রি হিসেবে পাওয়া যাবে।
উন্নত ব্যবহার {#advanced-usage}
সীমাবদ্ধ ডিকোডিং
LiteRT-LM সীমাবদ্ধ ডিকোডিং সমর্থন করে, যার ফলে আপনি মডেলের আউটপুটে নির্দিষ্ট কাঠামো, যেমন JSON স্কিমা, রেজেক্স প্যাটার্ন বা ব্যাকরণের নিয়ম, প্রয়োগ করতে পারেন।
এটি সক্রিয় করতে, ConversationConfig এ EnableConstrainedDecoding(true) সেট করুন এবং একটি ConstraintProviderConfig প্রদান করুন (যেমন, regex/JSON/grammar সাপোর্টের জন্য LlGuidanceConfig )। তারপর, SendMessage এ OptionalArgs মাধ্যমে কনস্ট্রেইন্টগুলো পাস করুন।
উদাহরণ: রেজেক্স সীমাবদ্ধতা
LlGuidanceConstraintArg constraint_arg;
constraint_arg.constraint_type = LlgConstraintType::kRegex;
constraint_arg.constraint_string = "a+b+"; // Force output to match this regex
auto response = conversation->SendMessage(
user_message,
{.decoding_constraint = constraint_arg}
);
JSON স্কিমা এবং লার্ক গ্রামার সমর্থন সহ সম্পূর্ণ বিবরণের জন্য, কনস্ট্রেইন্ড ডিকোডিং ডকুমেন্টেশন দেখুন।
সরঞ্জাম ব্যবহার
টুল কলিং এলএলএম-কে ক্লায়েন্ট-সাইড ফাংশন সম্পাদনের অনুরোধ করার সুযোগ দেয়। আপনি কথোপকথনের Preface নাম দিয়ে টুলগুলো সংজ্ঞায়িত করেন। যখন মডেল একটি টুল কল আউটপুট করে, আপনি সেটি গ্রহণ করেন, আপনার অ্যাপ্লিকেশনে সংশ্লিষ্ট ফাংশনটি সম্পাদন করেন এবং ফলাফলটি মডেলে ফেরত পাঠান।
উচ্চ-স্তরের প্রবাহ:
- টুল ঘোষণা করুন:
PrefaceJSON-এ টুলগুলো (নাম, বিবরণ, প্যারামিটার) সংজ্ঞায়িত করুন। - কল সনাক্ত করুন: রেসপন্সে
model_message["tool_calls"]চেক করুন। - সম্পাদন করুন: অনুরোধ করা টুলটির জন্য আপনার অ্যাপ্লিকেশন লজিক চালান।
- প্রতিক্রিয়া জানান:
role: "tool"সহ টুলটির আউটপুট সম্বলিত একটি বার্তা মডেলে ফেরত পাঠান।
সম্পূর্ণ বিবরণ এবং একটি পূর্ণাঙ্গ চ্যাট লুপ উদাহরণের জন্য, টুল ব্যবহারের ডকুমেন্টেশন দেখুন।