code refactored to have one method to calculate the final prompt. see #580
This commit is contained in:
parent
a505f22261
commit
b08b8563d0
5 changed files with 67 additions and 104 deletions
|
|
@ -1900,9 +1900,6 @@
|
||||||
"auto_summary_failed": {
|
"auto_summary_failed": {
|
||||||
"message": "Failed to generate AI summary. Please confirm your settings and try again."
|
"message": "Failed to generate AI summary. Please confirm your settings and try again."
|
||||||
},
|
},
|
||||||
"auto_summary_prompt": {
|
|
||||||
"message": "Please provide a concise summary of the following email message. The summary should be 3-5 sentences maximum and capture the main points:\n\n"
|
|
||||||
},
|
|
||||||
"customPrompts_export_include_api_settings": {
|
"customPrompts_export_include_api_settings": {
|
||||||
"message": "Do you want to include the API settings in the export? Be aware that also the API Key will be saved in the file!",
|
"message": "Do you want to include the API settings in the export? Be aware that also the API Key will be saved in the file!",
|
||||||
"description": ""
|
"description": ""
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ mzta-background.js (checks summarize_auto + summarize_display_mode prefs)
|
||||||
| `js/mzta-prompts.js` | Prompt definitions (built-in) and custom prompt loading |
|
| `js/mzta-prompts.js` | Prompt definitions (built-in) and custom prompt loading |
|
||||||
| `js/mzta-placeholders.js` | Placeholder definitions and resolution logic |
|
| `js/mzta-placeholders.js` | Placeholder definitions and resolution logic |
|
||||||
| `js/mzta-utils.js` | General utilities (email parsing, storage helpers, etc.) |
|
| `js/mzta-utils.js` | General utilities (email parsing, storage helpers, etc.) |
|
||||||
| `js/mzta-utils-prompt.js` | Prompt-specific utilities (text truncation, lang injection) |
|
| `js/mzta-utils-prompt.js` | Prompt-specific utilities (text truncation, lang injection, `buildSummaryPrompt()` for unified summary prompt assembly) |
|
||||||
| `js/mzta-compose-script.js` | Content script for compose and message display: injects AI response into compose window, renders summary/spam banners in message display |
|
| `js/mzta-compose-script.js` | Content script for compose and message display: injects AI response into compose window, renders summary/spam banners in message display |
|
||||||
| `js/mzta-chatgpt.js` | ChatGPT Web integration (opens browser window, reads DOM) |
|
| `js/mzta-chatgpt.js` | ChatGPT Web integration (opens browser window, reads DOM) |
|
||||||
| `js/mzta-special-commands.js` | Handles special prompt actions (add_tags, calendar, task) |
|
| `js/mzta-special-commands.js` | Handles special prompt actions (add_tags, calendar, task) |
|
||||||
|
|
|
||||||
|
|
@ -74,13 +74,17 @@ The summarize feature uses two distinct prompt pathways:
|
||||||
- Default prompt texts are stored as i18n keys: `prompt_summarize_full_text`, `prompt_summarize_email_template_full_text`, `prompt_summarize_email_separator_full_text`
|
- Default prompt texts are stored as i18n keys: `prompt_summarize_full_text`, `prompt_summarize_email_template_full_text`, `prompt_summarize_email_separator_full_text`
|
||||||
|
|
||||||
**Inline Summary on Message Display** (automatic or manual per `summarize_auto` pref):
|
**Inline Summary on Message Display** (automatic or manual per `summarize_auto` pref):
|
||||||
- Uses a single i18n string `auto_summary_prompt` concatenated with the message body text
|
- Uses the same 3 special prompts as webchat mode, via `taPromptUtils.buildSummaryPrompt()` in `js/mzta-utils-prompt.js`
|
||||||
- Does **not** use the 3 special prompts above
|
|
||||||
- Does **not** support `chatgpt_web` connection type (shows error if configured)
|
- Does **not** support `chatgpt_web` connection type (shows error if configured)
|
||||||
- Result is rendered as a styled banner at the top of the message body via `mzta-compose-script.js`
|
- Result is rendered as a styled banner at the top of the message body via `mzta-compose-script.js`
|
||||||
- Banner includes a refresh button (↻) to regenerate the summary
|
- Banner includes a refresh button (↻) to regenerate the summary
|
||||||
- Cached per-message via `taSummaryStore` / `taStorage` (max 100 entries)
|
- Cached per-message via `taSummaryStore` / `taStorage` (max 100 entries)
|
||||||
|
|
||||||
|
**Unified Prompt Building** — `taPromptUtils.buildSummaryPrompt(messageDataArray)`:
|
||||||
|
- All summary paths (inline, webchat single, webchat multi) use this single method
|
||||||
|
- Accepts an array of `{ message, fullMessage }` entries
|
||||||
|
- Returns `{ promptText, promptInfo }` where `promptInfo` is the `prompt_summarize` prompt object
|
||||||
|
|
||||||
## Prompt Types Reference
|
## Prompt Types Reference
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { placeholdersUtils } from './mzta-placeholders.js';
|
import { placeholdersUtils } from './mzta-placeholders.js';
|
||||||
import { extractJsonObject } from './mzta-utils.js';
|
import {
|
||||||
|
extractJsonObject,
|
||||||
|
getMailBody,
|
||||||
|
htmlBodyToPlainText
|
||||||
|
} from './mzta-utils.js';
|
||||||
|
import { getSpecialPrompts } from './mzta-prompts.js';
|
||||||
import { prefs_default } from '../options/mzta-options-default.js';
|
import { prefs_default } from '../options/mzta-options-default.js';
|
||||||
|
|
||||||
export const taPromptUtils = {
|
export const taPromptUtils = {
|
||||||
|
|
@ -126,6 +131,48 @@ export const taPromptUtils = {
|
||||||
return chatgpt_lang;
|
return chatgpt_lang;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
async buildSummaryPrompt(messageDataArray) {
|
||||||
|
const specialPrompts = await getSpecialPrompts();
|
||||||
|
const prompt = specialPrompts.find(p => p.id === 'prompt_summarize');
|
||||||
|
const prompt_email = specialPrompts.find(p => p.id === 'prompt_summarize_email_template');
|
||||||
|
const prompt_email_separator = specialPrompts.find(p => p.id === 'prompt_summarize_email_separator');
|
||||||
|
|
||||||
|
const chatgpt_lang = await taPromptUtils.getDefaultLang(prompt);
|
||||||
|
|
||||||
|
const prompt_string = await taPromptUtils.preparePrompt({
|
||||||
|
curr_prompt: prompt,
|
||||||
|
chatgpt_lang: chatgpt_lang,
|
||||||
|
});
|
||||||
|
const prompt_email_separator_string = await taPromptUtils.preparePrompt({
|
||||||
|
curr_prompt: prompt_email_separator,
|
||||||
|
chatgpt_lang: chatgpt_lang,
|
||||||
|
});
|
||||||
|
|
||||||
|
const messages_list = [];
|
||||||
|
for (let entry of messageDataArray) {
|
||||||
|
const bodyHtml = getMailBody(entry.fullMessage);
|
||||||
|
let bodyText = htmlBodyToPlainText(bodyHtml.html);
|
||||||
|
if (bodyText.length === 0) {
|
||||||
|
bodyText = bodyHtml.text || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
messages_list.push(await taPromptUtils.preparePrompt({
|
||||||
|
curr_prompt: prompt_email,
|
||||||
|
curr_message: entry.message,
|
||||||
|
chatgpt_lang: chatgpt_lang,
|
||||||
|
body_text: bodyText,
|
||||||
|
subject_text: entry.fullMessage.headers.subject,
|
||||||
|
msg_text: bodyHtml,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const messages_string = messages_list.join(prompt_email_separator_string);
|
||||||
|
const promptText = prompt_string + prompt_email_separator_string + messages_string;
|
||||||
|
|
||||||
|
return { promptText, promptInfo: prompt };
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts tags from the response text.
|
* Extracts tags from the response text.
|
||||||
* @param {string} response_text - The response text from which to extract tags.
|
* @param {string} response_text - The response text from which to extract tags.
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,7 @@ import {
|
||||||
import { taPromptUtils } from './js/mzta-utils-prompt.js';
|
import { taPromptUtils } from './js/mzta-utils-prompt.js';
|
||||||
import { mzta_specialCommand } from './js/mzta-special-commands.js';
|
import { mzta_specialCommand } from './js/mzta-special-commands.js';
|
||||||
import {
|
import {
|
||||||
getSpamFilterPrompt,
|
getSpamFilterPrompt
|
||||||
getSpecialPrompts
|
|
||||||
} from './js/mzta-prompts.js';
|
} from './js/mzta-prompts.js';
|
||||||
import { taSpamReport } from './js/mzta-spamreport.js';
|
import { taSpamReport } from './js/mzta-spamreport.js';
|
||||||
import { taSummaryStore } from './js/mzta-summarystore.js';
|
import { taSummaryStore } from './js/mzta-summarystore.js';
|
||||||
|
|
@ -484,13 +483,6 @@ async function _generateSummaryForMessage(headerMessageId, tabId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const fullMessage = await browser.messages.getFull(messageResult.messages[0].id);
|
const fullMessage = await browser.messages.getFull(messageResult.messages[0].id);
|
||||||
const mailBody = getMailBody(fullMessage);
|
|
||||||
let bodyText = htmlBodyToPlainText(mailBody.html);
|
|
||||||
if (bodyText.length === 0) {
|
|
||||||
bodyText = mailBody.text.replace(/\s+/g, ' ').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
const promptText = browser.i18n.getMessage('auto_summary_prompt') + bodyText;
|
|
||||||
|
|
||||||
const connectionType = getConnectionType(prefs, {}, 'summarize');
|
const connectionType = getConnectionType(prefs, {}, 'summarize');
|
||||||
|
|
||||||
|
|
@ -501,6 +493,8 @@ async function _generateSummaryForMessage(headerMessageId, tabId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { promptText } = await taPromptUtils.buildSummaryPrompt([{ message: messageResult.messages[0], fullMessage }]);
|
||||||
|
|
||||||
const cmd = new mzta_specialCommand({
|
const cmd = new mzta_specialCommand({
|
||||||
prompt: promptText,
|
prompt: promptText,
|
||||||
llm: connectionType,
|
llm: connectionType,
|
||||||
|
|
@ -532,22 +526,6 @@ async function _generateSummaryForMessage(headerMessageId, tabId) {
|
||||||
|
|
||||||
async function _openSummaryWebchat(headerMessageId, tabId) {
|
async function _openSummaryWebchat(headerMessageId, tabId) {
|
||||||
try {
|
try {
|
||||||
const specialPrompts = await getSpecialPrompts();
|
|
||||||
const prompt = specialPrompts.find(p => p.id === 'prompt_summarize');
|
|
||||||
const prompt_email = specialPrompts.find(p => p.id === 'prompt_summarize_email_template');
|
|
||||||
const prompt_email_separator = specialPrompts.find(p => p.id === 'prompt_summarize_email_separator');
|
|
||||||
|
|
||||||
const chatgpt_lang = await taPromptUtils.getDefaultLang(prompt);
|
|
||||||
|
|
||||||
const prompt_string = await taPromptUtils.preparePrompt({
|
|
||||||
curr_prompt: prompt,
|
|
||||||
chatgpt_lang: chatgpt_lang,
|
|
||||||
});
|
|
||||||
const prompt_email_separator_string = await taPromptUtils.preparePrompt({
|
|
||||||
curr_prompt: prompt_email_separator,
|
|
||||||
chatgpt_lang: chatgpt_lang,
|
|
||||||
});
|
|
||||||
|
|
||||||
const messageResult = await browser.messages.query({ headerMessageId: headerMessageId });
|
const messageResult = await browser.messages.query({ headerMessageId: headerMessageId });
|
||||||
if (!messageResult || messageResult.messages.length === 0) {
|
if (!messageResult || messageResult.messages.length === 0) {
|
||||||
console.error("[ThunderAI] _openSummaryWebchat: Message not found for headerMessageId:", headerMessageId);
|
console.error("[ThunderAI] _openSummaryWebchat: Message not found for headerMessageId:", headerMessageId);
|
||||||
|
|
@ -556,24 +534,10 @@ async function _openSummaryWebchat(headerMessageId, tabId) {
|
||||||
|
|
||||||
const curr_message = messageResult.messages[0];
|
const curr_message = messageResult.messages[0];
|
||||||
const curr_message_full = await browser.messages.getFull(curr_message.id);
|
const curr_message_full = await browser.messages.getFull(curr_message.id);
|
||||||
const curr_body_full_html = getMailBody(curr_message_full);
|
|
||||||
let curr_body_full_text = htmlBodyToPlainText(curr_body_full_html.html);
|
|
||||||
if (curr_body_full_text.length === 0) {
|
|
||||||
curr_body_full_text = curr_body_full_html.text;
|
|
||||||
}
|
|
||||||
|
|
||||||
const email_text = await taPromptUtils.preparePrompt({
|
const { promptText, promptInfo } = await taPromptUtils.buildSummaryPrompt([{ message: curr_message, fullMessage: curr_message_full }]);
|
||||||
curr_prompt: prompt_email,
|
|
||||||
curr_message: curr_message,
|
|
||||||
chatgpt_lang: chatgpt_lang,
|
|
||||||
body_text: curr_body_full_text,
|
|
||||||
subject_text: curr_message_full.headers.subject,
|
|
||||||
msg_text: curr_body_full_html,
|
|
||||||
});
|
|
||||||
|
|
||||||
const full_prompt = prompt_string + prompt_email_separator_string + email_text;
|
openChatGPT(promptText, promptInfo.action, tabId, promptInfo.name, promptInfo.need_custom_text, promptInfo);
|
||||||
|
|
||||||
openChatGPT(full_prompt, prompt.action, tabId, prompt.name, prompt.need_custom_text, prompt);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[ThunderAI] Error opening summary webchat:", error);
|
console.error("[ThunderAI] Error opening summary webchat:", error);
|
||||||
}
|
}
|
||||||
|
|
@ -1464,63 +1428,14 @@ async function processEmails(args) {
|
||||||
await _generateSummaryForMessage(messageArray[0].headerMessageId, tabId);
|
await _generateSummaryForMessage(messageArray[0].headerMessageId, tabId);
|
||||||
} else {
|
} else {
|
||||||
// Webchat mode, or inline with multiple messages (fallback to webchat)
|
// Webchat mode, or inline with multiple messages (fallback to webchat)
|
||||||
// we have three prompts, the actual assignment for the LLM, the email
|
const messageDataArray = [];
|
||||||
// template prompt, and the email separator prompt
|
|
||||||
const specialPrompts = await getSpecialPrompts();
|
|
||||||
const prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize');
|
|
||||||
const prompt_email = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template');
|
|
||||||
const prompt_email_separator = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_separator');
|
|
||||||
|
|
||||||
const chatgpt_lang = await taPromptUtils.getDefaultLang(prompt);
|
|
||||||
|
|
||||||
// replace placeholders in the prompts the assignment prompt and email
|
|
||||||
// separator prompt do not have a message as context, so there is only
|
|
||||||
// limited things to replace
|
|
||||||
const prompt_string = await taPromptUtils.preparePrompt({
|
|
||||||
curr_prompt: prompt,
|
|
||||||
chatgpt_lang: chatgpt_lang,
|
|
||||||
});
|
|
||||||
const prompt_email_separator_string = await taPromptUtils.preparePrompt({
|
|
||||||
curr_prompt: prompt_email_separator,
|
|
||||||
chatgpt_lang: chatgpt_lang,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// assemble all email messages into one string and add the assignment prompt
|
|
||||||
const messages_list = [];
|
|
||||||
for (let curr_message of messageArray) {
|
for (let curr_message of messageArray) {
|
||||||
|
const fullMessage = await browser.messages.getFull(curr_message.id);
|
||||||
// extract body of current message as text
|
messageDataArray.push({ message: curr_message, fullMessage });
|
||||||
const curr_message_full = await browser.messages.getFull(curr_message.id);
|
|
||||||
const curr_body_full_html = getMailBody(curr_message_full);
|
|
||||||
let curr_body_full_text = htmlBodyToPlainText(curr_body_full_html.html);
|
|
||||||
if( curr_body_full_text.length === 0) {
|
|
||||||
taLog.log("No HTML found in the message body, using plain text...");
|
|
||||||
curr_body_full_text = curr_message_full.text;
|
|
||||||
}
|
}
|
||||||
|
const { promptText, promptInfo } = await taPromptUtils.buildSummaryPrompt(messageDataArray);
|
||||||
|
|
||||||
messages_list.push(await taPromptUtils.preparePrompt({
|
openChatGPT(promptText, promptInfo.action, tabId, promptInfo.name, promptInfo.need_custom_text, promptInfo);
|
||||||
curr_prompt: prompt_email,
|
|
||||||
curr_message: curr_message,
|
|
||||||
chatgpt_lang: chatgpt_lang,
|
|
||||||
body_text: curr_body_full_text,
|
|
||||||
subject_text: curr_message_full.headers.subject,
|
|
||||||
msg_text: curr_body_full_html,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
const messages_string = messages_list.join(prompt_email_separator_string);
|
|
||||||
|
|
||||||
const full_prompt = prompt_string + prompt_email_separator_string + messages_string;
|
|
||||||
|
|
||||||
// send the prompt to the chat interface
|
|
||||||
openChatGPT(
|
|
||||||
full_prompt,
|
|
||||||
prompt.action,
|
|
||||||
tabId,
|
|
||||||
prompt.name,
|
|
||||||
prompt.need_custom_text,
|
|
||||||
prompt
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue