بث الرسائل باستخدام Google Chat API

يشرح هذا الدليل كيفية بث الرسائل بشكل تدريجي في Google Chat باستخدام مورد StreamMessage في Chat API. يتيح البث لتطبيق Google Chat عرض مؤشرات التقدم المباشرة، والخطوات الوسيطة للاستدلال أو تنفيذ الأدوات، والردود النصية المتزايدة قبل إنهاء الرسالة.

تم تصميم ميزة "البث" لتطبيقات Chat المستندة إلى الذكاء الاصطناعي التوليدي أو سير العمل في الخلفية التي تستغرق وقتًا طويلاً، حيث يستغرق إنشاء ردّ كامل عدة ثوانٍ أو دقائق.

طريقة عمل ميزة "بث الرسائل"

تمرّ رسالة البث بحالة بث نشطة قبل أن تصبح موردًا عاديًا من نوع Message في مساحة:

  1. بدء سلسلة محادثات (spaces.streamMessages.create): ينشئ تطبيق Chat StreamMessage في مساحة تتضمّن سلاسل محادثات، ويشير إلى رسالة تفاعل المستخدم التي يردّ عليها. تعرض واجهة برمجة التطبيقات مؤشر تقدّم مباشرًا في سلسلة المحادثات وتعرض اسم مورد StreamMessage وnextChunkToken أوليًا.
  2. تعديل سلسلة البيانات (appendStreamMessageContent أو patch): عندما يُنشئ تطبيق Chat مخرجات، يرسل تعديلات متسلسلة باستخدام أحدث nextChunkToken:
    • يجب استدعاء spaces.streamMessages.appendStreamMessageContent لدمج أجزاء نصية جديدة أو إلحاق خطوات وسيطة أو إضافة اقتباسات مضمّنة أو تعديل progressText.
    • يمكنك استدعاء spaces.streamMessages.patch لاستبدال أجزاء المحتوى الذي يتم بثه أو تعديل progressText في مكانه.
  3. إنهاء البث أو تجاهله (commit أو delete):
    • يُرجى الاتصال بـ spaces.streamMessages.commit لإنهاء البث وتحويله إلى مورد Message دائم. يمكنك أيضًا إرفاق عناصر مخصّصة للتثبيت فقط، مثل البطاقات والتطبيقات المصغّرة الملحقة ومصادر التذييل، عند التثبيت.
    • يمكنك استدعاء spaces.streamMessages.delete لتجاهل بث نشط بدون حفظ رسالة في المساحة.

عندما يكون البث نشطًا، يمكن فقط لمرسل الرسالة المرجعية (referencedMessage) التي يتم بثها النقر على إيقاف لإلغاء عملية الإنشاء. يرسل Chat حدث أمر إلغاء النظام إلى تطبيق Chat حتى تتمكّن من إيقاف العمل في الخلفية وإما تنفيذ مخرجات جزئية أو حذف البث.

المتطلبات الأساسية

لبث الرسائل باستخدام Chat API، يجب إكمال المتطلبات الأساسية التالية:

  • حساب Business أو Enterprise على Google Workspace مع إمكانية الوصول إلى Google Chat
  • إعداد البيئة:
  • أضِف تطبيق Chat إلى مساحة Chat تتضمّن سلاسل محادثات (أو رسالة مباشرة بين شخصَين تحتوي على رسالة واحدة على الأقل)، واحصل على اسم المورد لرسالة يمكن الوصول إليها للردّ عليها (spaces/SPACE_ID/messages/MESSAGE_ID).
  • بالنسبة إلى نماذج Python، ثبِّت مكتبة برامج Google API للغة Python و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 (مطلوبة): تصنيف حالة نص عادي غير فارغ (يصل إلى 250 حرفًا) يظهر بجانب مؤشر مستوى التقدّم، مثل "Thinking...".
  • ‫markupSyntax (اختياري): بنية تنسيق النص للرسالة، مثل MARKUP_SYNTAX_MARKDOWN أو MARKUP_SYNTAX_CHAT (يتم ضبطها تلقائيًا على البنية التي تم ضبطها في تطبيق Chat إذا كانت MARKUP_SYNTAX_UNSPECIFIED). يمكنك ضبط 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:

  • يجب اجتياز أحدث اختبار nextChunkToken في chunkToken. يؤدي كل طلب ناجح إلى عرض 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.
  • يجب تضمين أحدث nextChunkToken داخل نص طلب StreamMessage، وتسجيل nextChunkToken الجديد الذي تم عرضه في الردّ.
  • عندما تكون قيمة streamContentChunks هي updateMask، تحلّ الأجزاء المقدَّمة محلّ المحتوى الذي تم بثّه سابقًا بدلاً من إضافتها إليه.
  • عندما تكون السمة progressText في updateMask، يجب أن تكون السمة progressText نصًا عاديًا غير فارغ يصل إلى 250 حرفًا.

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"]

إنهاء بث

عند انتهاء عملية الإنشاء، يمكنك استدعاء spaces.streamMessages.commit مع أحدث chunkToken لإنهاء البث وتحويله إلى مورد 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. لا يمكن أن يتجاوز النص النهائي الملتزم به 32,000 بايت.
step ‫create، appendStreamMessageContent، patch، commit elements.steps.steps[] خطوة معالجة وسيطة باستخدام نص عادي title (مطلوب) وdescription اختياري.
citation ‫create، appendStreamMessageContent، patch، commit elements.citations[] يجب تضمين Citation مع id أبجدي رقمي (أقل من 63 حرفًا، ويُسمح باستخدام الشرطات السفلية) وcitedSources. يتطلّب ذلك علامات markupSyntax: "MARKUP_SYNTAX_MARKDOWN" وعلامات <chat-citation data-id="ID">...</chat-citation> مطابقة في text. يؤدي إرسال citation مع id حالي إلى استبدال الاقتباس السابق.
card commit فقط cardsV2[] بطاقة CardWithId تفاعلية أو معلوماتية
accessoryWidget commit فقط accessoryWidgets[] AccessoryWidget الأزرار المعروضة أسفل الرسالة، مثل أزرار الملاحظات
citedSource commit فقط elements.citedSources[] رابط التذييل CitedSource المعروض أسفل الرسالة بدون علامات الاقتباس المضمّنة

التعامل مع إلغاء تبادُل الرسائل من قِبل المستخدم

عندما يكون البث نشطًا، يمكن فقط لمرسل الرسالة المرجعية (referencedMessage) التي يتم بثها النقر على إيقاف في رسالة البث. عندما يوقف المستخدم بثًا، يرسل Chat حدث تفاعل بأمر النظام يحتوي على cancelStream.streamMessage (اسم المورد spaces/{space}/streamMessages/{stream_message} للبث المتوقف) إلى نقطة نهاية تطبيق Chat.

تعتمد بنية حمولة JSON الواردة على ما إذا كنت تنشئ تطبيق Chat كإضافة في Google Workspace أو باستخدام أحداث التفاعل في 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. يمكنك حلّ مشكلة البث النشط باستخدام إحدى الطرق التالية:
    • الاحتفاظ بالناتج الجزئي: يمكنك استدعاء spaces.streamMessages.commit باستخدام أحدث chunkToken (مع إلحاق ملاحظة اختياريًا مثل "\n\n_Generation stopped._").
    • تجاهُل الردّ: يمكنك استدعاء spaces.streamMessages.delete لعدم حفظ أي شيء في سلسلة المحادثات.
  3. عرض ردّ JSON فارغ من نوع HTTP 200 OK ({}) من معالج أحداث التفاعل

القيود

تنطبق القيود التالية على ميزة "بث الرسائل":

  • توفّر المنصات: لا تظهر ميزة "بث الرسائل" إلا في Chat على الويب. وستتوفّر قريبًا إمكانية استخدام أجهزة Android وiOS.
  • انتهاء مهلة البث: تنتهي مهلة StreamMessage النشط بعد 10 دقائق من إنشائه. يجب أن يستدعي تطبيق Chat spaces.streamMessages.commit أو spaces.streamMessages.delete خلال 10 دقائق من بدء البث.