1. Giới thiệu
Google Workspace Studio cho phép bạn tự động hoá các quy trình kinh doanh trên các ứng dụng của Google Workspace như Gmail, Google Chat, Google Drive và Google Trang tính. Khi quy trình công việc của bạn cần bắt đầu từ một ứng dụng web bên ngoài hoặc chạy logic tuỳ chỉnh trong môi trường đám mây của riêng bạn, bạn có thể mở rộng Google Workspace Studio bằng Tiện ích bổ sung của Google Workspace HTTP trong Node.js trên Cloud Run:
- Bước bắt đầu tuỳ chỉnh (
workflowTrigger): Bắt đầu một quy trình của Google Workspace Studio khi một sự kiện bên ngoài xảy ra (chẳng hạn như khách hàng gửi phiếu yêu cầu hỗ trợ trong một cổng thông tin nội bộ trên web) bằng cách gọi API RESTtriggers.firecủa Google Workspace Studio. - Bước hành động tuỳ chỉnh (
workflowAction): Nhận các biến từ những bước trước đó trong quy trình, chạy logic tuỳ chỉnh hoặc suy luận AI trong dịch vụ Node.js của bạn và trả các biến đầu ra về Google Workspace Studio.
Trong lớp học lập trình này, bạn sẽ xây dựng và triển khai một tiện ích HTTP hoàn chỉnh bằng Node.js cho Google Workspace Studio trên Cloud Run, sử dụng Cloud Firestore để duy trì các lượt đăng ký kích hoạt quy trình đang hoạt động và các phiếu yêu cầu hỗ trợ đã gửi trên các bản sửa đổi vùng chứa, đồng thời phân loại mức độ khẩn cấp của phiếu yêu cầu hỗ trợ trong bước thao tác tuỳ chỉnh bằng Gemini 3.8 Flash (gemini-3.8-flash) trên Nền tảng tác nhân Gemini Enterprise với một cơ chế dự phòng so khớp từ khoá linh hoạt.
Sản phẩm bạn sẽ tạo ra
- Một ứng dụng web Support Quick Portal và tiện ích bổ sung HTTP của Google Workspace được tạo bằng Node.js, Express và Firestore trên Cloud Run.
- Bước bắt đầu tuỳ chỉnh Phiếu yêu cầu hỗ trợ mới (
supportTicketTrigger) duy trì các lượt đăng ký quy trình đang hoạt động trong một bộ sưu tậpstudio_triggersFirestore, ghi nhật ký các phiếu yêu cầu đã gửi trong một bộ sưu tậpsupport_ticketsFirestore và kích hoạt bất cứ khi nào một phiếu yêu cầu được gửi trong cổng thông tin web – truyềnticketTitlevàticketDescriptionvào một quy trình Google Workspace Studio. - Một bước thao tác tuỳ chỉnh Phát hiện mức độ khẩn cấp (
urgencyDetectorStep) phân loại mức độ khẩn cấp của phiếu yêu cầu hỗ trợ bằng Gemini 3.8 Flash (gemini-3.8-flash) trên Nền tảng Tác nhân Gemini Enterprise (aiplatform.googleapis.com), với cơ chế dự phòng tự động là so khớp từ khoá (urgent,blocker,critical).
Kiến thức bạn sẽ học được
- Cách định cấu hình tệp kê khai triển khai Tiện ích bổ sung Google Workspace HTTP (
deployment.json) bằng các phần tửworkflowTriggervàworkflowAction. - Cách duy trì các lượt đăng ký kích hoạt Google Workspace Studio (
triggerId,notifyUrivàuserOAuthToken) trong một bộ sưu tậpstudio_triggersFirestore và kích hoạt các luồng bằng cách sử dụng API RESTtriggers.fire. - Cách tạo một bước tuỳ chỉnh
workflowActiontrong Node.js bằng đầu ra có cấu trúc Gemini 3.8 Flash (gemini-3.8-flash) trên Nền tảng Tác nhân Gemini Enterprise với một từ khoá dự phòng.
Điều kiện tiên quyết
- Tài khoản Google Workspace có quyền truy cập vào Google Workspace Studio.
- Một dự án Google Cloud đã bật tính năng thanh toán, được tạo trong cùng một tổ chức Google Workspace với tài khoản người dùng của bạn để bạn có thể cài đặt các bản triển khai tiện ích bổ sung chưa xuất bản để kiểm thử.
2. Thiết lập dự án trên đám mây của Google Cloud và Firestore
Trong bước này, bạn sẽ định cấu hình màn hình xin phép bằng OAuth của dự án, bật các API Google Cloud và Google Workspace cần thiết trong Cloud Shell, cung cấp cơ sở dữ liệu (default) Firestore và khởi chạy tài khoản dịch vụ uỷ quyền tiện ích bổ sung.
- Mở Google Cloud Console, chọn dự án trên đám mây của bạn trên Google Cloud rồi nhấp vào biểu tượng Kích hoạt Cloud Shell trong thanh điều hướng trên cùng.
- Định cấu hình màn hình xin phép bằng OAuth để Google Workspace có thể cung cấp một ứng dụng OAuth cho tiện ích bổ sung của bạn:
- Mở trang Thương hiệu của Nền tảng xác thực của Google.
- Nếu được nhắc, hãy nhấp vào Bắt đầu. (Nếu bạn đã định cấu hình màn hình xin phép, hãy chuyển sang bước 3.)
- Trong phần Thông tin ứng dụng, hãy nhập
Support Extensioncho Tên ứng dụng, chọn Email hỗ trợ người dùng rồi nhấp vào Tiếp theo. - Trong phần Đối tượng, hãy chọn Nội bộ rồi nhấp vào Tiếp theo.
- Trong phần Thông tin liên hệ, hãy nhập địa chỉ email của bạn rồi nhấp vào Tiếp theo.
- Trong phần Hoàn tất, hãy đồng ý với Chính sách dữ liệu người dùng của dịch vụ API của Google, nhấp vào Tiếp tục rồi nhấp vào Tạo.
- Trong Cloud Shell, hãy đặt dự án đang hoạt động (thay thế
YOUR_PROJECT_IDbằng mã dự án Google Cloud của bạn) và bật các API bắt buộc:gcloud config set project YOUR_PROJECT_ID gcloud services enable \ aiplatform.googleapis.com \ firestore.googleapis.com \ run.googleapis.com \ cloudbuild.googleapis.com \ artifactregistry.googleapis.com \ appsmarket-component.googleapis.com \ gsuiteaddons.googleapis.com \ workspacestudio.googleapis.com - Cung cấp cơ sở dữ liệu
(default)Firestore trongus-central1(nếu chưa có) và khởi chạy tài khoản dịch vụ Google Workspace Add-ons:gcloud firestore databases describe --database="(default)" >/dev/null 2>&1 || \ gcloud firestore databases create \ --database="(default)" \ --location=us-central1 \ --type=firestore-native \ --quiet gcloud workspace-add-ons get-authorization
3. Tạo ứng dụng Node.js bằng Firestore và Gemini 3.8 Flash
Trong bước này, bạn sẽ tạo ứng dụng Node.js trong ~/studio-support-addon. Để giữ cho mã có tính mô-đun và dễ đọc, bạn sẽ sắp xếp dự án thành 5 tệp tập trung:
firestore.js: Khởi động ứng dụng Cloud Firestore (các tập hợpstudio_triggersvàsupport_tickets) và làm mới mã thông báo OAuth được lưu vào bộ nhớ đệm.starter.js: Triển khai webhook của bước bắt đầu tuỳ chỉnh Phiếu yêu cầu hỗ trợ mới (/onConfigTriggervà/onManageTrigger).action.js: Triển khai webhook của bước thao tác tuỳ chỉnh Phát hiện mức độ khẩn cấp (/onConfigUrgencyvà/onExecuteUrgency) bằng Gemini 3.8 Flash (gemini-3.8-flash) với một phương án dự phòng khớp từ khoá.portal.js: Phục vụ giao diện người dùng web Support Quick Portal (GET /) và kích hoạt các trình kích hoạt Google Workspace Studio đang hoạt động (POST /api/submit-ticket).index.js: Kết nối tất cả các tuyến đường Express với nhau và khởi động máy chủ HTTP.
Khởi động dự án và package.json
- Tạo một thư mục dự án rồi chuyển đến thư mục đó:
mkdir -p ~/studio-support-addon && cd ~/studio-support-addon - Tạo
package.jsonbằngexpress,@google-cloud/firestorevà@google/genai:cat << 'EOF' > package.json { "name": "studio-support-addon", "version": "1.0.0", "type": "module", "main": "index.js", "scripts": { "start": "node index.js" }, "dependencies": { "@google-cloud/firestore": "^7.11.0", "@google/genai": "^1.0.0", "express": "^4.21.2" } } EOF
firestore.js – Trạng thái Firestore được chia sẻ và làm mới mã thông báo OAuth
Tạo firestore.js để quản lý 2 tập hợp Firestore và luôn cập nhật mã thông báo OAuth của người dùng đã lưu vào bộ nhớ đệm:
studio_triggers: Lưu trữ các gói thuê bao Google Workspace Studio đang hoạt động (triggerId,notifyUrivàuserOAuthToken) để các gói này vẫn hoạt động sau khi Cloud Run khởi động lại vùng chứa và các sự kiện giảm xuống 0.support_tickets: Lưu trữ hồ sơ của từng phiếu yêu cầu hỗ trợ được gửi qua cổng thông tin.refreshTokenInFirestore(req): Bất cứ khi nào Google Workspace Studio gọi bất kỳ điểm cuối webhook nào của bạn, hệ thống sẽ bao gồm mộtauthorizationEventObject.userOAuthTokencó thời hạn ngắn. Trợ giúp này sẽ cập nhật mã thông báo mới nhất cho các tài liệu kích hoạt đang hoạt động để các lệnh gọitriggers.fireở chế độ nền vẫn được uỷ quyền.
cat << 'EOF' > firestore.js
import { Firestore } from '@google-cloud/firestore';
export const db = new Firestore({
projectId: process.env.GOOGLE_CLOUD_PROJECT || undefined,
databaseId: '(default)',
ignoreUndefinedProperties: true,
});
export const triggersCollection = db.collection(
process.env.FIRESTORE_TRIGGERS_COLLECTION || 'studio_triggers'
);
export const ticketsCollection = db.collection(
process.env.FIRESTORE_TICKETS_COLLECTION || 'support_tickets'
);
// Keep cached userOAuthToken fresh across active trigger documents
export async function refreshTokenInFirestore(req) {
const freshToken = req.body?.authorizationEventObject?.userOAuthToken;
if (!freshToken) return;
try {
const snapshot = await triggersCollection.get();
if (snapshot.empty) return;
const batch = db.batch();
snapshot.docs.forEach((doc) => {
batch.set(
doc.ref,
{ userOAuthToken: freshToken, updatedAt: new Date().toISOString() },
{ merge: true }
);
});
await batch.commit();
} catch (err) {
console.error('Error refreshing OAuth token in Firestore:', err.message);
}
}
EOF
starter.js – Bước tuỳ chỉnh để bắt đầu (workflowTrigger)
Tạo starter.js để triển khai 2 điểm cuối webhook mà bước bắt đầu tuỳ chỉnh của Google Workspace Studio yêu cầu:
onConfigTrigger(POST /onConfigTrigger): Được gọi khi người dùng chọn Phiếu yêu cầu hỗ trợ mới làm điểm bắt đầu của quy trình trong Google Workspace Studio. Trả về một thao tác điều hướngpushCardmô tả thành phần khởi động.onManageTrigger(POST /onManageTrigger): Được gọi khi người dùng Bật (req.body.workflow.triggerCreation) hoặc Tắt / xoá (req.body.workflow.triggerDeletion) một luồng. Lưu hoặc xoá tài liệu đăng ký trong bộ sưu tậpstudio_triggersFirestore.
cat << 'EOF' > starter.js
import { triggersCollection, refreshTokenInFirestore } from './firestore.js';
// Custom Starter Configuration Card
export async function onConfigTrigger(req, res) {
await refreshTokenInFirestore(req);
res.status(200).json({
action: {
navigations: [
{
pushCard: {
sections: [
{
header: 'Support Ticket Listener',
widgets: [
{
textParagraph: {
text: 'This starter listens for new tickets submitted through the Support Quick Portal and stores subscriptions in Firestore.',
},
},
],
},
],
},
},
],
},
});
}
// Custom Starter Subscription Lifecycle (Firestore studio_triggers collection)
export async function onManageTrigger(req, res) {
try {
const triggerCreation = req.body?.workflow?.triggerCreation;
const triggerDeletion = req.body?.workflow?.triggerDeletion;
const userOAuthToken =
req.body?.authorizationEventObject?.userOAuthToken || null;
if (triggerCreation?.triggerId) {
const triggerId = String(triggerCreation.triggerId);
const docId = encodeURIComponent(triggerId);
await triggersCollection.doc(docId).set(
{
triggerId,
notifyUri: triggerCreation.notifyUri || null,
...(userOAuthToken ? { userOAuthToken } : {}),
updatedAt: new Date().toISOString(),
},
{ merge: true }
);
}
if (triggerDeletion?.triggerId) {
const triggerId = String(triggerDeletion.triggerId);
const docId = encodeURIComponent(triggerId);
await triggersCollection.doc(docId).delete();
}
if (!triggerCreation && !triggerDeletion && userOAuthToken) {
await refreshTokenInFirestore(req);
}
} catch (err) {
console.error('Error in /onManageTrigger:', err.message);
}
res.status(200).json({});
}
EOF
action.js – Bước hành động tuỳ chỉnh (workflowAction) với Gemini 3.8 Flash
Tạo action.js để triển khai 2 điểm cuối webhook mà bước thao tác tuỳ chỉnh của Google Workspace Studio yêu cầu:
onConfigUrgency(POST /onConfigUrgency): Trả về một thẻ cấu hình có tiện íchtextInputđặthostAppDataSource.workflowDataSource.includeVariables: true, cho phép người dùng chọn biếnticketDescriptiondo bước bắt đầu xuất ra.onExecuteUrgency(POST /onExecuteUrgency): Đọc dữ liệu đầu vàoticketDescriptiontừreq.body.workflow.actionInvocation.inputs, phân loại mức độ tác động và mức độ khẩn cấp của dữ liệu đó đối với doanh nghiệp bằng Gemini 3.8 Flash (gemini-3.8-flash) trên Nền tảng tác nhân Gemini Enterprise với đầu ra có cấu trúc (responseSchemaenum["High", "Normal"]), quay lạidetectKeywordUrgency()(urgent,blocker,critical) nếu lệnh gọi mô hình không thành công và trả về biến đầu raurgencyLevelbằnghostAppAction.workflowAction.returnOutputVariablesAction.
cat << 'EOF' > action.js
import { GoogleGenAI, Type } from '@google/genai';
import { refreshTokenInFirestore } from './firestore.js';
// Initialize Google GenAI SDK for the Gemini Enterprise Agent Platform
const ai = new GoogleGenAI({
vertexai: true,
project: process.env.GOOGLE_CLOUD_PROJECT,
location: 'global',
});
// Fallback keyword classifier if the Gemini API call is unavailable
export function detectKeywordUrgency(description) {
const lower = (description || '').toLowerCase();
return lower.includes('urgent') ||
lower.includes('blocker') ||
lower.includes('critical')
? 'High'
: 'Normal';
}
// Custom Action Step Configuration Card
export async function onConfigUrgency(req, res) {
await refreshTokenInFirestore(req);
res.status(200).json({
action: {
navigations: [
{
pushCard: {
sections: [
{
header: 'Urgency Detector Step',
widgets: [
{
textInput: {
name: 'ticketDescription',
label: 'Source Description',
hintText:
'Select the description variable outputted by the starter',
hostAppDataSource: {
workflowDataSource: {
includeVariables: true,
},
},
},
},
],
},
],
},
},
],
},
});
}
// Custom Action Step Execution: Gemini 3.8 Flash with keyword fallback
export async function onExecuteUrgency(req, res) {
await refreshTokenInFirestore(req);
const inputs = req.body?.workflow?.actionInvocation?.inputs || {};
const description = inputs.ticketDescription?.stringValues?.[0] || '';
let urgencyLevel = detectKeywordUrgency(description);
try {
const response = await ai.models.generateContent({
model: 'gemini-3.8-flash',
contents: `Evaluate the business impact and time sensitivity of this support ticket description and classify its urgency:\n\n${description}`,
config: {
responseMimeType: 'text/x.enum',
responseSchema: {
type: Type.STRING,
enum: ['High', 'Normal'],
},
},
});
const candidate = (response.text || '').trim();
if (candidate === 'High' || candidate === 'Normal') {
urgencyLevel = candidate;
}
} catch (err) {
console.error('Gemini fallback to keyword matching:', err.message);
}
res.status(200).json({
hostAppAction: {
workflowAction: {
returnOutputVariablesAction: {
variables: {
urgencyLevel: {
stringValues: [urgencyLevel],
},
},
},
},
},
});
}
EOF
portal.js – Hỗ trợ giao diện người dùng Cổng thông tin nhanh và trình điều phối triggers.fire
Tạo portal.js để phân phát cổng thông tin trên web và gửi yêu cầu hỗ trợ đến Google Workspace Studio:
renderPortal(GET /): Truy vấn tập hợpstudio_triggersFirestore để cho biết có bao nhiêu điều kiện kích hoạt Google Workspace Studio đang hoạt động đã được đăng ký và phân phát biểu mẫu gửi phiếu yêu cầu bằng HTML.submitTicket(POST /api/submit-ticket): Lặp lại tất cả các tài liệu kích hoạt đang hoạt động trongstudio_triggers, gọi điểm cuốitriggers.firecủa Google Workspace Studio (https://workspacestudio.googleapis.com/v1/triggers/{triggerId}:fire) bằng các biến đầu raticketTitlevàticketDescriptionvà mộtrequestIdduy nhất, đồng thời lưu vé vào bộ sưu tậpsupport_ticketsFirestore.
cat << 'EOF' > portal.js
import { triggersCollection, ticketsCollection } from './firestore.js';
// Support Quick Portal UI
export async function renderPortal(req, res) {
let activeCount = 0;
try {
const snapshot = await triggersCollection.get();
activeCount = snapshot.size;
} catch (err) {
console.error('Error reading studio_triggers collection:', err.message);
}
res.status(200).send(`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Support Quick Portal</title>
<style>
body { font-family: Arial, sans-serif; padding: 24px; max-width: 540px; margin: auto; color: #202124; }
.badge { background: #e8f0fe; color: #1967d2; padding: 8px 12px; border-radius: 6px; font-size: 14px; margin-bottom: 16px; }
label { font-weight: bold; display: block; margin-top: 16px; }
input, textarea { width: 100%; margin-top: 6px; padding: 10px; box-sizing: border-box; border: 1px solid #dadce0; border-radius: 4px; }
button { background-color: #1a73e8; color: white; border: none; padding: 10px 18px; margin-top: 16px; font-weight: bold; cursor: pointer; border-radius: 4px; }
button:hover { background-color: #1557b0; }
#status { margin-top: 16px; font-weight: bold; }
</style>
</head>
<body>
<h2>Support Quick Portal</h2>
<div class="badge">
Active Google Workspace Studio triggers in Firestore (<code>studio_triggers</code>):
<strong id="trigger-count">${activeCount}</strong>
</div>
<p>Submit a support ticket below to fire your Google Workspace Studio flow.</p>
<label for="title">Ticket Title</label>
<input type="text" id="title" placeholder="e.g. Database failure">
<label for="description">Issue Description</label>
<textarea id="description" rows="4" placeholder="Describe the issue..."></textarea>
<button onclick="submitTicket()">Submit Ticket</button>
<div id="status"></div>
<script>
async function submitTicket() {
const title = document.getElementById('title').value.trim();
const description = document.getElementById('description').value.trim();
const statusEl = document.getElementById('status');
if (!title || !description) {
statusEl.style.color = '#d93025';
statusEl.textContent = 'Please fill out both fields.';
return;
}
statusEl.style.color = '#188038';
statusEl.textContent = 'Submitting ticket...';
try {
const res = await fetch('/api/submit-ticket', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, description }),
});
const data = await res.json();
if (data.ok) {
statusEl.textContent =
'Ticket saved to Firestore! Fired ' + data.triggersFired + ' Google Workspace Studio trigger(s).';
} else {
statusEl.style.color = '#d93025';
statusEl.textContent = 'Error: ' + (data.error || 'Unknown error');
}
} catch (err) {
statusEl.style.color = '#d93025';
statusEl.textContent = 'Request failed: ' + err.message;
}
}
</script>
</body>
</html>`);
}
// Portal Form Submission -> Fire Active Google Workspace Studio Triggers
export async function submitTicket(req, res) {
const title = req.body?.title || 'Untitled Ticket';
const description = req.body?.description || '';
const results = [];
try {
const snapshot = await triggersCollection.get();
for (const doc of snapshot.docs) {
const trigger = doc.data();
if (!trigger.triggerId || !trigger.userOAuthToken) continue;
const response = await fetch(
`https://workspacestudio.googleapis.com/v1/triggers/${encodeURIComponent(trigger.triggerId)}:fire`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${trigger.userOAuthToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'triggers/' + trigger.triggerId,
outputs: {
ticketTitle: { stringValues: [title] },
ticketDescription: { stringValues: [description] },
},
requestId:
'req_' + Date.now() + '_' + Math.floor(Math.random() * 1000),
}),
}
);
results.push({ triggerId: trigger.triggerId, status: response.status });
}
await ticketsCollection.add({
title,
description,
triggersFired: results.length,
createdAt: new Date().toISOString(),
});
res.status(200).json({ ok: true, triggersFired: results.length, results });
} catch (err) {
console.error('Error in /api/submit-ticket:', err.message);
res.status(500).json({ ok: false, error: err.message });
}
}
EOF
index.js – Điểm truy cập vào máy chủ Express
Tạo index.js để kết nối các tuyến cổng thông tin và điểm cuối webhook của Google Workspace Studio với nhau thành một máy chủ HTTP Express đang nghe trên PORT (mặc định là 8080 trên Cloud Run):
cat << 'EOF' > index.js
import express from 'express';
import { onConfigTrigger, onManageTrigger } from './starter.js';
import { onConfigUrgency, onExecuteUrgency } from './action.js';
import { renderPortal, submitTicket } from './portal.js';
const app = express();
app.use(express.json());
// Support Quick Portal routes
app.get('/', renderPortal);
app.post('/api/submit-ticket', submitTicket);
// Google Workspace Studio Custom Starter Step webhooks
app.post('/onConfigTrigger', onConfigTrigger);
app.post('/onManageTrigger', onManageTrigger);
// Google Workspace Studio Custom Action Step webhooks
app.post('/onConfigUrgency', onConfigUrgency);
app.post('/onExecuteUrgency', onExecuteUrgency);
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Support Extension listening on port ${PORT}`);
});
EOF
4. Triển khai lên Cloud Run và cài đặt tiện ích bổ sung
Trong bước này, bạn sẽ triển khai dịch vụ Node.js lên Cloud Run, cấp quyền IAM cho trình gọi Tiện ích bổ sung của Google Workspace, Firestore và quyền truy cập thời gian chạy của Nền tảng Agent, tạo tệp kê khai deployment.json và cài đặt việc triển khai tiện ích bổ sung.
- Triển khai dịch vụ
support-extensionvào Cloud Run bằng các biến môi trường của dự án và tập hợp Firestore:gcloud run deploy support-extension \ --source . \ --region us-central1 \ --allow-unauthenticated \ --set-env-vars="GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project),FIRESTORE_TRIGGERS_COLLECTION=studio_triggers,FIRESTORE_TICKETS_COLLECTION=support_tickets" \ --quiet - Cấp
roles/run.invokertrên dịch vụ Cloud Run cho tài khoản dịch vụ Google Workspace Add-ons để Google Workspace Studio có thể gọi các điểm cuối webhook của bạn:ADDON_SA=$(gcloud workspace-add-ons get-authorization --format="value(serviceAccountEmail)") gcloud run services add-iam-policy-binding support-extension \ --region=us-central1 \ --member="serviceAccount:${ADDON_SA}" \ --role="roles/run.invoker" \ --quiet - Cấp
roles/datastore.user(để đọc và ghi các tập hợpstudio_triggersvàsupport_ticketsFirestore) vàroles/aiplatform.user(để gọi Gemini trên Gemini Enterprise Agent Platform) cho tài khoản dịch vụ thời gian chạy Cloud Run:PROJECT_ID=$(gcloud config get-value project) PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)") RUNTIME_SA=$(gcloud run services describe support-extension --region=us-central1 --format="value(spec.template.spec.serviceAccountName)") RUNTIME_SA=${RUNTIME_SA:-"${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"} gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --member="serviceAccount:${RUNTIME_SA}" \ --role="roles/datastore.user" \ --condition=None \ --quiet gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --member="serviceAccount:${RUNTIME_SA}" \ --role="roles/aiplatform.user" \ --condition=None \ --quiet - Truy xuất URL Cloud Run đã triển khai và tạo tệp kê khai
deployment.jsonxác định các phần tửsupportTicketTrigger(workflowTrigger) vàurgencyDetectorStep(workflowAction):SERVICE_URL=$(gcloud run services describe support-extension --region=us-central1 --format="value(status.url)") cat << EOF > deployment.json { "oauthScopes": [ "https://www.googleapis.com/auth/workspace.studio.trigger", "https://www.googleapis.com/auth/userinfo.email" ], "addOns": { "common": { "name": "Support Extension", "logoUrl": "https://www.gstatic.com/images/branding/productlogos/buganizer/v1/192px.svg" }, "studio": { "flows": { "workflowElements": [ { "id": "supportTicketTrigger", "state": "ACTIVE", "name": "New Support Ticket", "description": "Fires when someone submits a ticket in the Support Quick Portal.", "workflowTrigger": { "inputs": [], "outputs": [ { "id": "ticketTitle", "description": "Ticket Title", "cardinality": "SINGLE", "dataType": { "basicType": "STRING" } }, { "id": "ticketDescription", "description": "Ticket Description", "cardinality": "SINGLE", "dataType": { "basicType": "STRING" } } ], "onConfigFunction": "${SERVICE_URL}/onConfigTrigger", "onManageFunction": "${SERVICE_URL}/onManageTrigger" } }, { "id": "urgencyDetectorStep", "state": "ACTIVE", "name": "Detect Urgency", "description": "Evaluates the ticket description to detect High or Normal urgency.", "workflowAction": { "inputs": [ { "id": "ticketDescription", "description": "Description to scan", "cardinality": "SINGLE", "dataType": { "basicType": "STRING" } } ], "outputs": [ { "id": "urgencyLevel", "description": "Detected Urgency (High / Normal)", "cardinality": "SINGLE", "dataType": { "basicType": "STRING" } } ], "onConfigFunction": "${SERVICE_URL}/onConfigUrgency", "onExecuteFunction": "${SERVICE_URL}/onExecuteUrgency" } } ] } }, "httpOptions": { "authorizationHeader": "SYSTEM_ID_TOKEN" } } } EOF - Tạo (hoặc thay thế) và cài đặt việc triển khai Tiện ích bổ sung Google Workspace cho tài khoản của bạn, đồng thời in URL Cổng thông tin hỗ trợ nhanh:
gcloud workspace-add-ons deployments create support-extension --deployment-file=deployment.json || \ gcloud workspace-add-ons deployments replace support-extension --deployment-file=deployment.json gcloud workspace-add-ons deployments install support-extension echo "Support Quick Portal URL: ${SERVICE_URL}"
5. Kiểm thử các bước tuỳ chỉnh trong Google Workspace Studio
- Mở Google Workspace Studio (làm mới thẻ trình duyệt nếu thẻ này đã mở) rồi nhấp vào Quy trình mới.
- Nhấp vào Chọn một tiện ích khởi động > Tiện ích hỗ trợ > Phiếu yêu cầu hỗ trợ mới.
- Nhấp vào Thêm bước (
+) > Tiện ích hỗ trợ > Phát hiện tính khẩn cấp. Trong trường Mô tả nguồn, hãy nhấp vào + Biến rồi chọn Mô tả vé. - Nhấp vào Thêm bước (
+) rồi thêm bước Chat (Trò chuyện) > Notify me in Chat (Thông báo cho tôi trong Chat) có các biến Ticket Title (Tiêu đề phiếu yêu cầu), Urgency Level (Mức độ khẩn cấp) và Ticket Description (Nội dung mô tả phiếu yêu cầu) trong thông báo. - Bật chế độ Bật ở góc trên cùng bên phải. Google Workspace Studio sẽ ngay lập tức gọi điểm cuối
/onManageTriggercủa bạn trên Cloud Run, điểm cuối này sẽ ghi gói thuê bao kích hoạt vào bộ sưu tậpstudio_triggerstrong Firestore. - Mở URL Cổng thông tin hỗ trợ nhanh (
https://support-extension-...run.app) trong một thẻ mới, xác nhận rằng cổng thông tin hiển thị1trình kích hoạt đang hoạt động trong Firestore và gửi 2 phiếu yêu cầu hỗ trợ để kiểm thử việc phân loại Gemini 3.8 Flash (gemini-3.8-flash):- Phiếu yêu cầu có mức độ tác động cao (Tiêu đề phiếu yêu cầu:
London office lockout, Nội dung mô tả vấn đề:All 500 employees in the London office are locked out of their workstations 20 minutes before the board presentation.): Ngay cả khi không có các từ khoá được mã hoá cứng nhưurgenthoặcblocker,gemini-3.8-flashvẫn phân loại phiếu yêu cầu này là có mức độ khẩn cấpHigh. - Phiếu yêu cầu thông thường (Tiêu đề phiếu yêu cầu:
Conference room adapters, Nội dung mô tả vấn đề:Could we order two extra HDMI adapters for the third-floor conference room next month?):gemini-3.8-flashphân loại phiếu yêu cầu này làNormalkhẩn cấp.
- Phiếu yêu cầu có mức độ tác động cao (Tiêu đề phiếu yêu cầu:
- Kiểm tra trong Google Chat và thẻ Hoạt động của Google Workspace Studio để xác minh rằng quy trình của bạn đã chạy cho cả hai yêu cầu hỗ trợ có
Urgency Level: HighvàUrgency Level: Normal.
6. Dọn dẹp
Để tránh bị tính phí liên tục cho tài khoản Google Cloud, hãy xoá các tài nguyên đã triển khai trong Cloud Shell:
gcloud workspace-add-ons deployments uninstall support-extension
gcloud workspace-add-ons deployments delete support-extension --quiet
gcloud run services delete support-extension --region=us-central1 --quiet
gcloud firestore databases delete --database="(default)" --quiet
7. Xin chúc mừng!
Bạn đã tạo, triển khai và kiểm thử một tiện ích HTTP Node.js cho Google Workspace Studio bằng Firestore, Cloud Run và Gemini 3.8 Flash trên Gemini Enterprise Agent Platform!
Nội dung đã đề cập
- Định cấu hình tệp kê khai Tiện ích bổ sung HTTP của Google Workspace Studio (
deployment.json) bằng các phần tửworkflowTriggervàworkflowAction. - Duy trì các gói thuê bao Google Workspace Studio
workflowTriggertrong tập hợpstudio_triggersFirestore và ghi lại các lượt gửi trên cổng thông tin trongsupport_ticketsđể các sự kiện kích hoạt vẫn hoạt động khi Cloud Run mở rộng quy mô và triển khai lại. - Xây dựng bước
workflowActionphân loại phiếu yêu cầu hỗ trợ bằng đầu ra có cấu trúc Gemini 3.8 Flash (gemini-3.8-flash) trên Nền tảng Tác nhân Gemini Enterprise, với cơ chế dự phòng khớp từ khoá linh hoạt.