Auto tagging obsidian notes w/ AI
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

add multiple ai services

+351 -117
+86
src/i18n/locales/ar.json
··· 1 + { 2 + "settings": { 3 + "title": "إعدادات AI Tagger", 4 + "provider": { 5 + "title": "مزود الذكاء الاصطناعي", 6 + "desc": "اختر مزود الذكاء الاصطناعي لإنشاء العلامات.", 7 + "anthropic": "Anthropic (Claude)", 8 + "openai": "OpenAI (GPT)", 9 + "mistral": "Mistral AI", 10 + "google": "Google (Gemini)", 11 + "custom": "نقطة نهاية مخصصة (متوافقة مع OpenAI)" 12 + }, 13 + "customEndpoint": { 14 + "title": "نقطة نهاية API مخصصة", 15 + "desc": "أدخل عنوان URL لنقطة نهاية API المتوافقة مع OpenAI.", 16 + "placeholder": "https://your-api-endpoint.com/v1/chat/completions" 17 + }, 18 + "apiKey": { 19 + "title": "مفتاح API", 20 + "desc": "مفتاح API الخاص بـ {provider}. مطلوب لاستخدام خدمة الذكاء الاصطناعي.", 21 + "getKey": "احصل عليه من {url} إذا لم يكن لديك واحد بالفعل.", 22 + "recommendation": "نوصي باستخدام مفتاح مخصص لهذا البرنامج المساعد.", 23 + "placeholder": "أدخل مفتاح API الخاص بك" 24 + }, 25 + "model": { 26 + "title": "نموذج الذكاء الاصطناعي", 27 + "desc": "اختر نموذج الذكاء الاصطناعي المستخدم لإنشاء العلامات.", 28 + "custom": "{model} (مخصص)" 29 + }, 30 + "maxTags": { 31 + "title": "الحد الأقصى لعدد العلامات", 32 + "desc": "حدد الحد الأقصى لعدد العلامات لإنشائها لكل ملاحظة." 33 + }, 34 + "promptStyle": { 35 + "title": "نمط المطالبة", 36 + "desc": "اختر نمط مطالبة محدد مسبقًا أو قم بإنشاء مطالبة مخصصة خاصة بك.", 37 + "standard": "قياسي", 38 + "descriptive": "وصفي", 39 + "academic": "أكاديمي", 40 + "concise": "موجز", 41 + "custom": "مخصص" 42 + }, 43 + "customPrompt": { 44 + "title": "قالب مطالبة مخصص", 45 + "desc": "قم بتخصيص المطالبة المرسلة إلى الذكاء الاصطناعي. استخدم {maxTags} و {content} كعناصر نائبة." 46 + }, 47 + "currentPrompt": { 48 + "title": "قالب المطالبة الحالي", 49 + "desc": "هذا هو قالب المطالبة الذي سيتم استخدامه (للقراءة فقط). قم بالتبديل إلى مخصص إذا كنت ترغب في تعديله." 50 + }, 51 + "language": { 52 + "title": "اللغة", 53 + "desc": "اختر لغة واجهة البرنامج المساعد." 54 + } 55 + }, 56 + "modals": { 57 + "confirm": "تأكيد", 58 + "cancel": "إلغاء", 59 + "settings": "فتح الإعدادات", 60 + "configError": "خطأ في تكوين علامات الذكاء الاصطناعي", 61 + "tagAll": "سيقوم هذا بوضع علامات على جميع الملاحظات في خزانتك باستخدام نموذج {model}. قد يستغرق هذا بعض الوقت ويستهلك رصيد API. هل تريد المتابعة؟" 62 + }, 63 + "notices": { 64 + "noActiveNote": "لا توجد ملاحظة نشطة للتعليم", 65 + "analyzing": "تحليل محتوى الملاحظة وإنشاء العلامات...", 66 + "tagSuccess": "تمت إضافة العلامات بنجاح: {tags}", 67 + "tagError": "خطأ في وضع علامة على الملاحظة: {error}", 68 + "startingBulk": "بدء وضع علامات على الملاحظات...", 69 + "processingNote": "معالجة: {file}\nالتقدم: {processed}/{total} ({successful} ناجح)", 70 + "bulkComplete": "اكتمل وضع العلامات: {successful}/{total} ملاحظات بنجاح", 71 + "bulkError": "خطأ أثناء وضع العلامات بالجملة: {error}" 72 + }, 73 + "errors": { 74 + "apiKeyMissing": "مفتاح API غير مكوّن. يرجى إضافة مفتاح API الخاص بك في إعدادات البرنامج المساعد.", 75 + "endpointMissing": "نقطة نهاية API المخصصة غير مكوّنة. يرجى إضافة عنوان URL الخاص بنقطة النهاية في إعدادات البرنامج المساعد.", 76 + "apiError": "فشل في إنشاء العلامات: {error}", 77 + "unknownProvider": "مزود غير معروف: {provider}" 78 + }, 79 + "commands": { 80 + "tagCurrent": "وضع علامة على الملاحظة الحالية باستخدام الذكاء الاصطناعي", 81 + "tagAll": "وضع علامات على جميع الملاحظات باستخدام الذكاء الاصطناعي" 82 + }, 83 + "ribbon": { 84 + "tooltip": "وضع علامات تلقائية باستخدام الذكاء الاصطناعي" 85 + } 86 + }
+86
src/i18n/locales/de.json
··· 1 + { 2 + "settings": { 3 + "title": "AI Tagger Einstellungen", 4 + "provider": { 5 + "title": "KI-Anbieter", 6 + "desc": "Wählen Sie, welchen KI-Anbieter Sie für die Generierung von Tags verwenden möchten.", 7 + "anthropic": "Anthropic (Claude)", 8 + "openai": "OpenAI (GPT)", 9 + "mistral": "Mistral AI", 10 + "google": "Google (Gemini)", 11 + "custom": "Benutzerdefinierter Endpunkt (OpenAI-kompatibel)" 12 + }, 13 + "customEndpoint": { 14 + "title": "Benutzerdefinierter API-Endpunkt", 15 + "desc": "Geben Sie die URL für Ihren benutzerdefinierten OpenAI-kompatiblen API-Endpunkt ein.", 16 + "placeholder": "https://your-api-endpoint.com/v1/chat/completions" 17 + }, 18 + "apiKey": { 19 + "title": "API-Schlüssel", 20 + "desc": "Ihr {provider} API-Schlüssel. Erforderlich, um den KI-Dienst zu nutzen.", 21 + "getKey": "Holen Sie ihn von {url}, wenn Sie noch keinen haben.", 22 + "recommendation": "Wir empfehlen, einen dedizierten Schlüssel für dieses Plugin zu verwenden.", 23 + "placeholder": "Geben Sie Ihren API-Schlüssel ein" 24 + }, 25 + "model": { 26 + "title": "KI-Modell", 27 + "desc": "Wählen Sie, welches KI-Modell für die Tag-Generierung verwendet werden soll.", 28 + "custom": "{model} (Benutzerdefiniert)" 29 + }, 30 + "maxTags": { 31 + "title": "Maximale Anzahl an Tags", 32 + "desc": "Legen Sie die maximale Anzahl an Tags fest, die pro Notiz generiert werden sollen." 33 + }, 34 + "promptStyle": { 35 + "title": "Prompt-Stil", 36 + "desc": "Wählen Sie einen vordefinierten Prompt-Stil oder erstellen Sie Ihren eigenen benutzerdefinierten Prompt.", 37 + "standard": "Standard", 38 + "descriptive": "Beschreibend", 39 + "academic": "Akademisch", 40 + "concise": "Prägnant", 41 + "custom": "Benutzerdefiniert" 42 + }, 43 + "customPrompt": { 44 + "title": "Benutzerdefinierte Prompt-Vorlage", 45 + "desc": "Passen Sie den an die KI gesendeten Prompt an. Verwenden Sie {maxTags} und {content} als Platzhalter." 46 + }, 47 + "currentPrompt": { 48 + "title": "Aktuelle Prompt-Vorlage", 49 + "desc": "Dies ist die Prompt-Vorlage, die verwendet wird (schreibgeschützt). Wechseln Sie zu Benutzerdefiniert, wenn Sie sie bearbeiten möchten." 50 + }, 51 + "language": { 52 + "title": "Sprache", 53 + "desc": "Wählen Sie die Sprache für die Plugin-Oberfläche." 54 + } 55 + }, 56 + "modals": { 57 + "confirm": "Bestätigen", 58 + "cancel": "Abbrechen", 59 + "settings": "Einstellungen öffnen", 60 + "configError": "KI-Tagging Konfigurationsfehler", 61 + "tagAll": "Dies wird alle Notizen in Ihrem Vault mit dem Modell {model} taggen. Dies kann einige Zeit dauern und API-Guthaben verbrauchen. Möchten Sie fortfahren?" 62 + }, 63 + "notices": { 64 + "noActiveNote": "Keine aktive Notiz zum Taggen", 65 + "analyzing": "Analysiere Notizinhalt und generiere Tags...", 66 + "tagSuccess": "Tags erfolgreich hinzugefügt: {tags}", 67 + "tagError": "Fehler beim Taggen der Notiz: {error}", 68 + "startingBulk": "Beginne mit dem Taggen von Notizen...", 69 + "processingNote": "Verarbeite: {file}\nFortschritt: {processed}/{total} ({successful} erfolgreich)", 70 + "bulkComplete": "Tagging von {successful}/{total} Notizen erfolgreich abgeschlossen", 71 + "bulkError": "Fehler beim Massen-Tagging: {error}" 72 + }, 73 + "errors": { 74 + "apiKeyMissing": "API-Schlüssel nicht konfiguriert. Bitte fügen Sie Ihren API-Schlüssel in den Plugin-Einstellungen hinzu.", 75 + "endpointMissing": "Benutzerdefinierter API-Endpunkt nicht konfiguriert. Bitte fügen Sie Ihre Endpunkt-URL in den Plugin-Einstellungen hinzu.", 76 + "apiError": "Fehler beim Generieren von Tags: {error}", 77 + "unknownProvider": "Unbekannter Anbieter: {provider}" 78 + }, 79 + "commands": { 80 + "tagCurrent": "Aktuelle Notiz mit KI taggen", 81 + "tagAll": "Alle Notizen mit KI taggen" 82 + }, 83 + "ribbon": { 84 + "tooltip": "Auto-Tagging mit KI" 85 + } 86 + }
+9 -5
src/i18n/locales/index.ts
··· 1 - import en from './en.json'; 2 - import es from './es.json'; 1 + import ar from "./ar.json"; 2 + import de from "./de.json"; 3 + import en from "./en.json"; 4 + import es from "./es.json"; 3 5 4 6 export type TranslationKey = keyof typeof en; 5 7 6 8 export const locales = { 9 + ar, 10 + de, 7 11 en, 8 12 es, 9 - // Add more languages here 10 13 }; 11 14 12 15 export const languageNames = { 16 + ar: "العربية", 17 + de: "Deutsch", 13 18 en: "English", 14 19 es: "Español", 15 - // Add more language names here 16 - }; 20 + };
+88 -6
src/i18n/translationService.ts
··· 1 1 import { locales } from './locales'; 2 - import { Language } from '../models/types'; 2 + import { LanguageCode } from '../models/types'; 3 + import { App } from 'obsidian'; 3 4 4 5 class TranslationService { 5 - private currentLanguage: Language = 'en'; 6 + private currentLanguage: LanguageCode = 'en'; 7 + private app: App | null = null; 6 8 7 9 constructor() { 8 - // Use browser language as default if supported 9 - const browserLang = window.navigator.language.split('-')[0] as Language; 10 + // Default to browser language initially 11 + // Will be overridden by Obsidian language or user setting 12 + const browserLang = window.navigator.language.split('-')[0] as LanguageCode; 10 13 if (this.isLanguageSupported(browserLang)) { 11 14 this.currentLanguage = browserLang; 12 15 } 13 16 } 14 17 15 - public setLanguage(lang: Language): void { 18 + // Store bound event handler for proper cleanup 19 + private boundCheckForLanguageChanges: (() => void) | null = null; 20 + 21 + /** 22 + * Initialize the service with the Obsidian app instance 23 + * This allows getting the app's configured language and listening for changes 24 + */ 25 + public initializeApp(app: App): void { 26 + this.app = app; 27 + 28 + // Set up event listener for when Obsidian's language changes 29 + // Obsidian doesn't directly expose a language change event, but when the app 30 + // locale changes, many UI elements will be updated and we can listen for those changes 31 + this.boundCheckForLanguageChanges = this.checkForLanguageChanges.bind(this); 32 + this.app.workspace.on('layout-change', this.boundCheckForLanguageChanges); 33 + } 34 + 35 + /** 36 + * Clean up event listeners when plugin is unloaded 37 + */ 38 + public cleanup(): void { 39 + if (this.app && this.boundCheckForLanguageChanges) { 40 + this.app.workspace.off('layout-change', this.boundCheckForLanguageChanges); 41 + this.boundCheckForLanguageChanges = null; 42 + } 43 + } 44 + 45 + /** 46 + * Check if Obsidian's language has changed and update if needed 47 + */ 48 + private checkForLanguageChanges(): void { 49 + if (!this.app) return; 50 + 51 + const currentObsidianLang = this.getObsidianLanguage(); 52 + if (currentObsidianLang !== this.currentLanguage) { 53 + this.setLanguage(currentObsidianLang); 54 + } 55 + } 56 + 57 + /** 58 + * Get the ISO code for the currently configured Obsidian app language 59 + * @returns The language code (defaults to 'en') 60 + */ 61 + public getObsidianLanguage(): LanguageCode { 62 + if (!this.app) return 'en'; 63 + 64 + // Get language from Obsidian 65 + // @ts-ignore - getLanguage() exists but isn't in the type definitions 66 + const obsidianLang = this.app.vault.getConfig('language') || 'en'; 67 + 68 + // Handle special cases or normalize language code if needed 69 + const normalizedLang = this.normalizeLanguageCode(obsidianLang); 70 + 71 + return this.isLanguageSupported(normalizedLang) ? normalizedLang as LanguageCode : 'en'; 72 + } 73 + 74 + /** 75 + * Normalize language codes to match our supported formats 76 + */ 77 + private normalizeLanguageCode(langCode: string): string { 78 + // Handle specific language code mappings 79 + const mappings: Record<string, string> = { 80 + 'zh-cn': 'zh', 81 + 'zh-hans': 'zh', 82 + 'zh-hant': 'zh-TW', 83 + 'pt-pt': 'pt', 84 + 'pt-br': 'pt-BR' 85 + }; 86 + 87 + // Return the mapped value if it exists, otherwise return the original 88 + return mappings[langCode.toLowerCase()] || langCode; 89 + } 90 + 91 + /** 92 + * Set the current language for translations 93 + */ 94 + public setLanguage(lang: LanguageCode): void { 16 95 if (this.isLanguageSupported(lang)) { 17 96 this.currentLanguage = lang; 18 97 } else { ··· 21 100 } 22 101 } 23 102 24 - public getCurrentLanguage(): Language { 103 + /** 104 + * Get the current language being used for translations 105 + */ 106 + public getCurrentLanguage(): LanguageCode { 25 107 return this.currentLanguage; 26 108 } 27 109
+17 -5
src/main.ts
··· 19 19 async onload() { 20 20 await this.loadSettings(); 21 21 22 - // Initialize language from settings 23 - import('./i18n').then(({ i18n }) => { 24 - i18n.setLanguage(this.settings.language); 25 - }); 22 + // Initialize language service with app instance and set language to Obsidian's language 23 + const { i18n } = await import('./i18n'); 24 + i18n.initializeApp(this.app); 25 + 26 + // Always use Obsidian's language setting 27 + const obsidianLang = i18n.getObsidianLanguage(); 28 + i18n.setLanguage(obsidianLang); 29 + 30 + // Only update settings if the language has changed 31 + if (this.settings.language !== obsidianLang) { 32 + this.settings.language = obsidianLang; 33 + await this.saveSettings(); 34 + } 26 35 27 36 // Create an icon in the left ribbon 28 37 const ribbonIconEl = this.addRibbonIcon( ··· 51 60 } 52 61 53 62 onunload() { 54 - // Nothing specific to clean up 63 + // Clean up the translation service's event listeners 64 + import('./i18n').then(({ i18n }) => { 65 + i18n.cleanup(); 66 + }); 55 67 } 56 68 57 69 async loadSettings() {
+8 -3
src/models/constants.ts
··· 1 - import { AIProvider, AITaggerSettings, ProviderConfig } from "./types"; 1 + import { 2 + AIProvider, 3 + AITaggerSettings, 4 + ProviderConfig, 5 + ServiceTypeEnum, 6 + } from "./types"; 2 7 3 8 // Define prompt templates 4 9 export const PROMPT_TEMPLATES = { ··· 67 72 }; 68 73 69 74 export const DEFAULT_SETTINGS: AITaggerSettings = { 75 + serviceType: ServiceTypeEnum.CLOUD, 70 76 provider: AIProvider.Anthropic, 71 77 apiKey: "", 72 78 modelName: MODEL_CONFIGS[AIProvider.Anthropic].defaultModel, ··· 74 80 promptOption: "standard", 75 81 promptTemplate: PROMPT_TEMPLATES.standard, 76 82 customEndpoint: "", 77 - language: "en", 78 - }; 83 + };
+7 -24
src/models/types.ts
··· 8 8 Custom = "custom", 9 9 } 10 10 11 - export type LanguageCode = 12 - | "ar" // Arabic 13 - | "cs" // Czech 14 - | "da" // Danish 15 - | "de" // German 16 - | "en" // English 17 - | "es" // Spanish 18 - | "fr" // French 19 - | "id" // Indonesian 20 - | "it" // Italian 21 - | "ja" // Japanese 22 - | "ko" // Korean 23 - | "nl" // Dutch 24 - | "no" // Norwegian 25 - | "pl" // Polish 26 - | "pt" // Portuguese 27 - | "pt-BR" // Brazilian Portuguese 28 - | "ro" // Romanian 29 - | "ru" // Russian 30 - | "tr" // Turkish 31 - | "uk" // Ukrainian 32 - | "zh" // Chinese (Simplified) 33 - | "zh-TW"; // Chinese (Traditional) 11 + export type ServiceType = "Cloud Service" | "Local Service"; 12 + 13 + export enum ServiceTypeEnum { 14 + CLOUD = "Cloud Service", 15 + LOCAL = "Local Service", 16 + } 34 17 35 18 export interface AITaggerSettings { 36 19 provider: AIProvider; ··· 40 23 promptOption: string; 41 24 promptTemplate: string; 42 25 customEndpoint: string; 43 - language: LanguageCode; 26 + serviceType: ServiceType; 44 27 } 45 28 46 29 export interface ModelInfo {
+19 -10
src/services/notificationService.ts
··· 1 1 import { Notice } from "obsidian"; 2 - import { i18n } from "../i18n"; 3 2 4 3 interface PersistentNoticeOptions { 5 4 duration?: number; ··· 8 7 9 8 export class NotificationService { 10 9 private static defaultOptions: PersistentNoticeOptions = { 11 - duration: 3000, // 3 seconds for regular notices 10 + duration: 3000, // 3 seconds for regular notices 12 11 errorDuration: 5000, // 5 seconds for error notices 13 12 }; 14 13 ··· 22 21 notice: Notice; 23 22 setSuccess: (message: string) => void; 24 23 setError: (message: string) => void; 25 - setProgress: (processed: number, successful: number, total: number, currentFile: string) => void; 24 + setProgress: ( 25 + processed: number, 26 + successful: number, 27 + total: number, 28 + currentFile: string 29 + ) => void; 26 30 } { 27 31 const opts = { ...this.defaultOptions, ...options }; 28 32 const notice = new Notice(initialMessage, 0); // 0 means don't auto-hide 29 33 30 34 return { 31 35 notice, 32 - 36 + 33 37 setSuccess: (message: string) => { 34 38 notice.setMessage(message); 35 39 setTimeout(() => notice.hide(), opts.duration); 36 40 }, 37 - 41 + 38 42 setError: (message: string) => { 39 43 notice.setMessage(message); 40 44 setTimeout(() => notice.hide(), opts.errorDuration); 41 45 }, 42 - 43 - setProgress: (processed: number, successful: number, total: number, currentFile: string) => { 46 + 47 + setProgress: ( 48 + processed: number, 49 + successful: number, 50 + total: number, 51 + currentFile: string 52 + ) => { 44 53 notice.setMessage( 45 54 `Processing: ${currentFile}\nProgress: ${processed}/${total} (${successful} successful)` 46 55 ); 47 - } 56 + }, 48 57 }; 49 58 } 50 59 ··· 54 63 static showNotice(message: string, duration = 3000): Notice { 55 64 return new Notice(message, duration); 56 65 } 57 - 66 + 58 67 /** 59 68 * Shows an error notice 60 69 */ 61 70 static showError(message: string, duration = 5000): Notice { 62 71 return new Notice(message, duration); 63 72 } 64 - } 73 + }
-25
src/services/tagGenerator.ts
··· 8 8 ): Promise<string[]> { 9 9 validateSettings(settings); 10 10 11 - const languageNames: Record<string, string> = { 12 - ar: "Arabic", 13 - cs: "Czech", 14 - da: "Danish", 15 - de: "German", 16 - en: "English", 17 - es: "Spanish", 18 - fr: "French", 19 - id: "Indonesian", 20 - it: "Italian", 21 - ja: "Japanese", 22 - ko: "Korean", 23 - nl: "Dutch", 24 - no: "Norwegian", 25 - pl: "Polish", 26 - pt: "Portuguese", 27 - "pt-BR": "Brazilian Portuguese", 28 - ro: "Romanian", 29 - ru: "Russian", 30 - tr: "Turkish", 31 - uk: "Ukrainian", 32 - zh: "Chinese (Simplified)", 33 - "zh-TW": "Chinese (Traditional)", 34 - }; 35 - 36 11 // Replace placeholders in the prompt template 37 12 const prompt = settings.promptTemplate 38 13 .replace("{maxTags}", settings.maxTags.toString())
+28 -38
src/ui/AITaggerSettingTab.ts
··· 1 1 import { App, PluginSettingTab, Setting } from "obsidian"; 2 - import { AIProvider } from "../models/types"; 3 - import { MODEL_CONFIGS, PROMPT_TEMPLATES } from "../models/constants"; 2 + import { i18n } from "../i18n"; 4 3 import AITaggerPlugin from "../main"; 5 - import { i18n, languageNames } from "../i18n"; 4 + import { MODEL_CONFIGS, PROMPT_TEMPLATES } from "../models/constants"; 5 + import { AIProvider } from "../models/types"; 6 6 7 7 export class AITaggerSettingTab extends PluginSettingTab { 8 8 plugin: AITaggerPlugin; ··· 16 16 const { containerEl } = this; 17 17 containerEl.empty(); 18 18 19 - this.addLanguageSection(containerEl); 20 19 this.addProviderSection(containerEl); 21 20 this.addApiSection(containerEl); 22 21 this.addTaggingOptionsSection(containerEl); 23 22 this.addPromptSection(containerEl); 24 23 } 25 - 26 - private addLanguageSection(containerEl: HTMLElement): void { 27 - new Setting(containerEl) 28 - .setName(i18n.t("settings.language.title")) 29 - .setDesc(i18n.t("settings.language.desc")) 30 - .addDropdown((dropdown) => { 31 - // Add all supported languages 32 - Object.entries(languageNames).forEach(([code, name]) => { 33 - dropdown.addOption(code, name); 34 - }); 35 - 36 - dropdown 37 - .setValue(this.plugin.settings.language) 38 - .onChange(async (value) => { 39 - this.plugin.settings.language = value; 40 - i18n.setLanguage(value); 41 - await this.plugin.saveSettings(); 42 - this.display(); // Refresh the UI with the new language 43 - }); 44 - return dropdown; 45 - }); 46 - } 47 24 48 25 private addProviderSection(containerEl: HTMLElement): void { 26 + new Setting(containerEl); 27 + // setting for cloud vs local service 28 + 49 29 // AI Provider selection 50 30 new Setting(containerEl) 51 31 .setName(i18n.t("settings.provider.title")) 52 32 .setDesc(i18n.t("settings.provider.desc")) 53 33 .addDropdown((dropdown) => { 54 34 dropdown 55 - .addOption(AIProvider.Anthropic, i18n.t("settings.provider.anthropic")) 35 + .addOption( 36 + AIProvider.Anthropic, 37 + i18n.t("settings.provider.anthropic") 38 + ) 56 39 .addOption(AIProvider.OpenAI, i18n.t("settings.provider.openai")) 57 40 .addOption(AIProvider.Mistral, i18n.t("settings.provider.mistral")) 58 41 .addOption(AIProvider.Google, i18n.t("settings.provider.google")) ··· 96 79 const providerConfig = MODEL_CONFIGS[this.plugin.settings.provider]; 97 80 98 81 // API Key with provider-specific description 99 - const providerName = this.plugin.settings.provider === AIProvider.Custom 100 - ? "" 101 - : this.plugin.settings.provider; 102 - 82 + const providerName = 83 + this.plugin.settings.provider === AIProvider.Custom 84 + ? "" 85 + : this.plugin.settings.provider; 86 + 103 87 new Setting(containerEl) 104 88 .setName(i18n.t("settings.apiKey.title")) 105 89 .setDesc( 106 - i18n.t("settings.apiKey.desc", { provider: providerName }) + " " + 107 - (providerConfig.apiKeyUrl 108 - ? i18n.t("settings.apiKey.getKey", { url: providerConfig.apiKeyUrl }) 109 - : "") + " " + 110 - i18n.t("settings.apiKey.recommendation") 90 + i18n.t("settings.apiKey.desc", { provider: providerName }) + 91 + " " + 92 + (providerConfig.apiKeyUrl 93 + ? i18n.t("settings.apiKey.getKey", { 94 + url: providerConfig.apiKeyUrl, 95 + }) 96 + : "") + 97 + " " + 98 + i18n.t("settings.apiKey.recommendation") 111 99 ) 112 100 .addText((text) => 113 101 text ··· 137 125 ) { 138 126 dropdown.addOption( 139 127 this.plugin.settings.modelName, 140 - i18n.t("settings.model.custom", { model: this.plugin.settings.modelName }) 128 + i18n.t("settings.model.custom", { 129 + model: this.plugin.settings.modelName, 130 + }) 141 131 ); 142 132 } 143 133 ··· 230 220 .setClass("ai-tagger-wide-setting"); 231 221 } 232 222 } 233 - } 223 + }
+3 -1
tsconfig.json
··· 11 11 "importHelpers": true, 12 12 "isolatedModules": true, 13 13 "strictNullChecks": true, 14 + "allowSyntheticDefaultImports": true, 15 + "resolveJsonModule": true, 14 16 "lib": [ 15 17 "DOM", 16 18 "ES5", ··· 21 23 "include": [ 22 24 "**/*.ts" 23 25 ] 24 - } 26 + }