mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-30 19:19:03 +01:00 
			
		
		
		
	show user at the top of settings if there are issues
This commit is contained in:
		
							parent
							
								
									1844ad7b49
								
							
						
					
					
						commit
						fe1faf77e2
					
				| @ -56,6 +56,9 @@ export default class AiSettingsWidget extends OptionsWidget { | ||||
|         <div class="options-section"> | ||||
|             <h4>${t("ai_llm.title")}</h4> | ||||
| 
 | ||||
|             <!-- Add warning alert div --> | ||||
|             <div class="provider-validation-warning alert alert-warning" style="display: none;"></div> | ||||
| 
 | ||||
|             <div class="form-group"> | ||||
|                 <label class="tn-checkbox"> | ||||
|                     <input class="ai-enabled form-check-input" type="checkbox"> | ||||
| @ -335,6 +338,8 @@ export default class AiSettingsWidget extends OptionsWidget { | ||||
|         $aiEnabled.on('change', async () => { | ||||
|             await this.updateOption('aiEnabled', $aiEnabled.prop('checked') ? "true" : "false"); | ||||
|             this.updateAiSectionVisibility(); | ||||
|             // Display validation warnings when AI is enabled/disabled
 | ||||
|             await this.displayValidationWarnings(); | ||||
|         }); | ||||
| 
 | ||||
|         const $ollamaEnabled = this.$widget.find('.ollama-enabled'); | ||||
| @ -345,6 +350,8 @@ export default class AiSettingsWidget extends OptionsWidget { | ||||
|         const $aiProviderPrecedence = this.$widget.find('.ai-provider-precedence'); | ||||
|         $aiProviderPrecedence.on('change', async () => { | ||||
|             await this.updateOption('aiProviderPrecedence', $aiProviderPrecedence.val() as string); | ||||
|             // Display validation warnings after changing precedence list
 | ||||
|             await this.displayValidationWarnings(); | ||||
|         }); | ||||
| 
 | ||||
|         const $aiTemperature = this.$widget.find('.ai-temperature'); | ||||
| @ -481,6 +488,8 @@ export default class AiSettingsWidget extends OptionsWidget { | ||||
|         const $embeddingDefaultProvider = this.$widget.find('.embedding-default-provider'); | ||||
|         $embeddingDefaultProvider.on('change', async () => { | ||||
|             await this.updateOption('embeddingsDefaultProvider', $embeddingDefaultProvider.val() as string); | ||||
|             // Display validation warnings after changing default provider
 | ||||
|             await this.displayValidationWarnings(); | ||||
|         }); | ||||
| 
 | ||||
|         const $embeddingGenerationLocation = this.$widget.find('.embedding-generation-location'); | ||||
| @ -593,6 +602,9 @@ export default class AiSettingsWidget extends OptionsWidget { | ||||
|         this.$widget.find('.embedding-default-dimension').val(options.embeddingDefaultDimension || '1536'); | ||||
| 
 | ||||
|         this.updateAiSectionVisibility(); | ||||
| 
 | ||||
|         // Call displayValidationWarnings instead of directly calling validateEmbeddingProviders
 | ||||
|         this.displayValidationWarnings(); | ||||
|     } | ||||
| 
 | ||||
|     updateAiSectionVisibility() { | ||||
| @ -1003,5 +1015,99 @@ export default class AiSettingsWidget extends OptionsWidget { | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     // Replace displayValidationWarnings method with client-side implementation
 | ||||
|     async displayValidationWarnings() { | ||||
|         if (!this.$widget) return; | ||||
| 
 | ||||
|         const $warningDiv = this.$widget.find('.provider-validation-warning'); | ||||
| 
 | ||||
|         try { | ||||
|             // Get required data from current settings
 | ||||
|             const aiEnabled = this.$widget.find('.ai-enabled').prop('checked'); | ||||
| 
 | ||||
|             // If AI isn't enabled, don't show warnings
 | ||||
|             if (!aiEnabled) { | ||||
|                 $warningDiv.hide(); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             // Get default embedding provider
 | ||||
|             const defaultProvider = this.$widget.find('.embedding-default-provider').val() as string; | ||||
| 
 | ||||
|             // Get provider precedence
 | ||||
|             const precedenceStr = this.$widget.find('.ai-provider-precedence').val() as string; | ||||
|             let precedenceList: string[] = []; | ||||
| 
 | ||||
|             if (precedenceStr) { | ||||
|                 if (precedenceStr.startsWith('[') && precedenceStr.endsWith(']')) { | ||||
|                     precedenceList = JSON.parse(precedenceStr); | ||||
|                 } else if (precedenceStr.includes(',')) { | ||||
|                     precedenceList = precedenceStr.split(',').map(p => p.trim()); | ||||
|                 } else { | ||||
|                     precedenceList = [precedenceStr]; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Get enabled providers
 | ||||
|             // Since we don't have direct access to DB from client, we'll use the UI state
 | ||||
|             // This is an approximation - enabled providers are generally those with API keys or enabled state
 | ||||
|             const enabledProviders: string[] = []; | ||||
| 
 | ||||
|             // OpenAI is enabled if API key is set
 | ||||
|             const openaiKey = this.$widget.find('.openai-api-key').val() as string; | ||||
|             if (openaiKey) { | ||||
|                 enabledProviders.push('openai'); | ||||
|             } | ||||
| 
 | ||||
|             // Anthropic is enabled if API key is set
 | ||||
|             const anthropicKey = this.$widget.find('.anthropic-api-key').val() as string; | ||||
|             if (anthropicKey) { | ||||
|                 enabledProviders.push('anthropic'); | ||||
|             } | ||||
| 
 | ||||
|             // Ollama is enabled if checkbox is checked
 | ||||
|             const ollamaEnabled = this.$widget.find('.ollama-enabled').prop('checked'); | ||||
|             if (ollamaEnabled) { | ||||
|                 enabledProviders.push('ollama'); | ||||
|             } | ||||
| 
 | ||||
|             // Local is always available
 | ||||
|             enabledProviders.push('local'); | ||||
| 
 | ||||
|             // Perform validation checks
 | ||||
|             const defaultInPrecedence = precedenceList.includes(defaultProvider); | ||||
|             const defaultIsEnabled = enabledProviders.includes(defaultProvider); | ||||
|             const allPrecedenceEnabled = precedenceList.every(p => enabledProviders.includes(p)); | ||||
| 
 | ||||
|             // Build warning message if there are issues
 | ||||
|             if (!defaultInPrecedence || !defaultIsEnabled || !allPrecedenceEnabled) { | ||||
|                 let message = 'There are issues with your AI provider configuration:'; | ||||
| 
 | ||||
|                 if (!defaultInPrecedence) { | ||||
|                     message += `<br>• The default embedding provider "${defaultProvider}" is not in your provider precedence list.`; | ||||
|                 } | ||||
| 
 | ||||
|                 if (!defaultIsEnabled) { | ||||
|                     message += `<br>• The default embedding provider "${defaultProvider}" is not enabled.`; | ||||
|                 } | ||||
| 
 | ||||
|                 if (!allPrecedenceEnabled) { | ||||
|                     const disabledProviders = precedenceList.filter(p => !enabledProviders.includes(p)); | ||||
|                     message += `<br>• The following providers in your precedence list are not enabled: ${disabledProviders.join(', ')}.`; | ||||
|                 } | ||||
| 
 | ||||
|                 message += '<br><br>Please check your AI settings.'; | ||||
| 
 | ||||
|                 $warningDiv.html(message); | ||||
|                 $warningDiv.show(); | ||||
|             } else { | ||||
|                 $warningDiv.hide(); | ||||
|             } | ||||
|         } catch (error) { | ||||
|             console.error('Error validating embedding providers:', error); | ||||
|             $warningDiv.hide(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -7,6 +7,7 @@ import log from '../log.js'; | ||||
| import { ContextExtractor } from './context/index.js'; | ||||
| import semanticContextService from './semantic_context_service.js'; | ||||
| import indexService from './index_service.js'; | ||||
| import { getEmbeddingProvider, getEnabledEmbeddingProviders } from './embeddings/providers.js'; | ||||
| 
 | ||||
| type ServiceProviders = 'openai' | 'anthropic' | 'ollama'; | ||||
| 
 | ||||
| @ -50,8 +51,13 @@ export class AIServiceManager { | ||||
|                     if (customOrder.startsWith('[') && customOrder.endsWith(']')) { | ||||
|                         parsed = JSON.parse(customOrder); | ||||
|                     } else if (typeof customOrder === 'string') { | ||||
|                         // If it's a string with commas, split it
 | ||||
|                         if (customOrder.includes(',')) { | ||||
|                             parsed = customOrder.split(',').map(p => p.trim()); | ||||
|                         } else { | ||||
|                             // If it's a simple string (like "ollama"), convert to single-item array
 | ||||
|                             parsed = [customOrder]; | ||||
|                         } | ||||
|                     } else { | ||||
|                         // Fallback to default
 | ||||
|                         parsed = defaultOrder; | ||||
| @ -74,6 +80,10 @@ export class AIServiceManager { | ||||
|             } | ||||
| 
 | ||||
|             this.initialized = true; | ||||
| 
 | ||||
|             // Remove the validateEmbeddingProviders call since we now do validation on the client
 | ||||
|             // this.validateEmbeddingProviders();
 | ||||
| 
 | ||||
|             return true; | ||||
|         } catch (error) { | ||||
|             // If options table doesn't exist yet, use defaults
 | ||||
| @ -83,6 +93,87 @@ export class AIServiceManager { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Validate embedding providers configuration | ||||
|      * - Check if embedding default provider is in provider precedence list | ||||
|      * - Check if all providers in precedence list and default provider are enabled | ||||
|      * | ||||
|      * @returns A warning message if there are issues, or null if everything is fine | ||||
|      */ | ||||
|     async validateEmbeddingProviders(): Promise<string | null> { | ||||
|         try { | ||||
|             // Check if AI is enabled, if not, skip validation
 | ||||
|             const aiEnabled = await options.getOptionBool('aiEnabled'); | ||||
|             if (!aiEnabled) { | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
|             // Get default embedding provider
 | ||||
|             const defaultProviderName = await options.getOption('embeddingsDefaultProvider') || 'openai'; | ||||
| 
 | ||||
|             // Parse provider precedence list (similar to updateProviderOrder)
 | ||||
|             let precedenceList: string[] = []; | ||||
|             const precedenceOption = await options.getOption('aiProviderPrecedence'); | ||||
| 
 | ||||
|             if (precedenceOption) { | ||||
|                 if (precedenceOption.startsWith('[') && precedenceOption.endsWith(']')) { | ||||
|                     precedenceList = JSON.parse(precedenceOption); | ||||
|                 } else if (typeof precedenceOption === 'string') { | ||||
|                     if (precedenceOption.includes(',')) { | ||||
|                         precedenceList = precedenceOption.split(',').map(p => p.trim()); | ||||
|                     } else { | ||||
|                         precedenceList = [precedenceOption]; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Get enabled providers
 | ||||
|             const enabledProviders = await getEnabledEmbeddingProviders(); | ||||
|             const enabledProviderNames = enabledProviders.map(p => p.name); | ||||
| 
 | ||||
|             // Check if default provider is in precedence list
 | ||||
|             const defaultInPrecedence = precedenceList.includes(defaultProviderName); | ||||
| 
 | ||||
|             // Check if default provider is enabled
 | ||||
|             const defaultIsEnabled = enabledProviderNames.includes(defaultProviderName); | ||||
| 
 | ||||
|             // Check if all providers in precedence list are enabled
 | ||||
|             const allPrecedenceEnabled = precedenceList.every(p => | ||||
|                 enabledProviderNames.includes(p) || p === 'local'); | ||||
| 
 | ||||
|             // Return warning message if there are issues
 | ||||
|             if (!defaultInPrecedence || !defaultIsEnabled || !allPrecedenceEnabled) { | ||||
|                 let message = 'There are issues with your AI provider configuration:'; | ||||
| 
 | ||||
|                 if (!defaultInPrecedence) { | ||||
|                     message += `\n• The default embedding provider "${defaultProviderName}" is not in your provider precedence list.`; | ||||
|                 } | ||||
| 
 | ||||
|                 if (!defaultIsEnabled) { | ||||
|                     message += `\n• The default embedding provider "${defaultProviderName}" is not enabled.`; | ||||
|                 } | ||||
| 
 | ||||
|                 if (!allPrecedenceEnabled) { | ||||
|                     const disabledProviders = precedenceList.filter(p => | ||||
|                         !enabledProviderNames.includes(p) && p !== 'local'); | ||||
|                     message += `\n• The following providers in your precedence list are not enabled: ${disabledProviders.join(', ')}.`; | ||||
|                 } | ||||
| 
 | ||||
|                 message += '\n\nPlease check your AI settings.'; | ||||
| 
 | ||||
|                 // Log warning to console
 | ||||
|                 log.error('AI Provider Configuration Warning: ' + message); | ||||
| 
 | ||||
|                 return message; | ||||
|             } | ||||
| 
 | ||||
|             return null; | ||||
|         } catch (error) { | ||||
|             log.error(`Error validating embedding providers: ${error}`); | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Ensure manager is initialized before using | ||||
|      */ | ||||
| @ -217,6 +308,10 @@ export default { | ||||
|     async generateChatCompletion(messages: Message[], options: ChatCompletionOptions = {}): Promise<ChatResponse> { | ||||
|         return getInstance().generateChatCompletion(messages, options); | ||||
|     }, | ||||
|     // Add validateEmbeddingProviders method
 | ||||
|     async validateEmbeddingProviders(): Promise<string | null> { | ||||
|         return getInstance().validateEmbeddingProviders(); | ||||
|     }, | ||||
|     // Context and index related methods
 | ||||
|     getContextExtractor() { | ||||
|         return getInstance().getContextExtractor(); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 perf3ct
						perf3ct