/**
* 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;
}
/**
* Creates a space in Google Chat with the provided title and members, and posts an
* initial message to it.
*
* @param {Object} formData the data submitted by the user. It should contain the fields
* title, description, and users.
* @return {string} the resource name of the new space.
*/
function createChatSpace(formData) {
const users = formData.users.trim().length > 0 ? formData.users.split(',') : [];
const spaceName = setUpSpace_(formData.title, users);
addAppToSpace_(spaceName);
createMessage_(spaceName, formData.description);
return spaceName;
}
/**
* Creates a space in Google Chat with the provided display name and members.
*
* @return {string} the resource name of the new space.
*/
function setUpSpace_(displayName, users) {
const memberships = users.map(email => ({
member: {
name: `users/${email}`,
type: "HUMAN"
}
}));
const request = {
space: {
displayName: displayName,
spaceType: "SPACE",
externalUserAllowed: true
},
memberships: memberships
};
// Call Chat API method spaces.setup
const space = Chat.Spaces.setup(request);
return space.name;
}
/**
* Adds this Chat app to the space.
*
* @return {string} the resource name of the new membership.
*/
function addAppToSpace_(spaceName) {
const request = {
member: {
name: "users/app",
type: "BOT"
}
};
// Call Chat API method spaces.members.create
const membership = Chat.Spaces.Members.create(request, spaceName);
return membership.name;
}
/**
* Posts a text message to the space on behalf of the user.
*
* @return {string} the resource name of the new message.
*/
function createMessage_(spaceName, text) {
const request = {
text: text
};
// Call Chat API method spaces.messages.create
const message = Chat.Spaces.Messages.create(request, spaceName);
return message.name;
}
DocsApi.gs
เรียกใช้ Google Docs API เพื่อสร้างเอกสารของ Google เอกสารใน
Google ไดรฟ์ของผู้ใช้ และเขียนข้อมูลสรุปเกี่ยวกับเหตุการณ์
ที่สร้างใน VertexAiApi.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 ข้อมูลสรุปนี้โพสต์ไว้ในหมวดหมู่
เอกสารใน DocsAPI.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 prompt =
"Summarize the following conversation between Engineers resolving an incident"
+ " in a few sentences. Use only the information from the conversation.\n\n"
+ chatHistory;
const request = {
instances: [
{ prompt: prompt }
],
parameters: {
temperature: 0.2,
maxOutputTokens: 256,
topK: 40,
topP: 0.95
}
}
const fetchOptions = {
method: 'POST',
headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
contentType: 'application/json',
payload: JSON.stringify(request)
}
const response = UrlFetchApp.fetch(
`https://${VERTEX_AI_LOCATION_ID}-aiplatform.googleapis.com/v1`
+ `/projects/${PROJECT_ID}/locations/${VERTEX_AI_LOCATION_ID}`
+ "/publishers/google/models/text-bison:predict",
fetchOptions);
const payload = JSON.parse(response.getContentText());
return payload.predictions[0].content;
}
/**
* 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();
}
จด URL ของเว็บแอปไว้เพื่อเข้าชมในภายหลังเมื่อเริ่มเหตุการณ์
คัดลอกรหัสการทำให้ใช้งานได้ คุณใช้รหัสนี้ขณะกำหนดค่า
แอป Chat ในคอนโซล Google Cloud
คลิกเสร็จสิ้น
กำหนดค่าแอป Chat ในคอนโซล Google Cloud
ส่วนนี้จะแสดงวิธีกำหนดค่า Google Chat API ในคอนโซล Google Cloud
ที่มีข้อมูลเกี่ยวกับแอป Chat ของคุณ รวมถึง
รหัสการทำให้ใช้งานได้ที่คุณเพิ่งสร้างจาก Apps Script
ในคอนโซล Google Cloud ให้คลิกเมนูmenu>ผลิตภัณฑ์อื่นๆ>Google Workspace>คลังผลิตภัณฑ์>Google Chat API>จัดการ>การกำหนดค่า
ในปิดเหตุการณ์ ให้ป้อนคำอธิบายสำหรับการแก้ไขเหตุการณ์
เช่น Test complete
คลิกปิดเหตุการณ์
แอปการจัดการเหตุการณ์จะแสดงข้อความในพื้นที่ทำงานและสรุปข้อความเหล่านั้น
ด้วย Vertex AI วางข้อมูลสรุปในเอกสาร Google เอกสาร และแชร์
เอกสารในพื้นที่ทำงาน
ล้างข้อมูล
เพื่อเลี่ยงไม่ให้เกิดการเรียกเก็บเงินกับบัญชี Google Cloud ของคุณตาม
ซึ่งใช้ในบทแนะนำนี้ เราขอแนะนำให้คุณลบ
โปรเจ็กต์ที่อยู่ในระบบคลาวด์
ในคอนโซล Google Cloud ให้ไปที่หน้าจัดการทรัพยากร คลิก
เมนูmenu>IAM และ ผู้ดูแลระบบ>จัดการทรัพยากร
แอปตอบสนองต่อเหตุการณ์ตรวจสอบสิทธิ์ด้วยข้อมูลเข้าสู่ระบบของผู้ใช้เพื่อเรียกใช้ API
และเรียกใช้บริการ Google Cloud เช่น Chat API และ Vertex AI API
ซึ่งหมายความว่าผู้ใช้ที่เริ่มต้นเหตุการณ์ต้องมีสิทธิ์เข้าถึงเหตุการณ์เหล่านี้
บริการต่างๆ ลองเรียกใช้ Vertex AI API เพื่อให้แอปมีประสิทธิภาพยิ่งขึ้น
ด้วยบัญชีบริการ แทนที่จะเป็นข้อมูลเข้าสู่ระบบของผู้ใช้ที่เรียกใช้
คำสั่งเครื่องหมายทับ /closeIncident สำหรับความช่วยเหลือในการกำหนดค่าบัญชีบริการ
สำหรับ Vertex AI API โปรดดู
ใช้บัญชีบริการที่กำหนดเอง