1. مقدمة
تتيح لك Google Workspace Studio إنجاز العمليات التجارية آليًا في تطبيقات Google Workspace، مثل Gmail وGoogle Chat وGoogle Drive و"جداول بيانات Google". عندما تحتاج إلى بدء خطوات سير العمل من تطبيق ويب خارجي أو تنفيذ منطق مخصّص في بيئة السحابة الإلكترونية الخاصة بك، يمكنك توسيع نطاق Google Workspace Studio باستخدام إضافة Google Workspace HTTP في Node.js على Cloud Run:
- خطوة بدء مخصّصة (
workflowTrigger): تبدأ سير عمل Google Workspace Studio عند وقوع حدث خارجي، مثل إرسال أحد العملاء طلبًا في بوابة ويب داخلية، وذلك من خلال طلب واجهة برمجة تطبيقات REST الخاصة بـ Google Workspace Studiotriggers.fire. - خطوة الإجراء المخصّص (
workflowAction): تتلقّى هذه الخطوة متغيرات من الخطوات السابقة في المسار، وتنفّذ منطقًا مخصّصًا أو استنتاجًا مستندًا إلى الذكاء الاصطناعي في خدمة Node.js، وتعيد متغيرات الإخراج إلى Google Workspace Studio.
في هذا الدرس التطبيقي حول الترميز، ستنشئ وتنفّذ إضافة HTTP كاملة بلغة Node.js في Google Workspace Studio على Cloud Run، وتستخدم Cloud Firestore للاحتفاظ باشتراكات مشغّل التدفق النشط والتذاكر المُرسَلة في جميع مراجعات الحاويات، وتصنّف مدى إلحاح التذاكر في خطوة الإجراء المخصّص باستخدام Gemini 3.8 Flash (gemini-3.8-flash) على منصة وكيل Gemini Enterprise مع خيار احتياطي مرن لمطابقة الكلمات الرئيسية.
ما ستنشئه
- تطبيق ويب Support Quick Portal وإضافة HTTP في Google Workspace تم إنشاؤهما باستخدام Node.js وExpress وFirestore على Cloud Run
- خطوة بداية مخصّصة طلب دعم جديد (
supportTicketTrigger) تحتفظ باشتراكات المسار النشطة في مجموعةstudio_triggersFirestore، وتسجّل طلبات الدعم المُرسَلة في مجموعةsupport_ticketsFirestore، ويتم تشغيلها كلما تم إرسال طلب دعم في بوابة الويب، مع تمريرticketTitleوticketDescriptionإلى مسار Google Workspace Studio. - خطوة إجراء مخصّص التعرّف على مدى الإلحاح (
urgencyDetectorStep) تصنّف مدى إلحاح الطلب باستخدام Gemini 3.8 Flash (gemini-3.8-flash) على منصة وكلاء Gemini Enterprise (aiplatform.googleapis.com)، مع الرجوع تلقائيًا إلى مطابقة الكلمات الرئيسية (urgentوblockerوcritical).
أهداف الدورة التعليمية
- كيفية ضبط بيان نشر إضافة Google Workspace HTTP (
deployment.json) باستخدام العنصرَينworkflowTriggerوworkflowAction - كيفية الاحتفاظ باشتراكات مشغّلات Google Workspace Studio (
triggerIdوnotifyUriوuserOAuthToken) فيstudio_triggersمجموعة Firestore وتشغيل التدفقات باستخدام واجهةtriggers.fireREST API - كيفية إنشاء
workflowActionخطوة مخصّصة في Node.js باستخدام Gemini 3.8 Flash (gemini-3.8-flash) للناتج المنظَّم على Gemini Enterprise Agent Platform مع خيار احتياطي للكلمات الرئيسية
المتطلبات الأساسية
- حساب Google Workspace لديه إذن الوصول إلى Google Workspace Studio
- مشروع Google Cloud تم تفعيل الفوترة فيه، وتم إنشاؤه ضمن مؤسسة Google Workspace نفسها التي يتبع لها حسابك كمستخدم، وذلك حتى تتمكّن من تثبيت عمليات نشر الإضافات غير المنشورة بغرض الاختبار
2. إعداد مشروعك على Google Cloud وFirestore
في هذه الخطوة، يمكنك ضبط شاشة طلب الموافقة المتعلّقة ببروتوكول OAuth في مشروعك، وتفعيل واجهات برمجة تطبيقات Google Cloud وGoogle Workspace المطلوبة في Cloud Shell، وتوفير قاعدة بيانات (default) Firestore، وإعداد حساب خدمة تفويض الإضافة.
- افتح Google Cloud Console، واختَر مشروعك على السحابة الإلكترونية، ثم انقر على رمز تفعيل Cloud Shell في شريط التنقل العلوي.
- اضبط شاشة طلب الموافقة المتعلّقة ببروتوكول OAuth ليتمكّن Google Workspace من توفير عميل OAuth للإضافة:
- افتح صفحة "العلامة التجارية لمنصة Google للمصادقة".
- انقر على البدء إذا طُلب منك ذلك. (إذا سبق لك ضبط شاشة طلب الموافقة، انتقِل إلى الخطوة 3).
- ضمن معلومات التطبيق، أدخِل
Support Extensionفي حقل اسم التطبيق، واختَر البريد الإلكتروني لدعم المستخدمين، ثم انقر على التالي. - ضِمن الجمهور، اختَر داخلي وانقر على التالي.
- ضمن معلومات الاتصال، أدخِل عنوان بريدك الإلكتروني وانقر على التالي.
- ضمن إنهاء، وافِق على سياسة بيانات المستخدمين في خدمات Google API، ثم انقر على متابعة، ثم على إنشاء.
- في Cloud Shell، اضبط مشروعك النشط (استبدِل
YOUR_PROJECT_IDبمعرّف مشروعك على Google Cloud) وفعِّل واجهات برمجة التطبيقات المطلوبة: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 - وفِّر قاعدة بيانات
(default)Firestore فيus-central1(إذا لم تكن متوفّرة من قبل) وأنشئ حساب خدمة "إضافات Google Workspace":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- إنشاء تطبيق Node.js باستخدام Firestore وGemini 3.8 Flash
في هذه الخطوة، يمكنك إنشاء تطبيق Node.js في ~/studio-support-addon. للحفاظ على التعليمات البرمجية مجزأة وسهلة القراءة، يمكنك تنظيم المشروع في خمسة ملفات مركزة:
-
firestore.js: تهيئة برنامج Cloud Firestore (المجموعتانstudio_triggersوsupport_tickets) وإعادة تحميل رموز OAuth المميزة المخزّنة مؤقتًا -
starter.js: تنفّذ عمليات ربط الويب المخصّصة لخطوة البداية طلب دعم جديد (/onConfigTriggerو/onManageTrigger). action.js: تنفّذ عمليات ربط لخدمات الويب الخاصة بخطوات الإجراء المخصّص تحديد مدى الإلحاح (/onConfigUrgencyو/onExecuteUrgency) باستخدام Gemini 3.8 Flash (gemini-3.8-flash) مع خيار احتياطي لمطابقة الكلمات الرئيسية.portal.js: يعرض واجهة مستخدم الويب لبوابة الدعم السريع (GET /) ويطلق مشغّلات Google Workspace Studio النشطة (POST /api/submit-ticket).-
index.js: يربط جميع مسارات Express معًا ويبدأ خادم HTTP.
إعداد المشروع وpackage.json
- أنشئ دليل مشروع وانتقِل إليه:
mkdir -p ~/studio-support-addon && cd ~/studio-support-addon - إنشاء
package.jsonباستخدامexpressو@google-cloud/firestoreو@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: حالة Firestore المشترَكة وإعادة تحميل رمز OAuth المميز
أنشئ firestore.js لإدارة مجموعتَي Firestore والحفاظ على رموز OAuth المميزة للمستخدمين المخزّنة مؤقتًا:
-
studio_triggers: تخزِّن هذه السمة اشتراكات سير العمل النشطة في Google Workspace Studio (triggerIdوnotifyUriوuserOAuthToken) لكي تظل متاحة عند إعادة تشغيل حاوية Cloud Run وعند وقوع أحداث التوسيع إلى صفر. -
support_tickets: يخزِّن هذا القسم سجلاً لكل طلب دعم تم إرساله من خلال البوابة. refreshTokenInFirestore(req): عندما يتصل Google Workspace Studio بأي من نقاط نهاية Webhook، يتضمّنauthorizationEventObject.userOAuthTokenصالحًا لفترة قصيرة. تعدّل هذه الأداة المساعدة مستندات المشغّلات النشطة باستخدام الرمز المميّز الأحدث لكي تظل طلباتtriggers.fireفي الخلفية معتمَدة.
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 — خطوة مخصّصة للمبتدئين (workflowTrigger)
أنشئ starter.js لتنفيذ نقطتَي نهاية لبرنامج ربط الويب المطلوبتَين في خطوة بدء مخصّصة في Google Workspace Studio:
-
onConfigTrigger(POST /onConfigTrigger): يتم استدعاؤه عندما يختار المستخدم طلب دعم جديد كبداية لسير العمل في Google Workspace Studio. تعرض هذه السمةpushCardإجراء تنقّل يصف أداة بدء التشغيل. -
onManageTrigger(POST /onManageTrigger): يتم استدعاؤه عندما يفعِّل المستخدم مسارًا (On) (req.body.workflow.triggerCreation) أو يوقفه (Off) أو يحذفه (req.body.workflow.triggerDeletion). يحفظ مستند الاشتراك أو يحذفه في مجموعةstudio_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 — خطوة الإجراء المخصّص (workflowAction) باستخدام Gemini 3.8 Flash
أنشِئ action.js لتنفيذ نقطتَي نهاية لبرنامج ربط التطبيقات (Webhook) تتطلّبهما خطوة إجراء مخصّصة في Google Workspace Studio:
onConfigUrgency(POST /onConfigUrgency): تعرض بطاقة إعدادات تتضمّن أداةtextInputتحدّدhostAppDataSource.workflowDataSource.includeVariables: true، ما يتيح للمستخدمين اختيار قيمة المتغيّرticketDescriptionالتي تعرضها خطوة البداية.onExecuteUrgency(POST /onExecuteUrgency): يقرأ الإدخالticketDescriptionمنreq.body.workflow.actionInvocation.inputs، ويصنّف تأثيره على النشاط التجاري ومدى إلحاحه باستخدام Gemini 3.8 Flash (gemini-3.8-flash) على Gemini Enterprise Agent Platform مع ناتج منظَّم (responseSchemaenum["High", "Normal"])، ويعود إلىdetectKeywordUrgency()(urgentوblockerوcritical) في حال تعذّر تنفيذ طلب النموذج، ويعرض متغير الناتجurgencyLevelباستخدامhostAppAction.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: واجهة مستخدم "بوابة الدعم السريع" وtriggers.fire أداة الإرسال
أنشئ portal.js لعرض بوابة الويب وإرسال طلبات الدعم إلى Google Workspace Studio:
-
renderPortal(GET /): يطلب البحث في مجموعةstudio_triggersFirestore لعرض عدد مشغّلات Google Workspace Studio النشطة التي تم تسجيلها، ويعرض نموذج إرسال تذكرة HTML. -
submitTicket(POST /api/submit-ticket): تتكرّر هذه الخطوة على جميع مستندات المشغّل النشطة فيstudio_triggers، وتستدعي نقطة نهايةtriggers.fireفي Google Workspace Studio (https://workspacestudio.googleapis.com/v1/triggers/{triggerId}:fire) باستخدام متغيرَي الإخراجticketTitleوticketDescriptionوrequestIdفريد، وتحفظ التذكرة في مجموعةsupport_ticketsفي Firestore.
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: نقطة دخول خادم Express
أنشئ index.js لربط مسارات البوابة ونقاط نهاية الويب هوك في Google Workspace Studio معًا في خادم HTTP Express يستمع إلى PORT (الإعداد التلقائي 8080 على 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. النشر على Cloud Run وتثبيت الإضافة
في هذه الخطوة، يمكنك نشر خدمة Node.js على Cloud Run، ومنح أذونات "إدارة الهوية وإمكانية الوصول" لمشغّل إضافات Google Workspace وFirestore وإمكانية الوصول إلى وقت تشغيل Agent Platform، وإنشاء ملف deployment.json، وتثبيت عملية نشر الإضافة.
- انشر خدمة
support-extensionعلى Cloud Run مع متغيرات بيئة مشروعك ومجموعة 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 - امنح الإذن
roles/run.invokerلخدمة Cloud Run لحساب خدمة "إضافات Google Workspace" كي يتمكّن Workspace Studio من استدعاء نقاط نهاية خطاف الويب: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 - امنح الإذن
roles/datastore.user(للقراءة والكتابة في مجموعتَيstudio_triggersوsupport_ticketsFirestore) والإذنroles/aiplatform.user(لاستخدام Gemini على "منصة وكلاء Gemini Enterprise") لحساب خدمة وقت التشغيل في 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 - استرداد عنوان URL الذي تم نشره على Cloud Run وإنشاء ملف البيان
deployment.jsonالذي يحدّد العنصرَينsupportTicketTrigger(workflowTrigger) و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 - أنشئ (أو استبدِل) عملية نشر "إضافة Google Workspace" لحسابك وثبِّتها، ثم اطبع عنوان URL الخاص بـ "بوابة الدعم السريع":
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- اختبار الخطوات المخصّصة في Google Workspace Studio
- افتح Google Workspace Studio (أعِد تحميل علامة تبويب المتصفّح إذا كانت مفتوحة من قبل) وانقر على مسار عمل جديد.
- انقر على اختيار أداة مساعدة > إضافة الدعم > طلب دعم جديد.
- انقر على إضافة خطوة (
+) > إضافة دعم > رصد مدى الإلحاح. في حقل وصف المصدر، انقر على + المتغيّرات واختَر وصف التذكرة. - انقر على إضافة خطوة (
+) وأضِف خطوة Chat > إرسال إشعار إليّ في Chat تتضمّن المتغيّرات عنوان التذكرة ومستوى الأهمية ووصف التذكرة في الرسالة. - فعِّل الخيار تشغيل في أعلى يسار الصفحة. يطلب Google Workspace Studio على الفور نقطة النهاية
/onManageTriggerعلى Cloud Run، والتي تكتب اشتراك المشغّل النشط في المجموعةstudio_triggersفي Firestore. - افتح عنوان URL لبوابة الدعم السريع (
https://support-extension-...run.app) في علامة تبويب جديدة، وتأكَّد من أنّ البوابة تعرض مشغّلاً نشطًا1في Firestore، وأرسِل بطاقتَي دعم لاختبار تصنيف Gemini 3.8 Flash (gemini-3.8-flash):- تذكرة ذات تأثير كبير (عنوان التذكرة:
London office lockout، وصف المشكلة:All 500 employees in the London office are locked out of their workstations 20 minutes before the board presentation.): حتى بدون كلمات رئيسية مبرمَجة مثلurgentأوblocker، تصنّفgemini-3.8-flashهذه التذكرة على أنّها ذات أولويةHigh. - تذكرة روتينية (عنوان التذكرة:
Conference room adapters، وصف المشكلة:Could we order two extra HDMI adapters for the third-floor conference room next month?): تصنّفgemini-3.8-flashهذه التذكرة على أنّها ذات أولويةNormal.
- تذكرة ذات تأثير كبير (عنوان التذكرة:
- تأكَّد في Google Chat وفي علامة التبويب النشاط في Google Workspace Studio من أنّ مسار العمل تم تنفيذه لكلتا التذكرتين اللتين تحملان الرقمين
Urgency Level: HighوUrgency Level: Normal.
6. تَنظيم
لتجنُّب تحمّل رسوم مستمرة على حسابك على Google Cloud، عليك إزالة الموارد التي تم نشرها في 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. تهانينا!
لقد أنشأت ونشرت واختبرت إضافة HTTP بلغة Node.js في Google Workspace Studio باستخدام Firestore وCloud Run وGemini 3.8 Flash على Gemini Enterprise Agent Platform.
المواضيع التي تناولناها
- إعداد بيان إضافة HTTP في Google Workspace Studio (
deployment.json) باستخدام العنصرَينworkflowTriggerوworkflowAction - الاحتفاظ باشتراكات Google Workspace Studio
workflowTriggerفي مجموعةstudio_triggersFirestore وتسجيل عمليات إرسال البوابة فيsupport_ticketsلكي تنجو المشغّلات من عمليات توسيع نطاق Cloud Run وإعادة نشرها - إنشاء خطوة
workflowActionتصنّف بطاقات طلبات الدعم باستخدام Gemini 3.8 Flash (gemini-3.8-flash) الناتج المنظَّم على Gemini Enterprise Agent Platform، مع خيار احتياطي مرن لمطابقة الكلمات الرئيسية