Google Chat API ব্যবহার করে মেসেজ স্ট্রিম করুন

Chat API-তে StreamMessage রিসোর্স ব্যবহার করে Google Chat-এ কীভাবে ইনক্রিমেন্টাল মেসেজ স্ট্রিম করতে হয় তা এই গাইডে ব্যাখ্যা করা হয়েছে। স্ট্রিমিংয়ের মাধ্যমে আপনার Google Chat অ্যাপ লাইভ প্রগ্রেস ইন্ডিকেটর, ইন্টারমিডিয়েট রিজনিং বা টুল-এক্সিকিউশন স্টেপ এবং মেসেজ চূড়ান্ত করার আগে ইনক্রিমেন্টাল টেক্সট রেসপন্স দেখাতে পারে।

স্ট্রিমিং এমন চ্যাট অ্যাপের জন্য ডিজাইন করা হয়েছে যা জেনারেটিভ AI বা দীর্ঘ সময় ধরে চলা ব্যাকএন্ড ওয়ার্কফ্লো দ্বারা পরিচালিত হয় যেখানে সম্পূর্ণ উত্তর তৈরি করতে কয়েক সেকেন্ড বা মিনিট সময় লাগে।

মেসেজ স্ট্রিমিং কীভাবে কাজ করে

একটি স্ট্রিমিং মেসেজ, স্পেসে স্ট্যান্ডার্ড Message রিসোর্স হওয়ার আগে, অ্যাক্টিভ স্ট্রিমিং স্টেট হিসেবে প্রোগ্রেস করে:

  1. স্ট্রিম শুরু করুন (spaces.streamMessages.create): আপনার Chat অ্যাপ থ্রেড করা স্পেসে একটি StreamMessage তৈরি করে, যে ব্যবহারকারীর ইন্টার‍্যাকশন মেসেজের উত্তর দেওয়া হচ্ছে সেটির রেফারেন্স দেয়। API থ্রেডে একটি লাইভ প্রগ্রেস ইন্ডিকেটর দেখায় এবং একটি StreamMessage রিসোর্স নাম এবং একটি প্রাথমিক nextChunkToken রিটার্ন করে।
  2. স্ট্রিম আপডেট করুন (appendStreamMessageContent বা patch): আপনার Chat অ্যাপ আউটপুট জেনারেট করার সাথে সাথে, এটি লেটেস্ট nextChunkToken ব্যবহার করে ধারাবাহিক আপডেট পাঠায়:
    • নতুন টেক্সট চাঙ্ক কনক্যাটিনেট করতে, মধ্যবর্তী ধাপ যোগ করতে, ইনলাইন উদ্ধৃতি যোগ করতে অথবা progressText আপডেট করতে spaces.streamMessages.appendStreamMessageContent কল করুন।
    • স্ট্রিম করা কন্টেন্ট চাঙ্ক পরিবর্তন করতে spaces.streamMessages.patch কল করুন অথবা progressText আপডেট করুন।
  3. স্ট্রিম চূড়ান্ত বা বাতিল করা (commit বা delete):
    • স্ট্রিম চূড়ান্ত করতে spaces.streamMessages.commit কল করুন এবং এটি স্থায়ী Message রিসোর্সে পরিবর্তন করুন। এছাড়াও, আপনি কমিট করার সময় কার্ড, অ্যাক্সেসরি উইজেট ও ফুটার সোর্সের মতো শুধু-কমিট এলিমেন্ট অ্যাটাচ করতে পারেন।
    • স্পেসে মেসেজ সেভ না করে অ্যাক্টিভ স্ট্রিম বাতিল করতে spaces.streamMessages.delete কল করুন।

স্ট্রিম অ্যাক্টিভ থাকাকালীন, শুধুমাত্র রেফারেন্স করা মেসেজের প্রেরক (referencedMessage) যেটিতে স্ট্রিম করা হচ্ছে, তিনি জেনারেশন বাতিল করতে বন্ধ করুন বিকল্পে ক্লিক করতে পারবেন। Chat আপনার Chat অ্যাপে একটি বাতিলকরণ সিস্টেম কমান্ড ইভেন্ট পাঠায় যাতে আপনি ব্যাকএন্ড কাজ বন্ধ করতে পারেন এবং আংশিক আউটপুট কমিট করতে পারেন অথবা স্ট্রিম মুছে ফেলতে পারেন।

পূর্বশর্ত

Chat API-এর মাধ্যমে মেসেজ স্ট্রিম করতে, নিম্নলিখিত পূর্বপ্রয়োজনীয়তা সম্পূর্ণ করুন:

  • Google Chat-এ অ্যাক্সেস সহ Business বা Enterprise Google Workspace অ্যাকাউন্ট।
  • আপনার পরিবেশ সেট-আপ করুন:
  • আপনার Chat অ্যাপকে থ্রেডেড Chat স্পেসে (অথবা ১:১ সরাসরি মেসেজ যাতে আগে থেকেই অন্তত একটি মেসেজ আছে) যোগ করুন এবং উত্তর দেওয়ার জন্য (spaces/SPACE_ID/messages/MESSAGE_ID) অ্যাক্সেসযোগ্য মেসেজের রিসোর্স নাম পান।
  • Python স্যাম্পেলের জন্য, Python-এর জন্য Google API ক্লায়েন্ট লাইব্রেরি ইনস্টল করুন এবং google-auth, এবং Chat API পরিষেবা ক্লায়েন্ট শুরু করুন:

    pip install google-api-python-client google-auth
    from google.oauth2 import service_account
    from googleapiclient.discovery import build
    
    SCOPES = ["https://www.googleapis.com/auth/chat.bot"]
    creds = service_account.Credentials.from_service_account_file(
        "credentials.json", scopes=SCOPES
    )
    chat = build("chat", "v1", credentials=creds)
    

স্ট্রিম শুরু করুন

উত্তর স্ট্রিম করা শুরু করতে, spaces.streamMessages.create কল করুন এবং অনুরোধের বডিতে একটি StreamMessage পাস করুন:

  • referencedMessage (প্রয়োজনীয়): যে মেসেজ উত্তর ট্রিগার করেছে সেটির রিসোর্সের নাম, spaces/{space}/messages/{message} হিসেবে ফর্ম্যাট করা। রেফারেন্স করা মেসেজটি অবশ্যই একই স্পেসের হতে হবে এবং আপনার Chat অ্যাপের অ্যাক্সেস থাকতে হবে। Chat, referencedMessage-এর মতো একই থ্রেডে স্ট্রিম করা উত্তর পোস্ট করে।
  • progressText (প্রয়োজনীয়): প্রোগ্রেস ইন্ডিকেটরের পাশে দেখানো খালি নয় এমন প্লেন-টেক্সট স্ট্যাটাস লেবেল (সর্বাধিক ২৫০টি অক্ষর), যেমন "Thinking..."।
  • markupSyntax (ঐচ্ছিক): মেসেজের জন্য টেক্সট ফর্ম্যাটিং সিনট্যাক্স, যেমন MARKUP_SYNTAX_MARKDOWN বা MARKUP_SYNTAX_CHAT (MARKUP_SYNTAX_UNSPECIFIED হলে Chat অ্যাপের কনফিগার করা সিনট্যাক্সে ডিফল্ট হিসেবে সেট করা হয়)। ইনলাইন উদ্ধৃতি যোগ করার পরিকল্পনা থাকলে MARKUP_SYNTAX_MARKDOWN সেট করুন।
  • streamContentChunks (ঐচ্ছিক): অবিলম্বে দেখানোর জন্য প্রাথমিক text, step বা citation চাঙ্ক।

পরবর্তী কলের জন্য উত্তর থেকে name (spaces/{space}/streamMessages/{stream_message}) এবং nextChunkToken, দুটিই সেভ করুন।

HTTP

POST https://chat.googleapis.com/v1/spaces/SPACE_ID/streamMessages HTTP/1.1
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{
  "referencedMessage": "spaces/SPACE_ID/messages/MESSAGE_ID",
  "progressText": "Thinking...",
  "markupSyntax": "MARKUP_SYNTAX_MARKDOWN"
}

Python

stream = (
    chat.spaces()
    .streamMessages()
    .create(
        parent="spaces/SPACE_ID",
        body={
            "referencedMessage": "spaces/SPACE_ID/messages/MESSAGE_ID",
            "progressText": "Thinking...",
            "markupSyntax": "MARKUP_SYNTAX_MARKDOWN",
        },
    )
    .execute()
)

stream_name = stream["name"]
chunk_token = stream["nextChunkToken"]

এই পদ্ধতি StreamMessage রিসোর্স রিটার্ন করে:

{
  "name": "spaces/SPACE_ID/streamMessages/STREAM_MESSAGE_ID",
  "progressText": "Thinking...",
  "markupSyntax": "MARKUP_SYNTAX_MARKDOWN",
  "nextChunkToken": "INITIAL_CHUNK_TOKEN"
}

কন্টেন্ট চাঙ্ক যোগ করুন

আপনার Chat অ্যাপ ইন্টারমিডিয়েট ধাপ বা টেক্সট টোকেন তৈরি করলে, spaces.streamMessages.appendStreamMessageContent কল করুন:

  • chunkToken-এ লেটেস্ট nextChunkToken পাস করুন। প্রতিটি সফল কল একটি নতুন nextChunkToken রিটার্ন করে যা আপনার পরবর্তী আপডেট বা কমিট অনুরোধে পাস করতে হবে।
  • text চাঙ্ক সরাসরি আগে স্ট্রিম করা টেক্সটের সাথে কনক্যাটিনেট করে। প্রয়োজন হলে চাঙ্কের মধ্যে স্পেস বা নতুন লাইন যোগ করুন।
  • step চাঙ্ক মেসেজে দেখানো মধ্যবর্তী ধাপের তালিকায় যোগ করা হয়েছে।
  • progressText ঐচ্ছিক। আপনি progressText বাদ দিলে বা এটি ""-এ সেট করলে, Chat আগে থেকে সেট করা progressText দেখাতে থাকে।

HTTP

POST https://chat.googleapis.com/v1/spaces/SPACE_ID/streamMessages/STREAM_MESSAGE_ID:appendStreamMessageContent HTTP/1.1
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{
  "chunkToken": "INITIAL_CHUNK_TOKEN",
  "progressText": "Searching documentation...",
  "streamContentChunks": [
    {
      "step": {
        "title": "Search knowledge base",
        "description": "Found 3 matching articles."
      }
    },
    {
      "text": "See <chat-citation data-id=\"c1\">guide</chat-citation>:\n"
    },
    {
      "citation": {
        "id": "c1",
        "citedSources": [
          {
            "title": "System Architecture Guide",
            "uri": "https://example.com/docs/arch"
          }
        ]
      }
    }
  ]
}

Python

stream = (
    chat.spaces()
    .streamMessages()
    .appendStreamMessageContent(
        name=stream_name,
        body={
            "chunkToken": chunk_token,
            "progressText": "Searching documentation...",
            "streamContentChunks": [
                {
                    "step": {
                        "title": "Search knowledge base",
                        "description": "Found 3 matching articles.",
                    }
                },
                {
                    "text": (
                        'See <chat-citation data-id="c1">'
                        "guide</chat-citation>:\n"
                    )
                },
                {
                    "citation": {
                        "id": "c1",
                        "citedSources": [
                            {
                                "title": "System Architecture Guide",
                                "uri": "https://example.com/docs/arch",
                            }
                        ],
                    }
                },
            ],
        },
    )
    .execute()
)

chunk_token = stream["nextChunkToken"]

স্ট্রিম করা কন্টেন্ট বা প্রোগ্রেস টেক্সট পরিবর্তন করুন

আগে স্ট্রিম করা কন্টেন্ট আবার লিখতে হলে—যেমন, পোস্ট-প্রসেসিং বা নিরাপত্তা ফিল্টার চালানোর পরে—অথবা চাঙ্ক যোগ না করে শুধু progressText আপডেট করতে হলে, spaces.streamMessages.patch কল করুন:

  • আপডেট করার জন্য কমা দিয়ে আলাদা করা ফিল্ডের তালিকায় updateMask সেট করুন: progressText, streamContentChunks, অথবা progressText,streamContentChunks.
  • StreamMessage অনুরোধের বডিতে লেটেস্ট nextChunkToken অন্তর্ভুক্ত করুন এবং উত্তরে ফেরত আসা নতুন nextChunkToken রেকর্ড করুন।
  • streamContentChunks যখন updateMask-এ থাকে, তখন প্রদত্ত চাঙ্ক আগে স্ট্রিম করা কন্টেন্টের সাথে যোগ করার পরিবর্তে সেটিকে রিপ্লেস করে।
  • progressText, updateMask-এ থাকলে, progressText অবশ্যই খালি নয় এমন প্লেন টেক্সট হতে হবে, যা ২৫০টি অক্ষর পর্যন্ত হতে পারে।

HTTP

PATCH https://chat.googleapis.com/v1/spaces/SPACE_ID/streamMessages/STREAM_MESSAGE_ID?updateMask=progressText,streamContentChunks HTTP/1.1
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{
  "nextChunkToken": "LATEST_CHUNK_TOKEN",
  "progressText": "Formatting response...",
  "streamContentChunks": [
    {
      "text": "Updated response text."
    }
  ]
}

Python

stream = (
    chat.spaces()
    .streamMessages()
    .patch(
        name=stream_name,
        updateMask="progressText,streamContentChunks",
        body={
            "nextChunkToken": chunk_token,
            "progressText": "Formatting response...",
            "streamContentChunks": [
                {"text": "Updated response text."}
            ],
        },
    )
    .execute()
)

chunk_token = stream["nextChunkToken"]

স্ট্রিম চূড়ান্ত করা

জেনারেট করা হয়ে গেলে, লেটেস্ট chunkToken সহ spaces.streamMessages.commit কল করুন যাতে স্ট্রিমটি স্থায়ী Message রিসোর্সে চূড়ান্ত করা যায়:

  • আপনি চাইলে কমিট অনুরোধে চূড়ান্ত streamContentChunks অন্তর্ভুক্ত করতে পারেন, যার মধ্যে শুধু কমিট করা যায় এমন চাঙ্ক টাইপ (card, accessoryWidget এবং citedSource) অন্তর্ভুক্ত।
  • আপনি যদি আগের কলে খালি নয় এমন কন্টেন্ট স্ট্রিম করে থাকেন, তাহলে কমিট করার সময় streamContentChunks বাদ দিতে পারবেন। চূড়ান্ত কমিট করা মেসেজ খালি রাখা যাবে না।

HTTP

POST https://chat.googleapis.com/v1/spaces/SPACE_ID/streamMessages/STREAM_MESSAGE_ID:commit HTTP/1.1
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{
  "chunkToken": "LATEST_CHUNK_TOKEN",
  "streamContentChunks": [
    {
      "text": "All checks passed."
    },
    {
      "citedSource": {
        "title": "Deployment Runbook",
        "uri": "https://example.com/docs/runbook"
      }
    },
    {
      "card": {
        "cardId": "details-card",
        "card": {
          "header": {
            "title": "Build Status"
          },
          "sections": [
            {
              "widgets": [
                {
                  "textParagraph": {
                    "text": "All 42 checks succeeded."
                  }
                }
              ]
            }
          ]
        }
      }
    }
  ]
}

Python

status_card = {
    "cardId": "details-card",
    "card": {
        "header": {"title": "Build Status"},
        "sections": [
            {
                "widgets": [
                    {"textParagraph": {"text": "All 42 checks succeeded."}}
                ]
            }
        ],
    },
}

commit_response = (
    chat.spaces()
    .streamMessages()
    .commit(
        name=stream_name,
        body={
            "chunkToken": chunk_token,
            "streamContentChunks": [
                {"text": "All checks passed."},
                {
                    "citedSource": {
                        "title": "Deployment Runbook",
                        "uri": "https://example.com/docs/runbook",
                    }
                },
                {"card": status_card},
            ],
        },
    )
    .execute()
)

final_message = commit_response["message"]
print(f"Committed message: {final_message['name']}")

অ্যাক্টিভ স্ট্রিম বাতিল করা

যদি এমন কোনও সমস্যা হয় যা সমাধান করা যাবে না অথবা ব্যবহারকারী জেনারেশন বাতিল করে দেন এবং আপনি থ্রেডে আংশিক উত্তর রেখে যেতে না চান, তাহলে spaces.streamMessages.delete কল করুন:

HTTP

DELETE https://chat.googleapis.com/v1/spaces/SPACE_ID/streamMessages/STREAM_MESSAGE_ID HTTP/1.1
Authorization: Bearer ACCESS_TOKEN

Python

chat.spaces().streamMessages().delete(name=stream_name).execute()

কোনও স্ট্রিম Message-এ কমিট করা হয়ে গেলে, চূড়ান্ত করা মেসেজ মুছে দিতে চাইলে, পরিবর্তে spaces.messages.delete কল করুন।

যেসব কন্টেন্ট চাঙ্ক টাইপ কাজ করে

streamContentChunks-এর প্রতিটি এন্ট্রি StreamContentChunk ইউনিয়নের একটি ফিল্ড নির্দিষ্ট করে। কিছু চাঙ্ক টাইপ স্ট্রিম চলাকালীন পাঠানো যেতে পারে, অন্যগুলি শুধুমাত্র spaces.streamMessages.commit-এ গ্রহণ করা হয়:

চাঙ্ক ফিল্ড যেসব পদ্ধতি কাজ করে চূড়ান্ত Message ফিল্ড নোট
text create, appendStreamMessageContent, patch, commit text ইনক্রিমেন্টাল টেক্সট। appendStreamMessageContent-এ কনক্যাটিনেট করা হয়েছে; patch-এ পরিবর্তন করা হয়েছে। চূড়ান্ত কমিট করা টেক্সট ৩২,০০০ বাইটের বেশি হতে পারবে না।
step create, appendStreamMessageContent, patch, commit elements.steps.steps[] প্লেন-টেক্সট title (প্রয়োজনীয়) এবং ঐচ্ছিক description সহ ইন্টারমিডিয়েট প্রসেসিং ধাপ।
citation create, appendStreamMessageContent, patch, commit elements.citations[] ইনলাইন Citation যার সাথে বর্ণসাংখ্যিক id (৬৩ অক্ষরের কম, আন্ডারস্কোর ব্যবহার করা যাবে) এবং citedSources। text-এ markupSyntax: "MARKUP_SYNTAX_MARKDOWN" এবং ম্যাচিং <chat-citation data-id="ID">...</chat-citation> ট্যাগ থাকতে হবে। আগে থেকেই আছে এমন id-এর সাথে citation পাঠালে আগের উদ্ধৃতি ওভাররাইট হয়ে যায়।
card শুধুমাত্র commit cardsV2[] ইন্টার‍্যাক্টিভ বা তথ্যমূলক CardWithId কার্ড।
accessoryWidget শুধুমাত্র commit accessoryWidgets[] AccessoryWidget মেসেজের নিচে দেখানো বোতাম, যেমন, মতামত জানানোর বোতাম।
citedSource শুধুমাত্র commit elements.citedSources[] CitedSource মেসেজের নিচে ফুটার লিঙ্ক দেখানো হয়েছে ইনলাইন উদ্ধৃতি ট্যাগ ছাড়াই।

ব্যবহারকারীর অনুরোধে স্ট্রিম বাতিল করা ম্যানেজ করা

কোনও স্ট্রিম অ্যাক্টিভ থাকাকালীন, শুধুমাত্র রেফারেন্স করা মেসেজের প্রেরক (referencedMessage) স্ট্রিম করা মেসেজে বন্ধ করুন বিকল্পে ক্লিক করতে পারবেন। ব্যবহারকারী কোনও স্ট্রিম বন্ধ করলে, Chat আপনার Chat অ্যাপ এন্ডপয়েন্টে cancelStream.streamMessage (বন্ধ করা স্ট্রিমের spaces/{space}/streamMessages/{stream_message} রিসোর্স নাম) সহ একটি সিস্টেম কমান্ড ইন্টার‍্যাকশন ইভেন্ট পাঠায়।

ইনকামিং JSON পেলোডের স্ট্রাকচার নির্ভর করে আপনি Google Workspace অ্যাড-অন হিসেবে Chat অ্যাপ তৈরি করেছেন নাকি Chat API ইন্টার‍্যাকশন ইভেন্ট ব্যবহার করে তৈরি করেছেন তার উপর:

Google Workspace অ্যাড-অন

{
  "commonEventObject": {
    "hostApp": "CHAT"
  },
  "chat": {
    "user": {
      "name": "users/USER_ID"
    },
    "space": {
      "name": "spaces/SPACE_ID"
    },
    "systemCommandPayload": {
      "systemCommandMetadata": {
        "cancelStream": {
          "streamMessage": "spaces/SPACE_ID/streamMessages/STREAM_ID"
        }
      }
    }
  }
}

Google Chat API

{
  "type": "SYSTEM_COMMAND",
  "space": {
    "name": "spaces/SPACE_ID"
  },
  "user": {
    "name": "users/USER_ID"
  },
  "systemCommandMetadata": {
    "cancelStream": {
      "streamMessage": "spaces/SPACE_ID/streamMessages/STREAM_ID"
    }
  }
}

আপনার Chat অ্যাপ cancelStream ইভেন্ট পেলে:

  1. streamMessage-এর জন্য আরও টোকেন জেনারেট করা বা ডাউনস্ট্রিম টুল চালানো বন্ধ করতে আপনার ব্যাকগ্রাউন্ড ওয়ার্কারকে সিগন্যাল দিন।
  2. নিম্নলিখিত পদ্ধতিগুলির মধ্যে কোনও একটি ব্যবহার করে অ্যাক্টিভ স্ট্রিম সংক্রান্ত সমস্যার সমাধান করুন:
    • আংশিক আউটপুট রাখুন: লেটেস্ট chunkToken সহ spaces.streamMessages.commit কল করুন (বিকল্প হিসেবে "\n\n_Generation stopped._"-এর মতো নোট যোগ করুন)।
    • উত্তর বাতিল করা: spaces.streamMessages.delete-কে কল করুন যাতে থ্রেডে কিছুই সেভ না হয়।
  3. আপনার ইন্টার‍্যাকশন ইভেন্ট হ্যান্ডলার থেকে একটি খালি HTTP 200 OK JSON রেসপন্স ({}) ফেরত পাঠান।

সীমাবদ্ধতা

মেসেজ স্ট্রিমিংয়ের ক্ষেত্রে নিম্নলিখিত সীমাবদ্ধতা রয়েছে:

  • প্ল্যাটফর্মের উপলভ্যতা: মেসেজ স্ট্রিমিং শুধুমাত্র ওয়েবে Chat-এ দেখা যায়। Android ও iOS-এর জন্য সহায়তা শীঘ্রই উপলভ্য হবে।
  • স্ট্রিম টাইমআউট: একটি অ্যাক্টিভ StreamMessage তৈরি হওয়ার ১০ মিনিট পরে টাইমআউট হয়ে যায়। আপনার Chat অ্যাপকে অবশ্যই স্ট্রিম শুরু হওয়ার ১০ মিনিটের মধ্যে spaces.streamMessages.commit বা spaces.streamMessages.delete-কে কল করতে হবে।