|
@@ -34,6 +34,8 @@
|
|
|
updateOpenAIUrl
|
|
|
} from '$lib/apis/openai';
|
|
|
import { resetVectorDB } from '$lib/apis/rag';
|
|
|
+ import { setDefaultPromptSuggestions } from '$lib/apis/configs';
|
|
|
+ import { getBackendConfig } from '$lib/apis';
|
|
|
|
|
|
export let show = false;
|
|
|
|
|
@@ -99,6 +101,9 @@
|
|
|
let OPENAI_API_KEY = '';
|
|
|
let OPENAI_API_BASE_URL = '';
|
|
|
|
|
|
+ // Interface
|
|
|
+ let promptSuggestions = [];
|
|
|
+
|
|
|
// Addons
|
|
|
let titleAutoGenerate = true;
|
|
|
let speechAutoSend = false;
|
|
@@ -191,6 +196,11 @@
|
|
|
await models.set(await getModels());
|
|
|
};
|
|
|
|
|
|
+ const updateInterfaceHandler = async () => {
|
|
|
+ promptSuggestions = await setDefaultPromptSuggestions(localStorage.token, promptSuggestions);
|
|
|
+ await config.set(await getBackendConfig());
|
|
|
+ };
|
|
|
+
|
|
|
const toggleTheme = async () => {
|
|
|
if (theme === 'dark') {
|
|
|
theme = 'light';
|
|
@@ -577,6 +587,7 @@
|
|
|
API_BASE_URL = await getOllamaAPIUrl(localStorage.token);
|
|
|
OPENAI_API_BASE_URL = await getOpenAIUrl(localStorage.token);
|
|
|
OPENAI_API_KEY = await getOpenAIKey(localStorage.token);
|
|
|
+ promptSuggestions = $config?.default_prompt_suggestions;
|
|
|
}
|
|
|
|
|
|
let settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
|
|
@@ -745,6 +756,32 @@
|
|
|
</div>
|
|
|
<div class=" self-center">External</div>
|
|
|
</button>
|
|
|
+
|
|
|
+ <button
|
|
|
+ class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
|
|
+ 'interface'
|
|
|
+ ? 'bg-gray-200 dark:bg-gray-700'
|
|
|
+ : ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
|
|
|
+ on:click={() => {
|
|
|
+ selectedTab = 'interface';
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div class=" self-center mr-2">
|
|
|
+ <svg
|
|
|
+ xmlns="http://www.w3.org/2000/svg"
|
|
|
+ viewBox="0 0 16 16"
|
|
|
+ fill="currentColor"
|
|
|
+ class="w-4 h-4"
|
|
|
+ >
|
|
|
+ <path
|
|
|
+ fill-rule="evenodd"
|
|
|
+ d="M2 4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V4Zm10.5 5.707a.5.5 0 0 0-.146-.353l-1-1a.5.5 0 0 0-.708 0L9.354 9.646a.5.5 0 0 1-.708 0L6.354 7.354a.5.5 0 0 0-.708 0l-2 2a.5.5 0 0 0-.146.353V12a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5V9.707ZM12 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"
|
|
|
+ clip-rule="evenodd"
|
|
|
+ />
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <div class=" self-center">Interface</div>
|
|
|
+ </button>
|
|
|
{/if}
|
|
|
|
|
|
<button
|
|
@@ -797,34 +834,6 @@
|
|
|
<div class=" self-center">Chats</div>
|
|
|
</button>
|
|
|
|
|
|
- {#if !$config || ($config && !$config.auth)}
|
|
|
- <button
|
|
|
- class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
|
|
- 'auth'
|
|
|
- ? 'bg-gray-200 dark:bg-gray-700'
|
|
|
- : ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
|
|
|
- on:click={() => {
|
|
|
- selectedTab = 'auth';
|
|
|
- }}
|
|
|
- >
|
|
|
- <div class=" self-center mr-2">
|
|
|
- <svg
|
|
|
- xmlns="http://www.w3.org/2000/svg"
|
|
|
- viewBox="0 0 24 24"
|
|
|
- fill="currentColor"
|
|
|
- class="w-4 h-4"
|
|
|
- >
|
|
|
- <path
|
|
|
- fill-rule="evenodd"
|
|
|
- d="M12.516 2.17a.75.75 0 00-1.032 0 11.209 11.209 0 01-7.877 3.08.75.75 0 00-.722.515A12.74 12.74 0 002.25 9.75c0 5.942 4.064 10.933 9.563 12.348a.749.749 0 00.374 0c5.499-1.415 9.563-6.406 9.563-12.348 0-1.39-.223-2.73-.635-3.985a.75.75 0 00-.722-.516l-.143.001c-2.996 0-5.717-1.17-7.734-3.08zm3.094 8.016a.75.75 0 10-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 00-1.06 1.06l2.25 2.25a.75.75 0 001.14-.094l3.75-5.25z"
|
|
|
- clip-rule="evenodd"
|
|
|
- />
|
|
|
- </svg>
|
|
|
- </div>
|
|
|
- <div class=" self-center">Authentication</div>
|
|
|
- </button>
|
|
|
- {/if}
|
|
|
-
|
|
|
<button
|
|
|
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
|
|
'account'
|
|
@@ -877,7 +886,7 @@
|
|
|
<div class=" self-center">About</div>
|
|
|
</button>
|
|
|
</div>
|
|
|
- <div class="flex-1 md:min-h-[340px]">
|
|
|
+ <div class="flex-1 md:min-h-[380px]">
|
|
|
{#if selectedTab === 'general'}
|
|
|
<div class="flex flex-col space-y-3">
|
|
|
<div>
|
|
@@ -1048,7 +1057,7 @@
|
|
|
</div>
|
|
|
{:else if selectedTab === 'advanced'}
|
|
|
<div class="flex flex-col h-full justify-between text-sm">
|
|
|
- <div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-72">
|
|
|
+ <div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
|
|
|
<div class=" text-sm font-medium">Parameters</div>
|
|
|
|
|
|
<Advanced bind:options />
|
|
@@ -1483,6 +1492,103 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
+ <div class="flex justify-end pt-3 text-sm font-medium">
|
|
|
+ <button
|
|
|
+ class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded"
|
|
|
+ type="submit"
|
|
|
+ >
|
|
|
+ Save
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </form>
|
|
|
+ {:else if selectedTab === 'interface'}
|
|
|
+ <form
|
|
|
+ class="flex flex-col h-full justify-between space-y-3 text-sm"
|
|
|
+ on:submit|preventDefault={() => {
|
|
|
+ updateInterfaceHandler();
|
|
|
+ show = false;
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
|
|
|
+ <div class="flex w-full justify-between mb-2">
|
|
|
+ <div class=" self-center text-sm font-semibold">Default Prompt Suggestions</div>
|
|
|
+
|
|
|
+ <button
|
|
|
+ class="p-1 px-3 text-xs flex rounded transition"
|
|
|
+ type="button"
|
|
|
+ on:click={() => {
|
|
|
+ if (promptSuggestions.length === 0 || promptSuggestions.at(-1).content !== '') {
|
|
|
+ promptSuggestions = [...promptSuggestions, { content: '', title: ['', ''] }];
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <svg
|
|
|
+ xmlns="http://www.w3.org/2000/svg"
|
|
|
+ viewBox="0 0 20 20"
|
|
|
+ fill="currentColor"
|
|
|
+ class="w-4 h-4"
|
|
|
+ >
|
|
|
+ <path
|
|
|
+ d="M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z"
|
|
|
+ />
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div class="flex flex-col space-y-1">
|
|
|
+ {#each promptSuggestions as prompt, promptIdx}
|
|
|
+ <div class=" flex border dark:border-gray-600 rounded-lg">
|
|
|
+ <div class="flex flex-col flex-1">
|
|
|
+ <div class="flex border-b dark:border-gray-600 w-full">
|
|
|
+ <input
|
|
|
+ class="px-3 py-1.5 text-xs w-full bg-transparent outline-none border-r dark:border-gray-600"
|
|
|
+ placeholder="Title (e.g. Tell me a fun fact)"
|
|
|
+ bind:value={prompt.title[0]}
|
|
|
+ />
|
|
|
+
|
|
|
+ <input
|
|
|
+ class="px-3 py-1.5 text-xs w-full bg-transparent outline-none border-r dark:border-gray-600"
|
|
|
+ placeholder="Subtitle (e.g. about the Roman Empire)"
|
|
|
+ bind:value={prompt.title[1]}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <input
|
|
|
+ class="px-3 py-1.5 text-xs w-full bg-transparent outline-none border-r dark:border-gray-600"
|
|
|
+ placeholder="Prompt (e.g. Tell me a fun fact about the Roman Empire)"
|
|
|
+ bind:value={prompt.content}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <button
|
|
|
+ class="px-2"
|
|
|
+ type="button"
|
|
|
+ on:click={() => {
|
|
|
+ promptSuggestions.splice(promptIdx, 1);
|
|
|
+ promptSuggestions = promptSuggestions;
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <svg
|
|
|
+ xmlns="http://www.w3.org/2000/svg"
|
|
|
+ viewBox="0 0 20 20"
|
|
|
+ fill="currentColor"
|
|
|
+ class="w-4 h-4"
|
|
|
+ >
|
|
|
+ <path
|
|
|
+ d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
|
|
|
+ />
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ {/each}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {#if promptSuggestions.length > 0}
|
|
|
+ <div class="text-xs text-left w-full mt-2">
|
|
|
+ Adjusting these settings will apply changes universally to all users.
|
|
|
+ </div>
|
|
|
+ {/if}
|
|
|
+ </div>
|
|
|
+
|
|
|
<div class="flex justify-end pt-3 text-sm font-medium">
|
|
|
<button
|
|
|
class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded"
|