Gemini API ব্যাচ মোডটি স্ট্যান্ডার্ড খরচের 50% এ অ্যাসিঙ্ক্রোনাসভাবে প্রচুর পরিমাণে অনুরোধ প্রক্রিয়া করার জন্য ডিজাইন করা হয়েছে। টার্গেট টার্নঅ্যারাউন্ড টাইম হল 24 ঘন্টা, কিন্তু বেশিরভাগ ক্ষেত্রেই এটি অনেক দ্রুত।
বৃহৎ আকারের, অ-জরুরী কাজ যেমন ডেটা প্রাক-প্রক্রিয়াকরণ বা চলমান মূল্যায়নের জন্য ব্যাচ মোড ব্যবহার করুন যেখানে তাত্ক্ষণিক প্রতিক্রিয়ার প্রয়োজন হয় না।
একটি ব্যাচ কাজ তৈরি করা
ব্যাচ মোডে আপনার অনুরোধ জমা দেওয়ার দুটি উপায় রয়েছে:
- ইনলাইন অনুরোধ : আপনার ব্যাচ তৈরির অনুরোধে সরাসরি অন্তর্ভুক্ত
GenerateContentRequest
বস্তুর একটি তালিকা। এটি ছোট ব্যাচগুলির জন্য উপযুক্ত যা মোট অনুরোধের আকার 20MB এর নিচে রাখে। মডেল থেকে প্রত্যাবর্তিত আউটপুট হলinlineResponse
অবজেক্টের একটি তালিকা। - ইনপুট ফাইল : একটি JSON লাইনস (JSONL) ফাইল যেখানে প্রতিটি লাইনে একটি সম্পূর্ণ
GenerateContentRequest
অবজেক্ট থাকে। এই পদ্ধতি বড় অনুরোধের জন্য সুপারিশ করা হয়. মডেল থেকে ফিরে আউটপুট একটি JSONL ফাইল যেখানে প্রতিটি লাইন হয় একটিGenerateContentResponse
বা একটি স্থিতি অবজেক্ট।
ইনলাইন অনুরোধ
অল্প সংখ্যক অনুরোধের জন্য, আপনি সরাসরি আপনার BatchGenerateContentRequest
মধ্যে GenerateContentRequest
অবজেক্টগুলি এম্বেড করতে পারেন। নিম্নলিখিত উদাহরণটি ইনলাইন অনুরোধ সহ BatchGenerateContent
পদ্ধতিকে কল করে:
পাইথন
from google import genai
from google.genai import types
client = genai.Client()
# A list of dictionaries, where each is a GenerateContentRequest
inline_requests = [
{
'contents': [{
'parts': [{'text': 'Tell me a one-sentence joke.'}],
'role': 'user'
}]
},
{
'contents': [{
'parts': [{'text': 'Why is the sky blue?'}],
'role': 'user'
}]
}
]
inline_batch_job = client.batches.create(
model="models/gemini-2.5-flash",
src=inline_requests,
config={
'display_name': "inlined-requests-job-1",
},
)
print(f"Created batch job: {inline_batch_job.name}")
বিশ্রাম
curl https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:batchGenerateContent \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-X POST \
-H "Content-Type:application/json" \
-d '{
"batch": {
"display_name": "my-batch-requests",
"input_config": {
"requests": {
"requests": [
{
"request": {"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}]},
"metadata": {
"key": "request-1"
}
},
{
"request": {"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}]},
"metadata": {
"key": "request-2"
}
}
]
}
}
}
}'
ইনপুট ফাইল
অনুরোধের বড় সেটের জন্য, একটি JSON লাইনস (JSONL) ফাইল প্রস্তুত করুন। এই ফাইলের প্রতিটি লাইন অবশ্যই একটি JSON অবজেক্ট হতে হবে যাতে একটি ব্যবহারকারী-সংজ্ঞায়িত কী এবং একটি অনুরোধ অবজেক্ট থাকে, যেখানে অনুরোধটি একটি বৈধ GenerateContentRequest
অবজেক্ট। কোন অনুরোধের ফলাফল কোন আউটপুট তা নির্দেশ করতে প্রতিক্রিয়াতে ব্যবহারকারী-সংজ্ঞায়িত কী ব্যবহার করা হয়। উদাহরণস্বরূপ, request-1
হিসাবে সংজ্ঞায়িত কী সহ অনুরোধটির প্রতিক্রিয়া একই কী নামের সাথে টীকা করা হবে।
এই ফাইলটি ফাইল API ব্যবহার করে আপলোড করা হয়েছে। একটি ইনপুট ফাইলের জন্য সর্বাধিক অনুমোদিত ফাইলের আকার হল 2GB৷
নিম্নলিখিত একটি JSONL ফাইলের একটি উদাহরণ. আপনি my-batch-requests.json
নামে একটি ফাইলে এটি সংরক্ষণ করতে পারেন:
{"key": "request-1", "request": {"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}], "generation_config": {"temperature": 0.7}}}
{"key": "request-2", "request": {"contents": [{"parts": [{"text": "What are the main ingredients in a Margherita pizza?"}]}]}}
একইভাবে ইনলাইন অনুরোধের জন্য, আপনি প্রতিটি অনুরোধ JSON-এ সিস্টেম নির্দেশাবলী, সরঞ্জাম বা অন্যান্য কনফিগারেশনের মতো অন্যান্য প্যারামিটার নির্দিষ্ট করতে পারেন।
নিম্নলিখিত উদাহরণে দেখানো হিসাবে আপনি ফাইল API ব্যবহার করে এই ফাইলটি আপলোড করতে পারেন। আপনি যদি মাল্টিমোডাল ইনপুট নিয়ে কাজ করেন, আপনি আপনার JSONL ফাইলের মধ্যে অন্যান্য আপলোড করা ফাইল উল্লেখ করতে পারেন।
পাইথন
from google import genai
from google.genai import types
client = genai.Client()
# Create a sample JSONL file
with open("my-batch-requests.jsonl", "w") as f:
requests = [
{"key": "request-1", "request": {"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}]}},
{"key": "request-2", "request": {"contents": [{"parts": [{"text": "What are the main ingredients in a Margherita pizza?"}]}]}}
]
for req in requests:
f.write(json.dumps(req) + "\n")
# Upload the file to the File API
uploaded_file = client.files.upload(
file='my-batch-requests.jsonl',
config=types.UploadFileConfig(display_name='my-batch-requests', mime_type='jsonl')
)
print(f"Uploaded file: {uploaded_file.name}")
বিশ্রাম
tmp_batch_input_file=batch_input.tmp
echo -e '{"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}], "generationConfig": {"temperature": 0.7}}\n{"contents": [{"parts": [{"text": "What are the main ingredients in a Margherita pizza?"}]}]}' > batch_input.tmp
MIME_TYPE=$(file -b --mime-type "${tmp_batch_input_file}")
NUM_BYTES=$(wc -c < "${tmp_batch_input_file}")
DISPLAY_NAME=BatchInput
tmp_header_file=upload-header.tmp
# Initial resumable request defining metadata.
# The upload url is in the response headers dump them to a file.
curl "https://generativelanguage.googleapis.com/upload/v1beta/files \
-D "${tmp_header_file}" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "X-Goog-Upload-Protocol: resumable" \
-H "X-Goog-Upload-Command: start" \
-H "X-Goog-Upload-Header-Content-Length: ${NUM_BYTES}" \
-H "X-Goog-Upload-Header-Content-Type: ${MIME_TYPE}" \
-H "Content-Type: application/jsonl" \
-d "{'file': {'display_name': '${DISPLAY_NAME}'}}" 2> /dev/null
upload_url=$(grep -i "x-goog-upload-url: " "${tmp_header_file}" | cut -d" " -f2 | tr -d "\r")
rm "${tmp_header_file}"
# Upload the actual bytes.
curl "${upload_url}" \
-H "Content-Length: ${NUM_BYTES}" \
-H "X-Goog-Upload-Offset: 0" \
-H "X-Goog-Upload-Command: upload, finalize" \
--data-binary "@${tmp_batch_input_file}" 2> /dev/null > file_info.json
file_uri=$(jq ".file.uri" file_info.json)
নিম্নলিখিত উদাহরণটি ফাইল API ব্যবহার করে আপলোড করা ইনপুট ফাইল সহ BatchGenerateContent
পদ্ধতিকে কল করে:
পাইথন
# Assumes `uploaded_file` is the file object from the previous step
file_batch_job = client.batches.create(
model="gemini-2.5-flash",
src=uploaded_file.name,
config={
'display_name': "file-upload-job-1",
},
)
print(f"Created batch job: {file_batch_job.name}")
বিশ্রাম
BATCH_INPUT_FILE='files/123456' # File ID
curl https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:batchGenerateContent \
-X POST \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type:application/json" \
-d "{
'batch': {
'display_name': 'my-batch-requests',
'input_config': {
'requests': {
'file_name': ${BATCH_INPUT_FILE}
}
}
}
}"
আপনি যখন একটি ব্যাচের কাজ তৈরি করবেন, তখন আপনি একটি কাজের নাম ফেরত পাবেন। এই নামটি কাজের স্থিতি নিরীক্ষণের পাশাপাশি কাজ শেষ হওয়ার পরে ফলাফল পুনরুদ্ধার করার জন্য ব্যবহার করুন।
নিম্নলিখিত একটি উদাহরণ আউটপুট যা একটি কাজের নাম ধারণ করে:
Created batch job from file: batches/123456789
কনফিগারেশনের জন্য অনুরোধ করুন
আপনি যেকোন অনুরোধ কনফিগারেশন অন্তর্ভুক্ত করতে পারেন যা আপনি একটি স্ট্যান্ডার্ড নন-ব্যাচ অনুরোধে ব্যবহার করবেন। উদাহরণস্বরূপ, আপনি তাপমাত্রা, সিস্টেম নির্দেশাবলী বা এমনকি অন্যান্য পদ্ধতিতে পাস করতে পারেন। নিম্নলিখিত উদাহরণটি একটি উদাহরণ ইনলাইন অনুরোধ দেখায় যাতে অনুরোধগুলির একটির জন্য একটি সিস্টেম নির্দেশ রয়েছে:
inline_requests_list = [
{'contents': [{'parts': [{'text': 'Write a short poem about a cloud.'}]}]},
{'contents': [{'parts': [{'text': 'Write a short poem about a cat.'}]}], 'system_instructions': {'parts': [{'text': 'You are a cat. Your name is Neko.'}]}}
]
একইভাবে একটি অনুরোধের জন্য ব্যবহার করার জন্য সরঞ্জামগুলি নির্দিষ্ট করতে পারে। নিম্নলিখিত উদাহরণটি একটি অনুরোধ দেখায় যা Google অনুসন্ধান টুলকে সক্ষম করে:
inline_requests_list = [
{'contents': [{'parts': [{'text': 'Who won the euro 1998?'}]}]},
{'contents': [{'parts': [{'text': 'Who won the euro 2025?'}]}], 'tools': [{'google_search ': {}}]}
]
আপনি কাঠামোগত আউটপুটও নির্দিষ্ট করতে পারেন। নিচের উদাহরণটি দেখায় কিভাবে আপনার ব্যাচের অনুরোধের জন্য নির্দিষ্ট করতে হয়।
from google import genai
from pydantic import BaseModel, TypeAdapter
class Recipe(BaseModel):
recipe_name: str
ingredients: list[str]
client = genai.Client()
# A list of dictionaries, where each is a GenerateContentRequest
inline_requests = [
{
'contents': [{
'parts': [{'text': 'List a few popular cookie recipes, and include the amounts of ingredients.'}],
'role': 'user'
}],
'config': {
'response_mime_type': 'application/json',
'response_schema': list[Recipe]
}
},
{
'contents': [{
'parts': [{'text': 'List a few popular gluten free cookie recipes, and include the amounts of ingredients.'}],
'role': 'user'
}],
'config': {
'response_mime_type': 'application/json',
'response_schema': list[Recipe]
}
}
]
inline_batch_job = client.batches.create(
model="models/gemini-2.5-flash",
src=inline_requests,
config={
'display_name': "structured-output-job-1"
},
)
# wait for the job to finish
job_name = inline_batch_job.name
print(f"Polling status for job: {job_name}")
while True:
batch_job_inline = client.batches.get(name=job_name)
if batch_job_inline.state.name in ('JOB_STATE_SUCCEEDED', 'JOB_STATE_FAILED', 'JOB_STATE_CANCELLED', 'JOB_STATE_EXPIRED'):
break
print(f"Job not finished. Current state: {batch_job_inline.state.name}. Waiting 30 seconds...")
time.sleep(30)
print(f"Job finished with state: {batch_job_inline.state.name}")
# print the response
for i, inline_response in enumerate(batch_job_inline.dest.inlined_responses):
print(f"\n--- Response {i+1} ---")
# Check for a successful response
if inline_response.response:
# The .text property is a shortcut to the generated text.
print(inline_response.response.text)
কাজের অবস্থা নিরীক্ষণ
ব্যাচ জব তৈরি করার সময় প্রাপ্ত অপারেশনের নামটি ব্যবহার করুন তার স্থিতি পোল করতে। ব্যাচের চাকরির রাষ্ট্রীয় ক্ষেত্রটি তার বর্তমান অবস্থা নির্দেশ করবে। একটি ব্যাচের কাজ নিম্নলিখিত রাজ্যগুলির একটিতে হতে পারে:
-
JOB_STATE_PENDING
: চাকরিটি তৈরি করা হয়েছে এবং পরিষেবা দ্বারা প্রক্রিয়াকরণের জন্য অপেক্ষা করছে৷ -
JOB_STATE_RUNNING
: কাজ চলছে। -
JOB_STATE_SUCCEEDED
: কাজ সফলভাবে সম্পন্ন হয়েছে৷ আপনি এখন ফলাফল পুনরুদ্ধার করতে পারেন. -
JOB_STATE_FAILED
: চাকরি ব্যর্থ হয়েছে৷ আরো তথ্যের জন্য ত্রুটি বিবরণ চেক করুন. -
JOB_STATE_CANCELLED
: চাকরিটি ব্যবহারকারীর দ্বারা বাতিল করা হয়েছে। -
JOB_STATE_EXPIRED
: চাকরির মেয়াদ শেষ হয়ে গেছে কারণ এটি 48 ঘণ্টারও বেশি সময় ধরে চলছিল বা মুলতুবি ছিল। কাজ পুনরুদ্ধার করার জন্য কোন ফলাফল হবে না. আপনি আবার কাজ জমা দেওয়ার চেষ্টা করতে পারেন বা অনুরোধগুলিকে ছোট ব্যাচে বিভক্ত করতে পারেন।
আপনি কাজ শেষ হয়েছে কিনা তা যাচাই করতে পর্যায়ক্রমে পোল করতে পারেন।
পাইথন
# Use the name of the job you want to check
# e.g., inline_batch_job.name from the previous step
job_name = "YOUR_BATCH_JOB_NAME" # (e.g. 'batches/your-batch-id')
batch_job = client.batches.get(name=job_name)
completed_states = set([
'JOB_STATE_SUCCEEDED',
'JOB_STATE_FAILED',
'JOB_STATE_CANCELLED',
'JOB_STATE_EXPIRED',
])
print(f"Polling status for job: {job_name}")
batch_job = client.batches.get(name=job_name) # Initial get
while batch_job.state.name not in completed_states:
print(f"Current state: {batch_job.state.name}")
time.sleep(30) # Wait for 30 seconds before polling again
batch_job = client.batches.get(name=job_name)
print(f"Job finished with state: {batch_job.state.name}")
if batch_job.state.name == 'JOB_STATE_FAILED':
print(f"Error: {batch_job.error}")
ফলাফল পুনরুদ্ধার করা হচ্ছে
একবার চাকরির অবস্থা নির্দেশ করে যে আপনার ব্যাচের কাজ সফল হয়েছে, ফলাফলগুলি response
ক্ষেত্রে পাওয়া যায়।
পাইথন
import json
# Use the name of the job you want to check
# e.g., inline_batch_job.name from the previous step
job_name = "YOUR_BATCH_JOB_NAME"
batch_job = client.batches.get(name=job_name)
if batch_job.state.name == 'JOB_STATE_SUCCEEDED':
# If batch job was created with a file
if batch_job.dest and batch_job.dest.file_name:
# Results are in a file
result_file_name = batch_job.dest.file_name
print(f"Results are in file: {result_file_name}")
print("Downloading result file content...")
file_content = client.files.download(file=result_file_name)
# Process file_content (bytes) as needed
print(file_content.decode('utf-8'))
# If batch job was created with inline request
elif batch_job.dest and batch_job.dest.inlined_responses:
# Results are inline
print("Results are inline:")
for i, inline_response in enumerate(batch_job.dest.inlined_responses):
print(f"Response {i+1}:")
if inline_response.response:
# Accessing response, structure may vary.
try:
print(inline_response.response.text)
except AttributeError:
print(inline_response.response) # Fallback
elif inline_response.error:
print(f"Error: {inline_response.error}")
else:
print("No results found (neither file nor inline).")
else:
print(f"Job did not succeed. Final state: {batch_job.state.name}")
if batch_job.error:
print(f"Error: {batch_job.error}")
বিশ্রাম
BATCH_NAME="batches/123456" # Your batch job name
curl https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type:application/json" 2> /dev/null > batch_status.json
if jq -r '.done' batch_status.json | grep -q "false"; then
echo "Batch has not finished processing"
fi
batch_state=$(jq -r '.metadata.state' batch_status.json)
if [[ $batch_state = "JOB_STATE_SUCCEEDED" ]]; then
if [[ $(jq '.response | has("inlinedResponses")' batch_status.json) = "true" ]]; then
jq -r '.response.inlinedResponses' batch_status.json
exit
fi
responses_file_name=$(jq -r '.response.responsesFile' batch_status.json)
curl https://generativelanguage.googleapis.com/download/v1beta/$responses_file_name:download?alt=media \
-H "x-goog-api-key: $GEMINI_API_KEY" 2> /dev/null
elif [[ $batch_state = "JOB_STATE_FAILED" ]]; then
jq '.error' batch_status.json
elif [[ $batch_state == "JOB_STATE_CANCELLED" ]]; then
echo "Batch was cancelled by the user"
elif [[ $batch_state == "JOB_STATE_EXPIRED" ]]; then
echo "Batch expired after 48 hours"
fi
একটি ব্যাচের চাকরি বাতিল করা হচ্ছে
আপনি এটির নাম ব্যবহার করে একটি চলমান ব্যাচের কাজ বাতিল করতে পারেন। যখন একটি কাজ বাতিল করা হয়, এটি নতুন অনুরোধ প্রক্রিয়াকরণ বন্ধ করে দেয়।
পাইথন
# Cancel a batch job
client.batches.cancel(name=batch_job_to_cancel.name)
বিশ্রাম
BATCH_NAME="batches/123456" # Your batch job name
# Cancel the batch
curl https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME:cancel \
-H "x-goog-api-key: $GEMINI_API_KEY" \
# Confirm that the status of the batch after cancellation is JOB_STATE_CANCELLED
curl https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type:application/json" 2> /dev/null | jq -r '.metadata.state'
একটি ব্যাচ কাজ মুছে ফেলা হচ্ছে
আপনি এর নাম ব্যবহার করে একটি বিদ্যমান ব্যাচ কাজ মুছে ফেলতে পারেন। যখন একটি কাজ মুছে ফেলা হয়, এটি নতুন অনুরোধ প্রক্রিয়াকরণ বন্ধ করে দেয় এবং ব্যাচ কাজের তালিকা থেকে সরানো হয়।
পাইথন
# Delete a batch job
client.batches.delete(name=batch_job_to_delete.name)
বিশ্রাম
BATCH_NAME="batches/123456" # Your batch job name
# Delete the batch job
curl https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME:delete \
-H "x-goog-api-key: $GEMINI_API_KEY"
প্রযুক্তিগত বিবরণ
- সমর্থিত মডেল: ব্যাচ মোড জেমিনি মডেলের একটি পরিসর সমর্থন করে। ব্যাচ মোডের প্রতিটি মডেলের সমর্থনের জন্য মডেল পৃষ্ঠাটি পড়ুন। ব্যাচ মোডের জন্য সমর্থিত পদ্ধতিগুলি ইন্টারেক্টিভ (বা নন-ব্যাচ মোড) API-এ সমর্থিত হিসাবে একই।
- মূল্য নির্ধারণ: সমতুল্য মডেলের জন্য ব্যাচ মোড ব্যবহারের মান ইন্টারেক্টিভ API খরচের 50% মূল্য নির্ধারণ করা হয়েছে। বিস্তারিত জানার জন্য মূল্য পৃষ্ঠা দেখুন. এই বৈশিষ্ট্যের জন্য হারের সীমা সম্পর্কে বিশদ বিবরণের জন্য রেট সীমা পৃষ্ঠাটি পড়ুন।
- পরিষেবা স্তরের উদ্দেশ্য (SLO): ব্যাচের কাজগুলি 24-ঘন্টার টার্নঅ্যারাউন্ড সময়ের মধ্যে সম্পূর্ণ করার জন্য ডিজাইন করা হয়েছে। অনেক কাজ তাদের আকার এবং বর্তমান সিস্টেম লোডের উপর নির্ভর করে অনেক দ্রুত সম্পন্ন হতে পারে।
- ক্যাশিং: ব্যাচ অনুরোধের জন্য প্রসঙ্গ ক্যাশিং সক্ষম করা হয়েছে। যদি আপনার ব্যাচের একটি অনুরোধের ফলে ক্যাশে হিট হয়, ক্যাশে করা টোকেনগুলির দাম নন-ব্যাচ মোড ট্র্যাফিকের মতোই।
সর্বোত্তম অনুশীলন
- বড় অনুরোধের জন্য ইনপুট ফাইল ব্যবহার করুন: প্রচুর সংখ্যক অনুরোধের জন্য, সর্বদা ভাল ব্যবস্থাপনার জন্য ফাইল ইনপুট পদ্ধতি ব্যবহার করুন এবং
BatchGenerateContent
কলের জন্য অনুরোধের আকারের সীমা এড়াতে। মনে রাখবেন যে প্রতি ইনপুট ফাইলের জন্য 2GB ফাইলের আকারের সীমা রয়েছে৷ - ত্রুটি হ্যান্ডলিং: একটি কাজ শেষ হওয়ার পরে
failedRequestCount
জন্যbatchStats
পরীক্ষা করুন। ফাইল আউটপুট ব্যবহার করলে, এটি একটিGenerateContentResponse
বা সেই নির্দিষ্ট অনুরোধের জন্য একটি ত্রুটি নির্দেশ করে এমন একটি স্ট্যাটাস অবজেক্ট কিনা তা পরীক্ষা করতে প্রতিটি লাইন পার্স করুন। ত্রুটি কোডের সম্পূর্ণ সেটের জন্য সমস্যা সমাধানের নির্দেশিকা দেখুন। - একবার চাকরি জমা দিন: একটি ব্যাচের চাকরি তৈরি করা অসাধ্য নয়। আপনি যদি একই সৃষ্টির অনুরোধ দুইবার পাঠান, দুটি পৃথক ব্যাচের কাজ তৈরি হবে।
- খুব বড় ব্যাচগুলি ভেঙে দিন: যদিও টার্গেট টার্নআরাউন্ড সময় 24 ঘন্টা, প্রকৃত প্রক্রিয়াকরণের সময় সিস্টেম লোড এবং কাজের আকারের উপর ভিত্তি করে পরিবর্তিত হতে পারে। বড় চাকরির জন্য, যদি মধ্যবর্তী ফলাফল শীঘ্রই প্রয়োজন হয় তবে সেগুলিকে ছোট ব্যাচে বিভক্ত করার কথা বিবেচনা করুন।
এরপর কি
আরও উদাহরণের জন্য ব্যাচ মোড নোটবুক দেখুন।