mirror of
https://github.com/logancyang/obsidian-copilot.git
synced 2026-07-22 07:50:24 +00:00
Pre release updates (#48)
* Update setting desc for max tokens * Update wording and button order to avoid confusion * Use Mode Selection instead of Chain Selection everywhere * Add item to faq * Make create effect options and fix isVisible flag * Add video demo for custom prompt
This commit is contained in:
parent
011f103ec6
commit
4ed344451b
8 changed files with 88 additions and 31 deletions
28
README.md
28
README.md
|
|
@ -22,20 +22,26 @@ My goal is to make this AI assistant **local-first** and **privacy-focused**. Mo
|
|||
- No usage cap for GPT-4 like ChatGPT Plus.
|
||||
- One-click copying any message as markdown.
|
||||
- One-click saving the entire conversation as a note.
|
||||
- One-click using the active note as context, and start a discussion around it (currently only supports shorter notes)
|
||||
- Easy commands to **simplify, emojify, translate, rewrite into a tweet/thread,** and more.
|
||||
- Use the active note as context, and start a discussion around it by switching to "QA: Active Note" in the Mode Selection menu.
|
||||
- **NEW in v2.1.0**: **Unlimited context** when chatting with your long note, no more "context length exceeded" errors!!
|
||||
- This feature is powered by retrieval augmentation with a **local** vector store. No sending your data to a cloud-based vector search service!
|
||||
- Easy commands to **simplify, emojify, summarize, translate, change tone, fix grammar, rewrite into a tweet/thread, count tokens** and more.
|
||||
- Set your own parameters like LLM temperature, max tokens, conversation context based on your need (**pls be mindful of the API cost**).
|
||||
- **NEW in v2.1.0**: **Unlimited context** when chatting with your long note, no more "context length exceeded" errors!!
|
||||
- **NEW in v2.2.0**: **User custom prompt support added**! Now you can *add, apply, delete* your custom prompts, persisted in your local Obsidian environment!
|
||||
|
||||
## 🎬 Video Demos
|
||||
|
||||
#### 🎉 NEW in v2.2.0: User Custom Prompts!
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=apuV1Jz6ObE" target="_blank"><img src="./images/thumbnail2.png" width="700" /></a>
|
||||
|
||||
#### 🎉 NEW in v2.1.0: Unlimited Context Support for Active Note!
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=2va-Bu7cMKw" target="_blank"><img src="./images/thumbnail1.png" /></a>
|
||||
<a href="https://www.youtube.com/watch?v=2va-Bu7cMKw" target="_blank"><img src="./images/thumbnail1.png" width="700" /></a>
|
||||
|
||||
#### 🤗 How to use Copilot for beginners:
|
||||
#### 🤗 New to Copilot? Quick Guide for Beginners:
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=jRCDAg2sck8" target="_blank"><img src="./images/thumbnail.png" /></a>
|
||||
<a href="https://www.youtube.com/watch?v=jRCDAg2sck8" target="_blank"><img src="./images/thumbnail.png" width="700" /></a>
|
||||
|
||||
- Chat with ChatGPT, copy messages to note, save entire conversation as a note
|
||||
- QA around your past note
|
||||
|
|
@ -73,13 +79,21 @@ Now you can see the chat icon in your leftside ribbon, clicking on it will open
|
|||
## 🔔 Note
|
||||
- The chat history is not saved by default. Please use "**Save as Note**" to save it. The note will have a title `Chat-Year_Month_Day-Hour_Minute_Second`, you can change its name as needed.
|
||||
- "**New Chat**" clears all previous chat history. Again, please use "**Save as Note**" if you would like to save the chat.
|
||||
- "**Use Active Note as Context**" creates a local vector index for the active note so that you can chat with super long note! To start the QA, please switch from "Conversation" to "QA: Active Note" in the Chain Selection dropdown.
|
||||
- "**Use Active Note as Context**" creates a local vector index for the active note so that you can chat with super long note! To start the QA, please switch from "Conversation" to "QA: Active Note" in the Mode Selection dropdown.
|
||||
- You can set a very long context in the setting "**Conversation turns in context**" if needed.
|
||||
|
||||
#### 📣 Again, please always be mindful of the API cost if you use GPT-4 with a long context!
|
||||
|
||||
## 🤔 FAQ (please read before submitting an issue)
|
||||
|
||||
<details>
|
||||
<summary>It's not using my note as context</summary>
|
||||
|
||||
- Please don't forget to switch to "**QA: Active Note**" in the Mode Selection dropdown in order to start the QA. Copilot does not have your note as context in "Conversation" mode.
|
||||
<img src="./images/faq-mode-switch.png" alt="Settings" width="500">
|
||||
- In fact, you don't have to click the button on the right before starting the QA. Switching to QA mode in the dropdown directly is enough for Copilot to read the note as context. The button on the right is only for when you'd like to manually rebuild the index for the active note, like, when you'd like to switch context to another note, or you think the current index is corrupted because you switched the embedding provider, etc.
|
||||
- Reference issue: https://github.com/logancyang/obsidian-copilot/issues/51
|
||||
</details>
|
||||
<details>
|
||||
<summary>Unresponsive QA when using Huggingface as the Embedding Provider</summary>
|
||||
|
||||
|
|
|
|||
BIN
images/faq-mode-switch.png
Normal file
BIN
images/faq-mode-switch.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
BIN
images/thumbnail2.png
Normal file
BIN
images/thumbnail2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
|
|
@ -44,13 +44,26 @@ export class AddPromptModal extends Modal {
|
|||
);
|
||||
const promptField = promptContainer.createEl('textarea');
|
||||
|
||||
promptContainer.createEl(
|
||||
'p',
|
||||
{
|
||||
text: 'Save the prompt to the local prompt library. You can then use it with the Copilot command: *Apply custom prompt to selection*.',
|
||||
cls: 'custom-prompt-description',
|
||||
}
|
||||
);
|
||||
const descFragment = createFragment((frag) => {
|
||||
frag.appendText('Save the prompt to the local prompt library. You can then use it with the Copilot command: ');
|
||||
frag.createEl(
|
||||
'strong',
|
||||
{ text: 'Apply custom prompt to selection.' }
|
||||
);
|
||||
frag.createEl('br');
|
||||
frag.appendText('Check out the ');
|
||||
frag.createEl('a', {
|
||||
href: 'https://github.com/f/awesome-chatgpt-prompts',
|
||||
text: 'awesome chatGPT prompts',
|
||||
}).setAttr('target', '_blank');
|
||||
frag.appendText(' for inspiration.');
|
||||
});
|
||||
|
||||
const descContainer = promptContainer.createEl('p', {
|
||||
cls: 'custom-prompt-description',
|
||||
});
|
||||
|
||||
descContainer.appendChild(descFragment);
|
||||
|
||||
const saveButtonContainer = formContainer.createEl(
|
||||
'div',
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@ import React, {
|
|||
useState,
|
||||
} from 'react';
|
||||
|
||||
interface CreateEffectOptions {
|
||||
custom_temperature?: number;
|
||||
isVisible?: boolean;
|
||||
}
|
||||
|
||||
interface ChatProps {
|
||||
sharedState: SharedState;
|
||||
|
|
@ -143,7 +147,7 @@ const Chat: React.FC<ChatProps> = ({
|
|||
if (vectorStore) {
|
||||
activeNoteOnMessage = {
|
||||
sender: AI_SENDER,
|
||||
message: `I have read [[${noteName}]].\n\n Please switch to "QA: Active Note" to ask questions about it.`,
|
||||
message: `I have read [[${noteName}]].\n\n Please switch to "QA: Active Note" in Mode Selection to ask questions about it.`,
|
||||
isVisible: true,
|
||||
};
|
||||
if (currentChain === RETRIEVAL_QA_CHAIN) {
|
||||
|
|
@ -153,7 +157,7 @@ const Chat: React.FC<ChatProps> = ({
|
|||
await aiState.buildIndex(noteContent, docHash);
|
||||
activeNoteOnMessage = {
|
||||
sender: AI_SENDER,
|
||||
message: `Reading [[${noteName}]]...\n\n Please switch to "QA: Active Note" to ask questions about it.`,
|
||||
message: `Reading [[${noteName}]]...\n\n Please switch to "QA: Active Note" in Mode Selection to ask questions about it.`,
|
||||
isVisible: true,
|
||||
};
|
||||
}
|
||||
|
|
@ -196,17 +200,22 @@ const Chat: React.FC<ChatProps> = ({
|
|||
const createEffect = (
|
||||
eventType: string,
|
||||
promptFn: (selectedText: string, eventSubtype?: string) => string,
|
||||
custom_temperature?: number,
|
||||
options: CreateEffectOptions = {},
|
||||
) => {
|
||||
return () => {
|
||||
const { custom_temperature, isVisible = false } = options;
|
||||
const handleSelection = async (selectedText: string, eventSubtype?: string) => {
|
||||
// Create a user message with the selected text
|
||||
const promptMessage: ChatMessage = {
|
||||
message: promptFn(selectedText, eventSubtype),
|
||||
sender: USER_SENDER,
|
||||
isVisible: false,
|
||||
isVisible: isVisible,
|
||||
};
|
||||
|
||||
if (isVisible) {
|
||||
addMessage(promptMessage);
|
||||
}
|
||||
|
||||
// Have a hardcoded custom temperature for some commands that need more strictness
|
||||
aiState.langChainParams = {
|
||||
...aiState.langChainParams,
|
||||
|
|
@ -240,27 +249,42 @@ const Chat: React.FC<ChatProps> = ({
|
|||
useEffect(createEffect('simplifySelection', simplifyPrompt), []);
|
||||
useEffect(createEffect('emojifySelection', emojifyPrompt), []);
|
||||
useEffect(createEffect('removeUrlsFromSelection', removeUrlsFromSelectionPrompt), []);
|
||||
useEffect(createEffect('rewriteTweetSelection', rewriteTweetSelectionPrompt, 0.2), []);
|
||||
useEffect(createEffect('rewriteTweetThreadSelection', rewriteTweetThreadSelectionPrompt, 0.2), []);
|
||||
useEffect(
|
||||
createEffect(
|
||||
'rewriteTweetSelection', rewriteTweetSelectionPrompt, { custom_temperature: 0.2 },
|
||||
),
|
||||
[]
|
||||
);
|
||||
useEffect(
|
||||
createEffect(
|
||||
'rewriteTweetThreadSelection', rewriteTweetThreadSelectionPrompt, { custom_temperature: 0.2 },
|
||||
),
|
||||
[]
|
||||
);
|
||||
useEffect(createEffect('rewriteShorterSelection', rewriteShorterSelectionPrompt), []);
|
||||
useEffect(createEffect('rewriteLongerSelection', rewriteLongerSelectionPrompt), []);
|
||||
useEffect(createEffect('eli5Selection', eli5SelectionPrompt), []);
|
||||
useEffect(createEffect('rewritePressReleaseSelection', rewritePressReleaseSelectionPrompt), []);
|
||||
useEffect(
|
||||
createEffect("translateSelection", (selectedText, language) =>
|
||||
createEffect('translateSelection', (selectedText, language) =>
|
||||
createTranslateSelectionPrompt(language)(selectedText)
|
||||
),
|
||||
[]
|
||||
);
|
||||
useEffect(
|
||||
createEffect("changeToneSelection", (selectedText, tone) =>
|
||||
createEffect('changeToneSelection', (selectedText, tone) =>
|
||||
createChangeToneSelectionPrompt(tone)(selectedText)
|
||||
),
|
||||
[]
|
||||
);
|
||||
useEffect(
|
||||
createEffect("applyCustomPromptSelection", (selectedText, prompt) =>
|
||||
fillInSelectionForCustomPrompt(prompt)(selectedText)
|
||||
createEffect(
|
||||
'applyCustomPromptSelection',
|
||||
(selectedText, prompt) =>
|
||||
fillInSelectionForCustomPrompt(prompt)(selectedText),
|
||||
// Not showing the custom prompt in the chat UI for now, Leaving it here as an option.
|
||||
// To check the prompt, use Debug mode in the setting.
|
||||
// { isVisible: true },
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -116,10 +116,6 @@ const ChatIcons: React.FC<ChatIconsProps> = ({
|
|||
<SaveAsNoteIcon className='icon-scaler' />
|
||||
<span className="tooltip-text">Save as Note</span>
|
||||
</button>
|
||||
<button className='chat-icon-button' onClick={onUseActiveNoteAsContext}>
|
||||
<UseActiveNoteAsContextIcon className='icon-scaler' />
|
||||
<span className="tooltip-text">Rebuild Index for Active Note</span>
|
||||
</button>
|
||||
<div className="chat-icon-selection-tooltip">
|
||||
<div className="select-wrapper">
|
||||
<select
|
||||
|
|
@ -131,9 +127,13 @@ const ChatIcons: React.FC<ChatIconsProps> = ({
|
|||
<option value='llm_chain'>Conversation</option>
|
||||
<option value='retrieval_qa'>QA: Active Note</option>
|
||||
</select>
|
||||
<span className="tooltip-text">Chain Selection</span>
|
||||
<span className="tooltip-text">Mode Selection</span>
|
||||
</div>
|
||||
</div>
|
||||
<button className='chat-icon-button' onClick={onUseActiveNoteAsContext}>
|
||||
<UseActiveNoteAsContextIcon className='icon-scaler' />
|
||||
<span className="tooltip-text">Rebuild Index for Active Note</span>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ export default class CopilotPlugin extends Plugin {
|
|||
await this.dbPrompts.put({ _id: title, prompt: prompt });
|
||||
new Notice('Custom prompt saved successfully.');
|
||||
} catch (e) {
|
||||
new Notice('Error saving custom prompt.');
|
||||
new Notice('Error saving custom prompt. Please check if the title already exists.');
|
||||
console.error(e);
|
||||
}
|
||||
}).open();
|
||||
|
|
|
|||
|
|
@ -122,6 +122,12 @@ export class CopilotSettingTab extends PluginSettingTab {
|
|||
frag.appendText(
|
||||
"The maximum number of tokens to generate. Default is 1000."
|
||||
);
|
||||
frag.createEl(
|
||||
'strong',
|
||||
{
|
||||
text: 'This number plus the length of your prompt must be smaller than the context window of the model.'
|
||||
}
|
||||
)
|
||||
})
|
||||
)
|
||||
.addSlider(slider =>
|
||||
|
|
@ -164,7 +170,7 @@ export class CopilotSettingTab extends PluginSettingTab {
|
|||
);
|
||||
|
||||
containerEl.createEl('h4', { text: 'Vector-based QA Settings (BETA). No context limit!' });
|
||||
containerEl.createEl('h6', { text: 'To start the QA session, use the Chain Selection dropdown and select "QA: Active Note". Switch back to "Conversation" when you are done!' });
|
||||
containerEl.createEl('h6', { text: 'To start the QA session, use the Mode Selection dropdown and select "QA: Active Note". Switch back to "Conversation" when you are done!' });
|
||||
containerEl.createEl(
|
||||
'h6',
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue