@מ.ל.ל כתב:
@דורש-3 לא הבנתי אם זה על קבוצה בלבד או על כל שיחה שיש לי עם משתמש ?
שאלה מצוינת. התשובה הקצרה: זה עובד בדיוק אותו דבר, כי בגוגל צ'אט גם שיחה פרטית עם משתמש בודד היא בעצם חלל (Space), רק מסוג אחר. קבוצה היא חלל מסוג SPACE, ושיחה פרטית אחד על אחד היא חלל מסוג DIRECT_MESSAGE. מרגע שיש לכם את המזהה של החלל הפרטי, כל שאר המנגנון זהה, אותה בדיקה מחזורית ואותה תגובה.
ההבדל היחיד הוא איך משיגים את המזהה של השיחה הפרטית, ואיך מטפלים בכמה שיחות במקביל. נסביר את שניהם.
איך משיגים את מזהה השיחה הפרטית עם משתמש מסוים
יש שתי דרכים.
הדרך הפשוטה: שהמשתמש פשוט ישלח הודעה ראשונה לחשבון הבוט. מרגע שהוא כתב, לבוט כבר יש שיחה פתוחה איתו, ואתם יכולים לראות את מזהה השיחה. אפשר לראות אותו בכתובת של הדפדפן כשפותחים את השיחה, בדיוק כמו שמצאנו את מזהה הקבוצה.
הדרך התכנותית: לתת לקוד למצוא או לפתוח את השיחה לבד, לפי מזהה המשתמש. מזהה המשתמש נראה כמו users ואחריו מספר ארוך, והוא מופיע בשדה sender של כל הודעה שאותו אדם כותב. הנה פונקציה שמוצאת את השיחה הפרטית עם משתמש נתון, ואם אין עדיין שיחה, פותחת אחת:
// מחזירה את מזהה השיחה הפרטית עם משתמש מסוים (users/1234...)
function getDmSpace(userId) {
const token = ScriptApp.getOAuthToken();
// קודם מנסים למצוא שיחה קיימת
const find = UrlFetchApp.fetch(
'https://chat.googleapis.com/v1/spaces:findDirectMessage?name=' + encodeURIComponent(userId),
{ headers: { Authorization: 'Bearer ' + token }, muteHttpExceptions: true });
if (find.getResponseCode() === 200) {
return JSON.parse(find.getContentText()).name; // spaces/XXXX
}
// אם אין - פותחים שיחה חדשה עם המשתמש
const setup = UrlFetchApp.fetch('https://chat.googleapis.com/v1/spaces:setup', {
method: 'post', contentType: 'application/json',
headers: { Authorization: 'Bearer ' + token },
payload: JSON.stringify({
space: { spaceType: 'DIRECT_MESSAGE' },
memberships: [{ member: { name: userId, type: 'HUMAN' } }]
}),
muteHttpExceptions: true
});
if (setup.getResponseCode() === 200) {
return JSON.parse(setup.getContentText()).name;
}
console.log('לא הצלחתי לפתוח שיחה', setup.getContentText());
return null;
}
איך גורמים לבוט לענות לכמה שיחות פרטיות במקביל
הטריק היחיד שצריך לשים לב אליו הוא נקודת ההתחלה. בגרסת הקבוצה שמרנו חותמת זמן אחת בשם last. כשיש כמה שיחות, צריך חותמת זמן נפרדת לכל שיחה, אחרת הן ידרסו אחת את השנייה. פותרים את זה פשוט על ידי שמירת החותמת עם מפתח שכולל את מזהה השיחה.
הנה גרסה של הלולאה הראשית שעוברת על רשימת חללים, קבוצות או שיחות פרטיות, ומטפלת בכל אחת בנפרד:
// רשימת החללים שהבוט מאזין להם - אפשר לערבב קבוצות ושיחות פרטיות
const SPACES = [
'spaces/PASTE_GROUP_ID', // קבוצה
'spaces/PASTE_DM_ID' // שיחה פרטית עם משתמש מסוים
];
function checkAll() {
for (const space of SPACES) {
checkOneSpace(space);
}
}
function checkOneSpace(space) {
const props = PropertiesService.getScriptProperties();
const key = 'last_' + space; // חותמת זמן נפרדת לכל חלל
const last = props.getProperty(key);
if (!last) { props.setProperty(key, new Date().toISOString()); return; }
const res = Chat.Spaces.Messages.list(space, { pageSize: 15, orderBy: 'createTime desc' });
const fresh = (res.messages || []).filter(m => m.createTime > last);
if (!fresh.length) return;
props.setProperty(key, fresh[0].createTime);
fresh.reverse();
for (const m of fresh) {
if (isSelf(m)) continue;
const t = (m.text || '').trim();
if (!t) continue;
// בשיחה פרטית לרוב לא צריך מילת הפעלה, כי כל הודעה מכוונת לבוט
const answer = ask(t);
if (answer) postTo(space, answer);
}
}
// כמו post מהמדריך, רק שמקבל לאיזה חלל לכתוב
function postTo(space, text) {
UrlFetchApp.fetch('https://chat.googleapis.com/v1/' + space + '/messages', {
method: 'post', contentType: 'application/json',
headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
payload: JSON.stringify({ text: text }), muteHttpExceptions: true
});
}
שימו לב לשני דברים. ראשון, את הטריגר של הדקה מפנים עכשיו לפונקציה checkAll במקום לפונקציה של חלל בודד. שני, בשיחה פרטית בדרך כלל מוותרים על מילת ההפעלה, כי כל הודעה בשיחה אחד על אחד ממילא מכוונת לבוט, אז אפשר פשוט לענות על הכל. בקבוצה כן משאירים מילת הפעלה כדי שהבוט לא יתפרץ לכל שיחה.
מכשול אחד ששווה לדעת עליו מראש
בפתיחת שיחה פרטית יזומה מצד הבוט, כלומר כשהבוט הוא זה שמתחיל את השיחה עם מישהו שעדיין לא כתב לו, יש מגבלות תלוי בסוג החשבון וההגדרות. הדרך היציבה ביותר, שכמעט תמיד עובדת, היא שהמשתמש ישלח לבוט הודעה אחת ראשונה. מאותו רגע השיחה קיימת, הבוט רואה אותה, ויכול לענות לה חופשי. אם אתם בונים את זה למשפחה או לקבוצה סגורה, פשוט תבקשו מכל אחד לכתוב לבוט שלום פעם אחת בהתחלה, וזהו.
בקיצור, אין הבדל מהותי בין קבוצה למשתמש בודד. שניהם חללים, ואותו קוד מטפל בשניהם. ההבדל היחיד הוא מאיפה משיגים את המזהה, ולשמור חותמת זמן נפרדת לכל שיחה.