Initial commit of SnappyMail LLM Email Writing Prompts Plugin with Grok 3 API support

This commit is contained in:
Leopere 2025-05-15 17:09:56 -04:00
commit fe21504ab5
5 changed files with 304 additions and 0 deletions

View File

@ -0,0 +1,66 @@
---
description:
globs:
alwaysApply: false
---
# SnappyMail LLM Email Writing Prompts Plugin with Grok 3 API Support
## Overview
This plugin enhances SnappyMail, a lightweight web-based email client, by integrating AI-driven email writing prompts powered by xAI's Grok 3 API as the primary Large Language Model (LLM) provider, with fallbacks to other LLMs. The purpose is to assist users in drafting professional, concise, or creative emails through context-aware prompt suggestions, leveraging Grok 3's advanced reasoning capabilities.
## Purpose and Goals
- **Primary Goal**: Enable SnappyMail users to access Grok 3-generated prompts for drafting emails with high-quality, reasoning-focused outputs.
- **Secondary Goals**:
- Ensure compatibility with SnappyMail's lightweight and privacy-focused design.
- Provide a user-friendly interface for selecting and customizing prompts.
- Maintain performance and security standards for self-hosted environments.
- Allow fallback to other LLM APIs (e.g., OpenAI, Hugging Face) for flexibility.
## Target Audience
- **Primary Users**: Individuals and small businesses using SnappyMail for personal or professional email communication, especially those seeking AI-assisted writing with Grok 3's logical outputs.
- **Secondary Users**: System administrators managing SnappyMail instances who want to enhance functionality with Grok 3 integration.
- **Use Cases**:
- Professionals drafting formal emails (e.g., business proposals).
- Casual users writing personal emails with creative tones.
- Non-native speakers needing assistance with grammar and phrasing.
## Functional Requirements
### Core Features
- **Prompt Library**: A set of predefined prompts in categories like Professional, Creative, Assistance, and Quick Replies, optimized for Grok 3's reasoning capabilities.
- **Context-Aware Suggestions**: Analyzes email subject and body to suggest relevant prompts using Grok 3's chain-of-thought reasoning.
- **LLM Integration**: Primary provider is xAI Grok 3 API ([https://api.x.ai/v1/chat/completions](mdc:https:/api.x.ai/v1/chat/completions)), with configurable fallbacks to OpenAI, Hugging Face, or local LLMs.
- **Draft Generation**: Generates email drafts based on prompts and context, supporting multiple iterations (e.g., tone adjustments).
- **Custom Prompts**: Users can create and save custom prompts, stored securely as JSON files.
- **Privacy and Security**: No email data stored beyond API calls, with optional opt-in for context analysis and secure API key storage.
### User Interface
- **Compose Window Integration**: A "Smart Prompts" button or sidebar in the email composition interface for Grok 3-powered suggestions.
- **Settings Panel**: Options to configure Grok 3 API key, select model, manage custom prompts, and toggle context analysis.
- **Visual Design**: Matches SnappyMail's minimalist UI with dark mode and mobile responsiveness.
## Technical Requirements
- **Platform**: Compatible with SnappyMail v2.12+, PHP 7.4+, and JavaScript ES2018.
- **Plugin Architecture**: Located in `/plugins/llm-prompts/` with files like `index.php`, `js/`, `templates/`, and `config.json`.
- **LLM Integration**: Uses Grok 3 API with OpenAI SDK compatibility, secure API key storage, and fallback logic for other providers.
- **Security**: Encrypts API keys and prompts, sanitizes outputs to prevent XSS, and complies with GDPR.
## Implementation Plan
- **Phase 1**: Research and setup Grok 3 API access (2 weeks).
- **Phase 2**: Core development of prompt library and API integration (4 weeks).
- **Phase 3**: UI and settings development (3 weeks).
- **Phase 4**: Testing and security audits (3 weeks).
- **Phase 5**: Release and documentation (2 weeks).
## References
- SnappyMail Official Site: [https://snappymail.eu](mdc:https:/snappymail.eu)
- SnappyMail GitHub: [https://github.com/the-djmaze/snappymail](mdc:https:/github.com/the-djmaze/snappymail)
- xAI Grok 3 API: [https://x.ai/api](mdc:https:/x.ai/api)

View File

@ -0,0 +1,6 @@
{
"grok3_api_key": "",
"selected_model": "grok-3",
"enable_context_analysis": true,
"custom_prompts": []
}

View File

@ -0,0 +1,42 @@
<?php
class LLMPromptsPlugin extends /snappymail/v/0.0.0/app/libraries/SnappyMail/Plugins/AbstractPlugin
{
public $id = 'llm-prompts';
public $name = 'LLM Email Writing Prompts';
public $version = '1.0';
public $description = 'Enhances email composition with AI-driven prompts powered by xAI Grok 3 API.';
public $author = 'Your Name';
public $url = 'https://github.com/your-repo/llm-prompts';
public $license = 'MIT';
public function Boot()
{
$this->addJs('js/llm-prompts.js');
$this->addTemplate('templates/llm-prompts.html');
$this->addHook('filter.compose', 'onFilterCompose');
$this->addHook('action.pre-send', 'onActionPreSend');
}
public function onFilterCompose($oAccount, $oCompose)
{
// Inject UI for Smart Prompts in compose window
// This will be handled by JavaScript
}
public function onActionPreSend($oAccount, $oMessage)
{
// Validate content before sending if generated by LLM
// Add any necessary validation or sanitization
}
public function configMapping(): array
{
return [
'grok3_api_key' => ['string', ''],
'selected_model' => ['string', 'grok-3'],
'enable_context_analysis' => ['bool', true],
'custom_prompts' => ['json', '[]']
];
}
}

View File

@ -0,0 +1,148 @@
// LLM Prompts Plugin for SnappyMail
// Provides UI and API interaction for AI-driven email writing prompts
(function () {
'use strict';
// Initialize plugin when DOM is ready
document.addEventListener('DOMContentLoaded', function () {
if (typeof rl !== 'undefined') {
rl.addSettingsViewModel(
'LLMPromptsSettings',
'LLMPromptsSettings',
'LLM Prompts',
'Settings for AI-driven email writing prompts powered by Grok 3',
true
);
// Add UI for Smart Prompts in compose window
rl.addHook('view-model', function (vm) {
if (vm.viewModelName === 'ComposeViewModel') {
initComposeUI(vm);
}
});
}
});
function initComposeUI(composeVM) {
// Add Smart Prompts button or sidebar to compose window
const toolbar = document.querySelector('.compose-toolbar');
if (toolbar) {
const smartPromptsButton = document.createElement('button');
smartPromptsButton.className = 'button smart-prompts';
smartPromptsButton.innerHTML = 'Smart Prompts';
smartPromptsButton.onclick = function () {
toggleSmartPromptsSidebar(composeVM);
};
toolbar.appendChild(smartPromptsButton);
}
}
function toggleSmartPromptsSidebar(composeVM) {
// Toggle visibility of prompts sidebar
let sidebar = document.querySelector('.smart-prompts-sidebar');
if (!sidebar) {
sidebar = document.createElement('div');
sidebar.className = 'smart-prompts-sidebar';
sidebar.innerHTML = getPromptsHTML();
document.querySelector('.compose-box').appendChild(sidebar);
// Add event listeners for prompt selection
setupPrompts(sidebar, composeVM);
} else {
sidebar.style.display = sidebar.style.display === 'none' ? 'block' : 'none';
}
}
function getPromptsHTML() {
// HTML for prompt categories and suggestions
return `
<h3>Smart Prompts (Grok 3)</h3>
<div class="prompt-category">
<h4>Professional</h4>
<ul>
<li data-prompt="Write a concise follow-up email to a client">Follow-up Email</li>
<li data-prompt="Draft a professional proposal email">Proposal Email</li>
</ul>
</div>
<div class="prompt-category">
<h4>Creative</h4>
<ul>
<li data-prompt="Compose a friendly invitation for a team event">Team Event Invite</li>
</ul>
</div>
<div class="prompt-category">
<h4>Assistance</h4>
<ul>
<li data-prompt="Rephrase this email to sound more polite">Make Polite</li>
</ul>
</div>
<div class="prompt-category">
<h4>Quick Replies</h4>
<ul>
<li data-prompt="Generate a thank-you response for a received email">Thank You Reply</li>
</ul>
</div>
<div class="context-input">
<textarea placeholder="Add context or modify prompt..." rows="3"></textarea>
<button onclick="generateDraft(this)">Generate Draft</button>
</div>
`;
}
function setupPrompts(sidebar, composeVM) {
const prompts = sidebar.querySelectorAll('.prompt-category li');
prompts.forEach(prompt => {
prompt.onclick = function () {
const promptText = this.getAttribute('data-prompt');
sidebar.querySelector('.context-input textarea').value = promptText;
// Highlight selected prompt
prompts.forEach(p => p.classList.remove('selected'));
this.classList.add('selected');
};
});
}
function generateDraft(button) {
const sidebar = button.closest('.smart-prompts-sidebar');
const prompt = sidebar.querySelector('.context-input textarea').value;
const subject = document.querySelector('.compose-subject input').value;
const body = document.querySelector('.compose-body .editor').innerText;
// Make API call to Grok 3 or configured LLM
fetchLLMDraft(prompt, subject, body).then(draft => {
if (draft) {
// Insert draft into compose body
const editor = document.querySelector('.compose-body .editor');
editor.innerHTML = draft.replace(/\n/g, '<br>');
}
}).catch(error => {
console.error('Error generating draft:', error);
alert('Failed to generate draft. Please check settings.');
});
}
async function fetchLLMDraft(prompt, subject, body) {
// This would make an API call to the backend which handles Grok 3 API interaction
// For now, simulate an API call
const response = await fetch('/?/Api/LLMPrompts/GenerateDraft', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: prompt,
subject: subject,
body: body,
enableContextAnalysis: rl.settingsGet('LLMPromptsSettings.enable_context_analysis')
})
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
return data.result;
}
})();

View File

@ -0,0 +1,42 @@
<div data-bind="template: { name: 'PluginLLMPromptsSettings' }"></div>
<script type="text/html" id="PluginLLMPromptsSettings">
<div class="panel-heading">
<h2 class="panel-title">LLM Email Writing Prompts (Grok 3)</h2>
</div>
<div class="panel-body">
<div class="form-group">
<label for="grok3ApiKey">Grok 3 API Key</label>
<input type="password" class="form-control" id="grok3ApiKey" data-bind="textInput: grok3_api_key" placeholder="Enter your xAI Grok 3 API key">
<small class="form-text text-muted">Get your API key at <a href="https://x.ai/api" target="_blank">xAI API</a>.</small>
</div>
<div class="form-group">
<label for="selectedModel">Model Selection</label>
<select class="form-control" id="selectedModel" data-bind="value: selected_model">
<option value="grok-3">Grok 3</option>
<option value="grok-3-mini">Grok 3 Mini</option>
</select>
</div>
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="enableContextAnalysis" data-bind="checked: enable_context_analysis">
<label for="enableContextAnalysis">Enable Context Analysis (analyze email content for better suggestions)</label>
</div>
</div>
<div class="form-group">
<label>Custom Prompts</label>
<div data-bind="foreach: custom_prompts">
<div class="input-group mb-2">
<input type="text" class="form-control" data-bind="textInput: $data" placeholder="Enter custom prompt">
<div class="input-group-append">
<button class="btn btn-danger" type="button" data-bind="click: $parent.removeCustomPrompt.bind($parent, $index())">Remove</button>
</div>
</div>
</div>
<button class="btn btn-secondary" data-bind="click: addCustomPrompt">Add Custom Prompt</button>
</div>
</div>
<div class="panel-footer">
<button type="submit" class="btn btn-primary" data-bind="click: save">Save Changes</button>
</div>
</script>