Fix dev upstream merge conflicts

This commit is contained in:
Taylor Wilsdon
2024-12-18 12:04:55 -05:00
389 changed files with 127394 additions and 24628 deletions

View File

@@ -1,19 +1,24 @@
<script>
import { createEventDispatcher } from 'svelte';
import { createEventDispatcher, onMount } from 'svelte';
import { toast } from 'svelte-sonner';
const dispatch = createEventDispatcher();
import { knowledge, prompts } from '$lib/stores';
import { removeLastWordFromString } from '$lib/utils';
import { getPrompts } from '$lib/apis/prompts';
import { getKnowledgeBases } from '$lib/apis/knowledge';
import Prompts from './Commands/Prompts.svelte';
import Knowledge from './Commands/Knowledge.svelte';
import Models from './Commands/Models.svelte';
import { removeLastWordFromString } from '$lib/utils';
import { processWeb, processYoutubeVideo } from '$lib/apis/retrieval';
import Spinner from '$lib/components/common/Spinner.svelte';
export let prompt = '';
export let files = [];
let loading = false;
let commandElement = null;
export const selectUp = () => {
@@ -26,55 +31,90 @@
let command = '';
$: command = prompt?.split('\n').pop()?.split(' ')?.pop() ?? '';
let show = false;
$: show = ['/', '#', '@'].includes(command?.charAt(0)) || '\\#' === command.slice(0, 2);
$: if (show) {
init();
}
const init = async () => {
loading = true;
await Promise.all([
(async () => {
prompts.set(await getPrompts(localStorage.token));
})(),
(async () => {
knowledge.set(await getKnowledgeBases(localStorage.token));
})()
]);
loading = false;
};
</script>
{#if ['/', '#', '@'].includes(command?.charAt(0)) || '\\#' === command.slice(0, 2)}
{#if command?.charAt(0) === '/'}
<Prompts bind:this={commandElement} bind:prompt bind:files {command} />
{:else if (command?.charAt(0) === '#' && command.startsWith('#') && !command.includes('# ')) || ('\\#' === command.slice(0, 2) && command.startsWith('#') && !command.includes('# '))}
<Knowledge
bind:this={commandElement}
bind:prompt
command={command.includes('\\#') ? command.slice(2) : command}
on:youtube={(e) => {
console.log(e);
dispatch('upload', {
type: 'youtube',
data: e.detail
});
}}
on:url={(e) => {
console.log(e);
dispatch('upload', {
type: 'web',
data: e.detail
});
}}
on:select={(e) => {
console.log(e);
files = [
...files,
{
...e.detail,
status: 'processed'
}
];
{#if show}
{#if !loading}
{#if command?.charAt(0) === '/'}
<Prompts bind:this={commandElement} bind:prompt bind:files {command} />
{:else if (command?.charAt(0) === '#' && command.startsWith('#') && !command.includes('# ')) || ('\\#' === command.slice(0, 2) && command.startsWith('#') && !command.includes('# '))}
<Knowledge
bind:this={commandElement}
bind:prompt
command={command.includes('\\#') ? command.slice(2) : command}
on:youtube={(e) => {
console.log(e);
dispatch('upload', {
type: 'youtube',
data: e.detail
});
}}
on:url={(e) => {
console.log(e);
dispatch('upload', {
type: 'web',
data: e.detail
});
}}
on:select={(e) => {
console.log(e);
files = [
...files,
{
...e.detail,
status: 'processed'
}
];
dispatch('select');
}}
/>
{:else if command?.charAt(0) === '@'}
<Models
bind:this={commandElement}
{command}
on:select={(e) => {
prompt = removeLastWordFromString(prompt, command);
dispatch('select');
}}
/>
{:else if command?.charAt(0) === '@'}
<Models
bind:this={commandElement}
{command}
on:select={(e) => {
prompt = removeLastWordFromString(prompt, command);
dispatch('select', {
type: 'model',
data: e.detail
});
}}
/>
dispatch('select', {
type: 'model',
data: e.detail
});
}}
/>
{/if}
{:else}
<div
id="commands-container"
class="px-2 mb-2 text-left w-full absolute bottom-0 left-0 right-0 z-10"
>
<div class="flex w-full rounded-xl border border-gray-50 dark:border-gray-850">
<div
class="max-h-60 flex flex-col w-full rounded-xl bg-white dark:bg-gray-900 dark:text-gray-100"
>
<Spinner />
</div>
</div>
</div>
{/if}
{/if}

View File

@@ -159,7 +159,7 @@
{#if filteredItems.length > 0 || prompt.split(' ')?.at(0)?.substring(1).startsWith('http')}
<div
id="commands-container"
class="pl-3 pr-14 mb-3 text-left w-full absolute bottom-0 left-0 right-0 z-10"
class="px-2 mb-2 text-left w-full absolute bottom-0 left-0 right-0 z-10"
>
<div class="flex w-full rounded-xl border border-gray-50 dark:border-gray-850">
<div

View File

@@ -68,7 +68,7 @@
{#if filteredItems.length > 0}
<div
id="commands-container"
class="pl-3 pr-14 mb-3 text-left w-full absolute bottom-0 left-0 right-0 z-10"
class="px-2 mb-2 text-left w-full absolute bottom-0 left-0 right-0 z-10"
>
<div class="flex w-full rounded-xl border border-gray-50 dark:border-gray-850">
<div

View File

@@ -137,7 +137,7 @@
{#if filteredPrompts.length > 0}
<div
id="commands-container"
class="pl-3 pr-14 mb-3 text-left w-full absolute bottom-0 left-0 right-0 z-10"
class="px-2 mb-2 text-left w-full absolute bottom-0 left-0 right-0 z-10"
>
<div class="flex w-full rounded-xl border border-gray-50 dark:border-gray-850">
<div

View File

@@ -1,39 +1,52 @@
<script lang="ts">
import { DropdownMenu } from 'bits-ui';
import { flyAndScale } from '$lib/utils/transitions';
import { getContext } from 'svelte';
import { getContext, onMount, tick } from 'svelte';
import { config, user, tools as _tools, mobile } from '$lib/stores';
import { createPicker } from '$lib/utils/google-drive-picker';
import { getTools } from '$lib/apis/tools';
import Dropdown from '$lib/components/common/Dropdown.svelte';
import Tooltip from '$lib/components/common/Tooltip.svelte';
import DocumentArrowUpSolid from '$lib/components/icons/DocumentArrowUpSolid.svelte';
import Switch from '$lib/components/common/Switch.svelte';
import GlobeAltSolid from '$lib/components/icons/GlobeAltSolid.svelte';
import { config } from '$lib/stores';
import WrenchSolid from '$lib/components/icons/WrenchSolid.svelte';
import CameraSolid from '$lib/components/icons/CameraSolid.svelte';
const i18n = getContext('i18n');
export let screenCaptureHandler: Function;
export let uploadFilesHandler: Function;
export let uploadGoogleDriveHandler: Function;
export let selectedToolIds: string[] = [];
export let webSearchEnabled: boolean;
export let tools = {};
export let webSearchEnabled: boolean;
export let onClose: Function;
$: tools = Object.fromEntries(
Object.keys(tools).map((toolId) => [
toolId,
{
...tools[toolId],
enabled: selectedToolIds.includes(toolId)
}
])
);
let tools = {};
let show = false;
$: if (show) {
init();
}
const init = async () => {
if ($_tools === null) {
await _tools.set(await getTools(localStorage.token));
}
tools = $_tools.reduce((a, tool, i, arr) => {
a[tool.id] = {
name: tool.name,
description: tool.meta.description,
enabled: selectedToolIds.includes(tool.id)
};
return a;
}, {});
};
</script>
<Dropdown
@@ -60,49 +73,75 @@
{#if Object.keys(tools).length > 0}
<div class=" max-h-28 overflow-y-auto scrollbar-hidden">
{#each Object.keys(tools) as toolId}
<div
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer rounded-xl"
<button
class="flex w-full justify-between gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer rounded-xl"
on:click={() => {
tools[toolId].enabled = !tools[toolId].enabled;
}}
>
<div class="flex-1">
<div class="flex-1 truncate">
<Tooltip
content={tools[toolId]?.description ?? ''}
placement="top-start"
className="flex flex-1 gap-2 items-center"
className="flex flex-1 gap-2 items-center"
>
<WrenchSolid />
<div class="flex-shrink-0">
<WrenchSolid />
</div>
<div class=" line-clamp-1">{tools[toolId].name}</div>
<div class=" truncate">{tools[toolId].name}</div>
</Tooltip>
</div>
<Switch
bind:state={tools[toolId].enabled}
on:change={(e) => {
selectedToolIds = e.detail
? [...selectedToolIds, toolId]
: selectedToolIds.filter((id) => id !== toolId);
}}
/>
</div>
<div class=" flex-shrink-0">
<Switch
state={tools[toolId].enabled}
on:change={async (e) => {
const state = e.detail;
await tick();
if (state) {
selectedToolIds = [...selectedToolIds, toolId];
} else {
selectedToolIds = selectedToolIds.filter((id) => id !== toolId);
}
}}
/>
</div>
</button>
{/each}
</div>
<hr class="border-gray-100 dark:border-gray-800 my-1" />
<hr class="border-black/5 dark:border-white/5 my-1" />
{/if}
{#if $config?.features?.enable_web_search}
<div
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer rounded-xl"
<button
class="flex w-full justify-between gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer rounded-xl"
on:click={() => {
webSearchEnabled = !webSearchEnabled;
}}
>
<div class="flex-1 flex items-center gap-2">
<GlobeAltSolid />
<div class=" line-clamp-1">{$i18n.t('Web Search')}</div>
</div>
<Switch bind:state={webSearchEnabled} />
</div>
<Switch state={webSearchEnabled} />
</button>
<hr class="border-gray-100 dark:border-gray-800 my-1" />
<hr class="border-black/5 dark:border-white/5 my-1" />
{/if}
{#if !$mobile}
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl"
on:click={() => {
screenCaptureHandler();
}}
>
<CameraSolid />
<div class=" line-clamp-1">{$i18n.t('Capture')}</div>
</DropdownMenu.Item>
{/if}
<DropdownMenu.Item

View File

@@ -171,7 +171,7 @@
mediaRecorder.ondataavailable = (event) => audioChunks.push(event.data);
mediaRecorder.onstop = async () => {
console.log('Recording stopped');
if (($settings?.audio?.stt?.engine ?? '') === 'web') {
if ($config.audio.stt.engine === 'web' || ($settings?.audio?.stt?.engine ?? '') === 'web') {
audioChunks = [];
} else {
if (confirmed) {
@@ -229,8 +229,7 @@
console.log('recognition ended');
confirmRecording();
dispatch('confirm', transcription);
dispatch('confirm', { text: transcription });
confirmed = false;
loading = false;
};
@@ -251,6 +250,11 @@
if (recording && mediaRecorder) {
await mediaRecorder.stop();
}
if (speechRecognition) {
speechRecognition.stop();
}
stopDurationCounter();
audioChunks = [];
@@ -325,8 +329,8 @@
rounded-full"
on:click={async () => {
dispatch('cancel');
stopRecording();
dispatch('cancel');
}}
>
<svg