پاسخ دادن به رخدادها با Google Chat،‏ Vertex AI، و Google Apps Script

این آموزش نشان می‌دهد چگونه برنامه Google Chat بسازید که به حوادث به‌صورت هم‌زمان پاسخ می‌دهد. هنگام پاسخ دادن به یک حادثه، برنامه فضای Chat ایجاد و آن را تکمیل می‌کند، با پیام‌ها، دستورات برنامه، و کادرهای گفتگو، حل‌وفصل حادثه را تسهیل می‌کند، و از هوش مصنوعی برای خلاصه کردن پاسخ حادثه در سند «سندنگار Google» استفاده می‌کند.

این آموزش از محدوده‌های مجوزدهی که با https://www.googleapis.com/auth/chat.app.* شروع می‌شود استفاده می‌کند. برای اینکه برنامه Chat از این محدوده‌ها استفاده کند، باید یک تأیید سرپرست یک‌باره دریافت کنید.

حادثه رویدادی است که برای حل آن نیاز به توجه فوری یک تیم از افراد دارد. نمونه‌هایی از حادثه عبارت‌اند از:

  • پرونده‌ای حساس به زمان در پلاتفرم «مدیریت ارتباط با مشتری» (CRM) ایجاد می‌شود که نیاز دارد تیم خدمات برای حل آن با هم مشارکت کنند.
  • سیستمی آفلاین می‌شود و گروهی از مهندسان قابلیت اطمینان سایت (SRE) را مطلع می‌کند تا بتوانند با هم کار کنند و آن را دوباره آنلاین کنند.
  • زلزله‌ای با بزرگی بالا رخ می‌دهد و امدادگران باید پاسخ خود را هماهنگ کنند.

برای اهداف این آموزش گام‌به‌گام، هشدار حادثه زمانی شروع می‌شود که فردی حادثه را با کلیک روی دکمه‌ای در صفحه وب گزارش کند. صفحه وب با درخواست از کاربران برای وارد کردن اطلاعات اولیه حادثه، حادثه‌ای را شبیه‌سازی می‌کند: عنوان، شرح، و نشانی‌های ایمیل پاسخ‌دهندگان.

برنامه Chat مدیریت حادثه را در عمل ببینید:

  • وب‌سایتی که حادثه را شروع می‌کند.
    شکل ۱. وب‌سایتی که در آن می‌توان حادثه‌ای را گزارش کرد.
  • اعلان ایجاد فضای Chat رویداد.
    شکل ۲. اعلان ایجاد فضای گپ حادثه.
  • فضای Chat پاسخ به حادثه.
    شکل ۳. فضای Chat پاسخ به رویداد.
  • درحال حل‌وفصل کردن حادثه با فرمان خط مورب.
    شکل ۴. درحال حل‌وفصل کردن حادثه با فرمان خط مورب.
  • کادر گفتگوی حل‌وفصل حادثه.
    شکل ۵. کادر گفتگوی حل‌وفصل حادثه.
  • سند «سندنگار Google» هم‌رسانی‌شده در فضا برای حل‌وفصل حادثه.
    شکل ۶. سند «سندنگار Google» هم‌رسانی‌شده در فضا برای حل‌وفصل کردن حادثه.
  • سندنگار Google مربوط به حل‌وفصل حادثه خلاصه هوش مصنوعی.
    شکل ۷. سند «سندنگار Google» مربوط به حل‌وفصل حادثه خلاصه هوش مصنوعی.

پیش‌نیازها

اگر نیاز دارید هریک از این پیش‌نیازها برای سازمانتان روشن شود، از سرپرست Google Workspace خود بخواهید آن‌ها را روشن کند:

  • حساب «کسب‌وکار» یا «سازمانی» Google Workspace با دسترسی به Google Chat.
  • برای اینکه دایرکتوری (هم‌رسانی مخاطب) برای Google Workspace روشن باشد. برنامه حادثه از فهرست راهنما برای جستجوی اطلاعات تماس پاسخ‌دهندگان حادثه، مانند نام و نشانی ایمیل، استفاده می‌کند. پاسخ‌دهندگان به رویداد باید کاربرانی با حساب Chat در سازمان Google Workspace شما باشند.

اهداف

  • برنامه Chat بسازید که به رخدادها پاسخ دهد.
  • با انجام کارهای زیر به کاربران کمک کنید به رخدادها پاسخ دهند:
    • درحال ایجاد فضاهای پاسخ به حادثه.
    • ارسال پیام‌هایی که حوادث و پاسخ‌ها را خلاصه می‌کنند.
    • پشتیبانی از مشارکت با ویژگی‌های تعاملی برنامه Chat.
  • مکالمه‌ها و راه‌حل‌ها را با Vertex AI خلاصه کنید.

معماری

نمودار زیر معماری منابع Google Workspace و Google Cloud را که برنامه Chat پاسخ به حادثه استفاده می‌کند نشان می‌دهد.

معماری برنامه Chat پاسخ به حادثه

معماری نشان می‌دهد که برنامه Chat پاسخ به حادثه چگونه حادثه و حل‌وفصل را پردازش می‌کند.

  1. کاربری حادثه‌ای را از وب‌سایت خارجی میزبانی‌شده در Apps Script شروع می‌کند.

  2. وب‌سایت یک درخواست ناهمگام HTTP به برنامه Chat ارسال می‌کند که آن هم در Apps Script میزبانی می‌شود.

  3. برنامه Chat پاسخ به حادثه درخواست را پردازش می‌کند:

    1. خدمات «کیت توسعه نرم‌افزار سرپرست Apps Script» اطلاعات اعضای تیم را، مانند شناسه کاربر و نشانی ایمیل، دریافت می‌کند.

    2. با مجموعه‌ای از درخواست‌های HTTP به Chat API بااستفاده از سرویس پیشرفته Chat در Apps Script، برنامه Chat پاسخ به حادثه فضای Chat حادثه ایجاد می‌کند، آن را با اعضای تیم تکمیل می‌کند، و پیامی به فضا ارسال می‌کند.

  4. اعضای تیم درباره حادثه در فضای Chat بحث می‌کنند.

  5. یکی از اعضای تیم فرمان سریعی را فرا می‌خواند تا نشان دهد که حادثه حل‌وفصل شده است.

    1. تماس HTTP با Chat API بااستفاده از Apps Script سرویس پیشرفته Chat همه پیام‌های فضای Chat را فهرست می‌کند.

    2. ‫Vertex AI پیام‌های فهرست‌شده را دریافت می‌کند و خلاصه تولید می‌کند.

    3. سرویس Apps Script DocumentApp سند «سندنگار Google» را ایجاد می‌کند و خلاصه Vertex AI را به سند اضافه می‌کند.

    4. برنامه «گپ» پاسخ به حادثه با Chat API تماس می‌گیرد تا پیوند سند «سندنگار» خلاصه را در پیام هم‌رسانی کند.

آماده کردن محیط

این بخش نحوه ایجاد و پیکربندی پروژه Google Cloud را برای برنامه Chat نشان می‌دهد.

ایجاد پروژه Google Cloud

Google API Console

  1. در «کنسول Google API»، به «منو» > IAM و سرپرست > ایجاد پروژه بروید.

    رفتن به «ایجاد پروژه»

  2. در فیلد نام پروژه، نامی توصیفی برای پروژه خود وارد کنید.

    اختیاری: برای ویرایش شناسه پروژه، روی ویرایش کلیک کنید. شناسه پروژه را نمی‌توان پس‌از ایجاد پروژه تغییر داد، بنابراین شناسه‌ای را انتخاب کنید که در طول عمر پروژه نیازهای شما را برآورده کند.

  3. در فیلد مکان، روی مرور کردن کلیک کنید تا مکان‌های بالقوه برای پروژه‌تان نمایش داده شود. سپس روی انتخاب کلیک کنید.
  4. روی ایجاد کردن کلیک کنید. «کنسول Google API» به صفحه «داشبورد» هدایت می‌شود و پروژه شما ظرف چند دقیقه ایجاد می‌شود.

gcloud CLI

در یکی از محیط‌های توسعه زیر، به Google Cloud CLI (gcloud) دسترسی پیدا کنید:

  • Cloud Shell: برای استفاده از ترمینال آنلاین با gcloud CLI که ازقبل راه‌اندازی شده است، Cloud Shell را فعال کنید.
    فعال کردن Cloud Shell
  • صدف محلی: برای استفاده از محیط توسعه محلی، «رابط خط فرمان gcloud» را نصب و مقداردهی اولیه کنید.
    برای ایجاد پروژه Cloud، از دستور gcloud projects create استفاده کنید:
    gcloud projects create PROJECT_ID
    با تنظیم شناسه برای پروژه‌ای که می‌خواهید ایجاد کنید، PROJECT_ID را جایگزین کنید.

فعال کردن صورت‌حساب برای پروژه Cloud

Google API Console

  1. در «کنسول Google API»، به صورت‌حساب بروید. روی منو > صورت‌حساب > پروژه‌های من کلیک کنید.

    رفتن به «صورت‌حساب برای پروژه‌های من»

  2. در انتخاب سازمان، سازمانی را که با پروژه Google Cloud شما منسوب است انتخاب کنید.
  3. در ردیف پروژه، منو کنش‌ها () را باز کنید، روی تغییر صورت‌حساب کلیک کنید، و حساب Cloud Billing را انتخاب کنید.
  4. روی تنظیم حساب کلیک کنید.

gcloud CLI

  1. برای فهرست کردن حساب‌های صورت‌حساب دردسترس، این دستور را اجرا کنید:
    gcloud billing accounts list
  2. پیوند دادن حساب صورت‌حساب با پروژه Google Cloud:
    gcloud billing projects link PROJECT_ID --billing-account=BILLING_ACCOUNT_ID

    جایگزین کردن موارد زیر:

    • ‫PROJECT_ID شناسه پروژه برای پروژه Cloud است که می‌خواهید صورت‌حساب را برای آن فعال کنید.
    • ‫BILLING_ACCOUNT_ID شناسه حساب صورت‌حساب برای پیوند دادن با پروژه Google Cloud است.

فعال کردن میاناهای برنامه‌سازی کاربردی

Google API Console

  1. در «کنسول Google API»، «میانای برنامه‌سازی کاربردی Google Chat»، «میانای برنامه‌سازی کاربردی Google Docs»، «میانای برنامه‌سازی کاربردی Admin SDK»، «کیت توسعه نرم‌افزار Google Workspace Marketplace»، و «میانای برنامه‌سازی کاربردی Vertex AI» را فعال کنید.

    فعال کردن میاناهای برنامه‌سازی کاربردی

  2. تأیید کنید که میاناهای برنامه‌سازی کاربردی را در پروژه Cloud صحیح فعال می‌کنید، سپس روی بعدی کلیک کنید.

  3. تأیید کنید که درحال فعال کردن «میاناهای برنامه‌سازی کاربردی» صحیح هستید، سپس روی فعال کردن کلیک کنید.

gcloud CLI

  1. درصورت لزوم، پروژه Cloud کنونی را روی پروژه‌ای که با فرمان gcloud config set project ایجاد کرده‌اید تنظیم کنید:

    gcloud config set project PROJECT_ID

    PROJECT_ID را با شناسه پروژه پروژه Cloud که ایجاد کرده‌اید جایگزین کنید.

  2. میانای برنامه‌سازی کاربردی Google Chat، میانای برنامه‌سازی کاربردی «سندنگار Google»، میانای برنامه‌سازی کاربردی Admin SDK،‏ Google Workspace Marketplace SDK، و میانای برنامه‌سازی کاربردی Vertex AI را با gcloud services enable دستور فعال کنید:

    gcloud services enable chat.googleapis.com docs.googleapis.com admin.googleapis.com aiplatform.googleapis.com appsmarket-component.googleapis.com

راه‌اندازی اصالت‌سنجی و مجوز

برنامه Chat بااستفاده از اطلاعات اعتباری برنامه Chat به Google Chat API دسترسی پیدا می‌کند. برنامه با اطلاعات اعتباری کاربر به Admin SDK API و Google Docs API دسترسی دارد.

راه‌اندازی اصالت‌سنجی و اعطای اجازه کاربر

اصالت‌سنجی و صدور مجوز به برنامه Chat اجازه می‌دهد برای پردازش پاسخ به حادثه به منابع در Google Workspace و Google Cloud دسترسی داشته باشد. به‌طور دقیق، از اصالت‌سنجی کاربر برای فراخوانی Docs API و Admin SDK API استفاده می‌شود.

در این آموزش گام‌به‌گام، برنامه را به‌صورت داخلی در دامنه Workspace خودتان منتشر می‌کنید، بنابراین استفاده از اطلاعات جای‌بان قابل‌قبول است. پیش‌از انتشار برنامه در خارج، اطلاعات جای‌بان را با اطلاعات واقعی در صفحه موافقت جایگزین کنید.

  1. در «کنسول Google API»، به «منو» > پلاتفرم Google Auth > نمانام‌سازی بروید.

    رفتن به نمانام‌سازی

  2. اگر قبلاً پلاتفرم Google Auth را پیکربندی کرده‌اید، می‌توانید تنظیمات «صفحه رضایت OAuth» زیر را در نمانام‌سازی، مخاطب، و دسترسی به داده‌ها پیکربندی کنید. اگر پیامی با این مضمون دیدید: پلاتفرم «احراز هویت Google» هنوز پیکربندی نشده است، روی شروع به کار کلیک کنید:

    1. در بخش اطلاعات برنامه، در نام برنامه، Incident Management را تایپ کنید.
    2. در ایمیل پشتیبانی کاربر، نشانی ایمیل خودتان یا گروه Google مناسبی را انتخاب کنید.
    3. روی بعدی کلیک کنید.
    4. در بخش مخاطبان، داخلی را انتخاب کنید. اگر نمی‌توانید داخلی را انتخاب کنید، خارجی را انتخاب کنید.
    5. روی بعدی کلیک کنید.
    6. در بخش اطلاعات تماس، نشانی ایمیلی وارد کنید که ازطریق آن بتوانید از هرگونه تغییر در پروژه‌تان مطلع شوید.
    7. روی بعدی کلیک کنید.
    8. در بخش تکمیل، خط‌مشی داده‌های کاربر سرویس‌های Google API را مرور کنید و درصورت موافقت، با «خط‌مشی داده‌های کاربر سرویس‌های Google API» موافقم را انتخاب کنید.
    9. روی ادامه کلیک کنید.
    10. روی ایجاد کردن کلیک کنید.
    11. اگر خارجی را برای نوع کاربر انتخاب کردید، کاربران آزمایش را اضافه کنید:
      1. روی مخاطبان کلیک کنید.
      2. در بخش کاربران آزمایش، روی افزودن کاربران کلیک کنید.
      3. نشانی ایمیل خود و سایر کاربران آزمایش مجاز را وارد کنید، سپس روی ذخیره کلیک کنید.
  3. روی دسترسی به داده‌ها > افزودن یا برداشتن محدوده‌ها کلیک کنید. پانلی با فهرستی از محدوده‌ها برای هر API که در پروژه Google Cloud خود فعال کرده‌اید ظاهر می‌شود.

    1. در بخش افزودن دستی محدوده‌ها، محدوده‌های زیر را جای‌گذاری کنید:

      • https://www.googleapis.com/auth/documents
      • https://www.googleapis.com/auth/admin.directory.user.readonly
      • https://www.googleapis.com/auth/script.external_request
      • https://www.googleapis.com/auth/userinfo.email
      • https://www.googleapis.com/auth/cloud-platform
    2. روی افزودن به جدول کلیک کنید.

    3. روی به‌روزرسانی کلیک کنید.

    4. پس‌از انتخاب محدوده‌های موردنیاز برنامه‌تان، در صفحه دسترسی به داده‌ها، روی ذخیره کلیک کنید.

راه‌اندازی اصالت‌سنجی و مجوز برنامه

از «اصالت‌سنجی برنامه» برای فراخوانی Chat API استفاده می‌شود.

ایجاد حساب خدمات در کنسول Google Cloud

برای ایجاد حساب خدمات، این مراحل را دنبال کنید:

Google Cloud Console

  1. در «کنسول Google Cloud»، به «منو» > IAM و سرپرست > حساب‌های سرویس بروید.

    رفتن به «حساب‌های سرویس»

    مراحل باقی‌مانده در «کنسول Google Cloud» نشان داده می‌شود.

  2. پروژه Google Cloud را انتخاب کنید.
  3. روی ایجاد حساب سرویس کلیک کنید.
  4. نام حساب سرویسی را که می‌خواهید در Google Cloud Console نمایش داده شود وارد کنید.
  5. اگر نمی‌خواهید اکنون کنترل‌های دسترسی را تنظیم کنید، برای تکمیل ایجاد حساب سرویس روی تمام کلیک کنید. برای تنظیم کنترل‌های دسترسی در این لحظه، روی ایجاد و ادامه کلیک کنید و به مرحله بعد بروید.
  6. اختیاری: نقش‌هایی را به حساب خدمات خود اختصاص دهید تا علاوه‌بر منابع Google Workspace، دسترسی به منابع پروژه Google Cloud خود را نیز اعطا کنید. برای جزئیات بیشتر، به مدیریت دسترسی به پروژه‌ها، پوشه‌ها، و سازمان‌ها مراجعه کنید.
  7. روی ادامه کلیک کنید.
  8. اختیاری: کاربرها یا گروه‌هایی را که می‌توانند این حساب سرویس را مدیریت کنند و با آن کنش انجام دهند وارد کنید. برای جزئیات بیشتر، به جعل هویت حساب سرویس مراجعه کنید.
  9. برای تکمیل ایجاد حساب خدمات، روی تمام کلیک کنید.

    نشانی ایمیل حساب سرویس را یادداشت کنید.

gcloud CLI

  1. حساب سرویس را ایجاد کنید:
    gcloud iam service-accounts create SERVICE_ACCOUNT_NAME \
      --display-name="SERVICE_ACCOUNT_NAME"
  2. اختیاری: نقش‌هایی را به حساب خدمات خود اختصاص دهید تا علاوه‌بر منابع Google Workspace، دسترسی به منابع پروژه Google Cloud خود را نیز اعطا کنید. برای جزئیات بیشتر، به مدیریت دسترسی به پروژه‌ها، پوشه‌ها، و سازمان‌ها مراجعه کنید.

حساب سرویس در صفحه حساب سرویس نشان داده می‌شود. سپس، کلید خصوصی برای حساب سرویس ایجاد کنید.

ایجاد کلید خصوصی

برای ایجاد و بارگیری کلید خصوصی برای حساب سرویس، این مراحل را دنبال کنید:

  1. در «کنسول Google Cloud»، به «منو» > IAM و سرپرست > حساب‌های سرویس بروید.

    رفتن به «حساب‌های سرویس»

    مراحل باقی‌مانده در «کنسول Google Cloud» نشان داده می‌شود.

  2. پروژه Google Cloud را انتخاب کنید.
  3. روی نشانی ایمیل حساب سرویسی که می‌خواهید کلید برای آن ایجاد کنید کلیک کنید.
  4. روی برگه کلیدها کلیک کنید.
  5. روی منوِ کرکره‌ای افزودن کلید کلیک کنید، سپس ایجاد کلید جدید را انتخاب کنید.
  6. JSON را به‌عنوان نوع کلید انتخاب کنید و روی ایجاد کلیک کنید.

    جفت کلید عمومی/خصوصی جدید شما تولید می‌شود و به‌عنوان فایل کلید حساب خدماتی در ماشین شما بارگیری می‌شود. فایل JSON بارگیری‌شده را به‌عنوان credentials.json در دایرکتوری کاری‌تان ذخیره کنید. این فایل تنها نسخه این کلید است. پس‌از بارگیری فایل کلید، نمی‌توانید آن را دوباره بارگیری کنید. برای کسب اطلاعات درباره نحوه ذخیره ایمن کلید، روال‌های مطلوب برای مدیریت کلیدهای حساب سرویس را ببینید.

برای اطلاعات بیشتر درباره حساب‌های خدمات، حساب‌های خدمات در اسناد Google Cloud IAM را ببینید.

ایجاد کارخواه OAuth سازگار با Google Workspace Marketplace

برای ایجاد کارخواه OAuth سازگار با Google Workspace Marketplace، این مراحل را دنبال کنید:

  1. در «کنسول Google API»، به «منو» > IAM و سرپرست > حساب‌های سرویس بروید.

    رفتن به «حساب‌های سرویس»

  2. روی حساب سرویسی که برای برنامه Chat ایجاد کرده‌اید کلیک کنید.

  3. روی تنظیمات پیشرفته کلیک کنید.

  4. روی ایجاد کارخواه OAuth سازگار با Google Workspace Marketplace کلیک کنید.

  5. روی ادامه کلیک کنید.

پیام تأییدی ظاهر می‌شود که می‌گوید یک کارخواه OAuth سازگار با Google Workspace Marketplace ایجاد شده است.

ایجاد و استقرار برنامه Chat

در بخش زیر، کل پروژه Apps Script را که حاوی همه کد برنامه موردنیاز برای برنامه Chat شما است کپی و به‌روزرسانی می‌کنید، بنابراین نیازی به کپی و جای‌گذاری هر فایل نیست.

برخی‌از توابع در انتهای نامشان خط زیرین دارند، مثل concatenateAllSpaceMessages_() از ChatApp.gs. خط زیرین تابع را از صفحه وب مقداردهی اولیه رویداد پنهان می‌کند وقتی در مرورگر باز است. برای اطلاعات بیشتر، توابع خصوصی را ببینید.

‫Apps Script از دو نوع فایل پشتیبانی می‌کند: .gs دستورگان و .html فایل. برای رعایت این پشتیبانی، جاوا اسکریپت سمت مشتری برنامه در برچسب‌های <script /> و CSS آن در برچسب‌های <style /> در فایل HTML قرار می‌گیرد.

درصورت تمایل، می‌توانید کل پروژه را در GitHub مشاهده کنید.

مشاهده در GitHub

در اینجا نمای کلی هر فایل آورده شده است:

Consts.gs

ثابت‌هایی را که فایل‌های کد دیگر به آن‌ها ارجاع می‌دهند تعریف می‌کند، ازجمله شناسه پروژه Cloud، شناسه مکان Vertex AI، اطلاعات اعتباری برنامه برای حساب سرویس، و شناسه فرمان سریع برای بستن یک حادثه.

مشاهده Consts.gs کد

apps-script/chat/incident-response-app-auth/Consts.gs
const PROJECT_ID = 'replace-with-your-project-id';
const APP_CREDENTIALS = 'replace-with-your-app-credentials';
const APP_CREDENTIALS_SCOPES = 'https://www.googleapis.com/auth/chat.bot https://www.googleapis.com/auth/chat.app.memberships https://www.googleapis.com/auth/chat.app.spaces.create';
const VERTEX_AI_LOCATION_ID = 'us-central1';
const CLOSE_INCIDENT_COMMAND_ID = 1;
const MODEL_ID = 'gemini-2.5-flash-lite';
ChatApp.gs

رویدادهای تعامل Chat را مدیریت می‌کند، ازجمله پیام‌ها، کلیک‌های دکمه، فرمان‌های برنامه (onAppCommand)، و کادرهای گفتگو. با باز کردن کادر گفتگویی برای جمع‌آوری جزئیات حل‌وفصل حادثه، به فرمان سریع Close incident پاسخ می‌دهد. با فراخوانی روش spaces.messages.list در Chat API، پیام‌های فضا را می‌خواند. شناسه‌های کاربر را بااستفاده از سرویس «دایرکتوری» در «کیت توسعه نرم‌افزار سرپرست» در Apps Script دریافت می‌کند.

مشاهده ChatApp.gs کد

apps-script/chat/incident-response-app-auth/ChatApp.gs
/**
 * Responds to a MESSAGE event in Google Chat.
 * 
 * It always responds with a simple "Hello" text message.
 *
 * @param {Object} event the event object from Google Chat
 */
function onMessage(event) {
  return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    text: "Hello from Incident Response app!"
  }}}}};
}

/**
 * Responds to an APP_COMMAND event in Google Chat.
 *
 * @param {Object} event the event object from Google Chat
 */
function onAppCommand(event) {
  if (event.chat.appCommandPayload.appCommandMetadata.appCommandId != CLOSE_INCIDENT_COMMAND_ID) {
    return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: "Command not recognized. Use the quick command `Close incident` to close the incident managed by this space."
    }}}}};
  }
  return { action: { navigations: [{ pushCard: { sections: [{
    header: "Close Incident",
    widgets: [{
      textInput: {
        label: "Please describe the incident resolution",
        type: "MULTIPLE_LINE",
        name: "description"
      }
    }, {
      buttonList: { buttons: [{
        text: "Close Incident",
        onClick: { action: { function: "closeIncident" }}
      }]}
    }]
  }]}}]}};
}

/**
 * Responds to a BUTTON_CLICKED event in Google Chat from Close Incident dialog.
 *
 * @param {Object} event the event object from Google Chat
 */
function closeIncident(event) {
  if (event.chat.buttonClickedPayload.isDialogEvent) {
    if (event.chat.buttonClickedPayload.dialogEventType == 'SUBMIT_DIALOG') {
      return processSubmitDialog_(event);
    }
    return { action: { navigations: [{ endNavigation: {
      action: "CLOSE_DIALOG" }
    }]}};
  }
}

/**
 * Responds to a BUTTON_CLICKED event in Google Chat from Close Incident dialog submission.
 *
 * It creates a Doc with a summary of the incident information and posts a message
 * to the space with a link to the Doc.
 *
 * @param {Object} event the event object from Google Chat
 */
function processSubmitDialog_(event) {
  const resolution = event.commonEventObject.formInputs.description.stringInputs.value[0];
  const space = event.chat.buttonClickedPayload.space;
  const chatHistory = concatenateAllSpaceMessages_(space.name);
  const chatSummary = summarizeChatHistory_(chatHistory);
  const docUrl = createDoc_(space.displayName, resolution, chatHistory, chatSummary);
  return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    text: `Incident closed with the following resolution: ${resolution}\n\nHere is the automatically generated post-mortem:\n${docUrl}`
  }}}}};
}

/**
 * Lists all the messages in the Chat space, then concatenate all of them into
 * a single text containing the full Chat history.
 *
 * For simplicity for this demo, it only fetches the first 100 messages.
 *
 * @return {string} a text containing all the messages in the space in the format:
 *          Sender's name: Message
 */
function concatenateAllSpaceMessages_(spaceName) {
  // Call Chat API method spaces.messages.list
  const response = Chat.Spaces.Messages.list(spaceName, { 'pageSize': 100 });
  const messages = response.messages;
  // Fetch the display names of the message senders and returns a text
  // concatenating all the messages.
  let userMap = new Map();
  return messages
    .map(message => `${getUserDisplayName_(userMap, message.sender.name)}: ${message.text}`)
    .join('\n');
}

/**
 * Obtains the display name of a user by using the Admin Directory API.
 *
 * The fetched display name is cached in the provided map, so we only call the API
 * once per user.
 *
 * If the user does not have a display name, then the full name is used.
 *
 * @param {Map} userMap a map containing the display names previously fetched
 * @param {string} userName the resource name of the user
 * @return {string} the user's display name
 */
function getUserDisplayName_(userMap, userName) {
  if (userMap.has(userName)) {
    return userMap.get(userName);
  }
  let displayName = 'Unknown User';
  try {
    const user = AdminDirectory.Users.get(
      userName.replace("users/", ""),
      { projection: 'BASIC', viewType: 'domain_public' });
    displayName = user.name.displayName ? user.name.displayName : user.name.fullName;
  } catch (e) {
    // Ignore error if the API call fails (for example, because it's an
    // out-of-domain user or Chat app) and just use 'Unknown User'.
  }
  userMap.set(userName, displayName);
  return displayName;
}
ChatSpaceCreator.gs

داده‌های فرمی را که کاربران در صفحه وب اولیه رویداد وارد می‌کنند دریافت می‌کند و از آن برای راه‌اندازی فضای Chat با ایجاد و پر کردن آن استفاده می‌کند، و سپس پیامی درباره رویداد پست می‌کند.

مشاهده ChatSpaceCreator.gs کد

apps-script/chat/incident-response-app-auth/ChatSpaceCreator.gs
/**
 * Handles an incident by creating a chat space with the provided title and members, and posting a message.
 * All the actions are done using application credentials.
 *
 * @param {Object} formData - The data submitted by the user. It should contain the fields:
 *                           - title: The display name of the chat space.
 *                           - description: The description of the incident.
 *                           - users: A comma-separated string of user emails to be added to the space.
 * @return {string} The resource name of the new space.
 */
function handleIncident(formData) {
  const users = formData.users.trim().length > 0 ? formData.users.split(',') : [];
  const service = getService_();
  if (!service.hasAccess()) {
    console.error(service.getLastError());
    return;
   }
  const spaceName = createChatSpace_(formData.title, service);
  createHumanMembership_(spaceName, getUserEmail(), service);
  for (const user of users ){
    createHumanMembership_(spaceName, user, service);
  }
  createMessage_(spaceName, formData.description, service);
  return spaceName;
}

/**
 * Creates a chat space.
 *
 * @param {string} displayName - The name of the chat space.
 * @param {object} service - The credentials of the service account.
 * @returns {string} The resource name of the new space.
*/
function createChatSpace_(displayName, service) {
  try {
    // For private apps, the alias can be used
    const my_customer_alias = "customers/my_customer";
    // Specify the space to create.
    const space = {
        displayName: displayName,
        spaceType: 'SPACE',                
        customer: my_customer_alias
    };
    // Call Chat API with a service account to create a message.
    const createdSpace = Chat.Spaces.create(
        space,
        {},
        // Authenticate with the service account token.
        {'Authorization': 'Bearer ' + service.getAccessToken()});
    return createdSpace.name;
  } catch (err) {
    // TODO (developer) - Handle exception.
    console.log('Failed to create space with error %s', err.message);
  }
}


/**
 * Creates a human membership in a chat space.
 *
 * @param {string} spaceName - The resource name of the space.
 * @param {string} email - The email of the user to be added.
 * @param {object} service - The credentials of the service account.
 */
function createHumanMembership_(spaceName, email, service){
  try{
    const membership = {
      member: {
        name: 'users/'+email,
        // User type for the membership
        type: 'HUMAN'
      }
    };
    const result = Chat.Spaces.Members.create(
      membership,
      spaceName,
      {},
      {'Authorization': 'Bearer ' + service.getAccessToken()}
    );
  } catch (err){
    console.log('Failed to create membership with error %s', err.message)
  }

}

/**
 * Creates a chat message.
 *
 * @param {string} spaceName - The resource name of the space.
 * @param {string} message - The text to be posted.
 * @param {object} service - The credentials of the service account.
 * @return {string} the resource name of the new message.
 */
function createMessage_(spaceName, message, service) {
  try {
    const request = {
      text: message
    };
    // Call Chat API with a service account to create a message.
    const result = Chat.Spaces.Messages.create(
        request,
        spaceName,
        {},
        // Authenticate with the service account token.
        {'Authorization': 'Bearer ' + service.getAccessToken()});
    return result.name;
  } catch (err) {
    // TODO (developer) - Handle exception.
    console.log('Failed to create message with error %s', err.message);
  }
}

/**
 * Creates a service for the service account.
 * @return {object}  - The credentials of the service account.
 */
function getService_() {
  return OAuth2.createService(APP_CREDENTIALS.client_email)
      .setTokenUrl('https://oauth2.googleapis.com/token')
      .setPrivateKey(APP_CREDENTIALS.private_key)
      .setIssuer(APP_CREDENTIALS.client_email)
      .setSubject(APP_CREDENTIALS.client_email)
      .setScope(APP_CREDENTIALS_SCOPES)
      .setPropertyStore(PropertiesService.getScriptProperties());
}
DocsApi.gs

«میانای برنامه‌سازی کاربردی سندنگار» را فرا می‌خواند تا سند «سندنگار» را در Google Drive کاربر ایجاد کند و خلاصه اطلاعات رویداد را که در VertexAiApi.gs ایجاد شده است در سند بنویسد.

مشاهده DocsApi.gs کد

apps-script/chat/incident-response-app-auth/DocsApi.gs
/**
 * Creates a Doc in the user's Google Drive and writes a summary of the incident information to it.
 *
 * @param {string} title The title of the incident
 * @param {string} resolution Incident resolution described by the user
 * @param {string} chatHistory The whole Chat history be included in the document
 * @param {string} chatSummary A summary of the Chat conversation to be included in the document
 * @return {string} the URL of the created Doc
 */
function createDoc_(title, resolution, chatHistory, chatSummary) {
  let doc = DocumentApp.create(title);
  let body = doc.getBody();
  body.appendParagraph(`Post-Mortem: ${title}`).setHeading(DocumentApp.ParagraphHeading.TITLE);
  body.appendParagraph("Resolution").setHeading(DocumentApp.ParagraphHeading.HEADING1);
  body.appendParagraph(resolution);
  body.appendParagraph("Summary of the conversation").setHeading(DocumentApp.ParagraphHeading.HEADING1);
  body.appendParagraph(chatSummary);
  body.appendParagraph("Full Chat history").setHeading(DocumentApp.ParagraphHeading.HEADING1);
  body.appendParagraph(chatHistory);
  return doc.getUrl();
}
VertexAiApi.gs

مکالمه را در فضای Chat بااستفاده از Vertex AI API خلاصه می‌کند. این خلاصه در سندی که به‌طور ویژه در DocsAPI.gs ایجاد شده است پست می‌شود.

مشاهده VertexAiApi.gs کد

apps-script/chat/incident-response-app-auth/VertexAiApi.gs
/**
 * Summarizes a Chat conversation using the Vertex AI text prediction API.
 *
 * @param {string} chatHistory The Chat history that will be summarized.
 * @return {string} The content from the text prediction response.
 */
function summarizeChatHistory_(chatHistory) {
  const API_ENDPOINT = `https://${VERTEX_AI_LOCATION_ID}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${VERTEX_AI_LOCATION_ID}/publishers/google/models/${MODEL_ID}:generateContent`;
  const prompt =
    "Summarize the following conversation between Engineers resolving an incident"
      + " in a few sentences. Use only the information from the conversation.\n\n"
      + chatHistory;
  // Get the access token.
  const accessToken = ScriptApp.getOAuthToken();

  const headers = {
    'Authorization': 'Bearer ' + accessToken,
    'Content-Type': 'application/json',
  };
  const payload = {
    'contents': {
      'role': 'user',
      'parts' : [
        {
          'text': prompt
        }
      ]
    }
  }
  const options = {
    'method': 'post',
    'headers': headers,
    'payload': JSON.stringify(payload),
    'muteHttpExceptions': true,
  };
  try {
    const response = UrlFetchApp.fetch(API_ENDPOINT, options);
    const responseCode = response.getResponseCode();
    const responseText = response.getContentText();

    if (responseCode === 200) {
      const jsonResponse = JSON.parse(responseText);
      console.log(jsonResponse)
      if (jsonResponse.candidates && jsonResponse.candidates.length > 0) {
        return jsonResponse.candidates[0].content.parts[0].text; // Access the summarized text
      } else {
        return "No summary found in response.";
      }

    } else {
      console.error("Vertex AI API Error:", responseCode, responseText);
      return `Error: ${responseCode} - ${responseText}`;
    }
  } catch (e) {
    console.error("UrlFetchApp Error:", e);
    return "Error: " + e.toString();
  }
}
WebController.gs

وب‌سایت اولیه رویداد را ارائه می‌دهد.

مشاهده WebController.gs کد

apps-script/chat/incident-response-app-auth/WebController.gs
/**
 * Serves the web page from Index.html.
 */
function doGet() {
  return HtmlService
    .createTemplateFromFile('Index')
    .evaluate();
}

/**
 * Serves the web content from the specified filename.
 */
function include(filename) {
  return HtmlService
    .createHtmlOutputFromFile(filename)
    .getContent();
}

/**
 * Returns the email address of the user running the script.
 */
function getUserEmail() {
  return Session.getActiveUser().getEmail();
}
Index.html

HTML تشکیل‌دهنده وب‌سایت اولیه حادثه.

مشاهده Index.html کد

apps-script/chat/incident-response-app-auth/Index.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet'>
    <?!= include('Stylesheet'); ?>
  </head>
  <body>
    <div class="container">
      <div class="content">
        <h1>Incident Manager</h1>
        <form id="incident-form" onsubmit="handleFormSubmit(this)">
          <div id="form">
            <p>
              <label for="title">Incident title</label><br/>
              <input type="text" name="title" id="title" />
            </p>
            <p>
              <label for="users">Incident responders</label><br/>
              <small>
                Please enter a comma-separated list of email addresses of the users
                that should be added to the space.
                Do not include <?= getUserEmail() ?> as it will be added automatically.
              </small><br/>
              <input type="text" name="users" id="users" />
            </p>
            <p>
              <label for="description">Initial message</label></br>
              <small>This message will be posted after the space is created.</small><br/>
              <textarea name="description" id="description"></textarea>
            </p>
            <p class="text-center">
              <input type="submit" value="CREATE CHAT SPACE" />
            </p>
          </div>
          <div id="output" class="hidden"></div>
          <div id="clear" class="hidden">
            <input type="reset" value="CREATE ANOTHER INCIDENT" onclick="onReset()" />
          </div>
        </form>
      </div>
    </div>
    <?!= include('JavaScript'); ?>
  </body>
</html>
JavaScript.html

رفتار فرم را، ازجمله ارسال‌ها، خطاها، و پاک‌سازی‌ها، برای وب‌سایت مقداردهی اولیه رویداد مدیریت می‌کند. توسط تابع سفارشی include در WebController.gs در Index.html گنجانده شده است.

مشاهده JavaScript.html کد

apps-script/chat/incident-response-app-auth/JavaScript.html
<script>
  var formDiv = document.getElementById('form');
  var outputDiv = document.getElementById('output');
  var clearDiv = document.getElementById('clear');

  function handleFormSubmit(formObject) {
    event.preventDefault();
    outputDiv.innerHTML = 'Please wait while we create the space...';
    hide(formDiv);
    show(outputDiv);
    google.script.run
      .withSuccessHandler(updateOutput)
      .withFailureHandler(onFailure)
      .handleIncident(formObject);
  }

  function updateOutput(response) {
    var spaceId = response.replace('spaces/', '');
    outputDiv.innerHTML =
      '<p>Space created!</p><p><a href="https://mail.google.com/chat/#chat/space/'
        + spaceId
        + '" target="_blank">Open space</a></p>';
    show(outputDiv);
    show(clearDiv);
  }

  function onFailure(error) {
    outputDiv.innerHTML = 'ERROR: ' + error.message;
    outputDiv.classList.add('error');
    show(outputDiv);
    show(clearDiv);
  }

  function onReset() {
    outputDiv.innerHTML = '';
    outputDiv.classList.remove('error');
    show(formDiv);
    hide(outputDiv);
    hide(clearDiv);
  }

  function hide(element) {
    element.classList.add('hidden');
  }

  function show(element) {
    element.classList.remove('hidden');
  }
</script>
Stylesheet.html

«سی‌اس‌اس» برای وب‌سایت اولیه حادثه. این مورد توسط تابع سفارشی include در WebController.gs به Index.html اضافه شده است.

مشاهده Stylesheet.html کد

apps-script/chat/incident-response-app-auth/Stylesheet.html
<style>
  * {
    box-sizing: border-box;
  }
  body {
    font-family: Roboto, Arial, Helvetica, sans-serif;
  }
  div.container {
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    top: 0; bottom: 0; left: 0; right: 0;
  }
  div.content {
    width: 80%;
    max-width: 1000px;
    padding: 1rem;
    border: 1px solid #999;
    border-radius: 0.25rem;
    box-shadow: 0 2px 2px 0 rgba(66, 66, 66, 0.08), 0 2px 4px 2px rgba(66, 66, 66, 0.16);
  }
  h1 {
    text-align: center;
    padding-bottom: 1rem;
    margin: 0 -1rem 1rem -1rem;
    border-bottom: 1px solid #999;
  }
 #output {
    text-align: center;
    min-height: 250px;
  }
  div#clear {
    text-align: center;
    padding-top: 1rem;
    margin: 1rem -1rem 0 -1rem;
    border-top: 1px solid #999;
  }
  input[type=text], textarea {
    width: 100%;
    padding: 1rem 0.5rem;
    margin: 0.5rem 0;
    border: 0;
    border-bottom: 1px solid #999;
    background-color: #f0f0f0;
  }
  textarea {
    height: 5rem;
  }
  small {
    color: #999;
  }
  input[type=submit], input[type=reset] {
    padding: 1rem;
    border: none;
    background-color: #6200ee;
    color: #fff;
    border-radius: 0.25rem;
    width: 25%;
  }
  .hidden {
    display: none;
  }
  .text-center {
    text-align: center;
  }
  .error {
    color: red;
  }
</style>

شماره و شناسه پروژه Cloud خود را پیدا کنید

  1. در «کنسول Google API»، به پروژه Cloud خود بروید.

    رفتن به Google API Console

  2. روی «تنظیمات و ابزارها» > تنظیمات پروژه کلیک کنید.

  3. مقادیر موجود در فیلدهای شماره پروژه و شناسه پروژه را یادداشت کنید. از آن‌ها در بخش‌های زیر استفاده می‌کنید.

ایجاد پروژه Apps Script

برای ایجاد پروژه Apps Script و متصل کردن آن به پروژه Cloud خود:

  1. برای باز کردن پروژه پاسخ به رویدادها با Google Chat Apps Script، روی دکمه زیر کلیک کنید.
    باز کردن پروژه
  2. روی نمای کلی کلیک کنید.
  3. در صفحه نمای کلی، روی نماد تهیه کپی تهیه رونوشت کلیک کنید.
  4. نام کپی پروژه Apps Script خود را وارد کنید:

    1. روی کپی «پاسخ به رویدادها با Google Chat» کلیک کنید.

    2. در عنوان پروژه، Incident Management Chat app را تایپ کنید.

    3. روی تغییر نام کلیک کنید.

  5. در کپی پروژه Apps Script، به Consts.gs فایل بروید و YOUR_PROJECT_ID را با شناسه پروژه Cloud خود جایگزین کنید.

تنظیم پروژه Cloud برای پروژه Apps Script

  1. در پروژه Apps Script خود، روی نماد تنظیمات پروژه تنظیمات پروژه کلیک کنید.
  2. در بخش پروژه Google Cloud Platform (GCP)، روی تغییر پروژه کلیک کنید.
  3. در شماره پروژه GCP، شماره پروژه Cloud خود را جای‌گذاری کنید.
  4. روی تنظیم پروژه کلیک کنید. پروژه Cloud و پروژه Apps Script اکنون متصل هستند.

ایجاد پیاده‌سازی Apps Script

اکنون که همه کدها در جای خود قرار دارند، پروژه Apps Script را پیاده‌سازی کنید. هنگام پیکربندی برنامه Chat در Google Cloud، از شناسه استقرار استفاده می‌کنید.

  1. در Apps Script، پروژه برنامه پاسخ به حادثه را باز کنید.

    رفتن به Apps Script

  2. روی استقرار > استقرار جدید کلیک کنید.

  3. اگر برافزا و برنامه وب ازقبل انتخاب نشده‌اند، در کنار انتخاب نوع، روی انواع استقرار نماد تنظیمات پروژه کلیک کنید و برافزا و برنامه وب را انتخاب کنید.

  4. در شرح، شرحی برای این نسخه وارد کنید، مثلاً Complete version of incident management app.

  5. در اجرا به‌عنوان، کاربری که به برنامه وب دسترسی دارد را انتخاب کنید

  6. در بخش چه کسی دسترسی دارد، هر کسی در سازمان Workspace شما را انتخاب کنید، که در آن «سازمان Workspace شما» نام سازمان Google Workspace شما است.

  7. روی استقرار کلیک کنید. ‫Apps Script گزارش می‌دهد که پیاده‌سازی موفقیت‌آمیز بوده است و شناسه پیاده‌سازی و نشانی وب صفحه وب راه‌اندازی رویداد را ارائه می‌دهد.

  8. نشانی وب برنامه وب را یادداشت کنید تا بعداً هنگام شروع یک حادثه به آن مراجعه کنید. شناسه استقرار را کپی کنید. از این شناسه هنگام پیکربندی برنامه Chat در «کنسول Google API» استفاده می‌کنید.

  9. روی تمام کلیک کنید.

پیکربندی برنامه Chat در «کنسول Google API»

این بخش نحوه پیکربندی Google Chat API را در «کنسول Google API» با اطلاعاتی درباره برنامه Chat شما، ازجمله شناسه استقرار که به‌تازگی از پروژه Apps Script ایجاد کرده‌اید نشان می‌دهد.

  1. در «کنسول Google API»، روی منو > APIs و سرویس‌ها > APIs و سرویس‌های فعال > Google Chat API > پیکربندی کلیک کنید.

    رفتن به پیکربندی Chat API

  2. در نام برنامه، Incident Management را تایپ کنید.

  3. در نشانی وب چهرک، https://developers.google.com/chat/images/quickstart-app-avatar.png را تایپ کنید.

  4. در شرح، Responds to incidents. را تایپ کنید.

  5. کلید فعال کردن ویژگی‌های تعاملی را به حالت روشن تغییر دهید.

  6. در بخش عملکرد، گزینه پیوستن به فضاها و مکالمه‌های گروهی را انتخاب کنید.

  7. در بخش تنظیمات اتصال، Apps Script را انتخاب کنید.

  8. در شناسه پیاده‌سازی، «شناسه پیاده‌سازی Apps Script» را که قبلاً از پیاده‌سازی پروژه Apps Script کپی کرده‌اید جای‌گذاری کنید.

  9. در بخش محرک‌ها، onAppCommand را برای محرک فرمان برنامه پیکربندی کنید.

  10. فرمان سریعی را که برنامه Chat کاملاً پیاده‌سازی‌شده استفاده می‌کند ثبت کنید:

    1. در بخش فرمان‌ها، روی افزودن فرمان کلیک کنید.

    2. در شناسه فرمان، 1 را تایپ کنید.

    3. در شرح، تایپ کنید Closes the incident being discussed in the space.

    4. در بخش نوع فرمان، فرمان سریع را انتخاب کنید.

    5. در نام فرمان سریع، Close incident را تایپ کنید.

    6. باز کردن کادر گفتگو (یا کادر گفتگو) را انتخاب کنید.

    7. روی تمام کلیک کنید. فرمان ثبت و فهرست می‌شود.

  11. در بخش رؤیت‌پذیری، این برنامه Chat را برای افراد و گروه‌های خاصی در «دامنه Workspace» شما دردسترس قرار دهید و نشانی ایمیلتان را وارد کنید.

  12. در بخش گزارش‌ها، خطاهای گزارش به «گزارش‌گیری» را انتخاب کنید.

  13. روی ذخیره کلیک کنید. پیام ذخیره شدن پیکربندی نمایش داده می‌شود، یعنی برنامه برای آزمایش آماده است.

دریافت تأیید سرپرست

برای دریافت تأیید سرپرست، باید برنامه Chat را در «کیت توسعه نرم‌افزار Google Workspace Marketplace» پیکربندی کنید.

پیکربندی برنامه Chat در «کیت توسعه نرم‌افزار Google Workspace Marketplace»

برای پیکربندی برنامه Chat در کیت توسعه نرم‌افزار (SDK) ‏Google Workspace Marketplace، این مراحل را دنبال کنید:

  1. در «کنسول Google API»، به منو > میاناهای برنامه‌سازی کاربردی و سرویس‌ها > میاناهای برنامه‌سازی کاربردی و سرویس‌های فعال > Google Workspace Marketplace SDK > پیکربندی برنامه بروید.

    رفتن به «پیکربندی برنامه»

  2. صفحه «پیکربندی برنامه» را تکمیل کنید. نحوه پیکربندی برنامه Chat به مخاطب موردنظر شما و عوامل دیگر بستگی دارد. برای دریافت راهنمایی درباره تکمیل صفحه پیکربندی برنامه، پیکربندی برنامه در کیت توسعه نرم‌افزار را ببینید. برای اهداف این راهنما، اطلاعات زیر را وارد کنید:

    1. در بخش رؤیت‌پذیری برنامه، خصوصی را انتخاب کنید.
    2. در بخش تنظیمات نصب، نصب سرپرست را انتخاب کنید.
    3. در بخش یکپارچه‌سازی‌های برنامه، برنامه Chat را انتخاب کنید.
    4. در بخش محدوده‌های OAuth، محدوده‌های زیر را وارد کنید:
      • https://www.googleapis.com/auth/chat.app.spaces
      • https://www.googleapis.com/auth/chat.app.memberships
    5. در بخش اطلاعات توسعه‌دهنده، نام توسعه‌دهنده، نشانی وب‌سایت توسعه‌دهنده، و ایمیل توسعه‌دهنده را وارد کنید.
    6. روی ذخیره پیش‌نویس کلیک کنید.

پس‌از پیکربندی برنامه، فهرستگان فروشگاه را به‌روز کنید:

  1. در کنسول Google Cloud، به منو > میاناهای برنامه‌سازی کاربردی و سرویس‌ها > میاناهای برنامه‌سازی کاربردی و سرویس‌های فعال > Google Workspace Marketplace SDK > فهرستگان فروشگاه بروید.
  2. در جزئیات برنامه، «توسعه وب» را به‌عنوان «دسته» انتخاب کنید.
  3. در اجزای گرافیکی، نمادهای برنامه‌ها را در قالب‌های درخواستی بارگذاری کنید.
  4. در نماگرفت‌ها، نماگرفتی از برنامه بارگذاری کنید.
  5. در پیوندهای پشتیبانی، نشانی وب «شرایط خدمات»، نشانی وب «حریم خصوصی»، و نشانی وب «پشتیبانی» را تکمیل کنید.
  6. در توزیع، مناطقی را که این برنامه در آن‌ها دردسترس خواهد بود انتخاب کنید.
  7. روی منتشر کردن کلیک کنید.

دریافت تأیید سرپرست

اکنون که حساب سرویس شما برای دریافت تأیید سرپرست پیکربندی شده است، آن را از سرپرست Google Workspace که می‌تواند با پیروی از مراحل راه‌اندازی مجوز برای برنامه‌های Chat تأییدیه اعطا کند دریافت کنید.

آزمایش کردن برنامه Chat

برای آزمایش برنامه Chat مدیریت رخداد، رخدادی را از صفحه وب شروع کنید و تأیید کنید که برنامه Chat طبق انتظار کار می‌کند:

  1. به نشانی وب برنامه وب پیاده‌سازی Apps Script بروید.

  2. وقتی Apps Script برای دسترسی به داده‌هایتان اجازه می‌خواهد، روی مرور اجازه‌ها کلیک کنید، با «حساب Google» مناسبی در دامنه Google Workspace خودتان به سیستم وارد شوید، و روی اجازه دادن کلیک کنید.

  3. صفحه وب اولیه رویداد باز می‌شود. اطلاعات آزمایش را وارد کنید:

    1. در عنوان حادثه، The First Incident را تایپ کنید.
    2. درصورت تمایل، در پاسخ‌دهندگان به حادثه، نشانی‌های ایمیل پاسخ‌دهندگان به حادثه همکارتان را وارد کنید. آن‌ها باید کاربرانی با حساب Google Chat در سازمان Google Workspace شما باشند، درغیراین‌صورت فضا ایجاد نمی‌شود. نشانی ایمیل خودتان را وارد نکنید زیرا به‌طور خودکار اضافه می‌شود.
    3. در پیام اولیه، Testing the incident management Chat app. را تایپ کنید
  4. روی ایجاد فضای گپ کلیک کنید. پیام creating space ظاهر می‌شود.

  5. پس‌از ایجاد فضا، پیام Space created! نشان داده می‌شود. روی باز کردن فضا کلیک کنید، که فضا را در Chat در زبانه جدیدی باز می‌کند.

  6. درصورت تمایل، شما و دیگر پاسخ‌دهندگان به حادثه می‌توانید در فضا پیام ارسال کنید. این برنامه بااستفاده از Vertex AI این پیام‌ها را خلاصه می‌کند و سند گذشته‌نگری هم‌رسانی می‌کند.

  7. برای پایان دادن به پاسخ به حادثه و شروع فرایند حل‌وفصل، در فضای Chat، فرمان سریع Close incident را راه‌اندازی کنید. کادر گفتگوی مدیریت رویداد باز می‌شود.

  8. در بستن حادثه، شرحی برای حل‌وفصل حادثه وارد کنید، مثلاً Test complete.

  9. روی بستن حادثه کلیک کنید.

برنامه «مدیریت رخداد» پیام‌های فضا را فهرست می‌کند، آن‌ها را با Vertex AI خلاصه می‌کند، خلاصه را در سند «سندنگار Google» جای‌گذاری می‌کند، و سند را در فضا هم‌رسانی می‌کند.

مرتب‌سازی

برای اینکه هزینه منابع استفاده‌شده در این آموزش به حساب Google Cloud شما اضافه نشود، توصیه می‌کنیم پروژه Cloud را حذف کنید.

  1. در «کنسول Google API»، به صفحه مدیریت منابع بروید. روی منو > IAM و سرپرست > مدیریت منابع کلیک کنید.

    به «مدیر منابع» بروید

  2. در فهرست پروژه، پروژه‌ای را که می‌خواهید حذف کنید انتخاب کنید و سپس روی حذف کلیک کنید.
  3. در چارگوش گفتگو، شناسه پروژه را تایپ کنید و سپس روی خاموش کردن کلیک کنید تا پروژه حذف شود.
  • برنامه پاسخ به حادثه با اطلاعات کاربری کاربر احراز هویت می‌کند تا میاناهای برنامه‌سازی کاربردی را فراخوانی کند و خدمات Google Cloud، مانند میانای برنامه‌سازی کاربردی Chat و میانای برنامه‌سازی کاربردی Vertex AI را فراخوانی کند. این یعنی کاربری که حادثه‌ای را آغاز می‌کند باید به این سرویس‌ها دسترسی داشته باشد. برای اینکه برنامه قوی‌تر شود، به‌جای اطلاعات اعتباری کاربر فراخواننده فرمان سریع Close incident، با حساب خدمات با Vertex AI API تماس بگیرید. برای دریافت راهنمایی درباره پیکربندی حساب سرویس برای Vertex AI API، به استفاده از حساب سرویس سفارشی مراجعه کنید.

برنامه‌های گپ که برافزا نیستند: با Google Chat،‏ Vertex AI، و Google Apps Script (احراز هویت برنامه) به حوادث پاسخ دهید

دستورالعمل‌ها و نمونه‌های کد زیر برای برنامه Chat که برافزای Google Workspace نیست اعمال می‌شود (مشاهده در GitHub).

ایجاد و پیکربندی پروژه Apps Script

  1. پروژه Apps Script پاسخ به رویدادها با Google Chat برای برنامه Chat که برافزا نیست را باز کنید و کپی کنید.
  2. هنگام پیکربندی Chat API در «کنسول Google API»: ساخت این برنامه Chat به‌عنوان برافزای Google Workspace را لغو انتخاب کنید. کادر گفتگویی باز می‌شود که از شما می‌خواهد تأیید کنید. در چارگوش گفتگو، روی غیرفعال کردن کلیک کنید.
  3. فرمان خط مورب /closeIncident (شناسه فرمان 1، کادر گفتگویی را باز می‌کند را انتخاب کنید) را ثبت کنید و /closeIncident را در فضا تایپ کنید تا مشکل حل شود.

کد منبع

Consts.gs
apps-script/incident-response-app-auth/Consts.gs
const PROJECT_ID = 'replace-with-your-project-id';
const CLOSE_INCIDENT_COMMAND_ID = 1;
const APP_CREDENTIALS = 'replace-with-your-app-credentials';
const APP_CREDENTIALS_SCOPES = 'https://www.googleapis.com/auth/chat.bot https://www.googleapis.com/auth/chat.app.memberships https://www.googleapis.com/auth/chat.app.spaces.create';
const VERTEX_AI_LOCATION_ID = 'us-central1';
const MODEL_ID = 'gemini-1.5-flash-002';
ChatApp.gs
apps-script/incident-response-app-auth/ChatApp.gs
/**
 * Responds to a MESSAGE event in Google Chat.
 *
 * This app only responds to a slash command with the ID 1 ("/closeIncident").
 * It will respond to any other message with a simple "Hello" text message.
 *
 * @param {Object} event the event object from Google Chat
 */
function onMessage(event) {
  if (event.message.slashCommand) {
    return processSlashCommand_(event);
  }
  return { "text": "Hello from Incident Response app!" };
}

/**
 * Responds to a CARD_CLICKED event in Google Chat.
 *
 * This app only responds to one kind of dialog (Close Incident).
 *
 * @param {Object} event the event object from Google Chat
 */
function onCardClick(event) {
  if (event.isDialogEvent) {
    if (event.dialogEventType == 'SUBMIT_DIALOG') {
      return processSubmitDialog_(event);
    }
    return {
      actionResponse: {
        type: "DIALOG",
        dialogAction: {
          actionStatus: "OK"
        }
      }
    };
  }
}

/**
 * Responds to a MESSAGE event with a Slash command in Google Chat.
 *
 * This app only responds to a slash command with the ID 1 ("/closeIncident")
 * by returning a Dialog.
 *
 * @param {Object} event the event object from Google Chat
 */
function processSlashCommand_(event) {
  if (event.message.slashCommand.commandId != CLOSE_INCIDENT_COMMAND_ID) {
    return {
      "text": "Command not recognized. Use the command `/closeIncident` to close the incident managed by this space."
    };
  }
  const sections = [
    {
      header: "Close Incident",
      widgets: [
        {
          textInput: {
            label: "Please describe the incident resolution",
            type: "MULTIPLE_LINE",
            name: "description"
          }
        },
        {
          buttonList: {
            buttons: [
              {
                text: "Close Incident",
                onClick: {
                  action: {
                    function: "closeIncident"
                  }
                }
              }
            ]
          }
        }
      ]
    }
  ];
  return {
    actionResponse: {
      type: "DIALOG",
      dialogAction: {
        dialog: {
          body: {
            sections,
          }
        }
      }
    }
  };
}

/**
 * Responds to a CARD_CLICKED event with a Dialog submission in Google Chat.
 *
 * This app only responds to one kind of dialog (Close Incident).
 * It creates a Doc with a summary of the incident information and posts a message
 * to the space with a link to the Doc.
 *
 * @param {Object} event the event object from Google Chat
 */
function processSubmitDialog_(event) {
  const resolution = event.common.formInputs.description[""].stringInputs.value[0];
  const chatHistory = concatenateAllSpaceMessages_(event.space.name);
  const chatSummary = summarizeChatHistory_(chatHistory);
  const docUrl = createDoc_(event.space.displayName, resolution, chatHistory, chatSummary);
  return {
    actionResponse: {
      type: "NEW_MESSAGE",
    },
    text: `Incident closed with the following resolution: ${resolution}\n\nHere is the automatically generated post-mortem:\n${docUrl}`
  };
}

/**
 * Lists all the messages in the Chat space, then concatenate all of them into
 * a single text containing the full Chat history.
 *
 * For simplicity for this demo, it only fetches the first 100 messages.
 *
 * Messages with slash commands are filtered out, so the returned history will
 * contain only the conversations between users and not app command invocations.
 *
 * @return {string} a text containing all the messages in the space in the format:
 *          Sender's name: Message
 */
function concatenateAllSpaceMessages_(spaceName) {
  // Call Chat API method spaces.messages.list
  const response = Chat.Spaces.Messages.list(spaceName, { 'pageSize': 100 });
  const messages = response.messages;
  // Fetch the display names of the message senders and returns a text
  // concatenating all the messages.
  let userMap = new Map();
  return messages
    .filter(message => message.slashCommand === undefined)
    .map(message => `${getUserDisplayName_(userMap, message.sender.name)}: ${message.text}`)
    .join('\n');
}

/**
 * Obtains the display name of a user by using the Admin Directory API.
 *
 * The fetched display name is cached in the provided map, so we only call the API
 * once per user.
 *
 * If the user does not have a display name, then the full name is used.
 *
 * @param {Map} userMap a map containing the display names previously fetched
 * @param {string} userName the resource name of the user
 * @return {string} the user's display name
 */
function getUserDisplayName_(userMap, userName) {
  if (userMap.has(userName)) {
    return userMap.get(userName);
  }
  let displayName = 'Unknown User';
  try {
    const user = AdminDirectory.Users.get(
      userName.replace("users/", ""),
      { projection: 'BASIC', viewType: 'domain_public' });
    displayName = user.name.displayName ? user.name.displayName : user.name.fullName;
  } catch (e) {
    // Ignore error if the API call fails (for example, because it's an
    // out-of-domain user or Chat app)) and just use 'Unknown User'.
  }
  userMap.set(userName, displayName);
  return displayName;
}
ChatSpaceCreator.gs
apps-script/incident-response-app-auth/ChatSpaceCreator.gs
/**
 * Handles an incident by creating a chat space, adding members, and posting a message.
 * All the actions are done using application credentials.
 *
 * @param {Object} formData - The data submitted by the user. It should contain the fields:
 *                           - title: The display name of the chat space.
 *                           - description: The description of the incident.
 *                           - users: A comma-separated string of user emails to be added to the space.
 * @return {string} The resource name of the new space.
 */
function handleIncident(formData) {
  const users = formData.users.trim().length > 0 ? formData.users.split(',') : [];
  const service = getService_();
  if (!service.hasAccess()) {
    console.error(service.getLastError());
    return;
   }
  const spaceName = createChatSpace_(formData.title, service);
  createHumanMembership_(spaceName, getUserEmail(), service);
  for (const user of users ){
    createHumanMembership_(spaceName, user, service);
  }
  createMessage_(spaceName, formData.description, service);
  return spaceName;
}
/**
 * Creates a chat space with application credentials.
 *
 * @param {string} displayName - The name of the chat space.
 * @param {object} service - The credentials of the service account.
 * @returns {string} The resource name of the new space.
*/
function createChatSpace_(displayName, service) {
  try {
    // For private apps, the alias can be used
    const my_customer_alias = "customers/my_customer";
    // Specify the space to create.
    const space = {
        displayName: displayName,
        spaceType: 'SPACE',                
        customer: my_customer_alias
    };
    // Call Chat API with a service account to create a message.
    const createdSpace = Chat.Spaces.create(
        space,
        {},
        // Authenticate with the service account token.
        {'Authorization': 'Bearer ' + service.getAccessToken()});
    return createdSpace.name;
  } catch (err) {
    // TODO (developer) - Handle exception.
    console.log('Failed to create space with error %s', err.message);
  }
}
/*
 * Creates a chat message with application credentials.
 *
 * @param {string} spaceName - The resource name of the space.
 * @param {string} message - The text to be posted.
 * @param {object} service - The credentials of the service account.
 * @return {string} the resource name of the new space.
 */
function createMessage_(spaceName, message, service) {
  try {
    // Call Chat API with a service account to create a message.
    const result = Chat.Spaces.Messages.create(
        {'text': message},
        spaceName,
        {},
        // Authenticate with the service account token.
        {'Authorization': 'Bearer ' + service.getAccessToken()});

  } catch (err) {
    // TODO (developer) - Handle exception.
    console.log('Failed to create message with error %s', err.message);
  }
}
/**
 * Creates a human membership in a chat space with application credentials.
 *
 * @param {string} spaceName - The resource name of the space.
 * @param {string} email - The email of the user to be added.
 * @param {object} service - The credentials of the service account.
 */
function createHumanMembership_(spaceName, email, service){
  try{
    const membership = {
      member: {
        name: 'users/'+email,
        // User type for the membership
        type: 'HUMAN'
      }
    };
    const result = Chat.Spaces.Members.create(
      membership,
      spaceName,
      {},
      {'Authorization': 'Bearer ' + service.getAccessToken()}
    );
  } catch (err){
    console.log('Failed to create membership with error %s', err.message)
  }

}

 /*
 * Creates a service for the service account.
 * @return {object}  - The credentials of the service account.
 */
function getService_() {
  return OAuth2.createService(APP_CREDENTIALS.client_email)
      .setTokenUrl('https://oauth2.googleapis.com/token')
      .setPrivateKey(APP_CREDENTIALS.private_key)
      .setIssuer(APP_CREDENTIALS.client_email)
      .setSubject(APP_CREDENTIALS.client_email)
      .setScope(APP_CREDENTIALS_SCOPES)
      .setPropertyStore(PropertiesService.getScriptProperties());
}
DocsApi.gs
apps-script/incident-response-app-auth/DocsApi.gs
/**
 * Creates a Doc in the user's Google Drive and writes a summary of the incident information to it.
 *
 * @param {string} title The title of the incident
 * @param {string} resolution Incident resolution described by the user
 * @param {string} chatHistory The whole Chat history be included in the document
 * @param {string} chatSummary A summary of the Chat conversation to be included in the document
 * @return {string} the URL of the created Doc
 */
function createDoc_(title, resolution, chatHistory, chatSummary) {
  let doc = DocumentApp.create(title);
  let body = doc.getBody();
  body.appendParagraph(`Post-Mortem: ${title}`).setHeading(DocumentApp.ParagraphHeading.TITLE);
  body.appendParagraph("Resolution").setHeading(DocumentApp.ParagraphHeading.HEADING1);
  body.appendParagraph(resolution);
  body.appendParagraph("Summary of the conversation").setHeading(DocumentApp.ParagraphHeading.HEADING1);
  body.appendParagraph(chatSummary);
  body.appendParagraph("Full Chat history").setHeading(DocumentApp.ParagraphHeading.HEADING1);
  body.appendParagraph(chatHistory);
  return doc.getUrl();
}
VertexAiApi.gs
apps-script/incident-response-app-auth/VertexAiApi.gs
/**
 * Summarizes a Chat conversation using the Vertex AI text prediction API.
 *
 * @param {string} chatHistory The Chat history that will be summarized.
 * @return {string} The content from the text prediction response.
 */


function summarizeChatHistory_(chatHistory) {

  const API_ENDPOINT = `https://${VERTEX_AI_LOCATION_ID}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${VERTEX_AI_LOCATION_ID}/publishers/google/models/${MODEL_ID}:generateContent`;
  const prompt = "Summarize the following conversation between Engineers resolving an incident"
      + " in a few sentences. Use only the information from the conversation.\n\n" + chatHistory;
  // Get the access token.
  const accessToken = ScriptApp.getOAuthToken();

  const headers = {
    'Authorization': 'Bearer ' + accessToken,
    'Content-Type': 'application/json',
  };
  const payload = {
    'contents': {
      'role': 'user',
      'parts' : [
        {
          'text': prompt
        }
      ]
    }
  }
  const options = {
    'method': 'post',
    'headers': headers,
    'payload': JSON.stringify(payload),
    'muteHttpExceptions': true,
  };
  try {
    const response = UrlFetchApp.fetch(API_ENDPOINT, options);
    const responseCode = response.getResponseCode();
    const responseText = response.getContentText();

    if (responseCode === 200) {
      const jsonResponse = JSON.parse(responseText);
      console.log(jsonResponse)
      if (jsonResponse.candidates && jsonResponse.candidates.length > 0) {
        return jsonResponse.candidates[0].content.parts[0].text; // Access the summarized text
      } else {
        return "No summary found in response.";
      }

    } else {
      console.error("Vertex AI API Error:", responseCode, responseText);
      return `Error: ${responseCode} - ${responseText}`;
    }
  } catch (e) {
    console.error("UrlFetchApp Error:", e);
    return "Error: " + e.toString();
  }
}
WebController.gs
apps-script/incident-response-app-auth/WebController.gs
/**
 * Serves the web page from Index.html.
 */
function doGet() {
  return HtmlService
    .createTemplateFromFile('Index')
    .evaluate();
}

/**
 * Serves the web content from the specified filename.
 */
function include(filename) {
  return HtmlService
    .createHtmlOutputFromFile(filename)
    .getContent();
}

/**
 * Returns the email address of the user running the script.
 */
function getUserEmail() {
  return Session.getActiveUser().getEmail();
}
Index.html
apps-script/incident-response-app-auth/Index.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet'>
    <?!= include('Stylesheet'); ?>
  </head>
  <body>
    <div class="container">
      <div class="content">
        <h1>Incident Manager</h1>
        <form id="incident-form" onsubmit="handleFormSubmit(this)">
          <div id="form">
            <p>
              <label for="title">Incident title</label><br/>
              <input type="text" name="title" id="title" />
            </p>
            <p>
              <label for="users">Incident responders</label><br/>
              <small>
                Please enter a comma-separated list of email addresses of the users
                that should be added to the space.
                Do not include <?= getUserEmail() ?> as it will be added automatically.
              </small><br/>
              <input type="text" name="users" id="users" />
            </p>
            <p>
              <label for="description">Initial message</label></br>
              <small>This message will be posted after the space is created.</small><br/>
              <textarea name="description" id="description"></textarea>
            </p>
            <p class="text-center">
              <input type="submit" value="CREATE CHAT SPACE" />
            </p>
          </div>
          <div id="output" class="hidden"></div>
          <div id="clear" class="hidden">
            <input type="reset" value="CREATE ANOTHER INCIDENT" onclick="onReset()" />
          </div>
        </form>
      </div>
    </div>
    <?!= include('JavaScript'); ?>
  </body>
</html>
JavaScript.html
apps-script/incident-response-app-auth/JavaScript.html
<script>
  var formDiv = document.getElementById('form');
  var outputDiv = document.getElementById('output');
  var clearDiv = document.getElementById('clear');

  function handleFormSubmit(formObject) {
    event.preventDefault();
    outputDiv.innerHTML = 'Please wait while we create the space...';
    hide(formDiv);
    show(outputDiv);
    google.script.run
      .withSuccessHandler(updateOutput)
      .withFailureHandler(onFailure)
      .handleIncident(formObject);
  }

  function updateOutput(response) {
    var spaceId = response.replace('spaces/', '');
    outputDiv.innerHTML =
      '<p>Space created!</p><p><a href="https://mail.google.com/chat/#chat/space/'
        + spaceId
        + '" target="_blank">Open space</a></p>';
    show(outputDiv);
    show(clearDiv);
  }

  function onFailure(error) {
    outputDiv.innerHTML = 'ERROR: ' + error.message;
    outputDiv.classList.add('error');
    show(outputDiv);
    show(clearDiv);
  }

  function onReset() {
    outputDiv.innerHTML = '';
    outputDiv.classList.remove('error');
    show(formDiv);
    hide(outputDiv);
    hide(clearDiv);
  }

  function hide(element) {
    element.classList.add('hidden');
  }

  function show(element) {
    element.classList.remove('hidden');
  }
</script>
Stylesheet.html
apps-script/incident-response-app-auth/Stylesheet.html
<style>
  * {
    box-sizing: border-box;
  }
  body {
    font-family: Roboto, Arial, Helvetica, sans-serif;
  }
  div.container {
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    top: 0; bottom: 0; left: 0; right: 0;
  }
  div.content {
    width: 80%;
    max-width: 1000px;
    padding: 1rem;
    border: 1px solid #999;
    border-radius: 0.25rem;
    box-shadow: 0 2px 2px 0 rgba(66, 66, 66, 0.08), 0 2px 4px 2px rgba(66, 66, 66, 0.16);
  }
  h1 {
    text-align: center;
    padding-bottom: 1rem;
    margin: 0 -1rem 1rem -1rem;
    border-bottom: 1px solid #999;
  }
 #output {
    text-align: center;
    min-height: 250px;
  }
  div#clear {
    text-align: center;
    padding-top: 1rem;
    margin: 1rem -1rem 0 -1rem;
    border-top: 1px solid #999;
  }
  input[type=text], textarea {
    width: 100%;
    padding: 1rem 0.5rem;
    margin: 0.5rem 0;
    border: 0;
    border-bottom: 1px solid #999;
    background-color: #f0f0f0;
  }
  textarea {
    height: 5rem;
  }
  small {
    color: #999;
  }
  input[type=submit], input[type=reset] {
    padding: 1rem;
    border: none;
    background-color: #6200ee;
    color: #fff;
    border-radius: 0.25rem;
    width: 25%;
  }
  .hidden {
    display: none;
  }
  .text-center {
    text-align: center;
  }
  .error {
    color: red;
  }
</style>