diff --git a/README.md b/README.md index 183ef10..60277cb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Obsidian Smart Composer +# Smart Composer ![SC1_Title.gif](https://github.com/user-attachments/assets/a50a1f80-39ff-4eba-8090-e3d75e7be98c) @@ -131,7 +131,7 @@ Your feedback and experiences are crucial in making Smart Composer better for ev ## Contributing -We welcome all kinds of contributions to Obsidian Smart Composer, including bug reports, bug fixes, documentation improvements, and feature enhancements. +We welcome all kinds of contributions to Smart Composer, including bug reports, bug fixes, documentation improvements, and feature enhancements. **For major feature ideas, please create an issue first to discuss feasibility and implementation approach.** diff --git a/package-lock.json b/package-lock.json index f827a36..4bcbe9b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,6 @@ "react-markdown": "^9.0.1", "react-syntax-highlighter": "^15.5.0", "remark-gfm": "^4.0.0", - "turndown": "^7.2.0", "uuid": "^10.0.0", "zod": "^3.23.8" }, @@ -47,7 +46,6 @@ "@types/react": "^18.3.10", "@types/react-dom": "^18.3.0", "@types/react-syntax-highlighter": "^15.5.13", - "@types/turndown": "^5.0.5", "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "5.29.0", "@typescript-eslint/parser": "5.29.0", @@ -1939,11 +1937,6 @@ "yjs": ">=13.5.22" } }, - "node_modules/@mixmark-io/domino": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", - "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==" - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, @@ -2795,12 +2788,6 @@ "@types/estree": "*" } }, - "node_modules/@types/turndown": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@types/turndown/-/turndown-5.0.5.tgz", - "integrity": "sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w==", - "dev": true - }, "node_modules/@types/unist": { "version": "3.0.3", "license": "MIT" @@ -10355,14 +10342,6 @@ "dev": true, "license": "0BSD" }, - "node_modules/turndown": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.0.tgz", - "integrity": "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==", - "dependencies": { - "@mixmark-io/domino": "^2.2.0" - } - }, "node_modules/type-check": { "version": "0.4.0", "dev": true, diff --git a/package.json b/package.json index 91e8cad..2690cc1 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "@types/react": "^18.3.10", "@types/react-dom": "^18.3.0", "@types/react-syntax-highlighter": "^15.5.13", - "@types/turndown": "^5.0.5", "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "5.29.0", "@typescript-eslint/parser": "5.29.0", @@ -70,8 +69,7 @@ "react-markdown": "^9.0.1", "react-syntax-highlighter": "^15.5.0", "remark-gfm": "^4.0.0", - "turndown": "^7.2.0", "uuid": "^10.0.0", "zod": "^3.23.8" } -} \ No newline at end of file +} diff --git a/src/ChatView.tsx b/src/ChatView.tsx index c6cc9d3..3ee35db 100644 --- a/src/ChatView.tsx +++ b/src/ChatView.tsx @@ -38,7 +38,7 @@ export class ChatView extends ItemView { } getDisplayText() { - return 'Smart Composer Chat' + return 'Smart composer chat' } async onOpen() { diff --git a/src/OpenSettingsModal.ts b/src/OpenSettingsModal.ts index cd0fa74..94c5673 100644 --- a/src/OpenSettingsModal.ts +++ b/src/OpenSettingsModal.ts @@ -7,7 +7,7 @@ export class OpenSettingsModal extends Modal { this.setTitle(title) new Setting(this.contentEl).addButton((button) => { - button.setButtonText('Open Settings') + button.setButtonText('Open settings') button.onClick(() => { this.close() onSubmit() diff --git a/src/hooks/useChatHistory.ts b/src/hooks/useChatHistory.ts index 94a5e6c..0543364 100644 --- a/src/hooks/useChatHistory.ts +++ b/src/hooks/useChatHistory.ts @@ -100,8 +100,8 @@ export function useChatHistory() { ? editorStateToPlainText(firstUserMessage.content).substring( 0, 20, - ) || 'New Chat' - : 'New Chat', + ) || 'New chat' + : 'New chat', messages: serializedMessages, updatedAt: Date.now(), }) diff --git a/src/main.ts b/src/main.ts index 6790a8f..1157093 100644 --- a/src/main.ts +++ b/src/main.ts @@ -26,7 +26,7 @@ export default class SmartCopilotPlugin extends Plugin { this.registerView(APPLY_VIEW_TYPE, (leaf) => new ApplyView(leaf)) // This creates an icon in the left ribbon. - this.addRibbonIcon('message-square', 'Open Smart Composer', () => + this.addRibbonIcon('message-square', 'Open smart composer', () => this.openChatView(), ) @@ -160,9 +160,9 @@ export default class SmartCopilotPlugin extends Plugin { // chatProps is consumed in ChatView.tsx this.initialChatProps = chatProps - this.app.workspace.detachLeavesOfType(CHAT_VIEW_TYPE) + const leaf = this.app.workspace.getLeavesOfType(CHAT_VIEW_TYPE)[0] - await this.app.workspace.getRightLeaf(false)?.setViewState({ + await (leaf ?? this.app.workspace.getRightLeaf(false))?.setViewState({ type: CHAT_VIEW_TYPE, active: true, }) diff --git a/src/settings/SettingTab.tsx b/src/settings/SettingTab.tsx index 95d7eac..a3f2805 100644 --- a/src/settings/SettingTab.tsx +++ b/src/settings/SettingTab.tsx @@ -22,7 +22,7 @@ export class SmartCopilotSettingTab extends PluginSettingTab { const apiKeysHeading = new Setting(containerEl) .setHeading() - .setName('API Keys') + .setName('API keys') .setDesc('Enter your API keys for the services you want to use') apiKeysHeading.descEl.createEl('br') @@ -35,7 +35,7 @@ export class SmartCopilotSettingTab extends PluginSettingTab { }, }) - new Setting(containerEl).setName('OpenAI API Key').addText((text) => + new Setting(containerEl).setName('OpenAI API key').addText((text) => text .setPlaceholder('Enter your API key') .setValue(this.plugin.settings.openAIApiKey) @@ -47,7 +47,7 @@ export class SmartCopilotSettingTab extends PluginSettingTab { }), ) - new Setting(containerEl).setName('Groq API Key').addText((text) => + new Setting(containerEl).setName('Groq API key').addText((text) => text .setPlaceholder('Enter your API key') .setValue(this.plugin.settings.groqApiKey) @@ -59,7 +59,7 @@ export class SmartCopilotSettingTab extends PluginSettingTab { }), ) - new Setting(containerEl).setName('Anthropic API Key').addText((text) => + new Setting(containerEl).setName('Anthropic API key').addText((text) => text .setPlaceholder('Enter your API key') .setValue(this.plugin.settings.anthropicApiKey) @@ -72,7 +72,7 @@ export class SmartCopilotSettingTab extends PluginSettingTab { ) new Setting(containerEl) - .setName('Ollama Address') + .setName('Ollama address') .setDesc( 'Set the Ollama URL and port address - normally http://127.0.0.1:11434', ) @@ -87,10 +87,10 @@ export class SmartCopilotSettingTab extends PluginSettingTab { }), ) - new Setting(containerEl).setHeading().setName('Model Settings') + new Setting(containerEl).setHeading().setName('Model') new Setting(containerEl) - .setName('Chat Model') + .setName('Chat model') .setDesc('Choose the model you want to use for chat') .addDropdown((dropdown) => dropdown @@ -110,7 +110,7 @@ export class SmartCopilotSettingTab extends PluginSettingTab { ) new Setting(containerEl) - .setName('Apply Model') + .setName('Apply model') .setDesc('Choose the model you want to use for apply') .addDropdown((dropdown) => dropdown @@ -133,7 +133,7 @@ export class SmartCopilotSettingTab extends PluginSettingTab { ) new Setting(containerEl) - .setName('Embedding Model') + .setName('Embedding model') .setDesc('Choose the model you want to use for embeddings') .addDropdown((dropdown) => dropdown @@ -157,7 +157,7 @@ export class SmartCopilotSettingTab extends PluginSettingTab { new Setting(containerEl) .setHeading() - .setName('System Prompt') + .setName('System prompt') .setDesc('This prompt will be added to the beginning of every chat.') new Setting(containerEl) @@ -173,10 +173,10 @@ export class SmartCopilotSettingTab extends PluginSettingTab { }), ) - new Setting(containerEl).setHeading().setName('RAG Options') + new Setting(containerEl).setHeading().setName('RAG') new Setting(containerEl) - .setName('Chunk Size') + .setName('Chunk size') .setDesc( 'Set the chunk size for text splitting. After changing this, please re-index the vault using the "Rebuild entire vault index" command.', ) @@ -199,7 +199,7 @@ export class SmartCopilotSettingTab extends PluginSettingTab { ) new Setting(containerEl) - .setName('Threshold Tokens') + .setName('Threshold tokens') .setDesc( 'Maximum number of tokens before switching to RAG. If the total tokens from mentioned files exceed this, RAG will be used instead of including all file contents.', ) @@ -222,7 +222,7 @@ export class SmartCopilotSettingTab extends PluginSettingTab { ) new Setting(containerEl) - .setName('Minimum Similarity') + .setName('Minimum similarity') .setDesc( 'Minimum similarity score for RAG results. Higher values return more relevant but potentially fewer results.', ) diff --git a/src/utils/chatHistoryManager.ts b/src/utils/chatHistoryManager.ts index 734c144..62b85e5 100644 --- a/src/utils/chatHistoryManager.ts +++ b/src/utils/chatHistoryManager.ts @@ -17,7 +17,7 @@ export class ChatConversationManager { const newChatConversation: ChatConversation = { schemaVersion: CURRENT_SCHEMA_VERSION, id, - title: 'New Chat', + title: 'New chat', createdAt: Date.now(), updatedAt: Date.now(), messages: [], diff --git a/src/utils/promptGenerator.ts b/src/utils/promptGenerator.ts index d1c0091..ce75072 100644 --- a/src/utils/promptGenerator.ts +++ b/src/utils/promptGenerator.ts @@ -1,5 +1,4 @@ -import { App, TFile, requestUrl } from 'obsidian' -import TurndownService from 'turndown' +import { App, TFile, htmlToMarkdown, requestUrl } from 'obsidian' import { editorStateToPlainText } from '../components/chat-view/chat-input/utils/editor-state-to-plain-text' import { QueryProgressState } from '../components/chat-view/QueryProgress' @@ -390,24 +389,6 @@ ${transcript.map((t) => `${t.offset}: ${t.text}`).join('\n')}` const response = await requestUrl({ url }) - const turndown = new TurndownService() - - turndown.addRule('ignoreEmptyLinks', { - filter: (node) => { - return ( - node.nodeName === 'A' && - node.textContent?.trim() === '' && - !node.querySelector('img') - ) - }, - replacement: () => '', - }) - - turndown.remove('script') - turndown.remove('style') - - const markdown: string = turndown.turndown(response.text) - - return markdown + return htmlToMarkdown(response.text) } }