"...research_projects/controlnetxs/pipeline_controlnet_xs.py" did not exist on "5b6582cf73ca71cb8a7bef0c608ecf10399916bd"
Interface.svelte 10.5 KB
Newer Older
Timothy J. Baek's avatar
Timothy J. Baek committed
1
<script lang="ts">
Timothy J. Baek's avatar
Timothy J. Baek committed
2
3
4
	import { v4 as uuidv4 } from 'uuid';
	import { toast } from 'svelte-sonner';

Timothy J. Baek's avatar
Timothy J. Baek committed
5
	import { getBackendConfig, getTaskConfig, updateTaskConfig } from '$lib/apis';
Timothy J. Baek's avatar
Timothy J. Baek committed
6
7
8
	import { setDefaultPromptSuggestions } from '$lib/apis/configs';
	import { config, models, settings, user } from '$lib/stores';
	import { createEventDispatcher, onMount, getContext } from 'svelte';
Timothy J. Baek's avatar
Timothy J. Baek committed
9
10
11
12
13
14

	import { banners as _banners } from '$lib/stores';
	import type { Banner } from '$lib/types';

	import { getBanners, setBanners } from '$lib/apis/configs';

Timothy J. Baek's avatar
Timothy J. Baek committed
15
	import Tooltip from '$lib/components/common/Tooltip.svelte';
Timothy J. Baek's avatar
Timothy J. Baek committed
16
17
	import Switch from '$lib/components/common/Switch.svelte';

Timothy J. Baek's avatar
Timothy J. Baek committed
18
19
20
21
	const dispatch = createEventDispatcher();

	const i18n = getContext('i18n');

Timothy J. Baek's avatar
Timothy J. Baek committed
22
23
24
25
	let taskConfig = {
		TASK_MODEL: '',
		TASK_MODEL_EXTERNAL: '',
		TITLE_GENERATION_PROMPT_TEMPLATE: '',
Timothy J. Baek's avatar
Timothy J. Baek committed
26
27
		SEARCH_QUERY_GENERATION_PROMPT_TEMPLATE: '',
		SEARCH_QUERY_PROMPT_LENGTH_THRESHOLD: 0
Timothy J. Baek's avatar
Timothy J. Baek committed
28
	};
Timothy J. Baek's avatar
Timothy J. Baek committed
29

Timothy J. Baek's avatar
Timothy J. Baek committed
30
	let promptSuggestions = [];
Timothy J. Baek's avatar
Timothy J. Baek committed
31
	let banners: Banner[] = [];
Timothy J. Baek's avatar
Timothy J. Baek committed
32
33

	const updateInterfaceHandler = async () => {
Timothy J. Baek's avatar
Timothy J. Baek committed
34
35
		taskConfig = await updateTaskConfig(localStorage.token, taskConfig);

Timothy J. Baek's avatar
Timothy J. Baek committed
36
		promptSuggestions = await setDefaultPromptSuggestions(localStorage.token, promptSuggestions);
Timothy J. Baek's avatar
Timothy J. Baek committed
37
		await updateBanners();
Timothy J. Baek's avatar
Timothy J. Baek committed
38

Timothy J. Baek's avatar
Timothy J. Baek committed
39
40
41
42
		await config.set(await getBackendConfig());
	};

	onMount(async () => {
Timothy J. Baek's avatar
Timothy J. Baek committed
43
		taskConfig = await getTaskConfig(localStorage.token);
Timothy J. Baek's avatar
Timothy J. Baek committed
44
45

		promptSuggestions = $config?.default_prompt_suggestions;
Timothy J. Baek's avatar
Timothy J. Baek committed
46
47

		banners = await getBanners(localStorage.token);
Timothy J. Baek's avatar
Timothy J. Baek committed
48
	});
Timothy J. Baek's avatar
Timothy J. Baek committed
49
50
51
52

	const updateBanners = async () => {
		_banners.set(await setBanners(localStorage.token, banners));
	};
Timothy J. Baek's avatar
Timothy J. Baek committed
53
54
55
56
57
58
59
60
61
</script>

<form
	class="flex flex-col h-full justify-between space-y-3 text-sm"
	on:submit|preventDefault={() => {
		updateInterfaceHandler();
		dispatch('save');
	}}
>
Timothy J. Baek's avatar
Timothy J. Baek committed
62
	<div class="  overflow-y-scroll scrollbar-hidden h-full pr-1.5">
Timothy J. Baek's avatar
Timothy J. Baek committed
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
		<div>
			<div class=" mb-2.5 text-sm font-medium flex">
				<div class=" mr-1">{$i18n.t('Set Task Model')}</div>
				<Tooltip
					content={$i18n.t(
						'A task model is used when performing tasks such as generating titles for chats and web search queries'
					)}
				>
					<svg
						xmlns="http://www.w3.org/2000/svg"
						fill="none"
						viewBox="0 0 24 24"
						stroke-width="1.5"
						stroke="currentColor"
						class="w-5 h-5"
					>
						<path
							stroke-linecap="round"
							stroke-linejoin="round"
							d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z"
						/>
					</svg>
				</Tooltip>
			</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
87
			<div class="flex w-full gap-2">
Timothy J. Baek's avatar
Timothy J. Baek committed
88
89
90
91
				<div class="flex-1">
					<div class=" text-xs mb-1">{$i18n.t('Local Models')}</div>
					<select
						class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
Timothy J. Baek's avatar
Timothy J. Baek committed
92
						bind:value={taskConfig.TASK_MODEL}
Timothy J. Baek's avatar
Timothy J. Baek committed
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
						placeholder={$i18n.t('Select a model')}
					>
						<option value="" selected>{$i18n.t('Current Model')}</option>
						{#each $models.filter((m) => m.owned_by === 'ollama') as model}
							<option value={model.id} class="bg-gray-100 dark:bg-gray-700">
								{model.name}
							</option>
						{/each}
					</select>
				</div>

				<div class="flex-1">
					<div class=" text-xs mb-1">{$i18n.t('External Models')}</div>
					<select
						class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
Timothy J. Baek's avatar
Timothy J. Baek committed
108
						bind:value={taskConfig.TASK_MODEL_EXTERNAL}
Timothy J. Baek's avatar
Timothy J. Baek committed
109
110
111
112
113
114
115
116
117
118
119
120
						placeholder={$i18n.t('Select a model')}
					>
						<option value="" selected>{$i18n.t('Current Model')}</option>
						{#each $models as model}
							<option value={model.id} class="bg-gray-100 dark:bg-gray-700">
								{model.name}
							</option>
						{/each}
					</select>
				</div>
			</div>

Timothy J. Baek's avatar
Timothy J. Baek committed
121
			<div class="mt-3">
Timothy J. Baek's avatar
Timothy J. Baek committed
122
123
				<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Title Generation Prompt')}</div>
				<textarea
Timothy J. Baek's avatar
Timothy J. Baek committed
124
					bind:value={taskConfig.TITLE_GENERATION_PROMPT_TEMPLATE}
Timothy J. Baek's avatar
Timothy J. Baek committed
125
					class="w-full rounded-lg py-3 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none resize-none"
Timothy J. Baek's avatar
Timothy J. Baek committed
126
127
128
129
130
131
132
133
					rows="6"
				/>
			</div>

			<div class="mt-3">
				<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Search Query Generation Prompt')}</div>
				<textarea
					bind:value={taskConfig.SEARCH_QUERY_GENERATION_PROMPT_TEMPLATE}
Timothy J. Baek's avatar
Timothy J. Baek committed
134
					class="w-full rounded-lg py-3 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none resize-none"
Timothy J. Baek's avatar
Timothy J. Baek committed
135
					rows="6"
Timothy J. Baek's avatar
Timothy J. Baek committed
136
137
				/>
			</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
138
139
140
141
142
143
144
145
146
147
148

			<div class="mt-3">
				<div class=" mb-2.5 text-sm font-medium">
					{$i18n.t('Search Query Generation Prompt Length Threshold')}
				</div>
				<input
					bind:value={taskConfig.SEARCH_QUERY_PROMPT_LENGTH_THRESHOLD}
					class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none resize-none"
					type="number"
				/>
			</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
149
150
		</div>

Timothy J. Baek's avatar
Timothy J. Baek committed
151
		<hr class=" dark:border-gray-850 my-3" />
Timothy J. Baek's avatar
Timothy J. Baek committed
152

Timothy J. Baek's avatar
Timothy J. Baek committed
153
154
		<div class=" space-y-3 {banners.length > 0 ? ' mb-3' : ''}">
			<div class="flex w-full justify-between">
Timothy J. Baek's avatar
Timothy J. Baek committed
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
				<div class=" self-center text-sm font-semibold">
					{$i18n.t('Banners')}
				</div>

				<button
					class="p-1 px-3 text-xs flex rounded transition"
					type="button"
					on:click={() => {
						if (banners.length === 0 || banners.at(-1).content !== '') {
							banners = [
								...banners,
								{
									id: uuidv4(),
									type: '',
									title: '',
									content: '',
									dismissible: true,
									timestamp: Math.floor(Date.now() / 1000)
								}
							];
						}
					}}
				>
					<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 banners as banner, bannerIdx}
					<div class=" flex justify-between">
						<div class="flex flex-row flex-1 border rounded-xl dark:border-gray-800">
							<select
								class="w-fit capitalize rounded-xl py-2 px-4 text-xs bg-transparent outline-none"
								bind:value={banner.type}
								required
							>
								{#if banner.type == ''}
									<option value="" selected disabled class="text-gray-900">{$i18n.t('Type')}</option
									>
								{/if}
								<option value="info" class="text-gray-900">{$i18n.t('Info')}</option>
								<option value="warning" class="text-gray-900">{$i18n.t('Warning')}</option>
								<option value="error" class="text-gray-900">{$i18n.t('Error')}</option>
								<option value="success" class="text-gray-900">{$i18n.t('Success')}</option>
							</select>

							<input
								class="pr-5 py-1.5 text-xs w-full bg-transparent outline-none"
								placeholder={$i18n.t('Content')}
								bind:value={banner.content}
							/>

							<div class="relative top-1.5 -left-2">
								<Tooltip content={$i18n.t('Dismissible')} className="flex h-fit items-center">
									<Switch bind:state={banner.dismissible} />
								</Tooltip>
							</div>
						</div>

						<button
							class="px-2"
							type="button"
							on:click={() => {
								banners.splice(bannerIdx, 1);
								banners = banners;
							}}
						>
							<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>
		</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
245

Timothy J. Baek's avatar
Timothy J. Baek committed
246
		{#if $user.role === 'admin'}
Timothy J. Baek's avatar
Timothy J. Baek committed
247
			<div class=" space-y-3">
Timothy J. Baek's avatar
Timothy J. Baek committed
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
				<div class="flex w-full justify-between mb-2">
					<div class=" self-center text-sm font-semibold">
						{$i18n.t('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>
Timothy J. Baek's avatar
Timothy J. Baek committed
274
				<div class="grid lg:grid-cols-2 flex-col gap-1.5">
Timothy J. Baek's avatar
Timothy J. Baek committed
275
					{#each promptSuggestions as prompt, promptIdx}
Timothy J. Baek's avatar
Timothy J. Baek committed
276
277
278
						<div
							class=" flex border border-gray-100 dark:border-none dark:bg-gray-850 rounded-xl py-1.5"
						>
Timothy J. Baek's avatar
Timothy J. Baek committed
279
							<div class="flex flex-col flex-1 pl-1">
Timothy J. Baek's avatar
Timothy J. Baek committed
280
								<div class="flex border-b border-gray-100 dark:border-gray-800 w-full">
Timothy J. Baek's avatar
Timothy J. Baek committed
281
									<input
Timothy J. Baek's avatar
Timothy J. Baek committed
282
										class="px-3 py-1.5 text-xs w-full bg-transparent outline-none border-r border-gray-100 dark:border-gray-800"
Timothy J. Baek's avatar
Timothy J. Baek committed
283
284
285
286
287
										placeholder={$i18n.t('Title (e.g. Tell me a fun fact)')}
										bind:value={prompt.title[0]}
									/>

									<input
Timothy J. Baek's avatar
Timothy J. Baek committed
288
										class="px-3 py-1.5 text-xs w-full bg-transparent outline-none border-r border-gray-100 dark:border-gray-800"
Timothy J. Baek's avatar
Timothy J. Baek committed
289
290
291
292
293
294
										placeholder={$i18n.t('Subtitle (e.g. about the Roman Empire)')}
										bind:value={prompt.title[1]}
									/>
								</div>

								<input
Timothy J. Baek's avatar
Timothy J. Baek committed
295
									class="px-3 py-1.5 text-xs w-full bg-transparent outline-none border-r border-gray-100 dark:border-gray-800"
Timothy J. Baek's avatar
Timothy J. Baek committed
296
297
298
299
300
301
									placeholder={$i18n.t('Prompt (e.g. Tell me a fun fact about the Roman Empire)')}
									bind:value={prompt.content}
								/>
							</div>

							<button
Timothy J. Baek's avatar
Timothy J. Baek committed
302
								class="px-3"
Timothy J. Baek's avatar
Timothy J. Baek committed
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
								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">
						{$i18n.t('Adjusting these settings will apply changes universally to all users.')}
					</div>
				{/if}
			</div>
		{/if}
	</div>

	<div class="flex justify-end text-sm font-medium">
		<button
			class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
			type="submit"
		>
			{$i18n.t('Save')}
		</button>
	</div>
</form>