Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.4.0 #49

Merged
merged 27 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b2801b0
feat(settings): warn modal on using third parties
nicobrauchtgit Mar 11, 2024
25447db
fix(OpenAI onboarding): API key input updated immediately
nicobrauchtgit Mar 11, 2024
43464c3
feat(workflows): check for logs
nicobrauchtgit Mar 11, 2024
b414171
Merge branch 'main' into dev
nicobrauchtgit Mar 11, 2024
cebe8c3
Update console-logs.yml
nicobrauchtgit Mar 11, 2024
973a1bf
Merge branch 'main' into dev
nicobrauchtgit Mar 11, 2024
969a678
Update console-logs.yml
nicobrauchtgit Mar 11, 2024
090d810
Merge branch 'main' into dev
nicobrauchtgit Mar 11, 2024
3274be7
Update console-logs.yml
nicobrauchtgit Mar 11, 2024
8fcdda4
Merge branch 'main' into dev
nicobrauchtgit Mar 11, 2024
82594b8
Update console-logs.yml
nicobrauchtgit Mar 11, 2024
ada524a
Create create-check.js
nicobrauchtgit Mar 11, 2024
16c64ad
Merge branch 'main' into dev
nicobrauchtgit Mar 11, 2024
4f55097
refactor(lang): everything into en.json
Leo310 Mar 11, 2024
9f156ee
feat: toggle to autostart
Leo310 Mar 12, 2024
25d867d
fix(autostart): also init papa when autostart set to true
Leo310 Mar 13, 2024
55dc3a7
refactor(quick-settings): added sliders
Leo310 Mar 13, 2024
f9a690f
feat(settings): indicate wrong url or api key
nicobrauchtgit Mar 13, 2024
8af9bdf
feat: install set model
nicobrauchtgit Mar 13, 2024
58713aa
feat: cancel model download
nicobrauchtgit Mar 13, 2024
4881e93
fix(onboarding):choose embed model
nicobrauchtgit Mar 13, 2024
180cdd9
refactor(chat): message spacing
Leo310 Mar 14, 2024
97f20e7
refactor(settings): now disabled functionality
Leo310 Mar 14, 2024
306fc6a
feat: new Logo
Leo310 Mar 14, 2024
9a14470
fix(settings): api key, url error bg
nicobrauchtgit Mar 14, 2024
cd5936b
manifest version up
nicobrauchtgit Mar 14, 2024
b994f83
Merge branch 'main' into dev
nicobrauchtgit Mar 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/logs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Check for console.logs

on:
pull_request:
branches:
- main

jobs:
check-logs:
runs-on: ubuntu-latest
steps:
- name: get the sources
uses: actions/checkout@v2

- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '20'

- name: Install dependencies
run: npm ci

- name: Run check script
run: node .github/workflows/create-check.js
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Interact with your privacy focused assistant, leveraging Ollama or OpenAI, making your second brain even smarter.",
"author": "Leo310, nicobrauchtgit",
"authorUrl": "https://github.com/nicobrauchtgit",
"version": "0.3.2",
"version": "0.4.2",
"minAppVersion": "1.5.0",
"isDesktopOnly": true
}
35 changes: 21 additions & 14 deletions src/SmartSecondBrain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { isOllamaRunning, getOllamaModels } from './controller/Ollama';
import { isAPIKeyValid } from './controller/OpenAI';
import Log, { LogLvl } from './logging';
import { data, papaState, errorState, papaIndexingProgress, chatHistory, serializeChatHistory, runState, runContent } from './store';
import { _ } from 'svelte-i18n';

export default class SmartSecondBrain {
private papa: Papa;
Expand All @@ -20,23 +21,29 @@ export default class SmartSecondBrain {

async init() {
const d = get(data);
if (get(papaState) === 'running') return new Notice('Smart Second Brain is still running.', 4000);
const t = get(_);
if (get(papaState) === 'running') return new Notice(t('notice.still_running'), 4000);
else if (get(papaState) === 'indexing' || get(papaState) === 'loading') {
return new Notice('Please wait for the indexing to finish', 4000);
return new Notice(t('notice.still_indexing'), 4000);
} else if (d.isIncognitoMode && !(await isOllamaRunning())) {
papaState.set('error');
errorState.set('ollama-not-running');
return new Notice('Please make sure Ollama is running before initializing Smart Second Brain.', 4000);
return new Notice(t('notice.ollama_not_running'), 4000);
} else if (d.isIncognitoMode) {
const models = await getOllamaModels();
if (!models.includes(d.ollamaGenModel.model)) {
papaState.set('error');
errorState.set('ollama-model-not-installed');
return new Notice('Ollama model not installed. Please install the model before initializing Smart Second Brain.', 4000);
errorState.set('ollama-gen-model-not-installed');
return new Notice(t('notice.ollama_gen_model'), 4000);
}
if (!models.includes(d.ollamaEmbedModel.model)) {
papaState.set('error');
errorState.set('ollama-embed-model-not-installed');
return new Notice(t('notice.ollama_embed_model'), 4000);
}
} else if (!d.isIncognitoMode && !(await isAPIKeyValid(d.openAIGenModel.openAIApiKey))) {
papaState.set('error');
return new Notice('Please make sure OpenAI API Key is valid before initializing Smart Second Brain.', 4000);
return new Notice(t('notice.openai_key'), 4000);
}
if (get(papaState) !== 'indexing-pause') {
papaState.set('loading');
Expand All @@ -58,7 +65,7 @@ export default class SmartSecondBrain {
} catch (e) {
Log.error(e);
papaState.set('error');
return new Notice('Failed to initialize Smart Second Brain (Error: ' + e + '). Please retry.', 4000);
return new Notice(t('notice.failed', { values: { error: e } }), 4000);
}
// check if vector store data exists
if (await this.app.vault.adapter.exists(this.getVectorStorePath())) {
Expand All @@ -75,7 +82,6 @@ export default class SmartSecondBrain {
})
);
papaState.set('indexing');
// const embedNotice = new Notice('Indexing notes into your smart second brain...', 0);
let needsSave = false;
try {
for await (const result of this.papa.embedDocuments(docs)) {
Expand All @@ -93,23 +99,24 @@ export default class SmartSecondBrain {
Log.error(e);
papaState.set('error');
// TODO add error state
new Notice('Failed to index notes into your smart second brain. Please retry.', 4000);
new Notice(t('notice.failed_indexing'), 4000);
}
this.needsToSaveVectorStoreData = needsSave;
this.saveVectorStoreData();
if (get(papaIndexingProgress) === 100) {
new Notice('Smart Second Brain initialized.', 2000);
new Notice(t('notice.done'), 2000);
papaIndexingProgress.set(0);
papaState.set('idle');
}
}

canRunPapa() {
if (get(papaState) === 'running') return new Notice('Please wait for the current query to finish', 4000) && false;
const t = get(_);
if (get(papaState) === 'running') return new Notice(t('notice.still_running'), 4000) && false;
else if (get(papaState) === 'indexing' || get(papaState) === 'indexing-pause' || get(papaState) === 'loading')
return new Notice('Please wait for the indexing to finish', 4000) && false;
else if (get(papaState) === 'error') return new Notice('Please wait for the error to resolve', 4000) && false;
else if (get(papaState) !== 'idle') return new Notice('Please initialize your Smart Second Brain first', 4000) && false;
return new Notice(t('notice.still_indexing'), 4000) && false;
else if (get(papaState) === 'error') return new Notice(t('notice.error'), 4000) && false;
else if (get(papaState) !== 'idle') return new Notice(t('notice.not_initialized'), 4000) && false;
return true;
}

Expand Down
29 changes: 12 additions & 17 deletions src/components/Chat/Chat.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { afterUpdate } from 'svelte';
import DotAnimation from '../base/DotAnimation.svelte';
import MessageContainer from './MessageContainer.svelte';
import { t } from 'svelte-i18n';
import {
papaState,
chatHistory,
Expand Down Expand Up @@ -45,7 +46,7 @@
});

$: if ($runState === 'retrieving' && $runContent == '0') {
new Notice('No notes retrieved. Maybe lower the similarity threshold.');
new Notice($t('notice.no_notes_retrieved'));
}

let editElem: HTMLSpanElement;
Expand Down Expand Up @@ -90,11 +91,11 @@
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="flex {$data.isChatComfy ? 'justify-end' : ''} gap-1 opacity-0 group-hover:opacity-100">
{#if $isEditing && editMessageId === message.id}
<span aria-label="Copy Text" class={iconStyle} on:click|preventDefault={cancelEditing} use:icon={'x-circle'} />
<span aria-label={$t('chat.copy')} class={iconStyle} on:click|preventDefault={cancelEditing} use:icon={'x-circle'} />
{:else}
<!-- svelte-ignore a11y-no-static-element-interactions -->
<span
aria-label="Edit query and regenerate the answer"
aria-label={$t('chat.edit')}
class={iconStyle}
on:click|preventDefault={() => wrapperEditMessage(message, textarea)}
use:icon={'pencil-line'}
Expand All @@ -105,23 +106,17 @@
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<span
on:mouseover={onMouseOver}
use:renderMarkdown={message.content}
style="background: transparent;"
on:click={onClick}
bind:this={initialAssistantMessageSpan}
/>
<span on:mouseover={onMouseOver} use:renderMarkdown={message.content} on:click={onClick} bind:this={initialAssistantMessageSpan} />
<div class="flex gap-1 opacity-0 group-hover:opacity-100">
{#if !$isEditingAssistantMessage}
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span aria-label="Copy Text" class={iconStyle} on:click={() => toClipboard(message.content)} use:icon={'copy'} />
<span aria-label={$t('chat.copy')} class={iconStyle} on:click={() => toClipboard(message.content)} use:icon={'copy'} />
{#if $chatHistory.indexOf(message) !== 0}
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span
aria-label="Deletes all following Messages and regenerates the answer to the current query"
aria-label={$t('chat.regenerate')}
class={iconStyle}
on:click|preventDefault={() => redoGeneration(message)}
use:icon={'refresh-cw'}
Expand All @@ -131,7 +126,7 @@
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span
aria-label="Change the initial assistant message"
aria-label={$t('chat.change_assistant_prompt')}
class={iconStyle}
on:click|preventDefault={() => editInitialAssistantMessage(message.content, textarea)}
use:icon={'pencil-line'}
Expand All @@ -141,15 +136,15 @@
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<span
aria-label="Cancel editing"
aria-label={$t('chat.cancel_edit')}
class={iconStyle}
on:click|preventDefault={() => cancelEditingInitialAssistantMessage(initialAssistantMessageSpan)}
use:icon={'x-circle'}
/>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<span
aria-label="Reset to default"
aria-label={$t('chat.reset_assistant_prompt')}
class={iconStyle}
on:click={() => resetInitialAssistantMessage(initialAssistantMessageSpan)}
use:icon={'rotate-ccw'}
Expand All @@ -164,9 +159,9 @@
{#if $runState === 'startup'}
<DotAnimation />
{:else if $runState === 'retrieving'}
<p>Retrieving<DotAnimation /></p>
<p>{$t('chat.retrieving')}<DotAnimation /></p>
{:else if $runState === 'reducing'}
<p>Reducing {$runContent} Notes<DotAnimation /></p>
<p>{$t('chat.reducing', { values: { num: $runContent } })}<DotAnimation /></p>
{:else if $runState === 'generating' && $runContent}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
Expand Down
46 changes: 18 additions & 28 deletions src/components/Chat/Input.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<script lang="ts">
import { Notice, setIcon } from 'obsidian';
import type { KeyboardEventHandler } from 'svelte/elements';
import { nanoid } from 'nanoid';
import { t } from 'svelte-i18n';
import {
plugin,
data,
Expand All @@ -17,6 +16,7 @@
} from '../../store';
import ProgressCircle from '../base/ProgressCircle.svelte';
import { addMessage } from '../../controller/Messages';
import Logo from '../base/Logo.svelte';

export let textarea: HTMLTextAreaElement;

Expand Down Expand Up @@ -48,14 +48,9 @@
addMessage('Assistant', $runContent);
}
}
function injectContext(event: KeyboardEvent): KeyboardEventHandler<HTMLInputElement> {
if (event.key !== '[') return;
new Notice('Injecting context...');
}
function handleRAGToggle() {
$data.isUsingRag = !$data.isUsingRag;
$plugin.saveSettings();
new Notice($data.isUsingRag ? 'Now chatting with your Second Brain' : 'Now chatting with the LLM');
}

function handelEnter(event: KeyboardEvent) {
Expand All @@ -74,42 +69,38 @@
if (textarea.scrollHeight == 42) textarea.style.height = '2rem';
else textarea.style.height = textarea.scrollHeight + 'px';
}
const iconStyle = 'text-[--text-normal] hover:text-[--text-accent-hover]';
</script>

<!-- save delete and rag settings slightly above input field -->
<div class="relative">
<div
class="absolute -top-[54px] left-1/2 flex -translate-x-1/2 items-center gap-3 rounded-t-2xl border border-solid border-x-[--background-modifier-border] border-b-transparent border-t-[--background-modifier-border] {$isChatInSidebar
class="absolute -top-[62px] left-1/2 flex -translate-x-1/2 items-center gap-3 rounded-t-2xl border border-solid border-x-[--background-modifier-border] border-b-transparent border-t-[--background-modifier-border] {$isChatInSidebar
? 'bg-[--background-secondary]'
: 'bg-[--background-primary]'} p-2"
: 'bg-[--background-primary]'} pt-2 px-2"
>
{#if $chatHistory.length > 1}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
aria-label="Save the Chat to a file"
class="text-[--text-normal] hover:text-[--text-accent-hover]"
use:icon={'save'}
on:click={() => $plugin.saveChat()}
hidden={$papaState === 'running'}
/>
<div aria-label={$t('chat.save')} class={iconStyle} use:icon={'save'} on:click={() => $plugin.saveChat()} hidden={$papaState === 'running'} />
{/if}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
aria-label="Toggle between chatting with your Notes or the LLM"
aria-label={$data.isUsingRag ? $t('chat.toggle_llm') : $t('chat.toggle_papa')}
on:click={handleRAGToggle}
use:icon={'brain-circuit'}
class={`h-[--icon-xl] w-[--icon-xl] *:!h-[--icon-xl] *:!w-[--icon-xl] hover:text-[--text-accent-hover] ${
class={`h-[48px] w-[48px] *:!h-[48px] *:!w-[48px] hover:text-[--text-accent-hover] ${
$data.isUsingRag ? 'text-[--color-accent]' : 'text-[--text-normal]'
}`}
/>
>
<Logo />
</div>
{#if $chatHistory.length > 1}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
aria-label="Delete Chat History"
class="text-[--text-normal] hover:text-[--text-accent-hover]"
aria-label={$t('chat.delete')}
class={iconStyle}
on:click|preventDefault={chatHistory.reset}
use:icon={'trash-2'}
hidden={$papaState === 'running'}
Expand All @@ -122,35 +113,34 @@
bind:this={textarea}
id="chat-view-user-input-element"
class="h-8 max-h-40 flex-1 resize-none"
placeholder={'Chat with your second Brain...'}
placeholder={$t('chat.input_placeholder')}
bind:value={$chatInput}
on:keydown={handelEnter}
on:keyup={injectContext}
/>
{#if $papaState === 'running'}
<button
aria-label="Stop your Smart Second Brain"
aria-label={$t('chat.stop')}
on:click={() => ($runState = 'stopped')}
class="h-8 rounded-r-md px-4 py-2 transition duration-300 ease-in-out hover:bg-[--text-accent-hover]"
use:icon={'stop-circle'}
/>
{:else if $papaState === 'idle'}
<button
aria-label="Run your Smart Second Brain"
aria-label={$t('chat.send')}
on:click={runPapaFromInput}
class="h-8 rounded-r-md px-4 py-2 transition duration-300 ease-in-out hover:bg-[--text-accent-hover]"
use:icon={'send-horizontal'}
/>
{:else if $papaState === 'error'}
<button
aria-label="Retry initializing"
aria-label={$t('chat.retry_error')}
on:click={() => $plugin.s2b.init()}
class="h-8 rounded-l-md px-4 py-2 transition duration-300 ease-in-out hover:bg-[--text-accent-hover]"
use:icon={'refresh-cw'}
/>
{:else if $papaState === 'settings-change'}
<button
aria-label="Reinitialize, Settings changed"
aria-label={$t('chat.reintialize')}
on:click={() => $plugin.s2b.init()}
class="h-8 rounded-l-md px-4 py-2 transition duration-300 ease-in-out hover:bg-[--text-accent-hover]"
use:icon={'refresh-cw'}
Expand Down
10 changes: 6 additions & 4 deletions src/components/Chat/MessageContainer.svelte
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
<script lang="ts">
import { data, isChatInSidebar } from '../../store';
import { t } from 'svelte-i18n';

export let role: 'User' | 'Assistant';
</script>

{#if role === 'User'}
{#if $data.isChatComfy}
<div class="my-4 mr-4 flex justify-end">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="group max-w-[80%] rounded-t-lg rounded-bl-lg px-4" style="background-color: var(--text-selection);">
<div class="group max-w-[80%] [&_p]:mb-2 rounded-t-lg rounded-bl-lg pb-1 px-4" style="background-color: var(--text-selection);">
<slot />
</div>
</div>
{:else}
<div class="group border-x-0 border-b border-t-0 border-solid border-[--background-modifier-border] p-2 pr-4">
<div class="text-[--text-accent] mt-2 font-bold">User</div>
<div class="text-[--text-accent] mt-2 font-bold">{$t('chat.user')}</div>
<slot />
</div>
{/if}
{:else if $data.isChatComfy}
<div
class="group my-4 ml-4 w-fit max-w-[80%] rounded-t-lg rounded-br-lg p-1 pl-4 pr-4 {$isChatInSidebar
class="group ml-4 w-fit max-w-[80%] [&_p]:mb-2 rounded-t-lg rounded-br-lg pb-1 px-4 mt-4 pt-[1px] {$isChatInSidebar
? 'bg-[--background-secondary]'
: 'bg-[--background-primary]'}"
>
Expand All @@ -31,7 +33,7 @@
? 'bg-[--background-secondary]'
: 'bg-[--background-primary]'}"
>
<div class="text-[--text-accent] mt-2 font-bold">Smart2Brain</div>
<div class="text-[--text-accent] mt-2 font-bold">{$t('chat.assistant')}</div>
<slot />
</div>
{/if}
Loading
Loading