diff --git a/.gitignore b/.gitignore
index 27fadb2..2fff0b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
# Build artifacts
+dist/
*.xpi
*.zip
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..0772557
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,9 @@
+{
+ "semi": true,
+ "singleQuote": true,
+ "trailingComma": "es5",
+ "printWidth": 100,
+ "tabWidth": 2,
+ "arrowParens": "always",
+ "endOfLine": "lf"
+}
diff --git a/README.md b/README.md
index fb6bf43..594ee84 100644
--- a/README.md
+++ b/README.md
@@ -128,9 +128,13 @@ Choose from **5 leading cloud AI providers** or run a **local Ollama** model:
```bash
git clone https://github.com/Nigel1992/AutoSort-Plus.git
cd AutoSort-Plus
-zip -r autosortplus.xpi manifest.json background.js options.js options.html styles.css content.js icons/
+npm install
+npm run build
+npm run xpi
```
+Then load `autosortplus.xpi` as described in Option 1.
+
**[📥 Download Latest Release](https://github.com/Nigel1992/AutoSort-Plus/releases) • [📖 View Changelog](#-changelog)**
@@ -562,9 +566,9 @@ You can also manually label emails without AI analysis:
Status |
-| 🔴 High |
+🟢 Done |
Detailed Logging - Debug mode with console output |
-📋 Planned |
+✅ Completed |
| 🔴 High |
@@ -620,6 +624,67 @@ If you encounter any issues, please [open an issue on GitHub](https://github.com
---
+## Development
+
+### Prerequisites
+
+- Node.js 18+
+- npm
+
+### Setup
+
+```bash
+git clone https://github.com/Nigel1992/AutoSort-Plus.git
+cd AutoSort-Plus
+npm install
+```
+
+### Architecture
+
+```
+src/
+├── background/ Background script (AI, batch, folders, auto-sort)
+├── options/ Options page UI
+├── shared/ Shared utilities (logger, storage, i18n, tab-fetch)
+├── types/ TypeScript type definitions
+├── content.ts Content script
+├── ollama.ts Ollama API client
+├── workers/ Web Workers
+└── popup/ Web-accessible popups
+```
+
+### Commands
+
+| Command | Description |
+|---------|-------------|
+| `npm run build` | Build extension to `dist/` |
+| `npm run watch` | Build and watch for changes |
+| `npm run test` | Run tests |
+| `npm run test:watch` | Run tests in watch mode |
+| `npm run test:coverage` | Run tests with coverage report |
+| `npm run lint` | Lint source code |
+| `npm run format` | Check formatting |
+| `npm run format:fix` | Fix formatting |
+| `npm run typecheck` | TypeScript type checking |
+| `npm run check` | Full check (typecheck + lint + test) |
+| `npm run xpi` | Build + package as `.xpi` |
+
+### Load in Thunderbird
+
+1. `npm run build`
+2. In Thunderbird, go to `about:debugging` → This Thunderbird → Load Temporary Add-on
+3. Select `dist/manifest.json`
+
+### Tech Stack
+
+- TypeScript (strict mode)
+- esbuild (bundler)
+- Vitest (test framework)
+- ESLint + Prettier (code quality)
+- Thunderbird WebExtension APIs
+
+---
+
## 🙏 Contributing
We welcome contributions! Here's how to help:
diff --git a/_locales/en/messages.json b/_locales/en/messages.json
new file mode 100644
index 0000000..fdf9d78
--- /dev/null
+++ b/_locales/en/messages.json
@@ -0,0 +1,549 @@
+{
+ "extensionName": {
+ "message": "AutoSort+",
+ "description": "Extension name"
+ },
+ "extensionDescription": {
+ "message": "Automatically sort and label your emails with custom rules using AI",
+ "description": "Extension description"
+ },
+ "extensionDefaultTitle": {
+ "message": "AutoSort+ Settings",
+ "description": "Default title shown in browser action"
+ },
+ "pageTitle": {
+ "message": "AutoSort+ Settings",
+ "description": "HTML page title"
+ },
+ "pageHeading": {
+ "message": "AutoSort+ Settings",
+ "description": "Main page heading"
+ },
+ "batchProcessingTitle": {
+ "message": "Batch Processing In Progress",
+ "description": "Batch processing status panel title"
+ },
+ "batchPreparing": {
+ "message": "Preparing…",
+ "description": "Batch processing preparing text"
+ },
+ "batchPause": {
+ "message": "⏸ Pause",
+ "description": "Batch pause button text"
+ },
+ "batchResume": {
+ "message": "▶ Resume",
+ "description": "Batch resume button text"
+ },
+ "batchCancel": {
+ "message": "⏹ Cancel",
+ "description": "Batch cancel button text"
+ },
+ "aiSettingsTitle": {
+ "message": "🤖 AI Settings",
+ "description": "AI settings section header"
+ },
+ "providerSelectionTitle": {
+ "message": "Provider Selection",
+ "description": "Provider selection subsection header"
+ },
+ "aiProviderLabel": {
+ "message": "AI Provider:",
+ "description": "AI provider select label"
+ },
+ "providerGemini": {
+ "message": "Google Gemini (Recommended)",
+ "description": "Gemini provider option"
+ },
+ "providerOpenAI": {
+ "message": "OpenAI (ChatGPT)",
+ "description": "OpenAI provider option"
+ },
+ "providerAnthropic": {
+ "message": "Anthropic Claude",
+ "description": "Anthropic provider option"
+ },
+ "providerGroq": {
+ "message": "Groq (Fast & Free)",
+ "description": "Groq provider option"
+ },
+ "providerMistral": {
+ "message": "Mistral AI",
+ "description": "Mistral provider option"
+ },
+ "providerOllama": {
+ "message": "Ollama (Local LLM)",
+ "description": "Ollama provider option"
+ },
+ "providerOpenAICompatible": {
+ "message": "OpenAI-Compatible (Custom Endpoint)",
+ "description": "OpenAI-Compatible provider option"
+ },
+ "rateLimitWarningTitle": {
+ "message": "⚠️ Rate Limit Warning:",
+ "description": "Rate limit warning header"
+ },
+ "rateLimitWarningText": {
+ "message": "Free API tiers are severely limited when processing emails. You may only process 5-20 emails before hitting rate limits. Paid plans ($5-20/month) are recommended for daily email processing.",
+ "description": "Rate limit warning text"
+ },
+ "ollamaConfigTitle": {
+ "message": "🏠 Local Ollama Configuration",
+ "description": "Ollama configuration subsection header"
+ },
+ "ollamaUrlLabel": {
+ "message": "Ollama Server URL:",
+ "description": "Ollama URL label"
+ },
+ "ollamaUrlPlaceholder": {
+ "message": "http://localhost:11434",
+ "description": "Ollama URL placeholder"
+ },
+ "ollamaCpuOnly": {
+ "message": "Force CPU-only mode (disable GPU acceleration)",
+ "description": "Ollama CPU-only checkbox"
+ },
+ "ollamaModelLabel": {
+ "message": "Ollama Model:",
+ "description": "Ollama model select label"
+ },
+ "ollamaAuthTokenLabel": {
+ "message": "Ollama Auth Token (optional):",
+ "description": "Ollama auth token label"
+ },
+ "ollamaAuthTokenPlaceholder": {
+ "message": "If your Ollama server requires a token, enter it here",
+ "description": "Ollama auth token placeholder"
+ },
+ "ollamaAuthTokenHelp": {
+ "message": "Used for /api/chat and /api/pull requests when required.",
+ "description": "Ollama auth token help text"
+ },
+ "ollamaCustomModelPlaceholder": {
+ "message": "Enter custom model name",
+ "description": "Ollama custom model placeholder"
+ },
+ "ollamaDownloadModelLabel": {
+ "message": "Download Model:",
+ "description": "Ollama download model label"
+ },
+ "ollamaDownloadModelPlaceholder": {
+ "message": "e.g., llama3.2, mistral, qwen2.5:7b",
+ "description": "Ollama download model placeholder"
+ },
+ "ollamaDownloadButton": {
+ "message": "Download",
+ "description": "Download model button"
+ },
+ "ollamaListModelsButton": {
+ "message": "List Installed Models",
+ "description": "List installed models button"
+ },
+ "ollamaTestButton": {
+ "message": "Test Connection",
+ "description": "Test Ollama connection button"
+ },
+ "ollamaDiagnoseButton": {
+ "message": "Run Diagnostics",
+ "description": "Run Ollama diagnostics button"
+ },
+ "ollamaModelLlama2": {
+ "message": "Llama 2",
+ "description": "Ollama Llama 2 model option"
+ },
+ "ollamaModelLlama32": {
+ "message": "Llama 3.2",
+ "description": "Ollama Llama 3.2 model option"
+ },
+ "ollamaModelMistral": {
+ "message": "Mistral",
+ "description": "Ollama Mistral model option"
+ },
+ "ollamaModelPhi": {
+ "message": "Phi",
+ "description": "Ollama Phi model option"
+ },
+ "ollamaModelGemma": {
+ "message": "Gemma",
+ "description": "Ollama Gemma model option"
+ },
+ "ollamaModelQwen25": {
+ "message": "Qwen 2.5",
+ "description": "Ollama Qwen 2.5 model option"
+ },
+ "ollamaModelCustom": {
+ "message": "Custom (enter below)",
+ "description": "Ollama custom model option"
+ },
+ "openaiCompatibleTitle": {
+ "message": "🔗 OpenAI-Compatible Endpoint",
+ "description": "OpenAI-Compatible subsection header"
+ },
+ "openaiCompatibleBaseUrlLabel": {
+ "message": "Base URL:",
+ "description": "OpenAI-Compatible base URL label"
+ },
+ "openaiCompatibleBaseUrlPlaceholder": {
+ "message": "http://localhost:1234/v1 or https://api.provider.com/v1",
+ "description": "OpenAI-Compatible base URL placeholder"
+ },
+ "openaiCompatibleBaseUrlHelp": {
+ "message": "Enter base URL including /v1. Endpoint must use OpenAI format: /v1/chat/completions. Examples: LM Studio, LocalAI, vLLM, Together AI",
+ "description": "OpenAI-Compatible base URL help text"
+ },
+ "openaiCompatibleModelLabel": {
+ "message": "Model:",
+ "description": "OpenAI-Compatible model select label"
+ },
+ "openaiCompatibleModelSelect": {
+ "message": "-- Select model --",
+ "description": "OpenAI-Compatible model select default option"
+ },
+ "openaiCompatibleModelCustom": {
+ "message": "Custom (enter below)",
+ "description": "OpenAI-Compatible custom model option"
+ },
+ "openaiCompatibleModelCustomPlaceholder": {
+ "message": "Enter model name manually",
+ "description": "OpenAI-Compatible custom model placeholder"
+ },
+ "openaiCompatibleApiKeyLabel": {
+ "message": "API Key (optional):",
+ "description": "OpenAI-Compatible API key label"
+ },
+ "openaiCompatibleApiKeyPlaceholder": {
+ "message": "Leave empty for local endpoints without auth",
+ "description": "OpenAI-Compatible API key placeholder"
+ },
+ "openaiCompatibleApiKeyHelp": {
+ "message": "Required for cloud providers, optional for local servers",
+ "description": "OpenAI-Compatible API key help text"
+ },
+ "openaiCompatibleFetchModelsButton": {
+ "message": "Fetch Models",
+ "description": "Fetch models button"
+ },
+ "openaiCompatibleTestButton": {
+ "message": "Test Connection",
+ "description": "Test OpenAI-Compatible connection button"
+ },
+ "apiKeyTitle": {
+ "message": "🔑 API Key Configuration",
+ "description": "API key configuration subsection header"
+ },
+ "apiKeyLabel": {
+ "message": "API Key:",
+ "description": "API key input label"
+ },
+ "apiKeyPlaceholder": {
+ "message": "Enter your API key",
+ "description": "API key input placeholder"
+ },
+ "testApiButton": {
+ "message": "Test API Connection",
+ "description": "Test API connection button"
+ },
+ "getApiKeyButton": {
+ "message": "Get API Key",
+ "description": "Get API key button"
+ },
+ "geminiMultiKeysTitle": {
+ "message": "🔄 Multiple Gemini API Keys",
+ "description": "Multiple Gemini keys subsection header"
+ },
+ "geminiMultiKeysInfo": {
+ "message": "Add multiple API keys from different Google Cloud projects. The extension will automatically rotate between them when rate limits are reached.",
+ "description": "Multiple Gemini keys info text"
+ },
+ "addGeminiKeyButton": {
+ "message": "+ Add Another Gemini Key",
+ "description": "Add Gemini key button"
+ },
+ "geminiPaidPlan": {
+ "message": "I have a Gemini paid plan (removes rate limits)",
+ "description": "Gemini paid plan checkbox"
+ },
+ "generalSettingsTitle": {
+ "message": "⚙️ General Settings",
+ "description": "General settings subsection header"
+ },
+ "enableAiLabel": {
+ "message": "Enable AI-powered sorting",
+ "description": "Enable AI checkbox"
+ },
+ "enableDebugLabel": {
+ "message": "Enable debug mode (console logging)",
+ "description": "Enable debug mode checkbox"
+ },
+ "enableDebugHelp": {
+ "message": "Open Thunderbird Developer Tools (Ctrl+Shift+I) to view logs",
+ "description": "Debug mode help text"
+ },
+ "batchChunkSizeLabel": {
+ "message": "Batch chunk size:",
+ "description": "Batch chunk size label"
+ },
+ "batchChunkSizeHelp": {
+ "message": "Process N emails at once, wait for all responses, then continue (1-20)",
+ "description": "Batch chunk size help text"
+ },
+ "enableAutoSortLabel": {
+ "message": "Auto-sort new emails in Inbox",
+ "description": "Auto-sort checkbox label"
+ },
+ "enableAutoSortHelp": {
+ "message": "Automatically classify and move new Inbox emails using AI",
+ "description": "Auto-sort help text"
+ },
+ "geminiUsageTitle": {
+ "message": "📊 Gemini API Usage",
+ "description": "Gemini API usage subsection header"
+ },
+ "geminiDailyCount": {
+ "message": "Today's Usage: {count}/20 requests",
+ "description": "Gemini daily usage count",
+ "placeholders": {
+ "count": {
+ "content": "$1"
+ }
+ }
+ },
+ "geminiLastRequest": {
+ "message": "Last Request:",
+ "description": "Gemini last request label"
+ },
+ "geminiNever": {
+ "message": "Never",
+ "description": "Never used text"
+ },
+ "geminiResetTime": {
+ "message": "Daily Limit Resets:",
+ "description": "Gemini daily limit reset time label"
+ },
+ "geminiStatus": {
+ "message": "Status:",
+ "description": "Gemini status label"
+ },
+ "geminiStatusReady": {
+ "message": "Ready",
+ "description": "Gemini ready status"
+ },
+ "resetGeminiCounterButton": {
+ "message": "Reset Counter (New API Key)",
+ "description": "Reset Gemini counter button"
+ },
+ "refreshUsageButton": {
+ "message": "Refresh Usage",
+ "description": "Refresh usage button"
+ },
+ "refreshAllUsageButton": {
+ "message": "Refresh All Usage",
+ "description": "Refresh all usage button"
+ },
+ "howAiSortingTitle": {
+ "message": "ℹ️ How AI Sorting Works",
+ "description": "How AI sorting works subsection header"
+ },
+ "howAiSortingDesc": {
+ "message": "AutoSort+ uses AI to analyze your emails and automatically sort them into categories/folders based on their content. The AI will:",
+ "description": "AI sorting description"
+ },
+ "howAiSortingPoint1": {
+ "message": "Read and understand email content",
+ "description": "AI sorting capability 1"
+ },
+ "howAiSortingPoint2": {
+ "message": "Identify key topics and themes",
+ "description": "AI sorting capability 2"
+ },
+ "howAiSortingPoint3": {
+ "message": "Match emails to appropriate categories/folders",
+ "description": "AI sorting capability 3"
+ },
+ "howAiSortingPoint4": {
+ "message": "Learn from your manual corrections to improve accuracy",
+ "description": "AI sorting capability 4"
+ },
+ "customPromptTitle": {
+ "message": "📝 Custom Prompt",
+ "description": "Custom prompt section header"
+ },
+ "customPromptInfo": {
+ "message": "Customize the prompt sent to AI for email classification.",
+ "description": "Custom prompt info text"
+ },
+ "customPromptPlaceholders": {
+ "message": "Available placeholders:",
+ "description": "Custom prompt placeholders label"
+ },
+ "customPromptPlaceholderLabel": {
+ "message": "Your folder/label list",
+ "description": "Labels placeholder description"
+ },
+ "customPromptSubjectLabel": {
+ "message": "Email subject line",
+ "description": "Subject placeholder description"
+ },
+ "customPromptAuthorLabel": {
+ "message": "Sender email address/name",
+ "description": "Author placeholder description"
+ },
+ "customPromptAttachmentsLabel": {
+ "message": "Attachment filenames (comma-separated)",
+ "description": "Attachments placeholder description"
+ },
+ "customPromptBodyLabel": {
+ "message": "Email body content (recommended)",
+ "description": "Body placeholder description"
+ },
+ "customPromptEmailLabel": {
+ "message": "Email content (legacy, same as {body})",
+ "description": "Email placeholder description",
+ "placeholders": {
+ "body": {
+ "content": "$1"
+ }
+ }
+ },
+ "customPromptTip": {
+ "message": "Tip: Use {subject} and {attachments} for better classification accuracy.",
+ "description": "Custom prompt tip",
+ "placeholders": {
+ "subject": {
+ "content": "$1"
+ },
+ "attachments": {
+ "content": "$2"
+ }
+ }
+ },
+ "customPromptTextareaPlaceholder": {
+ "message": "Enter your custom prompt...",
+ "description": "Custom prompt textarea placeholder"
+ },
+ "resetPromptButton": {
+ "message": "Reset to Default",
+ "description": "Reset prompt button"
+ },
+ "customFoldersTitle": {
+ "message": "📁 Custom Categories/Folders",
+ "description": "Custom categories/folders section header"
+ },
+ "folderSourceTitle": {
+ "message": "Folder Source",
+ "description": "Folder source subsection header"
+ },
+ "loadImapFoldersButton": {
+ "message": "Load Folders from Mail Account",
+ "description": "Load IMAP folders button"
+ },
+ "folderLoadingText": {
+ "message": "Loading folders...",
+ "description": "Folder loading indicator text"
+ },
+ "folderFoundText": {
+ "message": "Found {count} folders in your mail account. Would you like to use these?",
+ "description": "Folder found text",
+ "placeholders": {
+ "count": {
+ "content": "$1"
+ }
+ }
+ },
+ "useImapFoldersButton": {
+ "message": "Use These Folders",
+ "description": "Use IMAP folders button"
+ },
+ "useCustomFoldersButton": {
+ "message": "Use Custom Folders Instead",
+ "description": "Use custom folders button"
+ },
+ "bulkImportLabel": {
+ "message": "Import Categories/Folders (one per line):",
+ "description": "Bulk import textarea label"
+ },
+ "bulkImportPlaceholder": {
+ "message": "Enter categories/folders, one per line",
+ "description": "Bulk import textarea placeholder"
+ },
+ "importButton": {
+ "message": "Import",
+ "description": "Import button"
+ },
+ "addButton": {
+ "message": "Add",
+ "description": "Add button"
+ },
+ "labelInputPlaceholder": {
+ "message": "Enter category/folder name",
+ "description": "Label input placeholder"
+ },
+ "moveHistoryTitle": {
+ "message": "📜 Move History",
+ "description": "Move history section header"
+ },
+ "clearHistoryButton": {
+ "message": "Clear History",
+ "description": "Clear history button"
+ },
+ "refreshHistoryButton": {
+ "message": "Refresh",
+ "description": "Refresh history button"
+ },
+ "historyHeaderTimestamp": {
+ "message": "Timestamp",
+ "description": "History table timestamp header"
+ },
+ "historyHeaderSubject": {
+ "message": "Subject",
+ "description": "History table subject header"
+ },
+ "historyHeaderStatus": {
+ "message": "Status",
+ "description": "History table status header"
+ },
+ "historyHeaderDestination": {
+ "message": "Destination",
+ "description": "History table destination header"
+ },
+ "saveSettingsButton": {
+ "message": "Save Settings",
+ "description": "Save settings button"
+ },
+ "providerInfoGemini": {
+ "message": "✓ Free tier: 5 requests/minute, 20/day per API key (enforced by addon)
✓ Tip: Create multiple API keys in different projects, switch keys when limit reached
✓ Check usage: AI Studio Usage
✓ Best for: General use, multilingual support
✓ Models: Gemini 2.5 Flash
✓ Check \"paid plan\" option to remove limits",
+ "description": "Gemini provider info HTML"
+ },
+ "providerInfoOpenai": {
+ "message": "✓ Free trial: $5 credit
✓ Best for: High accuracy, English content
✓ Models: GPT-4o-mini ($0.15/1M tokens)",
+ "description": "OpenAI provider info HTML"
+ },
+ "providerInfoAnthropic": {
+ "message": "✓ Free tier: Limited requests
✓ Best for: Long emails, detailed analysis
✓ Models: Claude 3 Haiku",
+ "description": "Anthropic provider info HTML"
+ },
+ "providerInfoGroq": {
+ "message": "✓ Free tier: 30 requests/minute
✓ Best for: Speed (fastest)
✓ Models: Llama 3.3 (Mixtral deprecated)",
+ "description": "Groq provider info HTML"
+ },
+ "providerInfoMistral": {
+ "message": "✓ Free tier: Limited requests
✓ Best for: European users, GDPR compliance
✓ Models: Mistral Small",
+ "description": "Mistral provider info HTML"
+ },
+ "providerInfoOllama": {
+ "message": "✓ 100% Free: Runs locally on your machine
✓ Privacy: No data sent to external servers
✓ No rate limits: Process unlimited emails
✓ Models: Llama 2/3, Mistral, Phi, Gemma, Qwen, and more
✓ Requires: Ollama installed and running locally
✓ Setup: Install Ollama, run \"ollama pull llama3.2\" to download a model",
+ "description": "Ollama provider info HTML"
+ },
+ "providerInfoOpenaiCompatible": {
+ "message": "✓ Compatible with: LocalAI, LM Studio, vLLM, Together AI, OpenRouter, DeepSeek, Fireworks, etc.
✓ Enter your endpoint base URL and model name
✓ API key optional for local servers
✓ Uses standard /v1/chat/completions format",
+ "description": "OpenAI-Compatible provider info HTML"
+ },
+ "freeBadge": {
+ "message": "FREE",
+ "description": "Free provider badge text"
+ },
+ "paidBadge": {
+ "message": "PAID",
+ "description": "Paid provider badge text"
+ }
+}
diff --git a/_locales/zh_CN/messages.json b/_locales/zh_CN/messages.json
new file mode 100644
index 0000000..6b31af4
--- /dev/null
+++ b/_locales/zh_CN/messages.json
@@ -0,0 +1,549 @@
+{
+ "extensionName": {
+ "message": "AutoSort+",
+ "description": "扩展名称"
+ },
+ "extensionDescription": {
+ "message": "使用 AI 自动分类和标记您的邮件",
+ "description": "扩展描述"
+ },
+ "extensionDefaultTitle": {
+ "message": "AutoSort+ 设置",
+ "description": "浏览器操作默认标题"
+ },
+ "pageTitle": {
+ "message": "AutoSort+ 设置",
+ "description": "HTML 页面标题"
+ },
+ "pageHeading": {
+ "message": "AutoSort+ 设置",
+ "description": "页面主标题"
+ },
+ "batchProcessingTitle": {
+ "message": "批量处理进行中",
+ "description": "批量处理状态面板标题"
+ },
+ "batchPreparing": {
+ "message": "准备中…",
+ "description": "批量处理准备中文字"
+ },
+ "batchPause": {
+ "message": "⏸ 暂停",
+ "description": "批量暂停按钮文字"
+ },
+ "batchResume": {
+ "message": "▶ 继续",
+ "description": "批量继续按钮文字"
+ },
+ "batchCancel": {
+ "message": "⏹ 取消",
+ "description": "批量取消按钮文字"
+ },
+ "aiSettingsTitle": {
+ "message": "🤖 AI 设置",
+ "description": "AI 设置区段标题"
+ },
+ "providerSelectionTitle": {
+ "message": "选择提供商",
+ "description": "提供商选择子区段标题"
+ },
+ "aiProviderLabel": {
+ "message": "AI 提供商:",
+ "description": "AI 提供商选择框标签"
+ },
+ "providerGemini": {
+ "message": "Google Gemini(推荐)",
+ "description": "Gemini 提供商选项"
+ },
+ "providerOpenAI": {
+ "message": "OpenAI (ChatGPT)",
+ "description": "OpenAI 提供商选项"
+ },
+ "providerAnthropic": {
+ "message": "Anthropic Claude",
+ "description": "Anthropic 提供商选项"
+ },
+ "providerGroq": {
+ "message": "Groq(快速且免费)",
+ "description": "Groq 提供商选项"
+ },
+ "providerMistral": {
+ "message": "Mistral AI",
+ "description": "Mistral 提供商选项"
+ },
+ "providerOllama": {
+ "message": "Ollama(本地大模型)",
+ "description": "Ollama 提供商选项"
+ },
+ "providerOpenAICompatible": {
+ "message": "OpenAI 兼容(自定义端点)",
+ "description": "OpenAI 兼容提供商选项"
+ },
+ "rateLimitWarningTitle": {
+ "message": "⚠️ 频率限制警告:",
+ "description": "频率限制警告标题"
+ },
+ "rateLimitWarningText": {
+ "message": "免费 API 层在处理邮件时受到严格限制。您可能在处理 5-20 封邮件后就达到频率限制。建议购买付费计划($5-20/月)以满足日常邮件处理需求。",
+ "description": "频率限制警告正文"
+ },
+ "ollamaConfigTitle": {
+ "message": "🏠 本地 Ollama 配置",
+ "description": "Ollama 配置子区段标题"
+ },
+ "ollamaUrlLabel": {
+ "message": "Ollama 服务器地址:",
+ "description": "Ollama 地址标签"
+ },
+ "ollamaUrlPlaceholder": {
+ "message": "http://localhost:11434",
+ "description": "Ollama 地址占位符"
+ },
+ "ollamaCpuOnly": {
+ "message": "强制仅使用 CPU(禁用 GPU 加速)",
+ "description": "Ollama CPU 模式复选框"
+ },
+ "ollamaModelLabel": {
+ "message": "Ollama 模型:",
+ "description": "Ollama 模型选择框标签"
+ },
+ "ollamaAuthTokenLabel": {
+ "message": "Ollama 认证令牌(可选):",
+ "description": "Ollama 认证令牌标签"
+ },
+ "ollamaAuthTokenPlaceholder": {
+ "message": "如果您的 Ollama 服务器需要令牌,请在此输入",
+ "description": "Ollama 认证令牌占位符"
+ },
+ "ollamaAuthTokenHelp": {
+ "message": "在需要时用于 /api/chat 和 /api/pull 请求。",
+ "description": "Ollama 认证令牌帮助文本"
+ },
+ "ollamaCustomModelPlaceholder": {
+ "message": "输入自定义模型名称",
+ "description": "Ollama 自定义模型占位符"
+ },
+ "ollamaDownloadModelLabel": {
+ "message": "下载模型:",
+ "description": "Ollama 下载模型标签"
+ },
+ "ollamaDownloadModelPlaceholder": {
+ "message": "例如:llama3.2, mistral, qwen2.5:7b",
+ "description": "Ollama 下载模型占位符"
+ },
+ "ollamaDownloadButton": {
+ "message": "下载",
+ "description": "下载模型按钮"
+ },
+ "ollamaListModelsButton": {
+ "message": "列出已安装模型",
+ "description": "列出已安装模型按钮"
+ },
+ "ollamaTestButton": {
+ "message": "测试连接",
+ "description": "测试 Ollama 连接按钮"
+ },
+ "ollamaDiagnoseButton": {
+ "message": "运行诊断",
+ "description": "运行 Ollama 诊断按钮"
+ },
+ "ollamaModelLlama2": {
+ "message": "Llama 2",
+ "description": "Ollama Llama 2 模型选项"
+ },
+ "ollamaModelLlama32": {
+ "message": "Llama 3.2",
+ "description": "Ollama Llama 3.2 模型选项"
+ },
+ "ollamaModelMistral": {
+ "message": "Mistral",
+ "description": "Ollama Mistral 模型选项"
+ },
+ "ollamaModelPhi": {
+ "message": "Phi",
+ "description": "Ollama Phi 模型选项"
+ },
+ "ollamaModelGemma": {
+ "message": "Gemma",
+ "description": "Ollama Gemma 模型选项"
+ },
+ "ollamaModelQwen25": {
+ "message": "Qwen 2.5",
+ "description": "Ollama Qwen 2.5 模型选项"
+ },
+ "ollamaModelCustom": {
+ "message": "自定义(下方输入)",
+ "description": "Ollama 自定义模型选项"
+ },
+ "openaiCompatibleTitle": {
+ "message": "🔗 OpenAI 兼容端点",
+ "description": "OpenAI 兼容子区段标题"
+ },
+ "openaiCompatibleBaseUrlLabel": {
+ "message": "基础地址:",
+ "description": "OpenAI 兼容基础地址标签"
+ },
+ "openaiCompatibleBaseUrlPlaceholder": {
+ "message": "http://localhost:1234/v1 或 https://api.provider.com/v1",
+ "description": "OpenAI 兼容基础地址占位符"
+ },
+ "openaiCompatibleBaseUrlHelp": {
+ "message": "请输入包含 /v1 的基础地址。端点必须使用 OpenAI 格式:/v1/chat/completions。例如:LM Studio, LocalAI, vLLM, Together AI",
+ "description": "OpenAI 兼容基础地址帮助文本"
+ },
+ "openaiCompatibleModelLabel": {
+ "message": "模型:",
+ "description": "OpenAI 兼容模型选择框标签"
+ },
+ "openaiCompatibleModelSelect": {
+ "message": "-- 选择模型 --",
+ "description": "OpenAI 兼容模型默认选项"
+ },
+ "openaiCompatibleModelCustom": {
+ "message": "自定义(下方输入)",
+ "description": "OpenAI 兼容自定义模型选项"
+ },
+ "openaiCompatibleModelCustomPlaceholder": {
+ "message": "手动输入模型名称",
+ "description": "OpenAI 兼容自定义模型占位符"
+ },
+ "openaiCompatibleApiKeyLabel": {
+ "message": "API 密钥(可选):",
+ "description": "OpenAI 兼容 API 密钥标签"
+ },
+ "openaiCompatibleApiKeyPlaceholder": {
+ "message": "本地无认证端点可留空",
+ "description": "OpenAI 兼容 API 密钥占位符"
+ },
+ "openaiCompatibleApiKeyHelp": {
+ "message": "云端提供商必需,本地服务器可选",
+ "description": "OpenAI 兼容 API 密钥帮助文本"
+ },
+ "openaiCompatibleFetchModelsButton": {
+ "message": "获取模型列表",
+ "description": "获取模型列表按钮"
+ },
+ "openaiCompatibleTestButton": {
+ "message": "测试连接",
+ "description": "测试 OpenAI 兼容连接按钮"
+ },
+ "apiKeyTitle": {
+ "message": "🔑 API 密钥配置",
+ "description": "API 密钥配置子区段标题"
+ },
+ "apiKeyLabel": {
+ "message": "API 密钥:",
+ "description": "API 密钥输入框标签"
+ },
+ "apiKeyPlaceholder": {
+ "message": "输入您的 API 密钥",
+ "description": "API 密钥输入框占位符"
+ },
+ "testApiButton": {
+ "message": "测试 API 连接",
+ "description": "测试 API 连接按钮"
+ },
+ "getApiKeyButton": {
+ "message": "获取 API 密钥",
+ "description": "获取 API 密钥按钮"
+ },
+ "geminiMultiKeysTitle": {
+ "message": "🔄 多个 Gemini API 密钥",
+ "description": "多个 Gemini 密钥子区段标题"
+ },
+ "geminiMultiKeysInfo": {
+ "message": "添加来自不同 Google Cloud 项目的多个 API 密钥。当达到频率限制时,扩展将自动在密钥间切换。",
+ "description": "多个 Gemini 密钥说明文本"
+ },
+ "addGeminiKeyButton": {
+ "message": "+ 添加另一个 Gemini 密钥",
+ "description": "添加 Gemini 密钥按钮"
+ },
+ "geminiPaidPlan": {
+ "message": "我已购买 Gemini 付费计划(解除频率限制)",
+ "description": "Gemini 付费计划复选框"
+ },
+ "generalSettingsTitle": {
+ "message": "⚙️ 常规设置",
+ "description": "常规设置子区段标题"
+ },
+ "enableAiLabel": {
+ "message": "启用 AI 邮件分类",
+ "description": "启用 AI 复选框"
+ },
+ "enableDebugLabel": {
+ "message": "启用调试模式(控制台日志)",
+ "description": "启用调试模式复选框"
+ },
+ "enableDebugHelp": {
+ "message": "打开 Thunderbird 开发者工具(Ctrl+Shift+I)查看日志",
+ "description": "调试模式帮助文本"
+ },
+ "batchChunkSizeLabel": {
+ "message": "批量处理数量:",
+ "description": "批量处理数量标签"
+ },
+ "batchChunkSizeHelp": {
+ "message": "每次处理 N 封邮件,等待所有响应后继续(1-20)",
+ "description": "批量处理数量帮助文本"
+ },
+ "enableAutoSortLabel": {
+ "message": "自动分类收件箱新邮件",
+ "description": "自动分类复选框标签"
+ },
+ "enableAutoSortHelp": {
+ "message": "使用 AI 自动分类和移动新收件箱邮件",
+ "description": "自动分类帮助文本"
+ },
+ "geminiUsageTitle": {
+ "message": "📊 Gemini API 使用情况",
+ "description": "Gemini API 使用情况子区段标题"
+ },
+ "geminiDailyCount": {
+ "message": "今日使用:{count}/20 次请求",
+ "description": "Gemini 每日使用统计",
+ "placeholders": {
+ "count": {
+ "content": "$1"
+ }
+ }
+ },
+ "geminiLastRequest": {
+ "message": "最后请求:",
+ "description": "Gemini 最后请求标签"
+ },
+ "geminiNever": {
+ "message": "从未",
+ "description": "从未使用文字"
+ },
+ "geminiResetTime": {
+ "message": "每日限制重置:",
+ "description": "Gemini 每日限制重置时间标签"
+ },
+ "geminiStatus": {
+ "message": "状态:",
+ "description": "Gemini 状态标签"
+ },
+ "geminiStatusReady": {
+ "message": "就绪",
+ "description": "Gemini 就绪状态"
+ },
+ "resetGeminiCounterButton": {
+ "message": "重置计数器(新 API 密钥)",
+ "description": "重置 Gemini 计数器按钮"
+ },
+ "refreshUsageButton": {
+ "message": "刷新使用情况",
+ "description": "刷新使用情况按钮"
+ },
+ "refreshAllUsageButton": {
+ "message": "刷新全部使用情况",
+ "description": "刷新全部使用情况按钮"
+ },
+ "howAiSortingTitle": {
+ "message": "ℹ️ AI 分类工作原理",
+ "description": "AI 分类工作原理子区段标题"
+ },
+ "howAiSortingDesc": {
+ "message": "AutoSort+ 使用 AI 分析您的邮件,并根据内容自动将其分类到类别/文件夹中。AI 将:",
+ "description": "AI 分类描述"
+ },
+ "howAiSortingPoint1": {
+ "message": "阅读并理解邮件内容",
+ "description": "AI 分类能力 1"
+ },
+ "howAiSortingPoint2": {
+ "message": "识别关键主题和主题线索",
+ "description": "AI 分类能力 2"
+ },
+ "howAiSortingPoint3": {
+ "message": "将邮件匹配到合适的类别/文件夹",
+ "description": "AI 分类能力 3"
+ },
+ "howAiSortingPoint4": {
+ "message": "从您的手动修正中学习,提高准确率",
+ "description": "AI 分类能力 4"
+ },
+ "customPromptTitle": {
+ "message": "📝 自定义提示词",
+ "description": "自定义提示词区段标题"
+ },
+ "customPromptInfo": {
+ "message": "自定义发送给 AI 的邮件分类提示词。",
+ "description": "自定义提示词说明"
+ },
+ "customPromptPlaceholders": {
+ "message": "可用占位符:",
+ "description": "自定义提示词占位符标签"
+ },
+ "customPromptPlaceholderLabel": {
+ "message": "您的文件夹/类别列表",
+ "description": "labels 占位符描述"
+ },
+ "customPromptSubjectLabel": {
+ "message": "邮件主题行",
+ "description": "subject 占位符描述"
+ },
+ "customPromptAuthorLabel": {
+ "message": "发件人邮箱地址/名称",
+ "description": "author 占位符描述"
+ },
+ "customPromptAttachmentsLabel": {
+ "message": "附件文件名(逗号分隔)",
+ "description": "attachments 占位符描述"
+ },
+ "customPromptBodyLabel": {
+ "message": "邮件正文内容(推荐)",
+ "description": "body 占位符描述"
+ },
+ "customPromptEmailLabel": {
+ "message": "邮件内容(旧版,同 {body})",
+ "description": "email 占位符描述",
+ "placeholders": {
+ "body": {
+ "content": "$1"
+ }
+ }
+ },
+ "customPromptTip": {
+ "message": "提示:使用 {subject} 和 {attachments} 可提高分类准确率。",
+ "description": "自定义提示词提示",
+ "placeholders": {
+ "subject": {
+ "content": "$1"
+ },
+ "attachments": {
+ "content": "$2"
+ }
+ }
+ },
+ "customPromptTextareaPlaceholder": {
+ "message": "输入您的自定义提示词...",
+ "description": "自定义提示词文本框占位符"
+ },
+ "resetPromptButton": {
+ "message": "恢复默认",
+ "description": "重置提示词按钮"
+ },
+ "customFoldersTitle": {
+ "message": "📁 自定义类别/文件夹",
+ "description": "自定义类别/文件夹区段标题"
+ },
+ "folderSourceTitle": {
+ "message": "文件夹来源",
+ "description": "文件夹来源子区段标题"
+ },
+ "loadImapFoldersButton": {
+ "message": "从邮件账户加载文件夹",
+ "description": "加载 IMAP 文件夹按钮"
+ },
+ "folderLoadingText": {
+ "message": "正在加载文件夹...",
+ "description": "文件夹加载提示文字"
+ },
+ "folderFoundText": {
+ "message": "在您的邮件账户中找到 {count} 个文件夹。要使用这些文件夹吗?",
+ "description": "找到文件夹提示文字",
+ "placeholders": {
+ "count": {
+ "content": "$1"
+ }
+ }
+ },
+ "useImapFoldersButton": {
+ "message": "使用这些文件夹",
+ "description": "使用 IMAP 文件夹按钮"
+ },
+ "useCustomFoldersButton": {
+ "message": "改用自定义文件夹",
+ "description": "使用自定义文件夹按钮"
+ },
+ "bulkImportLabel": {
+ "message": "导入类别/文件夹(每行一个):",
+ "description": "批量导入文本框标签"
+ },
+ "bulkImportPlaceholder": {
+ "message": "每行输入一个类别/文件夹",
+ "description": "批量导入文本框占位符"
+ },
+ "importButton": {
+ "message": "导入",
+ "description": "导入按钮"
+ },
+ "addButton": {
+ "message": "添加",
+ "description": "添加按钮"
+ },
+ "labelInputPlaceholder": {
+ "message": "输入类别/文件夹名称",
+ "description": "标签输入框占位符"
+ },
+ "moveHistoryTitle": {
+ "message": "📜 移动历史",
+ "description": "移动历史区段标题"
+ },
+ "clearHistoryButton": {
+ "message": "清除历史",
+ "description": "清除历史按钮"
+ },
+ "refreshHistoryButton": {
+ "message": "刷新",
+ "description": "刷新历史按钮"
+ },
+ "historyHeaderTimestamp": {
+ "message": "时间",
+ "description": "历史表格时间列标题"
+ },
+ "historyHeaderSubject": {
+ "message": "主题",
+ "description": "历史表格主题列标题"
+ },
+ "historyHeaderStatus": {
+ "message": "状态",
+ "description": "历史表格状态列标题"
+ },
+ "historyHeaderDestination": {
+ "message": "目标",
+ "description": "历史表格目标列标题"
+ },
+ "saveSettingsButton": {
+ "message": "保存设置",
+ "description": "保存设置按钮"
+ },
+ "providerInfoGemini": {
+ "message": "✓ 免费额度:每分钟 5 次请求,每天 20 次/API 密钥(扩展强制执行)
✓ 提示:在不同项目中创建多个 API 密钥,达到限制时切换密钥
✓ 查看使用情况:AI Studio 使用情况
✓ 适合:日常使用、多语言支持
✓ 模型:Gemini 2.5 Flash
✓ 勾选\"付费计划\"可解除限制",
+ "description": "Gemini 提供商信息 HTML"
+ },
+ "providerInfoOpenai": {
+ "message": "✓ 免费试用:$5 额度
✓ 适合:高准确率、英文内容
✓ 模型:GPT-4o-mini($0.15/1M tokens)",
+ "description": "OpenAI 提供商信息 HTML"
+ },
+ "providerInfoAnthropic": {
+ "message": "✓ 免费额度:有限请求
✓ 适合:长邮件、详细分析
✓ 模型:Claude 3 Haiku",
+ "description": "Anthropic 提供商信息 HTML"
+ },
+ "providerInfoGroq": {
+ "message": "✓ 免费额度:每分钟 30 次请求
✓ 适合:速度(最快)
✓ 模型:Llama 3.3(Mixtral 已弃用)",
+ "description": "Groq 提供商信息 HTML"
+ },
+ "providerInfoMistral": {
+ "message": "✓ 免费额度:有限请求
✓ 适合:欧洲用户、GDPR 合规
✓ 模型:Mistral Small",
+ "description": "Mistral 提供商信息 HTML"
+ },
+ "providerInfoOllama": {
+ "message": "✓ 100% 免费:在本地运行
✓ 隐私:数据不发送到外部服务器
✓ 无频率限制:无限制处理邮件
✓ 模型:Llama 2/3、Mistral、Phi、Gemma、Qwen 等
✓ 需要:安装 Ollama 并本地运行
✓ 设置:安装 Ollama 后运行 \"ollama pull llama3.2\" 下载模型",
+ "description": "Ollama 提供商信息 HTML"
+ },
+ "providerInfoOpenaiCompatible": {
+ "message": "✓ 兼容:LocalAI、LM Studio、vLLM、Together AI、OpenRouter、DeepSeek、Fireworks 等
✓ 输入端点基础地址和模型名称
✓ 本地服务器可选 API 密钥
✓ 使用标准 /v1/chat/completions 格式",
+ "description": "OpenAI 兼容提供商信息 HTML"
+ },
+ "freeBadge": {
+ "message": "免费",
+ "description": "免费提供商徽章文本"
+ },
+ "paidBadge": {
+ "message": "付费",
+ "description": "付费提供商徽章文本"
+ }
+}
diff --git a/api_ollama/index.html b/api_ollama/index.html
index de9afef..61ab74c 100644
--- a/api_ollama/index.html
+++ b/api_ollama/index.html
@@ -45,6 +45,6 @@ AutoSort+ - Ollama Chat
Initializing...
-
+