mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-29 11:02:28 +08:00
feat(llm): automatically fetch models when provider settings change
This commit is contained in:
parent
fe15a0378a
commit
3dee462476
@ -138,19 +138,80 @@ export default class AiSettingsWidget extends OptionsWidget {
|
||||
this.setupChangeHandler('.embedding-update-interval', 'embeddingUpdateInterval');
|
||||
|
||||
// Add provider selection change handlers for dynamic settings visibility
|
||||
this.$widget.find('.ai-selected-provider').on('change', () => {
|
||||
this.$widget.find('.ai-selected-provider').on('change', async () => {
|
||||
const selectedProvider = this.$widget.find('.ai-selected-provider').val() as string;
|
||||
this.$widget.find('.provider-settings').hide();
|
||||
if (selectedProvider) {
|
||||
this.$widget.find(`.${selectedProvider}-provider-settings`).show();
|
||||
// Automatically fetch models for the newly selected provider
|
||||
await this.fetchModelsForProvider(selectedProvider, 'chat');
|
||||
}
|
||||
});
|
||||
|
||||
this.$widget.find('.embedding-selected-provider').on('change', () => {
|
||||
this.$widget.find('.embedding-selected-provider').on('change', async () => {
|
||||
const selectedProvider = this.$widget.find('.embedding-selected-provider').val() as string;
|
||||
this.$widget.find('.embedding-provider-settings').hide();
|
||||
if (selectedProvider) {
|
||||
this.$widget.find(`.${selectedProvider}-embedding-provider-settings`).show();
|
||||
// Automatically fetch embedding models for the newly selected provider
|
||||
await this.fetchModelsForProvider(selectedProvider, 'embedding');
|
||||
}
|
||||
});
|
||||
|
||||
// Add base URL change handlers to trigger model fetching
|
||||
this.$widget.find('.openai-base-url').on('change', async () => {
|
||||
const selectedProvider = this.$widget.find('.ai-selected-provider').val() as string;
|
||||
const selectedEmbeddingProvider = this.$widget.find('.embedding-selected-provider').val() as string;
|
||||
if (selectedProvider === 'openai') {
|
||||
await this.fetchModelsForProvider('openai', 'chat');
|
||||
}
|
||||
if (selectedEmbeddingProvider === 'openai') {
|
||||
await this.fetchModelsForProvider('openai', 'embedding');
|
||||
}
|
||||
});
|
||||
|
||||
this.$widget.find('.anthropic-base-url').on('change', async () => {
|
||||
const selectedProvider = this.$widget.find('.ai-selected-provider').val() as string;
|
||||
if (selectedProvider === 'anthropic') {
|
||||
await this.fetchModelsForProvider('anthropic', 'chat');
|
||||
}
|
||||
});
|
||||
|
||||
this.$widget.find('.ollama-base-url').on('change', async () => {
|
||||
const selectedProvider = this.$widget.find('.ai-selected-provider').val() as string;
|
||||
const selectedEmbeddingProvider = this.$widget.find('.embedding-selected-provider').val() as string;
|
||||
if (selectedProvider === 'ollama') {
|
||||
await this.fetchModelsForProvider('ollama', 'chat');
|
||||
}
|
||||
if (selectedEmbeddingProvider === 'ollama') {
|
||||
await this.fetchModelsForProvider('ollama', 'embedding');
|
||||
}
|
||||
});
|
||||
|
||||
// Add API key change handlers to trigger model fetching
|
||||
this.$widget.find('.openai-api-key').on('change', async () => {
|
||||
const selectedProvider = this.$widget.find('.ai-selected-provider').val() as string;
|
||||
const selectedEmbeddingProvider = this.$widget.find('.embedding-selected-provider').val() as string;
|
||||
if (selectedProvider === 'openai') {
|
||||
await this.fetchModelsForProvider('openai', 'chat');
|
||||
}
|
||||
if (selectedEmbeddingProvider === 'openai') {
|
||||
await this.fetchModelsForProvider('openai', 'embedding');
|
||||
}
|
||||
});
|
||||
|
||||
this.$widget.find('.anthropic-api-key').on('change', async () => {
|
||||
const selectedProvider = this.$widget.find('.ai-selected-provider').val() as string;
|
||||
if (selectedProvider === 'anthropic') {
|
||||
await this.fetchModelsForProvider('anthropic', 'chat');
|
||||
}
|
||||
});
|
||||
|
||||
this.$widget.find('.voyage-api-key').on('change', async () => {
|
||||
const selectedEmbeddingProvider = this.$widget.find('.embedding-selected-provider').val() as string;
|
||||
if (selectedEmbeddingProvider === 'voyage') {
|
||||
// Voyage doesn't have dynamic model fetching yet, but we can add it here when implemented
|
||||
console.log('Voyage API key changed - model fetching not yet implemented');
|
||||
}
|
||||
});
|
||||
|
||||
@ -446,6 +507,49 @@ export default class AiSettingsWidget extends OptionsWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set model dropdown value, adding the option if it doesn't exist
|
||||
*/
|
||||
setModelDropdownValue(selector: string, value: string | undefined) {
|
||||
if (!this.$widget || !value) return;
|
||||
|
||||
const $dropdown = this.$widget.find(selector);
|
||||
|
||||
// Check if the value already exists as an option
|
||||
if ($dropdown.find(`option[value="${value}"]`).length === 0) {
|
||||
// Add the custom value as an option
|
||||
$dropdown.append(`<option value="${value}">${value} (current)</option>`);
|
||||
}
|
||||
|
||||
// Set the value
|
||||
$dropdown.val(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch models for a specific provider and model type
|
||||
*/
|
||||
async fetchModelsForProvider(provider: string, modelType: 'chat' | 'embedding') {
|
||||
if (!this.providerService) return;
|
||||
|
||||
try {
|
||||
switch (provider) {
|
||||
case 'openai':
|
||||
this.openaiModelsRefreshed = await this.providerService.refreshOpenAIModels(false, this.openaiModelsRefreshed);
|
||||
break;
|
||||
case 'anthropic':
|
||||
this.anthropicModelsRefreshed = await this.providerService.refreshAnthropicModels(false, this.anthropicModelsRefreshed);
|
||||
break;
|
||||
case 'ollama':
|
||||
this.ollamaModelsRefreshed = await this.providerService.refreshOllamaModels(false, this.ollamaModelsRefreshed);
|
||||
break;
|
||||
default:
|
||||
console.log(`Model fetching not implemented for provider: ${provider}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error fetching models for ${provider}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update provider settings visibility based on selected providers
|
||||
*/
|
||||
@ -470,7 +574,7 @@ export default class AiSettingsWidget extends OptionsWidget {
|
||||
/**
|
||||
* Called when the options have been loaded from the server
|
||||
*/
|
||||
optionsLoaded(options: OptionMap) {
|
||||
async optionsLoaded(options: OptionMap) {
|
||||
if (!this.$widget) return;
|
||||
|
||||
// AI Options
|
||||
@ -482,22 +586,22 @@ export default class AiSettingsWidget extends OptionsWidget {
|
||||
// OpenAI Section
|
||||
this.$widget.find('.openai-api-key').val(options.openaiApiKey || '');
|
||||
this.$widget.find('.openai-base-url').val(options.openaiBaseUrl || 'https://api.openai.com/v1');
|
||||
this.$widget.find('.openai-default-model').val(options.openaiDefaultModel || '');
|
||||
this.$widget.find('.openai-embedding-model').val(options.openaiEmbeddingModel || '');
|
||||
this.setModelDropdownValue('.openai-default-model', options.openaiDefaultModel);
|
||||
this.setModelDropdownValue('.openai-embedding-model', options.openaiEmbeddingModel);
|
||||
|
||||
// Anthropic Section
|
||||
this.$widget.find('.anthropic-api-key').val(options.anthropicApiKey || '');
|
||||
this.$widget.find('.anthropic-base-url').val(options.anthropicBaseUrl || 'https://api.anthropic.com');
|
||||
this.$widget.find('.anthropic-default-model').val(options.anthropicDefaultModel || '');
|
||||
this.setModelDropdownValue('.anthropic-default-model', options.anthropicDefaultModel);
|
||||
|
||||
// Voyage Section
|
||||
this.$widget.find('.voyage-api-key').val(options.voyageApiKey || '');
|
||||
this.$widget.find('.voyage-embedding-model').val(options.voyageEmbeddingModel || '');
|
||||
this.setModelDropdownValue('.voyage-embedding-model', options.voyageEmbeddingModel);
|
||||
|
||||
// Ollama Section
|
||||
this.$widget.find('.ollama-base-url').val(options.ollamaBaseUrl || 'http://localhost:11434');
|
||||
this.$widget.find('.ollama-default-model').val(options.ollamaDefaultModel || '');
|
||||
this.$widget.find('.ollama-embedding-model').val(options.ollamaEmbeddingModel || '');
|
||||
this.setModelDropdownValue('.ollama-default-model', options.ollamaDefaultModel);
|
||||
this.setModelDropdownValue('.ollama-embedding-model', options.ollamaEmbeddingModel);
|
||||
|
||||
// Embedding Options
|
||||
this.$widget.find('.embedding-selected-provider').val(options.embeddingSelectedProvider || 'openai');
|
||||
@ -512,6 +616,18 @@ export default class AiSettingsWidget extends OptionsWidget {
|
||||
// Show/hide provider settings based on selected providers
|
||||
this.updateProviderSettingsVisibility();
|
||||
|
||||
// Automatically fetch models for currently selected providers
|
||||
const selectedAiProvider = this.$widget.find('.ai-selected-provider').val() as string;
|
||||
const selectedEmbeddingProvider = this.$widget.find('.embedding-selected-provider').val() as string;
|
||||
|
||||
if (selectedAiProvider) {
|
||||
await this.fetchModelsForProvider(selectedAiProvider, 'chat');
|
||||
}
|
||||
|
||||
if (selectedEmbeddingProvider) {
|
||||
await this.fetchModelsForProvider(selectedEmbeddingProvider, 'embedding');
|
||||
}
|
||||
|
||||
// Display validation warnings
|
||||
this.displayValidationWarnings();
|
||||
}
|
||||
|
@ -93,9 +93,7 @@ export const TPL = `
|
||||
<div class="form-group">
|
||||
<label>${t("ai_llm.model")}</label>
|
||||
<select class="openai-default-model form-control">
|
||||
<option value="gpt-4o">GPT-4o (recommended)</option>
|
||||
<option value="gpt-4">GPT-4</option>
|
||||
<option value="gpt-3.5-turbo">GPT-3.5 Turbo</option>
|
||||
<option value="">${t("ai_llm.select_model")}</option>
|
||||
</select>
|
||||
<div class="form-text">${t("ai_llm.openai_model_description")}</div>
|
||||
<button class="btn btn-sm btn-outline-secondary refresh-openai-models">${t("ai_llm.refresh_models")}</button>
|
||||
@ -104,8 +102,7 @@ export const TPL = `
|
||||
<div class="form-group">
|
||||
<label>${t("ai_llm.embedding_model")}</label>
|
||||
<select class="openai-embedding-model form-control">
|
||||
<option value="text-embedding-3-small">text-embedding-3-small (recommended)</option>
|
||||
<option value="text-embedding-3-large">text-embedding-3-large</option>
|
||||
<option value="">${t("ai_llm.select_model")}</option>
|
||||
</select>
|
||||
<div class="form-text">${t("ai_llm.openai_embedding_model_description")}</div>
|
||||
</div>
|
||||
@ -135,9 +132,7 @@ export const TPL = `
|
||||
<div class="form-group">
|
||||
<label>${t("ai_llm.model")}</label>
|
||||
<select class="anthropic-default-model form-control">
|
||||
<option value="claude-3-opus-20240229">Claude 3 Opus (recommended)</option>
|
||||
<option value="claude-3-sonnet-20240229">Claude 3 Sonnet</option>
|
||||
<option value="claude-3-haiku-20240307">Claude 3 Haiku</option>
|
||||
<option value="">${t("ai_llm.select_model")}</option>
|
||||
</select>
|
||||
<div class="form-text">${t("ai_llm.anthropic_model_description")}</div>
|
||||
<button class="btn btn-sm btn-outline-secondary refresh-anthropic-models">${t("ai_llm.refresh_models")}</button>
|
||||
@ -162,9 +157,7 @@ export const TPL = `
|
||||
<div class="form-group">
|
||||
<label>${t("ai_llm.model")}</label>
|
||||
<select class="ollama-default-model form-control">
|
||||
<option value="llama3">llama3 (recommended)</option>
|
||||
<option value="mistral">mistral</option>
|
||||
<option value="phi3">phi3</option>
|
||||
<option value="">${t("ai_llm.select_model")}</option>
|
||||
</select>
|
||||
<div class="form-text">${t("ai_llm.ollama_model_description")}</div>
|
||||
<button class="btn btn-sm btn-outline-secondary refresh-models"><span class="bx bx-refresh"></span></button>
|
||||
@ -173,8 +166,7 @@ export const TPL = `
|
||||
<div class="form-group">
|
||||
<label>${t("ai_llm.embedding_model")}</label>
|
||||
<select class="ollama-embedding-model form-control">
|
||||
<option value="nomic-embed-text">nomic-embed-text (recommended)</option>
|
||||
<option value="all-MiniLM-L6-v2">all-MiniLM-L6-v2</option>
|
||||
<option value="">${t("ai_llm.select_model")}</option>
|
||||
</select>
|
||||
<div class="form-text">${t("ai_llm.ollama_embedding_model_description")}</div>
|
||||
</div>
|
||||
@ -221,8 +213,7 @@ export const TPL = `
|
||||
<div class="form-group">
|
||||
<label>${t("ai_llm.embedding_model")}</label>
|
||||
<select class="openai-embedding-model form-control">
|
||||
<option value="text-embedding-3-small">text-embedding-3-small (recommended)</option>
|
||||
<option value="text-embedding-3-large">text-embedding-3-large</option>
|
||||
<option value="">${t("ai_llm.select_model")}</option>
|
||||
</select>
|
||||
<div class="form-text">${t("ai_llm.openai_embedding_model_description")}</div>
|
||||
</div>
|
||||
@ -247,9 +238,7 @@ export const TPL = `
|
||||
<div class="form-group">
|
||||
<label>${t("ai_llm.embedding_model")}</label>
|
||||
<select class="voyage-embedding-model form-control">
|
||||
<option value="voyage-2">Voyage-2 (recommended)</option>
|
||||
<option value="voyage-2-code">Voyage-2-Code</option>
|
||||
<option value="voyage-large-2">Voyage-Large-2</option>
|
||||
<option value="">${t("ai_llm.select_model")}</option>
|
||||
</select>
|
||||
<div class="form-text">${t("ai_llm.voyage_embedding_model_description")}</div>
|
||||
</div>
|
||||
@ -267,8 +256,7 @@ export const TPL = `
|
||||
<div class="form-group">
|
||||
<label>${t("ai_llm.embedding_model")}</label>
|
||||
<select class="ollama-embedding-model form-control">
|
||||
<option value="nomic-embed-text">nomic-embed-text (recommended)</option>
|
||||
<option value="all-MiniLM-L6-v2">all-MiniLM-L6-v2</option>
|
||||
<option value="">${t("ai_llm.select_model")}</option>
|
||||
</select>
|
||||
<div class="form-text">${t("ai_llm.ollama_embedding_model_description")}</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user