General.svelte 21.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
		getEmbeddingConfig,
Steven Kreitzer's avatar
Steven Kreitzer committed
11
12
13
		updateEmbeddingConfig,
		getRerankingConfig,
		updateRerankingConfig
14
	} from '$lib/apis/rag';
Timothy J. Baek's avatar
Timothy J. Baek committed
15

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

20
21
	import Tooltip from '$lib/components/common/Tooltip.svelte';

22
23
	const i18n = getContext('i18n');

24
	export let saveHandler: Function;
Timothy J. Baek's avatar
Timothy J. Baek committed
25

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
26
27
	let scanDirLoading = false;
	let updateEmbeddingModelLoading = false;
Steven Kreitzer's avatar
Steven Kreitzer committed
28
	let updateRerankingModelLoading = false;
Timothy J. Baek's avatar
Timothy J. Baek committed
29

Timothy J. Baek's avatar
Timothy J. Baek committed
30
31
	let showResetConfirm = false;

32
	let embeddingEngine = '';
Timothy J. Baek's avatar
Timothy J. Baek committed
33
	let embeddingModel = '';
Steven Kreitzer's avatar
Steven Kreitzer committed
34
	let rerankingModel = '';
Timothy J. Baek's avatar
Timothy J. Baek committed
35

36
37
	let OpenAIKey = '';
	let OpenAIUrl = '';
38

Timothy J. Baek's avatar
Timothy J. Baek committed
39
40
	let chunkSize = 0;
	let chunkOverlap = 0;
Timothy J. Baek's avatar
Timothy J. Baek committed
41
	let pdfExtractImages = true;
Timothy J. Baek's avatar
Timothy J. Baek committed
42

43
44
	let querySettings = {
		template: '',
45
		r: 0.0,
46
47
		k: 4
	};
48

49
	const scanHandler = async () => {
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
50
		scanDirLoading = true;
51
		const res = await scanDocs(localStorage.token);
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
52
		scanDirLoading = false;
53
54
55

		if (res) {
			await documents.set(await getDocs(localStorage.token));
56
			toast.success($i18n.t('Scan complete!'));
57
58
59
		}
	};

60
	const embeddingModelUpdateHandler = async () => {
61
62
63
64
65
66
67
68
69
		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
70
71
72
73
74
75
76
77
			toast.error(
				$i18n.t(
					'Model filesystem path detected. Model shortname is required for update, cannot continue.'
				)
			);
			return;
		}

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

87
		if ((embeddingEngine === 'openai' && OpenAIKey === '') || OpenAIUrl === '') {
88
89
90
91
			toast.error($i18n.t('OpenAI URL/Key required.'));
			return;
		}

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

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

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

Steven Kreitzer's avatar
Steven Kreitzer committed
123
124
125
126
127
	const rerankingModelUpdateHandler = async () => {
		console.log('Update reranking model attempt:', rerankingModel);

		updateRerankingModelLoading = true;
		const res = await updateRerankingConfig(localStorage.token, {
128
			reranking_model: rerankingModel
Steven Kreitzer's avatar
Steven Kreitzer committed
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
		}).catch(async (error) => {
			toast.error(error);
			await setRerankingConfig();
			return null;
		});
		updateRerankingModelLoading = false;

		if (res) {
			console.log('rerankingModelUpdateHandler:', res);
			if (res.status === true) {
				toast.success($i18n.t('Reranking model set to "{{reranking_model}}"', res), {
					duration: 1000 * 10
				});
			}
		}
	};

Timothy J. Baek's avatar
Timothy J. Baek committed
146
	const submitHandler = async () => {
Timothy J. Baek's avatar
Timothy J. Baek committed
147
148
149
150
151
152
153
		const res = await updateRAGConfig(localStorage.token, {
			pdf_extract_images: pdfExtractImages,
			chunk: {
				chunk_overlap: chunkOverlap,
				chunk_size: chunkSize
			}
		});
154
		querySettings = await updateQuerySettings(localStorage.token, querySettings);
Timothy J. Baek's avatar
Timothy J. Baek committed
155
156
	};

157
158
159
160
161
162
163
	const setEmbeddingConfig = async () => {
		const embeddingConfig = await getEmbeddingConfig(localStorage.token);

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

164
165
			OpenAIKey = embeddingConfig.openai_config.key;
			OpenAIUrl = embeddingConfig.openai_config.url;
166
167
168
		}
	};

Steven Kreitzer's avatar
Steven Kreitzer committed
169
170
171
172
173
174
175
176
	const setRerankingConfig = async () => {
		const rerankingConfig = await getRerankingConfig(localStorage.token);

		if (rerankingConfig) {
			rerankingModel = rerankingConfig.reranking_model;
		}
	};

Timothy J. Baek's avatar
Timothy J. Baek committed
177
	onMount(async () => {
Timothy J. Baek's avatar
Timothy J. Baek committed
178
		const res = await getRAGConfig(localStorage.token);
Timothy J. Baek's avatar
Timothy J. Baek committed
179
180

		if (res) {
Timothy J. Baek's avatar
Timothy J. Baek committed
181
182
183
184
			pdfExtractImages = res.pdf_extract_images;

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

187
		await setEmbeddingConfig();
Steven Kreitzer's avatar
Steven Kreitzer committed
188
		await setRerankingConfig();
189

190
		querySettings = await getQuerySettings(localStorage.token);
Timothy J. Baek's avatar
Timothy J. Baek committed
191
	});
192
193
194
195
196
</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
197
		submitHandler();
198
199
200
		saveHandler();
	}}
>
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
201
	<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[22rem]">
202
		<div>
203
			<div class=" mb-2 text-sm font-medium">{$i18n.t('General Settings')}</div>
204

205
			<div class=" flex w-full justify-between">
Timothy J. Baek's avatar
Timothy J. Baek committed
206
				<div class=" self-center text-xs font-medium">{$i18n.t('Embedding Model Engine')}</div>
207
208
209
210
				<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
211
						placeholder="Select an embedding model engine"
212
213
214
215
216
217
						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
218
						}}
219
					>
220
						<option value="">{$i18n.t('Default (SentenceTransformers)')}</option>
221
						<option value="ollama">{$i18n.t('Ollama')}</option>
222
						<option value="openai">{$i18n.t('OpenAI')}</option>
223
					</select>
224
				</div>
225
			</div>
226
227
228
229
230
231

			{#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')}
232
						bind:value={OpenAIUrl}
233
234
235
236
237
238
						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')}
239
						bind:value={OpenAIKey}
240
241
242
243
						required
					/>
				</div>
			{/if}
244
		</div>
245

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

250
				{#if embeddingEngine === 'ollama'}
Timothy J. Baek's avatar
Timothy J. Baek committed
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
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
					<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>
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
				{: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>
378
					</div>
379
380
				{/if}

Timothy J. Baek's avatar
Timothy J. Baek committed
381
382
383
384
385
386
				<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>

387
388
				<hr class=" dark:border-gray-700 my-3" />

Steven Kreitzer's avatar
Steven Kreitzer committed
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
				<div class=" ">
					<div class=" mb-2 text-sm font-medium">{$i18n.t('Update Reranking Model')}</div>

					<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 reranking model (e.g. {{model}})', {
									model: rerankingModel.slice(-40)
								})}
								bind:value={rerankingModel}
							/>
						</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={() => {
								rerankingModelUpdateHandler();
							}}
							disabled={updateRerankingModelLoading}
						>
							{#if updateRerankingModelLoading}
								<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>
					</div>
				</div>

454
455
456
457
458
459
				<div class="mt-2 mb-1 text-xs text-gray-400 dark:text-gray-500">
					{$i18n.t(
						'Note: If you choose a reranking model, it will use that to score and rerank instead of the embedding model.'
					)}
				</div>

Steven Kreitzer's avatar
Steven Kreitzer committed
460
461
				<hr class=" dark:border-gray-700 my-3" />

462
463
464
465
466
				<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>

467
					<button
468
469
470
						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'
							: ''}"
471
						on:click={() => {
472
473
							scanHandler();
							console.log('check');
474
						}}
475
476
						type="button"
						disabled={scanDirLoading}
477
					>
478
479
480
481
						<div class="self-center font-medium">{$i18n.t('Scan')}</div>

						{#if scanDirLoading}
							<div class="ml-3 self-center">
482
								<svg
483
									class=" w-3 h-3"
484
485
486
487
488
489
490
									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;
491
										}
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
										@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
508
				</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
509

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

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

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
515
516
517
					<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>
518

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
519
520
							<div class="self-center p-3">
								<input
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
521
									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
522
523
524
525
526
527
528
529
									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
530

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
531
532
533
534
						<div class="flex w-full">
							<div class=" self-center text-xs font-medium min-w-fit">
								{$i18n.t('Chunk Overlap')}
							</div>
535

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
536
537
							<div class="self-center p-3">
								<input
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
538
									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
539
540
541
542
543
544
545
546
547
									type="number"
									placeholder={$i18n.t('Enter Chunk Overlap')}
									bind:value={chunkOverlap}
									autocomplete="off"
									min="0"
								/>
							</div>
						</div>
					</div>
548

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
549
					<div class="pr-2">
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
550
551
552
553
554
555
556
557
558
559
560
						<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>
561
562
563
					</div>
				</div>

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

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
566
567
568
569
570
571
572
573
574
				<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
575
									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
576
577
578
579
580
581
582
583
584
									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
585

586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
					<div class=" flex">
						<div class="  flex w-full justify-between">
							<div class="self-center text-xs font-medium flex-1">
								{$i18n.t('Relevance Threshold')}
							</div>

							<div class="self-center p-3">
								<input
									class=" w-full rounded-lg py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
									type="number"
									step="0.01"
									placeholder={$i18n.t('Enter Relevance Threshold')}
									bind:value={querySettings.r}
									autocomplete="off"
									min="0.0"
								/>
							</div>
						</div>
					</div>

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
606
607
608
609
					<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
610
							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
611
							rows="4"
Timothy J. Baek's avatar
Timothy J. Baek committed
612
						/>
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
613
					</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
614
615
				</div>

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

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
				{#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
636

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
						<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
686
					<button
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
687
						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
688
						on:click={() => {
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
689
							showResetConfirm = true;
Timothy J. Baek's avatar
Timothy J. Baek committed
690
691
						}}
					>
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
						<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
707
					</button>
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
708
				{/if}
Timothy J. Baek's avatar
Timothy J. Baek committed
709
			</div>
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
710
		</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
711
	</div>
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
712
713
714
715
716
717
718
719
	<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>
720
</form>