מוגן
-
בקשת מידע | איך רושמים מספר שלדה של אופניים חשמליים באתר הרישמי של ממשלת ישראל -
שאלה | פיתוח חדש לחיסכון בחשמל ובכסף וניהול מים חמים - אשמח לדעתכם כבעלי משפחותיש היום אפשרות מעשית לשלוט עם הטלפון הכשר בשיחה טלפונית על מוצר חשמלי כל שהוא כמו מזגן או מוצר אחר?
-
שיתוף | 'פלאפון מייל' - כולל קבלת ושליחת מיילים דרך הפלאפון, קריינות מקצועית, ועוד...@פלמנמוני בענין האנשי קשר אם יש אפשרות שלפני השליחה ואחרי ההקלדה של האיש קשר הוא יקריא את כתובת המייל זה יהיה יעייל מאוד, משום שכך יהיה ניתן לוודא שהמייל נשלח לכתובת הנכונה.
-
שיתוף | 'פלאפון מייל' - כולל קבלת ושליחת מיילים דרך הפלאפון, קריינות מקצועית, ועוד... -
שיתוף | 'פלאפון מייל' - כולל קבלת ושליחת מיילים דרך הפלאפון, קריינות מקצועית, ועוד...@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'); } -
שאלה | פיתוח חדש לחיסכון בחשמל ובכסף וניהול מים חמים - אשמח לדעתכם כבעלי משפחות -
שאלה | פיתוח חדש לחיסכון בחשמל ובכסף וניהול מים חמים - אשמח לדעתכם כבעלי משפחות@עדי-פרפרה לא יודע למה אבל זה מרגיש בטקסטים שאתה לא דובר עברית במקור או שאתה בוט
בכל אופן כמו שכתבו רבים אחרי, המודל שיביא הכי הרבה נתח שוק חרדי הוא חיוג למערכת טלפונית, עם אפשרות להקיש 1 ולשמוע נתונים של כמות המים החמים שנותרה וכמו כן אפשרויות נוספות כמו לכבות או להדליק את הדוד על טיימר וכדומה.
בהצלחה מרובה -
שאלה | פיתוח חדש לחיסכון בחשמל ובכסף וניהול מים חמים - אשמח לדעתכם כבעלי משפחות@עדי-פרפרה נראה לי שיהיה לזה הרבה ביקוש אם יהיה ניתן לשמוע נתונים כתחליף במערכת טלפונית!
-
שיתוף | קו תמלול שנשלח למייל דרך מודלים מתקדמים של ג'מיני כולל יצירת קריינות ממוחשבת ועוד..@ARISHאין מענה משרת API
-
בקשה | מחפש שיבנו לי קו בימות המשיח של בעלי מקצוע@שמואל-ח. תשלח אפיון
-
שיתוף | 'פלאפון מייל' - כולל קבלת ושליחת מיילים דרך הפלאפון, קריינות מקצועית, ועוד...@3157686 הסיבה לכך היא שמיילים ארוכים או מיילים קצרים אך עם ציטוט ארוך עוברים את המגבלה שהוא יכול לקריין בפעם אחת, אני ביקשתי מג'מיני שיבטל לי את התמלול של הציטוט בהודעות עם שרשורים ארוכים וכעת זה עובד לי מצוין
-
שיתוף | סקריפט לטמפרמונקי ליצירת Markdown במערכת הפניות של נטפרי! V 3.0@לאצי מאוד יפה אבל ההגדרה של הצבעים לא עובד בפועל!
-
באג | מעבר לשלוחה אחרת - לא עובד.@מנשה-2 תעשה ריענון לאתר ותגדיר שוב
-
שיתוף | חדש תזמון הודעות בגוגל צאט !!!!@לומדעס משהו מוזר.. בבוקר עבד לי וכעת הפסיק לעבוד, האופציה הזו לא נלחצת מה יכול להיות הסיבה?
