您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Assist in generating email replies using AI.
// ==UserScript== // @name AI Email Assistant for GMAIL // @namespace http://tampermonkey.net/ // @version 1.3.0 // @description Assist in generating email replies using AI. // @author Morgan Schaefer // @match https://mail.google.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=google.com // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; const LOCAL_STORAGE_KEY = 'openai_api_key'; function promptForApiKey() { let apiKey = window.prompt("Enter your OpenAI API Key:"); if (apiKey) { localStorage.setItem(LOCAL_STORAGE_KEY, apiKey); return apiKey; } alert("API Key is required to use this script."); return null; } function getApiKey() { let apiKey = localStorage.getItem(LOCAL_STORAGE_KEY); if (!apiKey) { apiKey = promptForApiKey(); } return apiKey; } const API_KEY = getApiKey(); if (!API_KEY) return; function createButton(label, onClick) { const button = document.createElement('button'); button.textContent = label; styleButton(button); button.addEventListener('click', onClick); return button; } function styleButton(button) { Object.assign(button.style, { margin: '5px', padding: '5px', backgroundColor: '#1a73e8', color: '#fff', border: 'none', borderRadius: '3px', cursor: 'pointer' }); } function appendButtonsToComposeWindow() { const composeWindow = document.querySelector('td.I5 form.bAs'); if (composeWindow) { const targetTable = composeWindow.querySelector('table.IG'); if (targetTable && !document.getElementById('ai-assistant-button')) { const newTr = document.createElement('tr'); newTr.id = 'ai-assistant-row'; const newTd = document.createElement('td'); newTd.colSpan = 2; // Create the AI Assistant button const assistantButton = createButton('Assistant AI', onButtonClick); assistantButton.id = 'ai-assistant-button'; // Create the input field const inputField = document.createElement('input'); inputField.type = 'text'; inputField.id = 'ai-input-field'; inputField.placeholder = 'Instructions supplémentaires...'; styleInputField(inputField); // Append the button and input field to the table cell newTd.appendChild(assistantButton); newTd.appendChild(inputField); newTr.appendChild(newTd); targetTable.querySelector('tbody').appendChild(newTr); } } } function styleInputField(input) { Object.assign(input.style, { marginLeft: '10px', padding: '5px', border: '1px solid #ccc', borderRadius: '3px', width: '200px' }); } function getEmailAddresses() { const fromElement = document.querySelector('span#\\:vf'); const toElement = document.querySelector('div.afZ.af1 div.akl'); const from = fromElement ? fromElement.textContent.trim() : 'Unknown Sender'; const to = toElement ? toElement.textContent.trim() : 'Unknown Recipient'; return { from, to }; } function getConversationContent() { const messages = document.querySelectorAll('.ii.gt .a3s.aiL'); return Array.from(messages).map(msg => { const parentContainer = msg.closest('.adn.ads'); const senderNameElement = parentContainer.querySelector('.gD span'); const senderName = senderNameElement ? senderNameElement.textContent : 'Unknown Sender'; const dateTimeElement = parentContainer.querySelector('.g3'); const dateTime = dateTimeElement ? dateTimeElement.getAttribute('title') : 'Unknown Date/Time'; const messageContent = msg.innerText.trim(); console.log(`Sender: ${senderName}, Date/Time: ${dateTime}`); return `Sender: ${senderName}, Date/Time: ${dateTime}\n${messageContent}`; }).join('\n\n').trim(); } async function fetchOpenAIResponse(endpoint, payload) { try { const response = await fetch(`https://api.openai.com/v1/${endpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_KEY}` }, body: JSON.stringify(payload) }); const data = await response.json(); return response.ok ? data.choices.map(choice => choice.message.content.trim()) : ['Failed to generate response.']; } catch (error) { console.error('Error fetching AI responses:', error); return ['Failed to generate response.']; } } async function generateAIResponses(prompt) { return fetchOpenAIResponse('chat/completions', { model: "gpt-4o-2024-08-06", messages: [ { role: "system", content: `You are an assistant that responds in the same language as the input.` }, { role: "user", content: prompt } ], max_tokens: 1500, temperature: 0.9 }); } async function identifyKeyPointsAndVariables(conversation) { return fetchOpenAIResponse('chat/completions', { model: "gpt-4o-2024-08-06", messages: [ { role: "system", content: `Tu es un assistant qui analyse un mail reçu et extrait les éléments de réponse que l'interlocuteur attend.` }, { role: "user", content: `${conversation}` } ], max_tokens: 150 }); } async function generateThreeDistinctResponses(keyPoints, additionalInstructions) { const initialResponse = await fetchOpenAIResponse('chat/completions', { model: "gpt-4o-2024-08-06", messages: [ { role: "system", content: `You are an assistant that provides concise and distinct responses. Generate three distinct short responses to the following key points. The response should not be longer than 6 words per key point.` }, { role: "user", content: `Provide three distinct responses for these key points or questions:\n\n${keyPoints}\n\n the responses must be variation of the response : ${additionalInstructions}` } ], max_tokens: 150, n: 1, temperature: 0.8 }); if (initialResponse && initialResponse.length > 0) { return initialResponse[0].split('\n').map(resp => resp.trim()).filter(Boolean).slice(0, 3); } return ['Failed to generate responses.']; } async function insertResponseInEmailBody(emailBody, response) { const fragment = document.createDocumentFragment(); response.split('\n').forEach((line) => { const textNode = document.createTextNode(line); fragment.appendChild(textNode); fragment.appendChild(document.createElement('br')); }); emailBody.appendChild(fragment); } async function onButtonClick() { const emailBody = document.querySelector('div[contenteditable="true"][role="textbox"]'); if (emailBody) { emailBody.focus(); const conversationContent = getConversationContent(); const { from, to } = getEmailAddresses(); // Get the additional instructions from the input field const additionalInstructions = document.getElementById('ai-input-field').value || ''; try { const keyPointsAndVariables = await identifyKeyPointsAndVariables(conversationContent); const shortResponses = await generateThreeDistinctResponses(keyPointsAndVariables, additionalInstructions); // Pass additional instructions here let buttonContainer = document.querySelector('#response-options-container'); if (!buttonContainer) { buttonContainer = document.createElement('div'); buttonContainer.id = 'response-options-container'; const composeWindow = document.querySelector('td.I5 form.bAs'); if (composeWindow) { composeWindow.appendChild(buttonContainer); } } displayResponseOptions(shortResponses, emailBody, conversationContent, buttonContainer, from, to, additionalInstructions); } catch (error) { console.error('Error inserting AI response:', error); } } } function displayResponseOptions(responses, emailBody, conversationContent, buttonContainer, from, to, additionalInstructions) { responses.forEach((response) => { const responseButton = createButton(response, async () => { const aiPrompt = `You are an email assistant tasked with generating a detailed response. The response is as follows:\n\nFrom: ${from}\nTo: ${to}\n\n${conversationContent}\n\n The reponse must be a elaboration of: ${additionalInstructions}\n\nBased on the above conversation, generate a detailed response using the selected short response option:\n\n${response}. You should generate only the body of the response`; const aiResponses = await generateAIResponses(aiPrompt); await insertResponseInEmailBody(emailBody, aiResponses[0]); }); buttonContainer.appendChild(responseButton); }); } function observeDOMChanges() { const observer = new MutationObserver(() => appendButtonsToComposeWindow()); observer.observe(document.body, { childList: true, subtree: true }); } observeDOMChanges(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址