שיתוף | 'פלאפון מייל' - כולל קבלת ושליחת מיילים דרך הפלאפון, קריינות מקצועית, ועוד...
-
@י.-י.-ל. מס' שנפתח במחשב חסום כברירת מחדל, אולם מס' שנפתח דרך הפלאפון פתוח כברירת מחדל
ההגיון בזה מאוד פשוט...@3157686 כתב בשיתוף | 'פלאפון מייל' - כולל קבלת ושליחת מיילים דרך הפלאפון, קריינות מקצועית, ועוד...:
מה יכולה ליהיות הבעיה?
כתוב לך מפורש, מה השאלה?
עליך להפעיל בגוגל קלאוד את השירות 'Generative Language API'אם כ"כ קשה לך לעשות את זה לבד, הנה תרגום גוגל ממה שקיבלת:
שגיאת תגובת Gemini: {"error":{"code":403,"message":"ממשק ה-API של השפה הגנרטיבית לא היה בשימוש בפרויקט 1032889097378 בעבר או שהוא מושבת. הפעל אותו על ידי ביקור בכתובת https://console.developers.google.com/apis/api/generativelanguage.googleapis.com/overview?project=1032889097378 ולאחר מכן נסה שוב. אם הפעלת ממשק API זה לאחרונה, המתן מספר דקות עד שהפעולה תופץ במערכות שלנו ו... נסה שוב.", "status":"PERMISSION_DENIED", "details":[{"@type":"type.googleapis.com/google.rpc.ErrorInfo", "reason":"SERVICE_DISABLED", "domain":"googleapis.com", "metadata":{"consumer":"projects/1032889097378", "containerInfo":"1032889097378", "serviceTitle":"Generative Language API", "activationUrl":"https://console.developers.google.com/apis/api/generativelanguage.googleapis.com/overview?project=1032889097378", "service":"generativelanguage.googleapis.com"}},{"@type":"type.googleapis.com/google.rpc.LocalizedMessage", "locale":"en-US", "message":"ל-Generative Language API יש לא נעשה בו שימוש בפרויקט 1032889097378 בעבר או שהוא מושבת. הפעל אותו על ידי ביקור בכתובת https://console.developers.google.com/apis/api/generativelanguage.googleapis.com/overview?project=1032889097378 ולאחר מכן נסה שוב. אם הפעלת את ה-API הזה לאחרונה, המתן מספר דקות עד שהפעולה תופץ במערכות שלנו ונסה שוב."},{"@type":"type.googleapis.com/google.rpc.Help","links":[{"description":"הפעלת API של מסוף המפתחים של גוגל","url":"https://console.developers.google.com/apis/api/generativelanguage.googleapis.com/overview?project=1032889097378"}]}]}}
-
@י.-י.-ל. מס' שנפתח במחשב חסום כברירת מחדל, אולם מס' שנפתח דרך הפלאפון פתוח כברירת מחדל
ההגיון בזה מאוד פשוט...@3157686 כתב בשיתוף | 'פלאפון מייל' - כולל קבלת ושליחת מיילים דרך הפלאפון, קריינות מקצועית, ועוד...:
מה יכולה ליהיות הבעיה?
כתוב לך מפורש, מה השאלה?
עליך להפעיל בגוגל קלאוד את השירות 'Generative Language API'אם כ"כ קשה לך לעשות את זה לבד, הנה תרגום גוגל ממה שקיבלת:
שגיאת תגובת Gemini: {"error":{"code":403,"message":"ממשק ה-API של השפה הגנרטיבית לא היה בשימוש בפרויקט 1032889097378 בעבר או שהוא מושבת. הפעל אותו על ידי ביקור בכתובת https://console.developers.google.com/apis/api/generativelanguage.googleapis.com/overview?project=1032889097378 ולאחר מכן נסה שוב. אם הפעלת ממשק API זה לאחרונה, המתן מספר דקות עד שהפעולה תופץ במערכות שלנו ו... נסה שוב.", "status":"PERMISSION_DENIED", "details":[{"@type":"type.googleapis.com/google.rpc.ErrorInfo", "reason":"SERVICE_DISABLED", "domain":"googleapis.com", "metadata":{"consumer":"projects/1032889097378", "containerInfo":"1032889097378", "serviceTitle":"Generative Language API", "activationUrl":"https://console.developers.google.com/apis/api/generativelanguage.googleapis.com/overview?project=1032889097378", "service":"generativelanguage.googleapis.com"}},{"@type":"type.googleapis.com/google.rpc.LocalizedMessage", "locale":"en-US", "message":"ל-Generative Language API יש לא נעשה בו שימוש בפרויקט 1032889097378 בעבר או שהוא מושבת. הפעל אותו על ידי ביקור בכתובת https://console.developers.google.com/apis/api/generativelanguage.googleapis.com/overview?project=1032889097378 ולאחר מכן נסה שוב. אם הפעלת את ה-API הזה לאחרונה, המתן מספר דקות עד שהפעולה תופץ במערכות שלנו ונסה שוב."},{"@type":"type.googleapis.com/google.rpc.Help","links":[{"description":"הפעלת API של מסוף המפתחים של גוגל","url":"https://console.developers.google.com/apis/api/generativelanguage.googleapis.com/overview?project=1032889097378"}]}]}}
-
@פלמנמוני מושלם אתה אלוף תודה
למה במיילים ארוכים הוא שולח רק חלק מהמייל? יש מה לעשות בנושא? -
@פלמנמוני מושלם אתה אלוף תודה
למה במיילים ארוכים הוא שולח רק חלק מהמייל? יש מה לעשות בנושא?@3157686 אתה יכול להכניס את הקוד הזה אך שים לב שיש בו כמה שינויים מהמקור.
- קובץ שמע מצורף שנשלח מושמע בקו לאחר השמעת ההודעה
- הקריינות היא רק של גוגל קלאוד בקול של אשה
ועוד כמה שינויים שביצעתי בג'ימיני
בהצלחה
const sheet = SpreadsheetApp.getActive(); const ss = SpreadsheetApp.getActiveSpreadsheet(); const ScriptProperties = PropertiesService.getScriptProperties(); const GOOGLE_TTS_VOICE = 'he-IL-Standard-A'; const GOOGLE_TTS_LANG = 'he-IL'; var SCRIPT_NAME = 'פלאפון-מייל'; const MainSheet = sheet.getSheetByName(SCRIPT_NAME); const SettingsSheet = sheet.getSheetByName('הגדרות'); const FilterSheet = sheet.getSheetByName('סינון'); const IdSheetSentEvenDay = sheet.getSheetByName('כתובות id שנשלחו ביום זוגי'); const IdSheetSentOddDay = sheet.getSheetByName('כתובות id שנשלחו ביום אי זוגי'); const ReplacementPatterns = sheet.getSheetByName('החלפות').getRange('A2:B').getValues(); const SettingsValues = SettingsSheet.getRange('B:B').getValues(); const DeleteSheets = SettingsValues[1][0]; const GOOGLE_API_KEY = SettingsValues[3][0]; const GOOGLE_TTS_SPEED = SettingsValues[4][0] || '1.0'; let username = SettingsValues[6][0]; let password = SettingsValues[7][0]; let token = SettingsValues[8][0]; const ExtensionArchive = SettingsValues[10][0]; const ExtensionSendMail = SettingsValues[11][0]; const ExtensionTzintuk = SettingsValues[12][0]; const TzintukimList = SettingsValues[13][0]; const TzintukTimeOut = SettingsValues[14][0]; const SearchWords = SettingsValues[16][0]; const WordsExclude = SettingsValues[17][0]; const TextSender = SettingsValues[19][0]; const TextSubject = SettingsValues[20][0]; const TextBody = SettingsValues[21][0]; const TextEnd = SettingsValues[22][0]; const TextDay = SettingsValues[23][0]; const TextDate = SettingsValues[24][0]; const TextHour = SettingsValues[25][0]; const TextAnd = SettingsValues[26][0]; const TextMinute = SettingsValues[27][0]; const TextAttachments = SettingsValues[28][0]; const TextNoAttachments = SettingsValues[29][0]; const NoTzintuk = SettingsValues[31][0]; const PathArchive = (`ivr2:${ExtensionArchive}/`); const PathTzintuk = (`ivr2:${ExtensionTzintuk}/`); const phones = (`tzl:${TzintukimList}`); const Url = 'https://www.call2all.co.il/ym/api/' const SearchByGmail = `${SearchWords} is:unread newer_than:1h -{in:draft ${WordsExclude}}` const HourAgo = new Date(Date.now()) const GEMINI_API_KEY = GOOGLE_API_KEY; var Sourcesheet = '1JTB8qWqubBkSvRgk5_DjlFhKqaSm0V4jwdS6gq6DxJY'; function mailToPhone() { for (let attempts = 1; attempts <= 3; attempts++) { if (testToken()) { checkForGmails(); processOutgoingMails(); break; } token = getToken(); } } function checkForGmails() { const EvenOrOdd = new Date().getDay() % 2; const SheetToday = EvenOrOdd === 1 ? IdSheetSentEvenDay : IdSheetSentOddDay; const LastRowEvenDay = IdSheetSentEvenDay.getLastRow(); const LastRowOddDay = IdSheetSentOddDay.getLastRow(); const SourceValuesEvenDay = LastRowEvenDay > 1 ? IdSheetSentEvenDay.getRange(`A2:A${LastRowEvenDay}`).getValues() : []; const SourceValuesOddDay = LastRowOddDay > 1 ? IdSheetSentOddDay.getRange(`A2:A${LastRowOddDay}`).getValues() : []; let didUpload = false; let newMailsCount = 0; let isVipBatch = false; const filters = getFilterLists(); const blockList = filters.blockedEmails; const vipList = filters.vipEmails; const blockedSubjects = filters.blockedSubjects; const Threads = GmailApp.search(SearchByGmail); for (const thread of Threads) { const Messages = thread.getMessages(); for (const message of Messages) { if (SourceValuesEvenDay.findIndex(e => e[0] === message.getId()) !== -1 || SourceValuesOddDay.findIndex(e => e[0] === message.getId()) !== -1 || message.getDate() < (HourAgo - 3600000)) { continue; } const senderFrom = message.getFrom(); const senderEmail = (senderFrom.match(/<([^>]+)>/) || [null, senderFrom])[1].toLowerCase(); const subject = message.getSubject().toLowerCase(); if (blockList.some(blocked => senderEmail.includes(blocked))) { markAsHandled(SheetToday, message.getId()); continue; } if (blockedSubjects.some(badWord => subject.includes(badWord))) { markAsHandled(SheetToday, message.getId()); continue; } if (vipList.some(vip => senderEmail.includes(vip))) { isVipBatch = true; } const Result = sendToYemot(message); if (Result) { newMailsCount++; didUpload = true; } SheetToday.getRange(SheetToday.getLastRow() + 1, 1).setNumberFormat("@").setValue(message.getId()); SpreadsheetApp.flush(); } } if (didUpload) { const getMenuVoiceResponse = fetch('GetIVR2Dir', { token, path: "/" }); let existingMenuText = getMenuVoiceResponse.extIni.menu_voice; let totalCount = newMailsCount; const regex = /(\d+) מיילים חדשים/; if (regex.test(existingMenuText)) { existingMenuText = existingMenuText.replace(regex, (match, oldCount) => { totalCount = parseInt(oldCount, 10) + newMailsCount; return `${totalCount} מיילים חדשים`; }); } else if (existingMenuText) { existingMenuText = `יש, ${newMailsCount} מיילים חדשים. ${existingMenuText}`; } else { existingMenuText = `יש, ${newMailsCount} מיילים חדשים. לשמיעת המיילים הקישו ${ExtensionArchive}. לשליחת מייל הקישו ${ExtensionSendMail}. להגדרות הצינתוקים הקישו ${ExtensionTzintuk}.`; } fetch('UpdateExtension', { token, path: "/", menu_voice: existingMenuText }); if (isVipBatch) { tzintuk(); } else { if (!isNowSilenceTime(NoTzintuk)) { tzintuk(); } } } } function sendToYemot(message) { const lMap = { 'א': 'אל"ף', 'ב': 'בי"ת', 'ג': 'גימ"ל', 'ד': 'דל"ת', 'ה': 'ה"א', 'ו': 'ו"ו', 'ז': 'זי"ן', 'ח': 'חי"ת', 'ט': 'טי"ת', 'י': 'יו"ד', 'כ': 'כ"ף', 'ל': 'למ"ד', 'מ': 'מ"ם', 'נ': 'נו"ן', 'ס': 'סמ"ך', 'ע': 'עי"ן', 'פ': 'פ"א', 'צ': 'צדי"ק', 'ק': 'קו"ף', 'ר': 'רי"ש', 'ש': 'שי"ן', 'ת': 'ת"ו' }; const MessageDate = message.getDate(); const FormattedHebrewDate = new Intl.DateTimeFormat('he-IL-u-ca-hebrew').format(MessageDate); const HebrewDay = ['ראשון', 'שני', 'שלישי', 'רביעי', 'חמישי', 'שישי', 'שבת']; const DateParts = FormattedHebrewDate.split(" "); const NumericDay = gimatria(DateParts[0]).split('').map(c => lMap[c] || c).join(' '); const MonthAndYear = DateParts.slice(1, -1).join(" "); const NumericYear = gimatria(DateParts[DateParts.length - 1].slice(-3)).split('').map(c => lMap[c] || c).join(' '); // --- חלק: ניקוי היסטוריית הודעות --- let cleanBody = message.getPlainBody(); // הסרת שורות ציטוט (המתחילות ב->) cleanBody = cleanBody.replace(/^>.*$/gm, ''); // רשימת תבניות המעידות על תחילת היסטוריה (אנגלית ועברית) const historySplitters = [ /On[\s\S]*?wrote:/i, // תבנית ג'ימייל אנגלית /בתאריך[\s\S]*?כתב:/, // תבנית ג'ימייל עברית /_{10,}/, // קו מפריד תחתון ארוך /-{10,}/, // קו מפריד אמצעי ארוך /From:[\s\S]*?Sent:/i // פורוורד או תבניות אאוטלוק ]; for (let pattern of historySplitters) { // חיתוך הטקסט ברגע שנמצאת תבנית היסטוריה const parts = cleanBody.split(pattern); if (parts.length > 1) { cleanBody = parts[0]; } } cleanBody = cleanBody.trim(); // הסרת רווחים מיותרים בהתחלה ובסוף // --- סוף חלק ניקוי הודעות --- // --- חלק חדש: טיפול בנושא ההודעה --- let rawSubject = message.getSubject() || ""; // ניקוי קידומות כמו Re, Fwd שגורמות לתרגום שגוי (כמו "מחדש") rawSubject = rawSubject.replace(/^([Rr][Ee]|[Ff][Ww][Dd]?):\s*/, '').trim(); let finalSubjectString = ""; if (rawSubject === "") { finalSubjectString = "אין נושא להודעה"; } else { let subjectTranslate; try { subjectTranslate = LanguageApp.translate(rawSubject, '', 'iw'); } catch (err) { subjectTranslate = rawSubject; } // כאן מחברים את המילה 'נושא' עם התרגום finalSubjectString = `${TextSubject}. ${subjectTranslate}`; } // --- סוף חלק טיפול בנושא --- let bodyTranslate; try { // שימוש ב-cleanBody במקום message.getPlainBody() bodyTranslate = LanguageApp.translate(cleanBody, '', 'iw'); } catch (err) { bodyTranslate = cleanBody; } const AttachmentNames = message.getAttachments().map(file => file.getName()); const fullSender = message.getFrom(); let senderName = fullSender; if (fullSender.includes('<')) { senderName = fullSender.split('<')[0].trim(); if (senderName === "") { senderName = fullSender.split('<')[1].split('@')[0].trim(); } } else if (fullSender.includes('@')) { senderName = fullSender.split('@')[0].trim(); } // שימוש במחרוזת הנושא המעובדת (finalSubjectString) במקום הלוגיקה הישנה const TtsStringTitle = `${TextSender}. ${senderName}. ${finalSubjectString}. ${AttachmentNames.length ? `${TextAttachments}. ${AttachmentNames.join(', ')}` : `${TextNoAttachments}.`} ${TextHour} ${MessageDate.getHours()} ${TextAnd} ${MessageDate.getMinutes()} ${TextMinute}. ${TextDay} ${HebrewDay[MessageDate.getDay()]}. ${TextDate} ${NumericDay} ${MonthAndYear} ${NumericYear}.`; let ttsString = `${TextBody}. ${bodyTranslate}.`; const attachments = message.getAttachments(); let audioFilesToUpload = []; for (let i = 0; i < attachments.length; i++) { let file = attachments[i]; if (isPdf(file)) { let pdfText = extractTextFromPdf(file); if (pdfText) { ttsString += `\nתוכן קובץ פי די אף, ${file.getName()}: ${pdfText}. סוף קובץ.`; } } else if (isAudio(file)) { audioFilesToUpload.push(file); ttsString += `\nמצורף קובץ שמע: ${file.getName()}. יושמע מיד עם סיום ההודעה...`; } } ReplacementPatterns.forEach(pattern => { const regex = new RegExp(pattern[0], 'g'); ttsString = ttsString.replace(regex, pattern[1]); }); // לוגיקת חיתוך לגוגל ומחרוזת מלאה לגיבוי const fullTtsString = ttsString + TextEnd; let googleTtsString = ttsString; if (googleTtsString.length > 4950) { googleTtsString = googleTtsString.substring(0, 4950); } googleTtsString += TextEnd; const MaxFileName = fetch('GetIVR2DirStats', { token, path: PathArchive }); if (MaxFileName.responseStatus === 'OK') { const LastFileName = MaxFileName.maxFile?.name?.split('.')[0]; let CurrentFileNum = (LastFileName !== undefined) ? Number(LastFileName) + 1 : 1; for (let j = 0; j < audioFilesToUpload.length; j++) { let attachmentName = CurrentFileNum.toString().padStart(3, '0') + ".wav"; if (uploadBlobToYemot(audioFilesToUpload[j], PathArchive, attachmentName, token, true)) { CurrentFileNum++; } } let BodyFileName = CurrentFileNum.toString().padStart(3, '0'); // ניסיון ראשון: Google Cloud TTS (עם הטקסט החתוך במידת הצורך) if (GOOGLE_API_KEY) { try { const titleBlob = googleTts(TtsStringTitle, GOOGLE_API_KEY, GOOGLE_TTS_LANG, GOOGLE_TTS_VOICE); const bodyBlob = googleTts(googleTtsString, GOOGLE_API_KEY, GOOGLE_TTS_LANG, GOOGLE_TTS_VOICE); if (titleBlob && bodyBlob) { const resTitle = uploadBlobToYemot(titleBlob, PathArchive, `${BodyFileName}-Title.mp3`, token, true); const resBody = uploadBlobToYemot(bodyBlob, PathArchive, `${BodyFileName}.mp3`, token, true); if (resTitle && resBody) return true; } } catch (e) { Logger.log(`Google TTS נכשל: ${e}. עובר לגיבוי רובוטי.`); } } // גיבוי: שליחה למנוע הרובוטי של ימות המשיח (טקסט מלא) try { const resTitle = fetch('UploadTextFile', { token, what: `${PathArchive}${BodyFileName}-Title.tts`, contents: TtsStringTitle }); const resBody = fetch('UploadTextFile', { token, what: `${PathArchive}${BodyFileName}.tts`, contents: fullTtsString }); return resTitle.responseStatus === 'OK' && resBody.responseStatus === 'OK'; } catch (e) { Logger.log(`שגיאה בגיבוי רובוטי: ${e}`); return false; } } return false; } // --- פונקציות עזר --- function isPdf(file) { return file.getContentType() === 'application/pdf' || file.getName().toLowerCase().endsWith('.pdf'); } function isAudio(file) { const type = file.getContentType(); const name = file.getName().toLowerCase(); return (type.startsWith('audio/') || type === 'application/octet-stream') && name.match(/\.(mp3|wav|m4a|wma|aac|ogg)$/); } function extractTextFromPdf(blob) { try { var newBlob = blob.copyBlob(); newBlob.setContentType('application/pdf'); const resource = { title: newBlob.getName(), mimeType: 'application/pdf' }; const file = Drive.Files.insert(resource, newBlob, { ocr: true, ocrLanguage: 'he' }); Utilities.sleep(1000); const doc = DocumentApp.openById(file.id); const text = doc.getBody().getText(); Drive.Files.remove(file.id); return text; } catch (e) { Logger.log("שגיאה בחילוץ טקסט מ-PDF: " + e); return ""; } } function testToken() { return !!token; } function getToken() { return token; } function fetch(action, params) { // כאן יש לממש את הקריאה ל-API של ימות המשיח Logger.log(`fetch action: ${action}`); return { responseStatus: 'OK', extIni: { menu_voice: "" }, maxFile: { name: "000.mp3" } }; } function uploadBlobToYemot(blob, path, name, tokenParam, binary) { // כאן יש לממש את העלאת ה-Blob לשרת Logger.log(`uploading ${name} to ${path}`); return true; } function googleTts(text, apiKey, lang, voice) { // כאן יש לממש את הקריאה ל-API של גוגל try { return Utilities.newBlob('', 'audio/mpeg', 'tts.mp3'); } catch (e) { Logger.log(`googleTts error: ${e}`); return null; } } function tzintuk() { Logger.log('tzintuk triggered'); } function isNowSilenceTime(range) { return false; } function getFilterLists() { return { blockedEmails: [], vipEmails: [], blockedSubjects: [] }; } function markAsHandled(sheet, id) { sheet.getRange(sheet.getLastRow() + 1, 1).setValue(id); } function gimatria(input) { return input; } function processOutgoingMails() { Logger.log('processOutgoingMails called'); } -
-
@מוגן כתב בשיתוף | 'פלאפון מייל' - כולל קבלת ושליחת מיילים דרך הפלאפון, קריינות מקצועית, ועוד...:
@3157686 האמת שהקוד שלי זה העבודה המדהימה של @פלמנמוני בתוספות קטנות ובדיוק בשביל התקלות שאתה מעלה בפוסטים אני מציע לך לשנות את הקוד
בכל אופן תמיד תוכל לשמור את הקוד המקורי ואם לא יתאים לך תחזיר אותואיפה אני משנה אותו?
וזה תמיד יהיה בקול של אישה?
יש אפשרות לשנות קול? -
@מוגן כתב בשיתוף | 'פלאפון מייל' - כולל קבלת ושליחת מיילים דרך הפלאפון, קריינות מקצועית, ועוד...:
@3157686 האמת שהקוד שלי זה העבודה המדהימה של @פלמנמוני בתוספות קטנות ובדיוק בשביל התקלות שאתה מעלה בפוסטים אני מציע לך לשנות את הקוד
בכל אופן תמיד תוכל לשמור את הקוד המקורי ואם לא יתאים לך תחזיר אותואיפה אני משנה אותו?
וזה תמיד יהיה בקול של אישה?
יש אפשרות לשנות קול?@3157686 כתב בשיתוף | 'פלאפון מייל' - כולל קבלת ושליחת מיילים דרך הפלאפון, קריינות מקצועית, ועוד...:
איפה אני משנה אותו?
וזה תמיד יהיה בקול של אישה?
יש אפשרות לשנות קול?בשורה הרביעית בסקריפט תוכל לשנות-
A/C - אישה
B/D - גבר
כרגע מוגדר D
שים לב שאם תעדכן בעתיד את הסקריפט תצטרך לשנות שובאגב, יש עכשיו עדכון זמין שגורם ששולח לקו רק את ההודעה האחרונה בשרשור
-
@חנני350 כתב בשיתוף | 'פלאפון מייל' - כולל קבלת ושליחת מיילים דרך הפלאפון, קריינות מקצועית, ועוד...:
לא מצליח לי לשלוח לאנשי קשר מישהו יכול להסביר לי למה?
תוקן הבאג שהיה, יש לעדכן את הסקריפט, ייתכן ויידרשו הרשאות
-
@פלמנמוני בענין האנשי קשר אם יש אפשרות שלפני השליחה ואחרי ההקלדה של האיש קשר הוא יקריא את כתובת המייל זה יהיה יעייל מאוד, משום שכך יהיה ניתן לוודא שהמייל נשלח לכתובת הנכונה.