Spaces:
Sleeping
Sleeping
| const CONFIG = { | |
| TRIAGE_API_URL: 'https://REPLACE_WITH_CLOUD_RUN_URL/api/triage', | |
| TRIAGE_API_KEY: 'REPLACE_WITH_TRIAGE_API_KEY', | |
| AUTO_SEND: false, | |
| MAX_THREADS_PER_RUN: 10, | |
| TRIAGED_LABEL: 'AI/Triaged', | |
| NEEDS_REVIEW_LABEL: 'AI/Needs-Review' | |
| }; | |
| function triageInboxAndReply() { | |
| const triagedLabel = getOrCreateLabel_(CONFIG.TRIAGED_LABEL); | |
| const reviewLabel = getOrCreateLabel_(CONFIG.NEEDS_REVIEW_LABEL); | |
| const query = 'in:inbox is:unread -label:"' + CONFIG.TRIAGED_LABEL + '"'; | |
| const threads = GmailApp.search(query, 0, CONFIG.MAX_THREADS_PER_RUN); | |
| for (const thread of threads) { | |
| try { | |
| const messages = thread.getMessages(); | |
| const message = messages[messages.length - 1]; | |
| const payload = { | |
| subject: message.getSubject() || '', | |
| sender: message.getFrom() || '', | |
| body: message.getPlainBody() || '' | |
| }; | |
| const triage = callTriageApi_(payload); | |
| const hasReplyAction = (triage.suggested_actions || []).indexOf('reply') !== -1; | |
| if (hasReplyAction && triage.suggested_reply) { | |
| if (CONFIG.AUTO_SEND) { | |
| message.reply(triage.suggested_reply); | |
| } else { | |
| message.createDraftReply(triage.suggested_reply); | |
| reviewLabel.addToThread(thread); | |
| } | |
| } | |
| applyActionLabels_(thread, triage.suggested_actions || []); | |
| triagedLabel.addToThread(thread); | |
| message.markRead(); | |
| } catch (error) { | |
| reviewLabel.addToThread(thread); | |
| Logger.log('Triage failed for thread ' + thread.getId() + ': ' + error); | |
| } | |
| } | |
| } | |
| function callTriageApi_(payload) { | |
| const response = UrlFetchApp.fetch(CONFIG.TRIAGE_API_URL, { | |
| method: 'post', | |
| contentType: 'application/json', | |
| headers: { | |
| 'x-api-key': CONFIG.TRIAGE_API_KEY | |
| }, | |
| payload: JSON.stringify(payload), | |
| muteHttpExceptions: true | |
| }); | |
| const code = response.getResponseCode(); | |
| if (code < 200 || code >= 300) { | |
| throw new Error('Triage API HTTP ' + code + ': ' + response.getContentText()); | |
| } | |
| return JSON.parse(response.getContentText()); | |
| } | |
| function applyActionLabels_(thread, actions) { | |
| const actionToLabel = { | |
| forward_to_it_sec: 'AI/Security', | |
| create_task: 'AI/Follow-Up', | |
| label_feedback: 'AI/Feedback', | |
| label_general: 'AI/General', | |
| move_to_junk: 'AI/Phishing', | |
| flag: 'AI/Important' | |
| }; | |
| for (const action of actions) { | |
| if (actionToLabel[action]) { | |
| getOrCreateLabel_(actionToLabel[action]).addToThread(thread); | |
| } | |
| } | |
| } | |
| function getOrCreateLabel_(name) { | |
| return GmailApp.getUserLabelByName(name) || GmailApp.createLabel(name); | |
| } | |
| function installTriageTrigger() { | |
| ScriptApp.getProjectTriggers().forEach(trigger => { | |
| if (trigger.getHandlerFunction() === 'triageInboxAndReply') { | |
| ScriptApp.deleteTrigger(trigger); | |
| } | |
| }); | |
| ScriptApp.newTrigger('triageInboxAndReply') | |
| .timeBased() | |
| .everyMinutes(5) | |
| .create(); | |
| } | |