Spaces:
Sleeping
Sleeping
<script lang="ts"> | |
import { toast } from 'svelte-sonner'; | |
import { onMount, tick, getContext } from 'svelte'; | |
import { openDB, deleteDB } from 'idb'; | |
import fileSaver from 'file-saver'; | |
const { saveAs } = fileSaver; | |
import { goto } from '$app/navigation'; | |
import { getModels as _getModels } from '$lib/apis'; | |
import { getAllChatTags } from '$lib/apis/chats'; | |
import { getPrompts } from '$lib/apis/prompts'; | |
import { getDocs } from '$lib/apis/documents'; | |
import { getTools } from '$lib/apis/tools'; | |
import { getBanners } from '$lib/apis/configs'; | |
import { getUserSettings } from '$lib/apis/users'; | |
import { | |
user, | |
showSettings, | |
settings, | |
models, | |
prompts, | |
documents, | |
tags, | |
banners, | |
showChangelog, | |
config, | |
showCallOverlay, | |
tools | |
} from '$lib/stores'; | |
import SettingsModal from '$lib/components/chat/SettingsModal.svelte'; | |
import Sidebar from '$lib/components/layout/Sidebar.svelte'; | |
import ChangelogModal from '$lib/components/ChangelogModal.svelte'; | |
import AccountPending from '$lib/components/layout/Overlay/AccountPending.svelte'; | |
const i18n = getContext('i18n'); | |
let loaded = false; | |
let DB = null; | |
let localDBChats = []; | |
const getModels = async () => { | |
return _getModels(localStorage.token); | |
}; | |
onMount(async () => { | |
if ($user === undefined) { | |
await goto('/auth'); | |
} else if (['user', 'admin'].includes($user.role)) { | |
try { | |
// Check if IndexedDB exists | |
DB = await openDB('Chats', 1); | |
if (DB) { | |
const chats = await DB.getAllFromIndex('chats', 'timestamp'); | |
localDBChats = chats.map((item, idx) => chats[chats.length - 1 - idx]); | |
if (localDBChats.length === 0) { | |
await deleteDB('Chats'); | |
} | |
} | |
console.log(DB); | |
} catch (error) { | |
// IndexedDB Not Found | |
} | |
const userSettings = await getUserSettings(localStorage.token).catch((error) => { | |
console.error(error); | |
return null; | |
}); | |
if (userSettings) { | |
await settings.set(userSettings.ui); | |
} else { | |
await settings.set(JSON.parse(localStorage.getItem('settings') ?? '{}')); | |
} | |
await Promise.all([ | |
(async () => { | |
models.set(await getModels()); | |
})(), | |
(async () => { | |
prompts.set(await getPrompts(localStorage.token)); | |
})(), | |
(async () => { | |
documents.set(await getDocs(localStorage.token)); | |
})(), | |
(async () => { | |
tools.set(await getTools(localStorage.token)); | |
})(), | |
(async () => { | |
banners.set(await getBanners(localStorage.token)); | |
})(), | |
(async () => { | |
tags.set(await getAllChatTags(localStorage.token)); | |
})() | |
]); | |
document.addEventListener('keydown', function (event) { | |
const isCtrlPressed = event.ctrlKey || event.metaKey; // metaKey is for Cmd key on Mac | |
// Check if the Shift key is pressed | |
const isShiftPressed = event.shiftKey; | |
// Check if Ctrl + Shift + O is pressed | |
if (isCtrlPressed && isShiftPressed && event.key.toLowerCase() === 'o') { | |
event.preventDefault(); | |
console.log('newChat'); | |
document.getElementById('sidebar-new-chat-button')?.click(); | |
} | |
// Check if Shift + Esc is pressed | |
if (isShiftPressed && event.key === 'Escape') { | |
event.preventDefault(); | |
console.log('focusInput'); | |
document.getElementById('chat-textarea')?.focus(); | |
} | |
// Check if Ctrl + Shift + ; is pressed | |
if (isCtrlPressed && isShiftPressed && event.key === ';') { | |
event.preventDefault(); | |
console.log('copyLastCodeBlock'); | |
const button = [...document.getElementsByClassName('copy-code-button')]?.at(-1); | |
button?.click(); | |
} | |
// Check if Ctrl + Shift + C is pressed | |
if (isCtrlPressed && isShiftPressed && event.key.toLowerCase() === 'c') { | |
event.preventDefault(); | |
console.log('copyLastResponse'); | |
const button = [...document.getElementsByClassName('copy-response-button')]?.at(-1); | |
console.log(button); | |
button?.click(); | |
} | |
// Check if Ctrl + Shift + S is pressed | |
if (isCtrlPressed && isShiftPressed && event.key.toLowerCase() === 's') { | |
event.preventDefault(); | |
console.log('toggleSidebar'); | |
document.getElementById('sidebar-toggle-button')?.click(); | |
} | |
// Check if Ctrl + Shift + Backspace is pressed | |
if (isCtrlPressed && isShiftPressed && event.key === 'Backspace') { | |
event.preventDefault(); | |
console.log('deleteChat'); | |
document.getElementById('delete-chat-button')?.click(); | |
} | |
// Check if Ctrl + . is pressed | |
if (isCtrlPressed && event.key === '.') { | |
event.preventDefault(); | |
console.log('openSettings'); | |
showSettings.set(!$showSettings); | |
} | |
// Check if Ctrl + / is pressed | |
if (isCtrlPressed && event.key === '/') { | |
event.preventDefault(); | |
console.log('showShortcuts'); | |
document.getElementById('show-shortcuts-button')?.click(); | |
} | |
}); | |
if ($user.role === 'admin') { | |
showChangelog.set(localStorage.version !== $config.version); | |
} | |
await tick(); | |
} | |
loaded = true; | |
}); | |
</script> | |
<SettingsModal bind:show={$showSettings} /> | |
<ChangelogModal bind:show={$showChangelog} /> | |
<div class="app relative"> | |
<div | |
class=" text-gray-700 dark:text-gray-100 bg-white dark:bg-gray-900 h-screen max-h-[100dvh] overflow-auto flex flex-row" | |
> | |
{#if loaded} | |
{#if !['user', 'admin'].includes($user.role)} | |
<AccountPending /> | |
{:else if localDBChats.length > 0} | |
<div class="fixed w-full h-full flex z-50"> | |
<div | |
class="absolute w-full h-full backdrop-blur-md bg-white/20 dark:bg-gray-900/50 flex justify-center" | |
> | |
<div class="m-auto pb-44 flex flex-col justify-center"> | |
<div class="max-w-md"> | |
<div class="text-center dark:text-white text-2xl font-medium z-50"> | |
Important Update<br /> Action Required for Chat Log Storage | |
</div> | |
<div class=" mt-4 text-center text-sm dark:text-gray-200 w-full"> | |
{$i18n.t( | |
"Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through" | |
)} | |
<span class="font-semibold dark:text-white" | |
>{$i18n.t('Settings')} > {$i18n.t('Chats')} > {$i18n.t('Import Chats')}</span | |
>. {$i18n.t( | |
'This ensures that your valuable conversations are securely saved to your backend database. Thank you!' | |
)} | |
</div> | |
<div class=" mt-6 mx-auto relative group w-fit"> | |
<button | |
class="relative z-20 flex px-5 py-2 rounded-full bg-white border border-gray-100 dark:border-none hover:bg-gray-100 transition font-medium text-sm" | |
on:click={async () => { | |
let blob = new Blob([JSON.stringify(localDBChats)], { | |
type: 'application/json' | |
}); | |
saveAs(blob, `chat-export-${Date.now()}.json`); | |
const tx = DB.transaction('chats', 'readwrite'); | |
await Promise.all([tx.store.clear(), tx.done]); | |
await deleteDB('Chats'); | |
localDBChats = []; | |
}} | |
> | |
Download & Delete | |
</button> | |
<button | |
class="text-xs text-center w-full mt-2 text-gray-400 underline" | |
on:click={async () => { | |
localDBChats = []; | |
}}>{$i18n.t('Close')}</button | |
> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
{/if} | |
<Sidebar /> | |
<slot /> | |
{/if} | |
</div> | |
</div> | |
<style> | |
.loading { | |
display: inline-block; | |
clip-path: inset(0 1ch 0 0); | |
animation: l 1s steps(3) infinite; | |
letter-spacing: -0.5px; | |
} | |
@keyframes l { | |
to { | |
clip-path: inset(0 -1ch 0 0); | |
} | |
} | |
pre[class*='language-'] { | |
position: relative; | |
overflow: auto; | |
/* make space */ | |
margin: 5px 0; | |
padding: 1.75rem 0 1.75rem 1rem; | |
border-radius: 10px; | |
} | |
pre[class*='language-'] button { | |
position: absolute; | |
top: 5px; | |
right: 5px; | |
font-size: 0.9rem; | |
padding: 0.15rem; | |
background-color: #828282; | |
border: ridge 1px #7b7b7c; | |
border-radius: 5px; | |
text-shadow: #c4c4c4 0 0 2px; | |
} | |
pre[class*='language-'] button:hover { | |
cursor: pointer; | |
background-color: #bcbabb; | |
} | |
</style> | |