feat(summary): implement new configuration model, fix multilingual support and fix error display

- Introduce localized UI strings for auto-summary feature across multiple languages
- Standardize error messages and implement consistent error propagation
- Refactor summary generation to align with v3.8.0 settings architecture
- Enhance user experience with localized loading and error states
- Improve code reliability through structured error handling and cleanup
This commit is contained in:
Ronald Klarenbeek 2026-01-02 22:42:46 +01:00
parent dc7c16a4e0
commit 80674c2e70
6 changed files with 189 additions and 1447 deletions

View file

@ -1003,34 +1003,6 @@
"message": "Extract all relevant details required to generate a calendar event from the following text. The extracted information should include:\n- Event Title\n- Start Date and Time (including timezone, if specified)\n- End Date and Time (including timezone, if specified)\n- Full day (if mentioned)\n- Attendees\nEnsure the data is formatted clearly and consistently so that it can be directly used for creating a calendar event.\nIf there are relative time references, consider that the date and time of the email are \"{%mail_datetime%}\". Calculate the start date and time based on this reference. If the calculated start date and time are earlier than \"{%current_datetime%}\", recalculate the start date and time using \"{%current_datetime%}\" as the base.\nIf the duration is not specified, set it to one hour.\nThese are the attendees: {%author%}, {%recipients%}, {%cc_list%}. If present, exclude my address: {%account_email_address%}.\nIf you're not able to get one or more of the required information, please respond with an empty string.\nGenerate a response in JSON format only. Do not include any additional text or explanations; provide only the JSON. Here is the format to be used:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Calendar event summary here\",\n\"forceAllDay\": false,\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nHere's the text:\"{%selected_text%}\"",
"description": ""
},
"Summarize_prompt_prefs_title": {
"message": "Add Summarization Options",
"description": ""
},
"prompt_summarize": {
"message": "Summarize this email or these emails",
"description": ""
},
"prompt_summarize_full_text": {
"message": "You are an assistant that summarizes email conversations.\n\nGiven an email thread, produce a concise, accurate summary that captures:\n\n- The main topic or purpose of the conversation\n- Key decisions, conclusions, or agreements\n- Important questions, requests, or action items\n- Who is responsible for each action item (if stated)\n\nOmit greetings, signatures, quoted text, and redundant back-and-forth.\nDo not add assumptions or information not present in the emails.\n\nWrite the summary in clear, neutral language suitable for a busy professional.",
"description": ""
},
"prompt_summarize_email_template": {
"message": "Summarize email template",
"description": ""
},
"prompt_summarize_email_template_full_text": {
"message": "From: {%author%}\nTo: {%recipients%}\nCC: {%cc_list%}\nSubject: {%mail_subject%}\nDate: {%mail_datetime%}\nAttachments:\n{%mail_attachments_info%}\n\nBody:\n{%mail_text_body%}",
"description": ""
},
"prompt_summarize_email_separator": {
"message": "Email separator",
"description": ""
},
"prompt_summarize_email_separator_full_text": {
"message": "\n\n---------- NEXT EMAIL ----------\n\n",
"description": ""
},
"prompt_get_task": {
"message": "Add a new task",
"description": ""
@ -1095,22 +1067,6 @@
"message": "You can change the prompt as you wish, but the response received from the AI must be in JSON format as specified in the default prompt!",
"description": ""
},
"prefs_OptionText_Summarize_infoline2": {
"message": "You can change the prompt as you wish, the first field is the main prompt, the second field is the template for a single mail. The list of emails will be appended to the main prompt. Emails will be separated by the separator specified in the third field.",
"description": ""
},
"prefs_OptionText_Summarize_main_prompt": {
"message": "The main prompt describing the task to be performed on all selected emails:",
"description": ""
},
"prefs_OptionText_Summarize_email_template": {
"message": "The template for a single email:",
"description": ""
},
"prefs_OptionText_Summarize_email_separator": {
"message": "The separator between emails:",
"description": ""
},
"prefs_OptionText_get_calendar_event_Sparks_not_present": {
"message": "To use the calendar event and task features, please install the ThunderAI Sparks addon.",
"description": ""
@ -1211,10 +1167,6 @@
"message": "If checked, the Model and API specified below will be used for adding tags to emails, regardless the one choosen in the ThunderAI options page.",
"description": ""
},
"prefs_OptionText_get_calendar_event_use_specific_integration_Info": {
"message": "If checked, the Model and API specified below will be used for creating calendar events, regardless the one choosen in the ThunderAI options page.",
"description": ""
},
"placeholder_thunderai_def_sign": {
"message": "Default signature as defined in ThunderAI options.",
"description": ""
@ -1243,22 +1195,6 @@
"message": "Manage spam filter settings",
"description": ""
},
"prefs_OptionText_summarize": {
"message": "Summarize mail",
"description": ""
},
"prefs_OptionText_summarize_use_specific_integration_Info": {
"message": "If checked, the Model and API specified below will be used for summarizing email(s), regardless the one choosen in the ThunderAI options page.",
"description": ""
},
"prefs_OptionText_summarize_Info": {
"message": "If checked, adds an option to context menu to summarize mail.",
"description": ""
},
"prefs_OptionText_btnManageSummarizeInfo": {
"message": "Manage summarize settings",
"description": ""
},
"SpamFilter_PageTitle": {
"message": "Manage Spam Filter Settings",
"description": ""
@ -1283,18 +1219,6 @@
"message": "Spam Filter Options",
"description": ""
},
"Summarize_PageTitle": {
"message": "Manage Summarize Settings",
"description": ""
},
"Summarize_info_default": {
"message": "In this page you can modify the default prompt used to summarize emails.",
"description": ""
},
"Summarize_prompt_text_title": {
"message": "Current prompt text",
"description": ""
},
"prefs_OptionText_use_specific_integration": {
"message": "Use specific Model and API",
"description": ""
@ -1355,11 +1279,11 @@
"message": "Report Date",
"description": ""
},
"yes_string": {
"spamfilter_moved": {
"message": "Yes",
"description": ""
},
"no_string": {
"spamfilter_not_moved": {
"message": "No",
"description": ""
},
@ -1371,8 +1295,20 @@
"message": "Analyze for spam",
"description": ""
},
"context_menu_mzta-summarize": {
"message": "Summarize",
"prefs_OptionText_add_tags_context_menu": {
"message": "Show the \"Add tags\" context menu item",
"description": ""
},
"prefs_OptionText_add_tags_context_menu_Info": {
"message": "If checked, the \"Add tags\" context menu item will be shown when right-clicking on an email in the messages list.",
"description": ""
},
"prefs_OptionText_spamfilter_context_menu": {
"message": "Show the \"Analyze for spam\" context menu item",
"description": ""
},
"prefs_OptionText_spamfilter_context_menu_Info": {
"message": "If checked, the \"Analyze for spam\" context menu item will be shown when right-clicking on an email in the messages list.",
"description": ""
},
"noActiveCalendar": {
@ -1427,16 +1363,12 @@
"message": "Problems setting CORS?",
"description": ""
},
"CORS_alternative_2_new": {
"message": "Press the button below to give the permission to the current host to avoid any CORS problem.",
"CORS_alternative_2": {
"message": "Press the button below to give the <all_urls> permission to avoid any CORS problem.",
"description": ""
},
"CORS_give_host_perm": {
"message": "Give permission to the current host",
"description": ""
},
"CORS_localhost_warn": {
"message": "If you are using localhost or 127.0.0.1 because the AI server is hosted on your PC, the <all_urls> permission is required.",
"CORS_give_allurls_perm": {
"message": "Give \"all URLs\" permission",
"description": ""
},
"prefs_OptionText_composing_plain_text": {
@ -1805,10 +1737,6 @@
"message": "You have denied the optional permission needed to fetch models for this integration.",
"description": ""
},
"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!",
"description": ""
},
"prefs_OptionText_auto_summary": {
"message": "Enable automatic AI summarization for message previews",
"description": ""
@ -1818,15 +1746,19 @@
"description": ""
},
"auto_summary_title": {
"message": "AI Summary",
"description": ""
"message": "ThunderAI Summary",
"description": "Title for the auto-summary pane"
},
"auto_summary_generating": {
"message": "Generating summary...",
"description": ""
"message": "Generating AI summary...",
"description": "Loading text shown while generating summary"
},
"auto_summary_failed": {
"message": "Failed to generate summary",
"description": ""
"message": "Failed to generate AI summary. Please confirm your settings and try again.",
"description": "Error message when summary generation fails"
},
"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",
"description": "Prompt template for AI summary generation"
}
}

View file

@ -956,10 +956,10 @@
"Report_Date": {
"message": "Fecha del informe"
},
"yes_string": {
"spamfilter_moved": {
"message": "Si"
},
"no_string": {
"spamfilter_not_moved": {
"message": "No"
},
"context_menu_mzta-add-tags": {
@ -968,6 +968,18 @@
"context_menu_mzta-spamfilter": {
"message": "Analizar el spam"
},
"prefs_OptionText_add_tags_context_menu": {
"message": "Mostrar el elemento del menú contextual “Añadir etiquetas”"
},
"prefs_OptionText_add_tags_context_menu_Info": {
"message": "Si está marcado, el elemento del menú contextual “Añadir etiquetas” se mostrará al hacer clic derecho en un correo electrónico de la lista de mensajes."
},
"prefs_OptionText_spamfilter_context_menu": {
"message": "Mostrar el elemento del menú contextual “Analizar el spam”"
},
"prefs_OptionText_spamfilter_context_menu_Info": {
"message": "Si está marcado, el elemento del menú contextual “Analizar el spam” se mostrará al hacer clic derecho en un correo electrónico de la lista de mensajes."
},
"noActiveCalendar": {
"message": "¡No se encontró un calendario editable!"
},
@ -1007,6 +1019,12 @@
"CORS_alternative_1": {
"message": "¿Problemas al configurar CORS?"
},
"CORS_alternative_2": {
"message": "Presiona el botón a continuación para otorgar el permiso <all_urls> y evitar cualquier problema de CORS."
},
"CORS_give_allurls_perm": {
"message": "Otorgar permiso “all URLs”"
},
"prefs_OptionText_composing_plain_text": {
"message": "Redactando en texto plano"
},
@ -1284,32 +1302,26 @@
"Anthropic_System_Prompt": {
"message": "Prompt del sistema"
},
"reset": {
"message": "Reiniciar"
}
},
"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!",
"description": ""
},
"prefs_OptionText_auto_summary": {
"message": "Enable automatic AI summarization for message previews",
"description": ""
"message": "Habilitar resumen automático de IA para vistas previas de mensajes"
},
"prefs_OptionText_auto_summary_Info": {
"message": "If checked, ThunderAI will automatically generate and display AI summaries above email messages when they are opened. Note that this means all messages you preview will immediately be sent to the configured AI service.",
"description": ""
"message": "Si está marcado, ThunderAI generará y mostrará automáticamente resúmenes de IA sobre los mensajes de correo electrónico cuando se abran. Tenga en cuenta que esto significa que todos los mensajes que previsualice se enviarán inmediatamente al servicio de IA configurado."
},
"auto_summary_title": {
"message": "AI Summary",
"description": ""
"message": "Resumen de ThunderAI",
"description": "Título del panel de resumen automático"
},
"auto_summary_generating": {
"message": "Generating summary...",
"description": ""
"message": "Generando resumen de IA...",
"description": "Texto de carga mostrado mientras se genera el resumen"
},
"auto_summary_failed": {
"message": "Failed to generate summary",
"description": ""
"message": "Error al generar el resumen de IA. Verifica tu configuración e inténtalo de nuevo.",
"description": "Mensaje de error cuando falla la generación del resumen"
},
"auto_summary_prompt": {
"message": "Proporciona un resumen conciso del siguiente mensaje de correo electrónico. El resumen debe tener un máximo de 3-5 oraciones y capturar los puntos principales:\n\n",
"description": "Plantilla de prompt para la generación de resúmenes de IA"
}
}

View file

@ -327,6 +327,9 @@
"chagpt_api_send_button": {
"message": "Utilisation du modèle"
},
"chagpt_api_connecting": {
"message": "Tentative de connexion à OpenAI ChatGPT en utilisant la clé API fournie"
},
"Debug": {
"message": "Debug"
},
@ -360,6 +363,12 @@
"ollama_empty_model": {
"message": "Vous n'avez pas choisi de modèle pour l'API Ollama. Veuillez en choisir un sur la page des options."
},
"ollama_api_connecting": {
"message": "Tentative de connexion au serveur local Ollama en utilisant l'hôte"
},
"andModel": {
"message": "et le modèle"
},
"error_connection_interrupted": {
"message": "La connexion au serveur a été interrompue de manière inattendue"
},
@ -390,6 +399,9 @@
"OpenAIComp_empty_model": {
"message": "Vous n'avez pas choisi de modèle pour l'API compatible OpenAI. Veuillez en choisir un dans la page des options."
},
"OpenAIComp_api_connecting": {
"message": "Tentative de connexion au serveur local de l'API compatible OpenAI en utilisant l'hôte"
},
"OpenAIComp_api_request_failed": {
"message": "La requête de l'API compatible OpenAI a échoué"
},
@ -669,6 +681,9 @@
"google_gemini_api_request_failed": {
"message": "La requête API Google Gemini a échoué"
},
"google_gemini_api_connecting": {
"message": "Tentative de connexion à Google Gemini en utilisant la clé API fournie"
},
"google_gemini_empty_apikey": {
"message": "Vous n'avez pas ajouté de clé API pour l'API Google Gemini. Veuillez en insérer une dans la page des options."
},
@ -777,7 +792,7 @@
"Moved_to_Spam": {
"message": "Déplacé dans le spam"
},
"no_string": {
"spamfilter_not_moved": {
"message": "Non"
},
"spamfilter_no_reports": {
@ -786,6 +801,9 @@
"SpamFilter_PageTitle": {
"message": "Gérer les paramètres du filtre anti-spam"
},
"sparks_not_installed": {
"message": "ThunderAI Sparks non installé!"
},
"SpamFilter_info_default": {
"message": "Sur cette page, vous pouvez modifier l'invite par défaut utilisée pour détecter les e-mails indésirables."
},
@ -798,7 +816,7 @@
"SpamReport_Title": {
"message": "Rapports du filtre anti-spam"
},
"yes_string": {
"spamfilter_moved": {
"message": "Oui"
},
"prefs_OptionText_add_tags_auto_Info": {
@ -840,6 +858,12 @@
"context_menu_mzta-add-tags": {
"message": "Ajouter des étiquettes"
},
"prefs_OptionText_spamfilter_context_menu": {
"message": "Afficher l'option \"Analyser comme spam\" dans le menu contextuel"
},
"prefs_OptionText_spamfilter_context_menu_Info": {
"message": "Si coché, l'option \"Analyser comme spam\" apparaîtra lors dun clic droit sur un e-mail dans la liste des messages."
},
"noActiveCalendar": {
"message": "Aucun calendrier modifiable trouvé!"
},
@ -855,6 +879,9 @@
"prefs_OptionText_calendar_enforce_timezone": {
"message": "Forcer le fuseau horaire spécifié"
},
"prefs_OptionText_add_tags_context_menu_Info": {
"message": "Si coché, l'option \"Ajouter des étiquettes\" apparaîtra lors dun clic droit sur un e-mail dans la liste des messages."
},
"chatgpt_win_diff_title": {
"message": "Différences entre le texte original et le texte modifié"
},
@ -870,6 +897,9 @@
"apiwebchat_error": {
"message": "Erreur"
},
"prefs_OptionText_add_tags_context_menu": {
"message": "Afficher l'option \"Ajouter des étiquettes\" dans le menu contextuel"
},
"apiwebchat_use_this_answer": {
"message": "Utiliser cette réponse"
},
@ -900,6 +930,12 @@
"CORS_alternative_1": {
"message": "Des problèmes pour configurer le CORS?"
},
"CORS_alternative_2": {
"message": "Appuie sur le bouton ci-dessous pour accorder la permission <all_urls> afin d'éviter tout problème lié au CORS."
},
"CORS_give_allurls_perm": {
"message": "Accorde la permission \"tous les URLs\""
},
"remember_CORS": {
"message": "N'oublie pas, tu dois configurer les paramètres CORS sur le serveur!"
},
@ -1300,32 +1336,27 @@
"prefs_anthropic_temperature_Info": {
"message": "Degré d'aléa injecté dans la réponse. La valeur par défaut est 1,0. La plage de valeurs s'étend di 0,0 à 1,0. Utilisez une température proche de 0,0 pour des tâches analytiques ou des choix multiples, et proche de 1,0 pour des tâches créatives et génératives. Notez que même avec une température de 0,0, les résultats ne seront pas totalement déterministes."
},
"reset": {
"message": "Réinitialiser"
}
},
"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!",
"description": ""
},
"prefs_OptionText_auto_summary": {
"message": "Enable automatic AI summarization for message previews",
"description": ""
"message": "Activer le résumé automatique par IA pour les aperçus de messages"
},
"prefs_OptionText_auto_summary_Info": {
"message": "If checked, ThunderAI will automatically generate and display AI summaries above email messages when they are opened. Note that this means all messages you preview will immediately be sent to the configured AI service.",
"message": "Si coché, ThunderAI générera et affichera automatiquement des résumés par IA au-dessus des messages lorsque vous les ouvrirez. Notez que cela signifie que tous les messages que vous prévisualisez seront immédiatement envoyés au service IA configuré.",
"description": ""
},
"auto_summary_title": {
"message": "AI Summary",
"description": ""
"message": "Résumé ThunderAI",
"description": "Titre du panneau de résumé automatique"
},
"auto_summary_generating": {
"message": "Generating summary...",
"description": ""
"message": "Génération du résumé IA...",
"description": "Texte de chargement affiché pendant la génération du résumé"
},
"auto_summary_failed": {
"message": "Failed to generate summary",
"description": ""
"message": "Échec de la génération du résumé IA. Veuillez vérifier vos paramètres et réessayer.",
"description": "Message d'erreur lorsque la génération du résumé échoue"
},
"auto_summary_prompt": {
"message": "Veuillez fournir un résumé concis du message suivant. Le résumé doit comporter au maximum 3 à 5 phrases et capturer les points principaux :\n\n",
"description": "Modèle d'invite pour la génération de résumés IA"
}
}

File diff suppressed because it is too large Load diff

View file

@ -14,12 +14,12 @@ async function showSummaryPane() {
// Create the title element
const summaryTitle = document.createElement("div");
summaryTitle.className = "thunderai-summary-title";
summaryTitle.innerText = "ThunderAI Summary";
summaryTitle.innerText = browser.i18n.getMessage("auto_summary_title");
// Create a loading indicator
const loadingIndicator = document.createElement("div");
loadingIndicator.className = "thunderai-summary-content";
loadingIndicator.innerText = "Generating AI summary...";
loadingIndicator.innerText = browser.i18n.getMessage("auto_summary_generating");
// Create the content element (initially hidden)
const summaryContent = document.createElement("div");
@ -45,12 +45,9 @@ async function showSummaryPane() {
summaryContent.style.display = 'block';
} catch (error) {
console.error("Error generating AI summary:", error);
loadingIndicator.innerText = "Failed to generate AI summary. Showing message preview instead.";
loadingIndicator.innerText = browser.i18n.getMessage("auto_summary_failed");
loadingIndicator.style.color = '#d70022';
// Fallback to showing truncated message content
const messageContent = getMessageContent();
loadingIndicator.innerText += "\n\n" + truncateMessageContent(messageContent);
}
}
@ -83,12 +80,8 @@ async function generateAISummary(messageContent) {
// Clean up the message content
const cleanedContent = messageContent.replace(/\s+/g, ' ').trim();
// Create a simple summary prompt
const summaryPrompt = `Please provide a concise summary of the following email message. The summary should be 3-5 sentences maximum and capture the main points:
${cleanedContent}
Summary:`;
// Create a simple summary prompt using localized string
const summaryPrompt = browser.i18n.getMessage("auto_summary_prompt") + cleanedContent;
// Request AI summary from the background script
return new Promise((resolve, reject) => {
@ -101,9 +94,10 @@ Summary:`;
if (response && response.summary) {
resolve(response.summary);
} else if (response && response.error) {
reject(new Error(response.error));
// Use the localized error message
reject(new Error(browser.i18n.getMessage("auto_summary_failed")));
} else {
reject(new Error("Failed to get AI summary"));
reject(new Error(browser.i18n.getMessage("auto_summary_failed")));
}
});
});

View file

@ -257,16 +257,23 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => {
});
// Use the existing ThunderAI infrastructure
// We need to adapt to the new v3.8.0 settings structure
const summary = await generateAISummaryUsingThunderAIInfrastructure(
message.content,
message.prompt,
prefs
{
...prefs,
// Add the dynamic settings that the new system expects
connection_type: prefs.connection_type,
// For summary, we don't have specific integration settings yet,
// so we'll use the global connection type
}
);
return { summary: summary };
} catch (error) {
console.error("[ThunderAI] Error generating summary:", error);
return { error: "Failed to generate AI summary: " + error.message };
return { error: "Failed to generate AI summary. Please confirm your settings and try again." };
}
}
return _generate_summary(message);
@ -1298,17 +1305,42 @@ async function generateAISummaryUsingThunderAIInfrastructure(content, prompt, pr
// Import the special command class
const { mzta_specialCommand } = await import('./js/mzta-special-commands.js');
// Determine which LLM to use based on user preferences
const llmType = getConnectionType(prefs.connection_type, {}, '');
// Create a prompt config for summary (similar to how other features do it)
// This adapts to the new v3.8.0 dynamic settings system
const summaryPromptConfig = {
id: 'auto_summary',
name: 'Auto Summary',
model: '', // Model will be determined by getConnectionType
connection_type: prefs.connection_type
};
// Create a special command instance
// Determine which LLM to use based on user preferences using the new v3.8.0 pattern
const llmType = getConnectionType(prefs, summaryPromptConfig, 'auto_summary');
// Get the appropriate model based on the connection type using dynamic settings
let model = '';
if (prefs.connection_type === 'chatgpt_api') {
model = prefs.chatgpt_model;
} else if (prefs.connection_type === 'ollama_api') {
model = prefs.ollama_model;
} else if (prefs.connection_type === 'openai_comp_api') {
model = prefs.openai_comp_model;
} else if (prefs.connection_type === 'google_gemini_api') {
model = prefs.google_gemini_model;
} else if (prefs.connection_type === 'anthropic_api') {
model = prefs.anthropic_model;
}
// Create a special command instance with the correct v3.8.0 pattern
const summaryCommand = new mzta_specialCommand({
prompt: prompt,
llm: llmType,
custom_model: prefs.chatgpt_model,
do_debug: prefs.do_debug
custom_model: model,
do_debug: prefs.do_debug,
config: summaryPromptConfig
});
try {
// Initialize the worker
await summaryCommand.initWorker();
@ -1319,6 +1351,10 @@ async function generateAISummaryUsingThunderAIInfrastructure(content, prompt, pr
const cleanedResponse = cleanAISummaryResponse(aiResponse);
return cleanedResponse;
} catch (error) {
console.error("[ThunderAI] Error in AI summary generation:", error);
throw error; // Re-throw to be handled by the caller
}
}
/**