From fde784afbf37edda944c7b7e853d63f6701614d4 Mon Sep 17 00:00:00 2001 From: dimitrievgs Date: Fri, 1 May 2026 22:43:00 +0300 Subject: [PATCH] Fix available models checking and models' choice settings --- main.ts | 110 ++++++++++++++++++++++++++++------- src/components/ChatPanel.ts | 10 +--- src/components/VoicePanel.ts | 2 +- src/views/ChatView.ts | 34 ++++------- 4 files changed, 104 insertions(+), 52 deletions(-) diff --git a/main.ts b/main.ts index 01058d7..ec524e2 100644 --- a/main.ts +++ b/main.ts @@ -18,12 +18,13 @@ interface LLMAgentSettings { excludedFolders: string[]; refCacheFolder: string; - voiceModel: string; + summarizationModel: string; + voiceCommandModel: string; voiceInterval: number; voiceDisplayLimit: number; // 3000 voiceContextLimit: number; // N2 символов для LLM - promptRegularPath: string; - promptCommandsPath: string; + promptRegular: string; + promptCommands: string; markerStart: string; // "старт" markerStop: string; // "стоп" } @@ -42,8 +43,8 @@ const DEFAULT_SETTINGS: LLMAgentSettings = { voiceInterval: 1, voiceDisplayLimit: 3000, voiceContextLimit: 3000, - promptRegularPath: '', - promptCommandsPath: '', + promptRegular: '', + promptCommands: '', markerStart: 'старт', markerStop: 'стоп' }; @@ -55,8 +56,9 @@ export default class LLMAgentPlugin extends Plugin { eventBus: EventBus; webSocketService: WebSocketService; activeStreamControllers: Map; + availableModels: string[]; - async syncVoiceSettings() { + async syncSettings() { try { const response = await fetch(`${this.settings.apiBaseUrl}/settings/sync`, { method: 'POST', @@ -71,6 +73,24 @@ export default class LLMAgentPlugin extends Plugin { } } + /** + * Загружает список доступных моделей с бэкенда. + * @returns {Promise} + */ + async fetchAvailableModels(): Promise { + try { + const response = await fetch(`${this.settings.apiBaseUrl}/models`); + if (!response.ok) { + throw new Error(`Ошибка загрузки моделей: ${response.status}`); + } + this.availableModels = await response.json(); + } catch (error) { + console.error('Ошибка загрузки доступных моделей:', error); + // Fallback к базовым моделям + this.availableModels = ['gemini-2.5-flash', 'gpt-4o-mini', 'claude-3-5-sonnet-20241022']; + } + } + async onload() { await this.loadSettings(); @@ -118,9 +138,9 @@ export default class LLMAgentPlugin extends Plugin { // This adds a settings tab so the user can configure various aspects of the plugin this.addSettingTab(new SampleSettingTab(this.app, this)); - + await this.fetchAvailableModels(); // Вызываем один раз при запуске - await this.syncVoiceSettings(); + await this.syncSettings(); } onunload() { @@ -144,6 +164,7 @@ export default class LLMAgentPlugin extends Plugin { async saveSettings() { await this.saveData(this.settings); + this.eventBus.emit('settings-changed'); } // ----------------------------------------------- View Management --------------------------------------------------------------- @@ -206,6 +227,32 @@ class SampleSettingTab extends PluginSettingTab { containerEl.createEl('h2', { text: 'Основные настройки' }); + new Setting(containerEl) + .setName('Модель по умолчанию') + .setDesc('Выберите модель для основного чата.') + .addDropdown((dropdown) => { + this.plugin.availableModels.forEach(model => dropdown.addOption(model, model)); + dropdown.setValue(this.plugin.settings.defaultModel) + .onChange(async (value) => { + this.plugin.settings.defaultModel = value; + await this.plugin.saveSettings(); + await this.plugin.syncSettings(); + }); + }); + + new Setting(containerEl) + .setName('Модель суммаризации') + .setDesc('Выберите модель для суммаризации.') + .addDropdown((dropdown) => { + this.plugin.availableModels.forEach(model => dropdown.addOption(model, model)); + dropdown.setValue(this.plugin.settings.summarizationModel) + .onChange(async (value) => { + this.plugin.settings.summarizationModel = value; + await this.plugin.saveSettings(); + await this.plugin.syncSettings(); + }); + }); + new Setting(containerEl) .setName('API Base URL') .setDesc('Базовый URL для API LLM Agent') @@ -216,6 +263,7 @@ class SampleSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.apiBaseUrl = value; await this.plugin.saveSettings(); + await this.plugin.syncSettings(); }) ); @@ -229,11 +277,25 @@ class SampleSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.systemPrompt = value; await this.plugin.saveSettings(); + await this.plugin.syncSettings(); }) ); containerEl.createEl('h2', { text: 'Голосовое управление (Voice Service)' }); + new Setting(containerEl) + .setName('Модель команд') + .setDesc('LLM для обработки голосовых команд.') + .addDropdown((dropdown) => { + this.plugin.availableModels.forEach(model => dropdown.addOption(model, model)); + dropdown.setValue(this.plugin.settings.voiceCommandModel) + .onChange(async (value) => { + this.plugin.settings.voiceCommandModel = value; + await this.plugin.saveSettings(); + await this.plugin.syncSettings(); + }); + }); + new Setting(containerEl) .setName('Интервал регулярного анализа (мин)') .setDesc('Как часто LLM анализирует последние фразы (Prompt 1).') @@ -243,7 +305,7 @@ class SampleSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.voiceInterval = Number(value); await this.plugin.saveSettings(); - await this.plugin.syncVoiceSettings(); + await this.plugin.syncSettings(); }) ); @@ -256,7 +318,7 @@ class SampleSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.voiceContextLimit = Number(value); await this.plugin.saveSettings(); - await this.plugin.syncVoiceSettings(); + await this.plugin.syncSettings(); }) ); @@ -270,7 +332,7 @@ class SampleSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.markerStart = value; await this.plugin.saveSettings(); - await this.plugin.syncVoiceSettings(); + await this.plugin.syncSettings(); }) ); @@ -284,7 +346,7 @@ class SampleSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.markerStop = value; await this.plugin.saveSettings(); - await this.plugin.syncVoiceSettings(); + await this.plugin.syncSettings(); }) ); @@ -294,11 +356,11 @@ class SampleSettingTab extends PluginSettingTab { .addTextArea((text) => text // .setPlaceholder('prompts/regular_analysis.md') - .setValue(this.plugin.settings.promptRegularPath) + .setValue(this.plugin.settings.promptRegular) .onChange(async (value) => { - this.plugin.settings.promptRegularPath = value; + this.plugin.settings.promptRegular = value; await this.plugin.saveSettings(); - await this.plugin.syncVoiceSettings(); + await this.plugin.syncSettings(); }) ); @@ -308,11 +370,11 @@ class SampleSettingTab extends PluginSettingTab { .addTextArea((text) => text // .setPlaceholder('prompts/voice_commands.md') - .setValue(this.plugin.settings.promptCommandsPath) + .setValue(this.plugin.settings.promptCommands) .onChange(async (value) => { - this.plugin.settings.promptCommandsPath = value; + this.plugin.settings.promptCommands = value; await this.plugin.saveSettings(); - await this.plugin.syncVoiceSettings(); + await this.plugin.syncSettings(); }) ); @@ -328,6 +390,7 @@ class SampleSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.promptsFolder = value; await this.plugin.saveSettings(); + await this.plugin.syncSettings(); }) ); @@ -341,6 +404,7 @@ class SampleSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.refCacheFolder = value; await this.plugin.saveSettings(); + await this.plugin.syncSettings(); }) ); @@ -352,6 +416,7 @@ class SampleSettingTab extends PluginSettingTab { toggle.setValue(this.plugin.settings.enableFileReferences).onChange(async (value) => { this.plugin.settings.enableFileReferences = value; await this.plugin.saveSettings(); + await this.plugin.syncSettings(); }) ); @@ -363,6 +428,7 @@ class SampleSettingTab extends PluginSettingTab { toggle.setValue(this.plugin.settings.enablePromptReferences).onChange(async (value) => { this.plugin.settings.enablePromptReferences = value; await this.plugin.saveSettings(); + await this.plugin.syncSettings(); }) ); @@ -374,6 +440,7 @@ class SampleSettingTab extends PluginSettingTab { toggle.setValue(this.plugin.settings.enableFileReferences).onChange(async (value) => { this.plugin.settings.enableFileReferences = value; await this.plugin.saveSettings(); + await this.plugin.syncSettings(); }) ); @@ -386,8 +453,9 @@ class SampleSettingTab extends PluginSettingTab { text.setPlaceholder('Путь к папке (например, templates/)' + index) .setValue(folder) .onChange(async (value) => { - this.plugin.settings.excludedFolders[index] = value; - await this.plugin.saveSettings(); + this.plugin.settings.excludedFolders[index] = value; + await this.plugin.saveSettings(); + await this.plugin.syncSettings(); // Очищаем кэш автокомплита при изменении настроек this.plugin.eventBus.emit('settings-changed'); }); @@ -399,6 +467,7 @@ class SampleSettingTab extends PluginSettingTab { .onClick(async () => { this.plugin.settings.excludedFolders.splice(index, 1); await this.plugin.saveSettings(); + await this.plugin.syncSettings(); this.display(); // Перерисовать настройки для обновления списка // Очищаем кэш автокомплита при изменении настроек this.plugin.eventBus.emit('settings-changed'); @@ -413,6 +482,7 @@ class SampleSettingTab extends PluginSettingTab { .onClick(async () => { this.plugin.settings.excludedFolders.push(''); // Добавляем пустое поле await this.plugin.saveSettings(); + await this.plugin.syncSettings(); this.display(); // Перерисовать настройки для обновления списка }); }); diff --git a/src/components/ChatPanel.ts b/src/components/ChatPanel.ts index 17eadfe..e918811 100644 --- a/src/components/ChatPanel.ts +++ b/src/components/ChatPanel.ts @@ -19,7 +19,6 @@ import { CacheManager } from 'src/references/CacheManager'; interface ChatPanelProps { chatHistory: ChatHistoryItem[]; onSendMessage: (message: string, selectedModel?: string, attachments?: Attachment[]) => void; - availableModels?: string[]; selectedModel?: string; plugin: LLMAgentPlugin; currentGraphCustomSystemPrompt: string | null; @@ -133,9 +132,9 @@ export class ChatPanel { } updateModelDropdown(): void { - if (!this.props.availableModels) return; + if (!this.props.plugin.availableModels) return; - this.modelDropdown.innerHTML = this.props.availableModels + this.modelDropdown.innerHTML = this.props.plugin.availableModels .map( (model) => `
@@ -410,11 +409,6 @@ export class ChatPanel { await this.renderHistory(); } - updateAvailableModels(models: string[]): void { - this.props.availableModels = models; - this.updateModelDropdown(); - } - destroy(): void { if (this.referenceAutocomplete) { this.referenceAutocomplete.destroy(); diff --git a/src/components/VoicePanel.ts b/src/components/VoicePanel.ts index b9b2154..c4cf4bd 100644 --- a/src/components/VoicePanel.ts +++ b/src/components/VoicePanel.ts @@ -66,7 +66,7 @@ export class VoicePanel { if (!body) return; if (data.obsidian_settings_fetched == false) // если это не сделать, то на беке останутся пустые настройки, если обсидиан запущен раньше бека { - this.plugin.syncVoiceSettings(); + this.plugin.syncSettings(); } if (this.activeTab === 'trans') body.textContent = data.transcription; if (this.activeTab === 'res1') body.textContent = data.response1; diff --git a/src/views/ChatView.ts b/src/views/ChatView.ts index 038e34e..28e7e15 100644 --- a/src/views/ChatView.ts +++ b/src/views/ChatView.ts @@ -19,7 +19,6 @@ export class ChatView extends ItemView { currentNode: string | null; chatContainer: HTMLDivElement; chatPanel: ChatPanel | null; - availableModels: string[]; currentGraphCustomSystemPrompt: string | null; currentStreamingNodeId: string | null = null; @@ -30,7 +29,6 @@ export class ChatView extends ItemView { this.selectedGraphId = null; this.currentNode = null; this.chatPanel = null; - this.availableModels = []; this.currentGraphCustomSystemPrompt = null; } @@ -54,19 +52,19 @@ export class ChatView extends ItemView { this.chatContainer = container.createDiv() as HTMLDivElement; this.chatContainer.addClass('llm-agent-chat-container'); - // Загружаем доступные модели - await this.fetchAvailableModels(); + // Загружаем доступные модели (TODO: проверить, что здесь это нужно, что не сделали этого ранее) + // await this.plugin.fetchAvailableModels(); // Инициализируем только чат панель с передачей plugin this.chatPanel = new ChatPanel(this.chatContainer, { chatHistory: this.chatHistory, onSendMessage: this.handleSendMessage.bind(this), - availableModels: this.availableModels, selectedModel: this.plugin.settings.defaultModel || 'gemini-2.5-flash', plugin: this.plugin, currentGraphCustomSystemPrompt: this.currentGraphCustomSystemPrompt }); + this.plugin.eventBus.on('settings-changed', this.handleSettingsChanged.bind(this)); this.plugin.eventBus.on('node-selected', this.handleNodeSelected.bind(this)); this.plugin.eventBus.on('new-chat', this.handleNewChat.bind(this)); this.plugin.eventBus.on('graph-selected', this.handleGraphSelected.bind(this)); @@ -84,6 +82,7 @@ export class ChatView extends ItemView { this.chatPanel.destroy(); this.chatPanel = null; } + this.plugin.eventBus.off('settings-changed', this.handleSettingsChanged); this.plugin.eventBus.off('node-selected', this.handleNodeSelected); this.plugin.eventBus.off('new-chat', this.handleNewChat); this.plugin.eventBus.off('graph-selected', this.handleGraphSelected); @@ -154,24 +153,6 @@ export class ChatView extends ItemView { } } - /** - * Загружает список доступных моделей с бэкенда. - * @returns {Promise} - */ - async fetchAvailableModels(): Promise { - try { - const response = await fetch(`${this.plugin.settings.apiBaseUrl}/models`); - if (!response.ok) { - throw new Error(`Ошибка загрузки моделей: ${response.status}`); - } - this.availableModels = await response.json(); - } catch (error) { - console.error('Ошибка загрузки доступных моделей:', error); - // Fallback к базовым моделям - this.availableModels = ['gemini-2.5-flash', 'gpt-4o-mini', 'claude-3-5-sonnet-20241022']; - } - } - // ----------------------------------------------- Event Handlers --------------------------------------------------------------- async handleSendMessage(message: string, selectedModel?: string, attachments?: Attachment[]): Promise { @@ -227,6 +208,13 @@ export class ChatView extends ItemView { } } + handleSettingsChanged(): void { + if (this.chatPanel) + { + this.chatPanel.setSelectedModel(this.plugin.settings.defaultModel); + } + } + /** * Обрабатывает выбор узла на графе. Загружает историю сообщений до выбранного узла * и обновляет панель чата.