• דף הבית
    • אינדקס קישורים
    • פוסטים אחרונים
    • משתמשים
    • חיפוש בהגדרות המתקדמות
    • חיפוש גוגל בפורום
    • ניהול המערכת
    • ניהול המערכת - שרת private
    • הרשמה
    • התחברות

    חיבור גוגל צ'אט לGoogle Apps Script

    מתוזמן נעוץ נעול הועבר פורום מפתחים API
    7 פוסטים 5 כותבים 117 צפיות 3 עוקבים
    טוען פוסטים נוספים
    • מהישן לחדש
    • מהחדש לישן
    • הכי הרבה הצבעות
    תגובה
    • תגובה כנושא
    התחברו כדי לפרסם תגובה
    נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
    • מ מנותק
      מאיר מלמד
      נערך לאחרונה על ידי

      אפשר לחבר את הצ'אט ללא חשבון עסקי?
      יש איזה דרך כל שהיא לעלות קבצים מהצ'אט למערכת שלי?

      תגובה 1 תגובה אחרונה תגובה ציטוט 0
      • ל מנותק
        ליאו
        נערך לאחרונה על ידי

        גימיניי טען שכן ובקלות

        מ תגובה 1 תגובה אחרונה תגובה ציטוט 0
        • מ מנותק
          מאיר מלמד @ליאו
          נערך לאחרונה על ידי

          @ליאו הוא בדרך כלל מבלבל את המוח. (לגבי ימות המשיח - אין לו ידע)
          אתה הצלחת?

          א תגובה 1 תגובה אחרונה תגובה ציטוט 0
          • א מנותק
            אA @מאיר מלמד
            נערך לאחרונה על ידי

            @מאיר-מלמד
            הוא טוען אבל די נכון, אבל צריך לבדוק

            מ תגובה 1 תגובה אחרונה תגובה ציטוט 0
            • מ מנותק
              מאיר מלמד @אA
              נערך לאחרונה על ידי

              @אA אם מישהו הצליח אני ישמח....

              תגובה 1 תגובה אחרונה תגובה ציטוט 0
              • ק מנותק
                קשאנוב
                נערך לאחרונה על ידי

                אין שום דרך!
                אין צורך לנסות!
                גימיני סתם מבלבל את המוח!

                ד תגובה 1 תגובה אחרונה תגובה ציטוט 0
                • ד מנותק
                  דורש 3 @קשאנוב
                  נערך לאחרונה על ידי

                  @מאיר-מלמד
                  חיבור Google Chat ל-Apps Script, ומשם לימות דרך גישור

                  מדריך מעשי למי שיש לו הבנה טכנית בסיסית. מסביר כל שלב, מה עושים, איך, ולמה. הפתרון כאן רץ אצלי בפועל, ובסוף יש דרך לבדוק בעצמכם שכל חלק עובד.

                  מה בונים, ולמה דווקא ככה

                  המטרה: בוט שיושב בקבוצת Google Chat, קורא את מה שנכתב, ומגיב או מעביר את זה הלאה. בשלב השני גם מזרים את ההודעות לקו טלפון בימות המשיח, כדי שאנשים בלי צ'אט יוכלו לחייג ולשמוע.

                  לפני שמתחילים, חשוב להבין שתי דרכים שלא עובדות, כי רוב האנשים מבזבזים עליהן ימים.

                  הדרך הראשונה שנכשלת היא Webhook נכנס. זה החיבור הרשמי שגוגל מציעה, אבל הכפתור ליצור Webhook פשוט אפור בחשבון פרטי, והוא זמין רק בחשבון עסקי מסוג Workspace Business עם הרשאות מנהל. חשבון Gmail רגיל, וגם חשבון Workspace יחיד בתשלום, לא יכולים.

                  הדרך השנייה שנכשלת היא רישום אפליקציית Chat רשמית ב-Google Cloud. גם היא דורשת Workspace, וגם שם נתקעים על הרשאות הוספה של האפליקציה לקבוצה.

                  הדרך שכן עובדת, וכמעט אף אחד לא מדבר עליה, היא לא לרשום שום בוט ולא ליצור שום Webhook. במקום זה פותחים חשבון גוגל רגיל, מכניסים אותו לקבוצה כחבר רגיל, ומריצים סקריפט שכל דקה שואל את גוגל אם יש הודעות חדשות. אם יש, הוא מגיב. כל הפעולות נעשות בזהות של אותו חשבון, בדיוק כמו בן אדם, אז אין צורך בשום רישום ובשום אישור מנהל. זה עובד גם בלי Workspace עסקי.

                  היתרון: פשוט, חינמי, ועובד בחשבון פרטי. החיסרון: יש עיכוב של עד דקה, כי זו בדיקה מחזורית ולא דחיפה מיידית, והבוט מופיע כמשתמש רגיל ולא עם תווית של אפליקציה.

                  המכשולים שתפגשו, מסודרים מראש

                  לפני הקוד, כדאי לדעת מה מחכה, כי כל אחד מאלה עצר אנשים בדרך:

                  החשבון שמריץ את הסקריפט חייב להיות חבר בקבוצה, אחרת הוא לא רואה כלום. פותחים את הסקריפט מהחשבון הזה, לא מהחשבון הפרטי שלכם. צריך להפעיל ידנית שירות שנקרא Advanced Chat Service, אחרת הפקודות לקריאת הודעות לא קיימות בכלל. בהרצה הראשונה גוגל מציגה מסך מפחיד שהאפליקציה לא מאומתת, וצריך לדעת לעבור אותו. בלי סימון של נקודת התחלה, הבוט יגיב לכל ההיסטוריה הישנה של הקבוצה בבת אחת. אם הבוט לא מזהה את ההודעות של עצמו, הוא נכנס ללולאה ומגיב לעצמו בלי סוף. וכשמגיעים לחלק של ימות, קריאה ישירה מ-Apps Script לשרת של ימות פשוט לא עוברת, וצריך רכיב מגשר באמצע.

                  עכשיו נעבור שלב שלב.

                  חלק א: לחבר את Google Chat ל-Apps Script

                  שלב 1: חשבון בוט ייעודי

                  פותחים או לוקחים חשבון גוגל נפרד שישמש כבוט. לא החשבון האישי שלכם, כי כל מה שהבוט יכתוב יופיע בשם החשבון הזה. נכנסים לחשבון הזה, נכנסים ל-Google Chat, ומוודאים שהוא חבר בקבוצה שבה הבוט אמור לפעול. אם הוא לא חבר, הוא לא יראה הודעות ולא יוכל לכתוב. המכשול הראשון טריוויאלי אבל קורה.

                  שלב 2: פתיחת פרויקט Apps Script

                  נכנסים לכתובת script.google.com. שימו לב היטב: צריך להיות מחוברים לחשבון של הבוט, לא לשלכם. אם יש לכם כמה חשבונות גוגל פתוחים בדפדפן, הכי בטוח לפתוח חלון גלישה פרטית ולהיכנס רק עם חשבון הבוט. זה מונע את הטעות הכי נפוצה, שבה הסקריפט נוצר בטעות תחת החשבון הלא נכון וכל ההרשאות אחר כך מתייחסות לחשבון הלא נכון. לוחצים על פרויקט חדש. קיבלתם עורך קוד שרץ על השרתים של גוגל בחינם, בלי להתקין כלום.

                  שלב 3: הפעלת שירות ה-Chat

                  שלב שאי אפשר לדלג עליו. בצד שמאל של העורך יש רשימה שנקראת Services עם סימן פלוס לידה. לוחצים על הפלוס, בוחרים מהרשימה את Google Chat API, ולוחצים Add. מה שזה עושה: מוסיף לקוד שלכם אובייקט בשם Chat שדרכו קוראים וכותבים הודעות. בלי זה, השורה שקוראת את ההודעות תיתן שגיאה שהמשתנה Chat לא מוגדר. הרבה אנשים מדביקים קוד, מקבלים את השגיאה הזאת, וחושבים שהקוד שבור, כשבעצם הם רק דילגו על השלב הזה.

                  שלב 4: מציאת מזהה הקבוצה

                  לכל קבוצה ב-Chat יש מזהה שנראה כמו spaces/AAAAxxxxxxx. הדרך הכי פשוטה להשיג אותו: פותחים את הקבוצה ב-Google Chat בדפדפן, ומסתכלים על שורת הכתובת למעלה. החלק שאחרי המילה space הוא המזהה. מעתיקים אותו בצד, נצטרך אותו בקוד.

                  שלב 5: הקוד המלא

                  מוחקים את מה שהיה בעורך ומדביקים את הקוד הזה במלואו. משנים רק שתי שורות למעלה: מזהה הקבוצה, ואם רוצים תשובות חכמות גם מפתח של Gemini. אם לא שמים מפתח Gemini, הבוט עדיין עובד ומגיב בתשובה פשוטה, כדי שתראו שהמנגנון חי.

                  // ===== הגדרות - שנו רק את השתיים הראשונות =====
                  const SPACE = 'spaces/PASTE_SPACE_ID';            // מזהה הקבוצה משלב 4
                  const GEMINI_API_KEY = 'PASTE_GEMINI_KEY';        // אופציונלי - אפשר להשאיר ריק
                  const GEMINI_MODEL = 'gemini-flash-lite-latest';
                  const TRIGGER = /בוט/i;                            // מילת ההפעלה בהודעה
                  
                  // ===== הלולאה הראשית - רצה כל דקה מהטריגר =====
                  function checkMessages() {
                    const props = PropertiesService.getScriptProperties();
                    const last = props.getProperty('last');
                  
                    // הרצה ראשונה: רק לסמן נקודת התחלה, בלי להגיב להיסטוריה
                    if (!last) {
                      props.setProperty('last', 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('last', fresh[0].createTime);
                    fresh.reverse(); // לטפל מהישן לחדש
                  
                    for (const m of fresh) {
                      if (isSelf(m)) continue;                    // לא להגיב לעצמו - מונע לולאה
                      const t = (m.text || '').trim();
                      if (!t || !TRIGGER.test(t)) continue;       // מגיב רק כשכתבו את מילת ההפעלה
                      const answer = ask(t);
                      if (answer) post(answer);
                    }
                  }
                  
                  // ===== האם ההודעה היא של הבוט עצמו =====
                  function isSelf(m) {
                    const me = Session.getActiveUser().getEmail();  // המייל של חשבון הבוט
                    return m.sender && m.sender.email && m.sender.email === me;
                  }
                  
                  // ===== שאלה ל-Gemini, או תשובת ברירת מחדל אם אין מפתח =====
                  function ask(question) {
                    if (!GEMINI_API_KEY || GEMINI_API_KEY.indexOf('PASTE') === 0) {
                      return 'קיבלתי: ' + question;               // מצב בדיקה בלי Gemini
                    }
                    const url = 'https://generativelanguage.googleapis.com/v1beta/models/'
                              + GEMINI_MODEL + ':generateContent?key=' + GEMINI_API_KEY;
                    const body = { contents: [{ role: 'user', parts: [{ text: question }] }] };
                    const r = UrlFetchApp.fetch(url, {
                      method: 'post', contentType: 'application/json',
                      payload: JSON.stringify(body), muteHttpExceptions: true
                    });
                    if (r.getResponseCode() !== 200) { console.log('Gemini', r.getContentText()); return null; }
                    try {
                      return JSON.parse(r.getContentText()).candidates[0].content.parts.map(p => p.text).join('').trim();
                    } catch (e) { return null; }
                  }
                  
                  // ===== כתיבת הודעה לקבוצה, בזהות חשבון הבוט =====
                  function post(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
                    });
                  }
                  

                  הסבר קצר על החלקים החשובים, כי כדאי להבין ולא רק להעתיק. הפונקציה checkMessages היא הלב. היא שומרת בזיכרון של הסקריפט חותמת זמן בשם last, שהיא הזמן של ההודעה האחרונה שכבר טופלה. בכל ריצה היא מבקשת את חמש עשרה ההודעות האחרונות, מסננת רק את אלה שחדשות יותר מ-last, ומטפלת בהן. הסינון הזה מונע מהבוט להגיב שוב ושוב לאותן הודעות. הפונקציה isSelf בודקת אם השולח הוא הבוט עצמו, לפי כתובת המייל, וזה מונע את הלולאה האינסופית שבה הבוט מגיב לתשובות של עצמו. הכתיבה חזרה נעשית עם ScriptApp.getOAuthToken, שזה מפתח הגישה הזמני של החשבון שמריץ את הסקריפט, כלומר הבוט כותב כאילו הוא יושב ומקליד בעצמו.

                  שלב 6: הרצה ראשונה ומעבר במסך ההרשאות

                  בוחרים למעלה בעורך את הפונקציה checkMessages מהרשימה הנפתחת, ולוחצים Run. כאן מגיע מכשול שמבלבל הרבה אנשים. גוגל תעצור ותבקש הרשאות, כי הקוד רוצה לגשת לצ'אט ולאינטרנט. מאשרים. אחר כך יופיע מסך אדום שאומר שהאפליקציה לא מאומתת ו-Google לא בדקה אותה. זה נשמע מפחיד אבל תקין לגמרי, כי זו אפליקציה פרטית שאתם עצמכם כתבתם רק לעצמכם. לוחצים על Advanced או על האפשרויות המתקדמות למטה, ואז על השורה שאומרת Go to project ולהמשיך. מאשרים את ההרשאות עד הסוף.

                  חשוב לדעת שההרצה הראשונה הזאת לא תעשה שום דבר גלוי. היא רק תרשום את חותמת הזמן ההתחלתית ותצא. זה בכוונה, כדי שהבוט לא יריק על הקבוצה תגובות לכל ההיסטוריה הישנה. אם דילגתם על השלב הזה, זה בדיוק המקור לתופעה שבה הבוט פתאום מגיב להמון הודעות ישנות.

                  שלב 7: הגדרת בדיקה אוטומטית כל דקה

                  עד עכשיו הסקריפט רץ רק כשלוחצים Run. כדי שיהפוך לבוט חי, צריך טריגר שמריץ אותו לבד. בצד שמאל בעורך יש אייקון של שעון מעורר, שנקרא Triggers. נכנסים לשם, לוחצים על Add Trigger למטה מימין, ובוחרים: הפונקציה checkMessages, מקור האירוע Time-driven, סוג Minutes timer, ותדירות Every minute. שומרים. מרגע זה גוגל מריצה את הבדיקה לבד כל דקה, גם כשהמחשב שלכם כבוי, כי הכל רץ בענן של גוגל.

                  זה גם המקום להבין למה בכלל פולינג ולא Webhook. Webhook היה נותן תגובה מיידית, אבל הוא חסום בחשבון פרטי כמו שהסברנו. הפולינג, כלומר הבדיקה כל דקה, הוא מה שמאפשר לעקוף את החסימה הזאת לגמרי, במחיר של עד דקה עיכוב.

                  שלב 8: בדיקה שהכל עובד

                  נכנסים לקבוצה מהחשבון האישי שלכם, לא של הבוט, וכותבים הודעה שמכילה את מילת ההפעלה, למשל: בוט מה שלומך. ממתינים עד דקה. הבוט אמור לענות. אם הגדרתם מפתח Gemini תקבלו תשובה חכמה, ואם לא, תקבלו את המילים קיבלתי ואת מה שכתבתם, וזה כבר מוכיח שכל השרשרת עובדת.

                  המכשולים הנפוצים, ואיך פותרים כל אחד

                  הבוט לא עונה בכלל. תסתכלו בעורך על החלק Executions בצד שמאל. אם checkMessages לא רצה, הטריגר לא הוגדר, חזרו לשלב שבע. אם הוא רץ ונתן שגיאה על המשתנה Chat, לא הפעלתם את Advanced Chat Service, חזרו לשלב שלוש. אם הוא רץ בלי שגיאה אבל אין תגובה, כנראה חשבון הבוט לא באמת חבר בקבוצה, או שמזהה הקבוצה לא נכון.

                  הבוט מגיב לעצמו בלולאה. זה קורה כשהבדיקה isSelf לא תופסת. ודאו שאתם מריצים את הסקריפט מחשבון הבוט, כי הבדיקה משווה מול המייל של החשבון שמריץ. אם החשבון לא נכון, ההשוואה נכשלת והלולאה מתחילה.

                  הבוט הגיב להמון הודעות ישנות בבת אחת. דילגתם על ההרצה הראשונה הריקה. כבו את הטריגר, הריצו ידנית פעם אחת את checkMessages כדי לרשום נקודת התחלה טרייה, ואז הפעילו את הטריגר מחדש.

                  תשובות Gemini חוזרות ריקות. או שהמפתח שגוי, או ששם המודל לא נתמך במפתח שלכם. אפשר לבדוק מול רשימת המודלים שהמפתח תומך בהם ולעדכן את שם המודל בהתאם.

                  חלק ב: החיבור לימות, ולמה הוא חייב גישור

                  כאן מגיע החלק שהכי חשוב להבין, ושהכי הרבה אנשים נכשלים בו בלי להבין למה. עד עכשיו הכל היה בתוך העולם של גוגל. הסקריפט קרא לשירותים של גוגל עצמה, ולכן הכל עבד חלק. ברגע שרוצים שהסקריפט יקרא החוצה, לשרת של ימות המשיח, נתקלים בקיר. הקריאה הישירה מ-Apps Script לשרת של ימות פשוט לא עוברת.

                  לפני שסומכים על המילה שלי, זו בדיקה שכל אחד יכול להריץ ולראות במו עיניו. פותחים פונקציה זמנית בעורך, מדביקים את השורות האלה, ומריצים:

                  function testYemotDirect() {
                    const r = UrlFetchApp.fetch('https://www.call2all.co.il/ym/api/GetSession', {
                      muteHttpExceptions: true
                    });
                    console.log('קוד: ' + r.getResponseCode());
                    console.log('תשובה: ' + r.getContentText());
                  }
                  

                  כשמריצים את זה מ-Apps Script, מקבלים כשל ולא תשובה תקינה של ימות. אם תריצו בדיוק את אותה קריאה מהדפדפן או מהמחשב שלכם, היא כן תעבוד. ההבדל הוא לא הכתובת ולא הפקודה, אלא מאיפה הבקשה יוצאת. בקשה שיוצאת מהשרתים של גוגל לא מתקבלת אצל ימות. זו ההוכחה, והיא חוזרת על עצמה בכל פעם.

                  הפתרון הוא לשים רכיב מגשר קטן באמצע, שיושב במקום שכן מורשה לדבר עם ימות. הרכיב מקבל את הבקשה מהסקריפט של גוגל ומעביר אותה הלאה לימות. הכלי הכי נוח לזה הוא Cloudflare Worker, שהוא סקריפט זעיר שרץ בענן של קלאודפלייר בחינם. הסקריפט של גוגל מדבר עם הגשר, והגשר מדבר עם ימות. ככה עוקפים את החסימה בלי לשנות כלום בקוד של הבוט עצמו.

                  קוד הגשר: Cloudflare Worker

                  זה כל הקוד של הגשר. הוא מקבל בקשה, מוודא שהיא מגיעה עם מילת סוד שרק אתם מכירים כדי שאף אחד אקראי לא ישתמש בו, ומעביר את התוכן לימות בפקודת העלאת קובץ:

                  export default {
                    async fetch(request, env) {
                      if (request.method !== 'POST') {
                        return new Response('POST only', { status: 405 });
                      }
                  
                      // הגנה: רק בקשות עם הסוד הנכון ממשיכות
                      if (request.headers.get('X-Auth') !== env.SHARED_SECRET) {
                        return new Response('forbidden', { status: 403 });
                      }
                  
                      const data = await request.json(); // { ext, file, contents }
                  
                      // בונים את הבקשה לימות בפורמט שהיא מצפה לו
                      const form = new URLSearchParams();
                      form.set('token', env.YEMOT_TOKEN);                       // מספר-המערכת:סיסמה
                      form.set('what', 'ivr2:' + data.ext + '/' + data.file);  // יעד הקובץ
                      form.set('contents', data.contents);                     // תוכן הטקסט
                  
                      const r = await fetch('https://www.call2all.co.il/ym/api/UploadTextFile', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                        body: form
                      });
                  
                      return new Response(await r.text(), { status: r.status });
                    }
                  };
                  

                  מילות הסוד לא יושבות בקוד אלא בהגדרות הסודיות של ה-Worker. במסך של Cloudflare, תחת Settings ואז Variables, מוסיפים שני משתני סוד. הראשון YEMOT_TOKEN, שהערך שלו הוא מספר המערכת שלכם, נקודתיים, והסיסמה. השני SHARED_SECRET, שהוא סתם מחרוזת ארוכה ואקראית שאתם ממציאים, וישמש כמפתח בין הסקריפט לגשר. לאחר הפרסום תקבלו כתובת של ה-Worker, משהו שמסתיים ב-workers.dev, וזאת הכתובת שהסקריפט יפנה אליה.

                  חיבור הסקריפט אל הגשר

                  חוזרים לסקריפט של גוגל ומוסיפים את הפונקציה שמעבירה את ההודעות דרך הגשר. שנו את הכתובת ואת הסוד לאלה שלכם:

                  const BRIDGE_URL = 'https://your-worker.workers.dev';  // כתובת ה-Worker
                  const BRIDGE_SECRET = 'PASTE_YOUR_SHARED_SECRET';       // אותו סוד כמו ב-Worker
                  const YEMOT_EXT = '5';        // מספר השלוחה בקו
                  const YEMOT_FILE = '000.tts'; // הקובץ שהמחייגים ישמעו
                  
                  function syncToYemot() {
                    const msgs = Chat.Spaces.Messages.list(SPACE, { pageSize: 10, orderBy: 'createTime desc' })
                      .messages || [];
                    const withText = msgs.filter(m => m.text && m.text.trim()).reverse();
                    if (!withText.length) return;
                  
                    const lines = withText.map(m => {
                      const who = m.sender && m.sender.displayName ? m.sender.displayName : 'בן משפחה';
                      return who + ' כתב: ' + m.text.trim();
                    });
                    const digest = 'ההודעות האחרונות בקבוצה. ' + lines.join('. ');
                  
                    UrlFetchApp.fetch(BRIDGE_URL, {
                      method: 'post',
                      contentType: 'application/json',
                      headers: { 'X-Auth': BRIDGE_SECRET },
                      payload: JSON.stringify({ ext: YEMOT_EXT, file: YEMOT_FILE, contents: digest }),
                      muteHttpExceptions: true
                    });
                  }
                  

                  מוסיפים לפונקציה הזאת טריגר משלה, בדיוק כמו בשלב שבע, שירוץ כל דקה או כל שתי דקות. מעכשיו, כל מה שנכתב בקבוצה נאסף, נשלח לגשר, והגשר מעלה אותו לימות כקובץ טקסט שהמערכת מקריאה בקול לכל מי שמחייג לשלוחה.

                  הוכחה שהגישור עובד

                  יש שתי בדיקות פשוטות. הראשונה: הריצו ידנית את syncToYemot מהעורך, ואז בקו ימות היכנסו לשלוחה שהגדרתם, ותראו שהקובץ 000.tts נוצר עם התוכן. אם הוא שם, הגשר העביר בהצלחה. השנייה, שמוכיחה את כל השרשרת ביחד: כתבו הודעה בקבוצה, המתינו דקה או שתיים, וחייגו לקו. אם אתם שומעים את ההודעה מוקראת, הוכחתם שהכל עובד מקצה לקצה, מהצ'אט, דרך הסקריפט, דרך הגשר, ועד הטלפון.

                  סיכום השרשרת

                  כדי לראות את התמונה השלמה, זה מה שקורה בכל מחזור. מישהו כותב בקבוצת Google Chat. הסקריפט של Apps Script, שרץ כחבר רגיל בקבוצה, קורא את ההודעה בבדיקה המחזורית שלו. אם צריך להעביר לימות, הוא לא פונה לימות ישירות, כי זה חסום, אלא שולח את התוכן ל-Cloudflare Worker. ה-Worker, שיושב במקום שמורשה לדבר עם ימות, מעלה את הטקסט כקובץ TTS לשלוחה. מחייגים לקו ושומעים את ההודעות מוקראות. שום חלק בשרשרת לא דורש חשבון עסקי, ושום חלק לא שולח שיחות יוצאות, אז אין שום סיכון של חיוג לא רצוי.
                  בהצלחה רבה!

                  תגובה 1 תגובה אחרונה תגובה ציטוט 0

                  שלום! נראה שהשיחה הזו מעניינת אותך, אבל עדיין אין לך חשבון.

                  נמאס לכם לגלול בין אותם הפוסטים בכל ביקור? כשנרשמים לחשבון, תמיד תחזרו בדיוק למקום שבו הייתם קודם, ותוכלו לבחור לקבל התראות על תגובות חדשות (בין אם במייל, ובין אם בהתראת פוש). תוכלו גם לשמור סימניות ולפרגן ב-upvote לפוסטים כדי להביע הערכה לחברי קהילה אחרים.

                  בעזרת התרומה שלך, הפוסט הזה יכול להיות אפילו טוב יותר 💗

                  הרשמה התחברות
                  • פוסט ראשון
                    פוסט אחרון