General.svelte 17.4 KB
Newer Older
1
2
<script lang="ts">
	import { getDocs } from '$lib/apis/documents';
3
	import {
Timothy J. Baek's avatar
Timothy J. Baek committed
4
5
		getRAGConfig,
		updateRAGConfig,
6
		getQuerySettings,
7
		scanDocs,
Timothy J. Baek's avatar
Timothy J. Baek committed
8
		updateQuerySettings,
9
		resetVectorDB,
Timothy J. Baek's avatar
Timothy J. Baek committed
10
11
		getEmbeddingConfig,
		updateEmbeddingConfig
12
	} from '$lib/apis/rag';
Timothy J. Baek's avatar
Timothy J. Baek committed
13

Timothy J. Baek's avatar
Timothy J. Baek committed
14
	import { documents, models } from '$lib/stores';
15
	import { onMount, getContext } from 'svelte';
Jannik Streidl's avatar
Jannik Streidl committed
16
	import { toast } from 'svelte-sonner';
17

18
19
	import Tooltip from '$lib/components/common/Tooltip.svelte';

20
21
	const i18n = getContext('i18n');

22
	export let saveHandler: Function;
Timothy J. Baek's avatar
Timothy J. Baek committed
23

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
24
25
	let scanDirLoading = false;
	let updateEmbeddingModelLoading = false;
Timothy J. Baek's avatar
Timothy J. Baek committed
26

Timothy J. Baek's avatar
Timothy J. Baek committed
27
28
	let showResetConfirm = false;

29
	let embeddingEngine = '';
Timothy J. Baek's avatar
Timothy J. Baek committed
30
31
	let embeddingModel = '';

32
33
	let OpenAIKey = '';
	let OpenAIUrl = '';
34

Timothy J. Baek's avatar
Timothy J. Baek committed
35
36
	let chunkSize = 0;
	let chunkOverlap = 0;
Timothy J. Baek's avatar
Timothy J. Baek committed
37
	let pdfExtractImages = true;
Timothy J. Baek's avatar
Timothy J. Baek committed
38

39
40
41
42
	let querySettings = {
		template: '',
		k: 4
	};
43

44
	const scanHandler = async () => {
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
45
		scanDirLoading = true;
46
		const res = await scanDocs(localStorage.token);
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
47
		scanDirLoading = false;
48
49
50

		if (res) {
			await documents.set(await getDocs(localStorage.token));
51
			toast.success($i18n.t('Scan complete!'));
52
53
54
		}
	};

55
	const embeddingModelUpdateHandler = async () => {
56
57
58
59
60
61
62
63
64
		if (embeddingEngine === '' && embeddingModel.split('/').length - 1 > 1) {
			toast.error(
				$i18n.t(
					'Model filesystem path detected. Model shortname is required for update, cannot continue.'
				)
			);
			return;
		}
		if (embeddingEngine === 'ollama' && embeddingModel === '') {
Timothy J. Baek's avatar
Timothy J. Baek committed
65
66
67
68
69
70
71
72
			toast.error(
				$i18n.t(
					'Model filesystem path detected. Model shortname is required for update, cannot continue.'
				)
			);
			return;
		}

73
		if (embeddingEngine === 'openai' && embeddingModel === '') {
Self Denial's avatar
Self Denial committed
74
75
76
77
78
			toast.error(
				$i18n.t(
					'Model filesystem path detected. Model shortname is required for update, cannot continue.'
				)
			);
79
80
81
			return;
		}

82
		if ((embeddingEngine === 'openai' && OpenAIKey === '') || OpenAIUrl === '') {
83
84
85
86
			toast.error($i18n.t('OpenAI URL/Key required.'));
			return;
		}

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
87
		console.log('Update embedding model attempt:', embeddingModel);
88

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
89
		updateEmbeddingModelLoading = true;
Timothy J. Baek's avatar
Timothy J. Baek committed
90
91
		const res = await updateEmbeddingConfig(localStorage.token, {
			embedding_engine: embeddingEngine,
92
93
94
95
			embedding_model: embeddingModel,
			...(embeddingEngine === 'openai'
				? {
						openai_config: {
96
97
							key: OpenAIKey,
							url: OpenAIUrl
98
99
100
						}
				  }
				: {})
Timothy J. Baek's avatar
Timothy J. Baek committed
101
		}).catch(async (error) => {
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
102
			toast.error(error);
103
			await setEmbeddingConfig();
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
104
105
			return null;
		});
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
106
		updateEmbeddingModelLoading = false;
107
108
109

		if (res) {
			console.log('embeddingModelUpdateHandler:', res);
110
			if (res.status === true) {
111
				toast.success($i18n.t('Embedding model set to "{{embedding_model}}"', res), {
Self Denial's avatar
Self Denial committed
112
113
					duration: 1000 * 10
				});
114
115
116
117
			}
		}
	};

Timothy J. Baek's avatar
Timothy J. Baek committed
118
	const submitHandler = async () => {
Timothy J. Baek's avatar
Timothy J. Baek committed
119
120
121
122
123
124
125
		const res = await updateRAGConfig(localStorage.token, {
			pdf_extract_images: pdfExtractImages,
			chunk: {
				chunk_overlap: chunkOverlap,
				chunk_size: chunkSize
			}
		});
126
		querySettings = await updateQuerySettings(localStorage.token, querySettings);
Timothy J. Baek's avatar
Timothy J. Baek committed
127
128
	};

129
130
131
132
133
134
135
	const setEmbeddingConfig = async () => {
		const embeddingConfig = await getEmbeddingConfig(localStorage.token);

		if (embeddingConfig) {
			embeddingEngine = embeddingConfig.embedding_engine;
			embeddingModel = embeddingConfig.embedding_model;

136
137
			OpenAIKey = embeddingConfig.openai_config.key;
			OpenAIUrl = embeddingConfig.openai_config.url;
138
139
140
		}
	};

Timothy J. Baek's avatar
Timothy J. Baek committed
141
	onMount(async () => {
Timothy J. Baek's avatar
Timothy J. Baek committed
142
		const res = await getRAGConfig(localStorage.token);
Timothy J. Baek's avatar
Timothy J. Baek committed
143
144

		if (res) {
Timothy J. Baek's avatar
Timothy J. Baek committed
145
146
147
148
			pdfExtractImages = res.pdf_extract_images;

			chunkSize = res.chunk.chunk_size;
			chunkOverlap = res.chunk.chunk_overlap;
Timothy J. Baek's avatar
Timothy J. Baek committed
149
		}
150

151
		await setEmbeddingConfig();
152

153
		querySettings = await getQuerySettings(localStorage.token);
Timothy J. Baek's avatar
Timothy J. Baek committed
154
	});
155
156
157
158
159
</script>

<form
	class="flex flex-col h-full justify-between space-y-3 text-sm"
	on:submit|preventDefault={() => {
Timothy J. Baek's avatar
Timothy J. Baek committed
160
		submitHandler();
161
162
163
		saveHandler();
	}}
>
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
164
	<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[22rem]">
165
		<div>
166
			<div class=" mb-2 text-sm font-medium">{$i18n.t('General Settings')}</div>
167

168
			<div class=" flex w-full justify-between">
Timothy J. Baek's avatar
Timothy J. Baek committed
169
				<div class=" self-center text-xs font-medium">{$i18n.t('Embedding Model Engine')}</div>
170
171
172
173
				<div class="flex items-center relative">
					<select
						class="dark:bg-gray-900 w-fit pr-8 rounded px-2 p-1 text-xs bg-transparent outline-none text-right"
						bind:value={embeddingEngine}
Timothy J. Baek's avatar
Timothy J. Baek committed
174
						placeholder="Select an embedding model engine"
175
176
177
178
179
180
						on:change={(e) => {
							if (e.target.value === 'ollama') {
								embeddingModel = '';
							} else if (e.target.value === 'openai') {
								embeddingModel = 'text-embedding-3-small';
							}
Timothy J. Baek's avatar
Timothy J. Baek committed
181
						}}
182
					>
183
						<option value="">{$i18n.t('Default (SentenceTransformers)')}</option>
184
						<option value="ollama">{$i18n.t('Ollama')}</option>
185
						<option value="openai">{$i18n.t('OpenAI')}</option>
186
					</select>
187
				</div>
188
			</div>
189
190
191
192
193
194

			{#if embeddingEngine === 'openai'}
				<div class="mt-1 flex gap-2">
					<input
						class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
						placeholder={$i18n.t('API Base URL')}
195
						bind:value={OpenAIUrl}
196
197
198
199
200
201
						required
					/>

					<input
						class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
						placeholder={$i18n.t('API Key')}
202
						bind:value={OpenAIKey}
203
204
205
206
						required
					/>
				</div>
			{/if}
207
		</div>
208

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
209
210
		<div class="space-y-2">
			<div>
Timothy J. Baek's avatar
Timothy J. Baek committed
211
212
				<div class=" mb-2 text-sm font-medium">{$i18n.t('Update Embedding Model')}</div>

213
				{#if embeddingEngine === 'ollama'}
Timothy J. Baek's avatar
Timothy J. Baek committed
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
245
246
247
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
274
275
276
277
278
279
280
					<div class="flex w-full">
						<div class="flex-1 mr-2">
							<select
								class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
								bind:value={embeddingModel}
								placeholder={$i18n.t('Select a model')}
								required
							>
								{#if !embeddingModel}
									<option value="" disabled selected>{$i18n.t('Select a model')}</option>
								{/if}
								{#each $models.filter((m) => m.id && !m.external) as model}
									<option value={model.name} class="bg-gray-100 dark:bg-gray-700"
										>{model.name + ' (' + (model.size / 1024 ** 3).toFixed(1) + ' GB)'}</option
									>
								{/each}
							</select>
						</div>
						<button
							class="px-2.5 bg-gray-100 hover:bg-gray-200 text-gray-800 dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-gray-100 rounded-lg transition"
							on:click={() => {
								embeddingModelUpdateHandler();
							}}
							disabled={updateEmbeddingModelLoading}
						>
							{#if updateEmbeddingModelLoading}
								<div class="self-center">
									<svg
										class=" w-4 h-4"
										viewBox="0 0 24 24"
										fill="currentColor"
										xmlns="http://www.w3.org/2000/svg"
										><style>
											.spinner_ajPY {
												transform-origin: center;
												animation: spinner_AtaB 0.75s infinite linear;
											}
											@keyframes spinner_AtaB {
												100% {
													transform: rotate(360deg);
												}
											}
										</style><path
											d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
											opacity=".25"
										/><path
											d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
											class="spinner_ajPY"
										/></svg
									>
								</div>
							{:else}
								<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="M12.416 3.376a.75.75 0 0 1 .208 1.04l-5 7.5a.75.75 0 0 1-1.154.114l-3-3a.75.75 0 0 1 1.06-1.06l2.353 2.353 4.493-6.74a.75.75 0 0 1 1.04-.207Z"
										clip-rule="evenodd"
									/>
								</svg>
							{/if}
						</button>
					</div>
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
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
				{:else}
					<div class="flex w-full">
						<div class="flex-1 mr-2">
							<input
								class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
								placeholder={$i18n.t('Update embedding model (e.g. {{model}})', {
									model: embeddingModel.slice(-40)
								})}
								bind:value={embeddingModel}
							/>
						</div>
						<button
							class="px-2.5 bg-gray-100 hover:bg-gray-200 text-gray-800 dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-gray-100 rounded-lg transition"
							on:click={() => {
								embeddingModelUpdateHandler();
							}}
							disabled={updateEmbeddingModelLoading}
						>
							{#if updateEmbeddingModelLoading}
								<div class="self-center">
									<svg
										class=" w-4 h-4"
										viewBox="0 0 24 24"
										fill="currentColor"
										xmlns="http://www.w3.org/2000/svg"
										><style>
											.spinner_ajPY {
												transform-origin: center;
												animation: spinner_AtaB 0.75s infinite linear;
											}
											@keyframes spinner_AtaB {
												100% {
													transform: rotate(360deg);
												}
											}
										</style><path
											d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
											opacity=".25"
										/><path
											d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
											class="spinner_ajPY"
										/></svg
									>
								</div>
							{:else}
								<svg
									xmlns="http://www.w3.org/2000/svg"
									viewBox="0 0 16 16"
									fill="currentColor"
									class="w-4 h-4"
								>
									<path
										d="M8.75 2.75a.75.75 0 0 0-1.5 0v5.69L5.03 6.22a.75.75 0 0 0-1.06 1.06l3.5 3.5a.75.75 0 0 0 1.06 0l3.5-3.5a.75.75 0 0 0-1.06-1.06L8.75 8.44V2.75Z"
									/>
									<path
										d="M3.5 9.75a.75.75 0 0 0-1.5 0v1.5A2.75 2.75 0 0 0 4.75 14h6.5A2.75 2.75 0 0 0 14 11.25v-1.5a.75.75 0 0 0-1.5 0v1.5c0 .69-.56 1.25-1.25 1.25h-6.5c-.69 0-1.25-.56-1.25-1.25v-1.5Z"
									/>
								</svg>
							{/if}
						</button>
341
					</div>
342
343
				{/if}

Timothy J. Baek's avatar
Timothy J. Baek committed
344
345
346
347
348
349
				<div class="mt-2 mb-1 text-xs text-gray-400 dark:text-gray-500">
					{$i18n.t(
						'Warning: If you update or change your embedding model, you will need to re-import all documents.'
					)}
				</div>

350
351
352
353
354
355
356
				<hr class=" dark:border-gray-700 my-3" />

				<div class="  flex w-full justify-between">
					<div class=" self-center text-xs font-medium">
						{$i18n.t('Scan for documents from {{path}}', { path: '/data/docs' })}
					</div>

357
					<button
358
359
360
						class=" self-center text-xs p-1 px-3 bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 rounded-lg flex flex-row space-x-1 items-center {scanDirLoading
							? ' cursor-not-allowed'
							: ''}"
361
						on:click={() => {
362
363
							scanHandler();
							console.log('check');
364
						}}
365
366
						type="button"
						disabled={scanDirLoading}
367
					>
368
369
370
371
						<div class="self-center font-medium">{$i18n.t('Scan')}</div>

						{#if scanDirLoading}
							<div class="ml-3 self-center">
372
								<svg
373
									class=" w-3 h-3"
374
375
376
377
378
379
380
									viewBox="0 0 24 24"
									fill="currentColor"
									xmlns="http://www.w3.org/2000/svg"
									><style>
										.spinner_ajPY {
											transform-origin: center;
											animation: spinner_AtaB 0.75s infinite linear;
381
										}
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
										@keyframes spinner_AtaB {
											100% {
												transform: rotate(360deg);
											}
										}
									</style><path
										d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
										opacity=".25"
									/><path
										d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
										class="spinner_ajPY"
									/></svg
								>
							</div>
						{/if}
					</button>
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
398
				</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
399

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
400
				<hr class=" dark:border-gray-700 my-3" />
Timothy J. Baek's avatar
Timothy J. Baek committed
401

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
402
403
				<div class=" ">
					<div class=" text-sm font-medium">{$i18n.t('Chunk Params')}</div>
404

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
405
406
407
					<div class=" flex">
						<div class="  flex w-full justify-between">
							<div class="self-center text-xs font-medium min-w-fit">{$i18n.t('Chunk Size')}</div>
408

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
409
410
							<div class="self-center p-3">
								<input
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
411
									class=" w-full rounded-lg py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
412
413
414
415
416
417
418
419
									type="number"
									placeholder={$i18n.t('Enter Chunk Size')}
									bind:value={chunkSize}
									autocomplete="off"
									min="0"
								/>
							</div>
						</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
420

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
421
422
423
424
						<div class="flex w-full">
							<div class=" self-center text-xs font-medium min-w-fit">
								{$i18n.t('Chunk Overlap')}
							</div>
425

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
426
427
							<div class="self-center p-3">
								<input
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
428
									class="w-full rounded-lg py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
429
430
431
432
433
434
435
436
437
									type="number"
									placeholder={$i18n.t('Enter Chunk Overlap')}
									bind:value={chunkOverlap}
									autocomplete="off"
									min="0"
								/>
							</div>
						</div>
					</div>
438

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
439
					<div class="pr-2">
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
440
441
442
443
444
445
446
447
448
449
450
						<div class="flex justify-between items-center text-xs">
							<div class=" text-xs font-medium">{$i18n.t('PDF Extract Images (OCR)')}</div>

							<button
								class=" text-xs font-medium text-gray-500"
								type="button"
								on:click={() => {
									pdfExtractImages = !pdfExtractImages;
								}}>{pdfExtractImages ? $i18n.t('On') : $i18n.t('Off')}</button
							>
						</div>
451
452
453
					</div>
				</div>

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
454
455
				<hr class=" dark:border-gray-700 my-3" />

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
456
457
458
459
460
461
462
463
464
				<div>
					<div class=" text-sm font-medium">{$i18n.t('Query Params')}</div>

					<div class=" flex">
						<div class="  flex w-full justify-between">
							<div class="self-center text-xs font-medium flex-1">{$i18n.t('Top K')}</div>

							<div class="self-center p-3">
								<input
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
465
									class=" w-full rounded-lg py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
466
467
468
469
470
471
472
473
474
									type="number"
									placeholder={$i18n.t('Enter Top K')}
									bind:value={querySettings.k}
									autocomplete="off"
									min="0"
								/>
							</div>
						</div>
					</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
475

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
476
477
478
479
					<div>
						<div class=" mb-2.5 text-sm font-medium">{$i18n.t('RAG Template')}</div>
						<textarea
							bind:value={querySettings.template}
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
480
							class="w-full rounded-lg px-4 py-3 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none resize-none"
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
481
							rows="4"
Timothy J. Baek's avatar
Timothy J. Baek committed
482
						/>
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
483
					</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
484
485
				</div>

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
486
				<hr class=" dark:border-gray-700 my-3" />
Timothy J. Baek's avatar
Timothy J. Baek committed
487

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
				{#if showResetConfirm}
					<div class="flex justify-between rounded-md items-center py-2 px-3.5 w-full transition">
						<div class="flex items-center space-x-3">
							<svg
								xmlns="http://www.w3.org/2000/svg"
								viewBox="0 0 16 16"
								fill="currentColor"
								class="w-4 h-4"
							>
								<path d="M2 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3Z" />
								<path
									fill-rule="evenodd"
									d="M13 6H3v6a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V6ZM5.72 7.47a.75.75 0 0 1 1.06 0L8 8.69l1.22-1.22a.75.75 0 1 1 1.06 1.06L9.06 9.75l1.22 1.22a.75.75 0 1 1-1.06 1.06L8 10.81l-1.22 1.22a.75.75 0 0 1-1.06-1.06l1.22-1.22-1.22-1.22a.75.75 0 0 1 0-1.06Z"
									clip-rule="evenodd"
								/>
							</svg>
							<span>{$i18n.t('Are you sure?')}</span>
						</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
506

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
						<div class="flex space-x-1.5 items-center">
							<button
								class="hover:text-white transition"
								on:click={() => {
									const res = resetVectorDB(localStorage.token).catch((error) => {
										toast.error(error);
										return null;
									});

									if (res) {
										toast.success($i18n.t('Success'));
									}

									showResetConfirm = false;
								}}
							>
								<svg
									xmlns="http://www.w3.org/2000/svg"
									viewBox="0 0 20 20"
									fill="currentColor"
									class="w-4 h-4"
								>
									<path
										fill-rule="evenodd"
										d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z"
										clip-rule="evenodd"
									/>
								</svg>
							</button>
							<button
								class="hover:text-white transition"
								on:click={() => {
									showResetConfirm = false;
								}}
							>
								<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>
					</div>
				{:else}
Timothy J. Baek's avatar
Timothy J. Baek committed
556
					<button
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
557
						class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition"
Timothy J. Baek's avatar
Timothy J. Baek committed
558
						on:click={() => {
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
559
							showResetConfirm = true;
Timothy J. Baek's avatar
Timothy J. Baek committed
560
561
						}}
					>
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
						<div class=" self-center mr-3">
							<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="M3.5 2A1.5 1.5 0 0 0 2 3.5v9A1.5 1.5 0 0 0 3.5 14h9a1.5 1.5 0 0 0 1.5-1.5v-7A1.5 1.5 0 0 0 12.5 4H9.621a1.5 1.5 0 0 1-1.06-.44L7.439 2.44A1.5 1.5 0 0 0 6.38 2H3.5Zm6.75 7.75a.75.75 0 0 0 0-1.5h-4.5a.75.75 0 0 0 0 1.5h4.5Z"
									clip-rule="evenodd"
								/>
							</svg>
						</div>
						<div class=" self-center text-sm font-medium">{$i18n.t('Reset Vector Storage')}</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
577
					</button>
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
578
				{/if}
Timothy J. Baek's avatar
Timothy J. Baek committed
579
			</div>
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
580
		</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
581
	</div>
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
582
583
584
585
586
587
588
589
	<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"
		>
			{$i18n.t('Save')}
		</button>
	</div>
590
</form>