diff --git a/src/components/VoicePanel.ts b/src/components/VoicePanel.ts index c4cf4bd..657beda 100644 --- a/src/components/VoicePanel.ts +++ b/src/components/VoicePanel.ts @@ -1,4 +1,5 @@ import LLMAgentPlugin from 'main'; +import { MarkdownRenderer } from 'obsidian'; export class VoicePanel { private activeTab: 'res1' | 'res2' | 'trans' = 'res1'; @@ -30,7 +31,6 @@ export class VoicePanel { `; - // Навешиваем логику вкладок this.container.querySelectorAll('.v-tab').forEach((tab) => { tab.addEventListener('click', (e) => { this.container.querySelectorAll('.v-tab').forEach((t) => t.classList.remove('active')); @@ -39,7 +39,6 @@ export class VoicePanel { }); }); - // Навешиваем управление через API const control = async (action: string) => { await fetch(`${this.plugin.settings.apiBaseUrl}/voice/control`, { method: 'POST', @@ -55,21 +54,49 @@ export class VoicePanel { async startPolling() { setInterval(async () => { - const res = await fetch(`${this.plugin.settings.apiBaseUrl}/voice/status`); - const data = await res.json(); - this.updateContent(data); - }, 3000); + try { + const res = await fetch(`${this.plugin.settings.apiBaseUrl}/voice/status`); + const data = await res.json(); + this.updateContent(data); + } catch (e) { + console.error("Voice status fetch error", e); + } + }, 1500); } - updateContent(data: any) { - const body = this.container.querySelector('#v-body'); + async updateContent(data: any) { + const body = this.container.querySelector('#v-body') as HTMLElement; if (!body) return; - if (data.obsidian_settings_fetched == false) // если это не сделать, то на беке останутся пустые настройки, если обсидиан запущен раньше бека - { + + if (data.obsidian_settings_fetched == false) { this.plugin.syncSettings(); } - if (this.activeTab === 'trans') body.textContent = data.transcription; - if (this.activeTab === 'res1') body.textContent = data.response1; - if (this.activeTab === 'res2') body.innerHTML = data.response2.join('
---
'); + + // Выбираем контент для отображения + let contentToRender = ""; + + if (this.activeTab === 'trans') { + // Транскрипцию обычно выводим как простой текст (или тоже можно через МК) + body.innerText = data.transcription || ""; + return; + } + + if (this.activeTab === 'res1') { + contentToRender = data.response1 || ""; + } else if (this.activeTab === 'res2') { + // Склеиваем массив ответов через горизонтальную линию Markdown + contentToRender = Array.isArray(data.response2) + ? data.response2.join('\n\n---\n\n') + : (data.response2 || ""); + } + + // Очищаем и рендерим Markdown + body.empty(); + await MarkdownRenderer.renderMarkdown( + contentToRender, + body, + '', + this.plugin + ); } -} +} \ No newline at end of file diff --git a/src/css/styles.css b/src/css/styles.css index 2c2b641..ac22bfd 100644 --- a/src/css/styles.css +++ b/src/css/styles.css @@ -781,6 +781,8 @@ height: 100%; display: flex; flex-direction: column; + user-select: text; /* Разрешает выделение текста */ + -webkit-user-select: text; /* Для совместимости с Obsidian/Electron */ } .voice-body { @@ -790,6 +792,9 @@ border: 1px inset var(--background-modifier-border); margin: 4px; padding: 8px; + user-select: text; + -webkit-user-select: text; + cursor: text; /* Меняет курсор на текстовый при наведении */ } .voice-header { @@ -823,6 +828,8 @@ .v-controls button { margin-right: 5px; padding: 4px 10px; + user-select: none; + -webkit-user-select: none; } .llm-agent-history-sidebar {