Переглянути джерело

refac: documents settings ui

Timothy Jaeryang Baek 2 місяців тому
батько
коміт
fa91d83ac3
1 змінених файлів з 445 додано та 494 видалено
  1. 445 494
      src/lib/components/admin/Settings/Documents.svelte

+ 445 - 494
src/lib/components/admin/Settings/Documents.svelte

@@ -241,7 +241,6 @@
 	};
 	};
 
 
 	const toggleHybridSearch = async () => {
 	const toggleHybridSearch = async () => {
-		querySettings.hybrid = !querySettings.hybrid;
 		querySettings = await updateQuerySettings(localStorage.token, querySettings);
 		querySettings = await updateQuerySettings(localStorage.token, querySettings);
 	};
 	};
 
 
@@ -313,372 +312,285 @@
 	}}
 	}}
 >
 >
 	<div class=" space-y-2.5 overflow-y-scroll scrollbar-hidden h-full pr-1.5">
 	<div class=" space-y-2.5 overflow-y-scroll scrollbar-hidden h-full pr-1.5">
-		<div class="flex flex-col gap-0.5">
-			<div class=" mb-0.5 text-sm font-medium">{$i18n.t('General Settings')}</div>
-
-			<div class=" flex w-full justify-between">
-				<div class=" self-center text-xs font-medium">{$i18n.t('Embedding Model Engine')}</div>
-				<div class="flex items-center relative">
-					<select
-						class="dark:bg-gray-900 w-fit pr-8 rounded-sm px-2 p-1 text-xs bg-transparent outline-hidden text-right"
-						bind:value={embeddingEngine}
-						placeholder="Select an embedding model engine"
-						on:change={(e) => {
-							if (e.target.value === 'ollama') {
-								embeddingModel = '';
-							} else if (e.target.value === 'openai') {
-								embeddingModel = 'text-embedding-3-small';
-							} else if (e.target.value === '') {
-								embeddingModel = 'sentence-transformers/all-MiniLM-L6-v2';
-							}
-						}}
-					>
-						<option value="">{$i18n.t('Default (SentenceTransformers)')}</option>
-						<option value="ollama">{$i18n.t('Ollama')}</option>
-						<option value="openai">{$i18n.t('OpenAI')}</option>
-					</select>
-				</div>
-			</div>
+		<div class="">
+			<div class="mb-3">
+				<div class=" mb-2.5 text-base font-medium">{$i18n.t('General')}</div>
+
+				<hr class=" border-gray-100 dark:border-gray-850 my-2" />
+
+				<div class="  mb-2.5 flex flex-col w-full justify-between">
+					<div class="flex w-full justify-between">
+						<div class=" self-center text-xs font-medium">{$i18n.t('Embedding Model Engine')}</div>
+						<div class="flex items-center relative">
+							<select
+								class="dark:bg-gray-900 w-fit pr-8 rounded-sm px-2 p-1 text-xs bg-transparent outline-hidden text-right"
+								bind:value={embeddingEngine}
+								placeholder="Select an embedding model engine"
+								on:change={(e) => {
+									if (e.target.value === 'ollama') {
+										embeddingModel = '';
+									} else if (e.target.value === 'openai') {
+										embeddingModel = 'text-embedding-3-small';
+									} else if (e.target.value === '') {
+										embeddingModel = 'sentence-transformers/all-MiniLM-L6-v2';
+									}
+								}}
+							>
+								<option value="">{$i18n.t('Default (SentenceTransformers)')}</option>
+								<option value="ollama">{$i18n.t('Ollama')}</option>
+								<option value="openai">{$i18n.t('OpenAI')}</option>
+							</select>
+						</div>
+					</div>
 
 
-			{#if embeddingEngine === 'openai'}
-				<div class="my-0.5 flex gap-2 pr-2">
-					<input
-						class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
-						placeholder={$i18n.t('API Base URL')}
-						bind:value={OpenAIUrl}
-						required
-					/>
+					{#if embeddingEngine === 'openai'}
+						<div class="my-0.5 flex gap-2 pr-2">
+							<input
+								class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
+								placeholder={$i18n.t('API Base URL')}
+								bind:value={OpenAIUrl}
+								required
+							/>
 
 
-					<SensitiveInput placeholder={$i18n.t('API Key')} bind:value={OpenAIKey} />
-				</div>
-			{:else if embeddingEngine === 'ollama'}
-				<div class="my-0.5 flex gap-2 pr-2">
-					<input
-						class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
-						placeholder={$i18n.t('API Base URL')}
-						bind:value={OllamaUrl}
-						required
-					/>
-
-					<SensitiveInput
-						placeholder={$i18n.t('API Key')}
-						bind:value={OllamaKey}
-						required={false}
-					/>
-				</div>
-			{/if}
+							<SensitiveInput placeholder={$i18n.t('API Key')} bind:value={OpenAIKey} />
+						</div>
+					{:else if embeddingEngine === 'ollama'}
+						<div class="my-0.5 flex gap-2 pr-2">
+							<input
+								class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
+								placeholder={$i18n.t('API Base URL')}
+								bind:value={OllamaUrl}
+								required
+							/>
 
 
-			{#if embeddingEngine === 'ollama' || embeddingEngine === 'openai'}
-				<div class="flex mt-0.5 space-x-2">
-					<div class=" self-center text-xs font-medium">{$i18n.t('Embedding Batch Size')}</div>
-					<div class=" flex-1">
-						<input
-							id="steps-range"
-							type="range"
-							min="1"
-							max="2048"
-							step="1"
-							bind:value={embeddingBatchSize}
-							class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
-						/>
-					</div>
-					<div class="">
-						<input
-							bind:value={embeddingBatchSize}
-							type="number"
-							class=" bg-transparent text-center w-14"
-							min="-2"
-							max="16000"
-							step="1"
-						/>
-					</div>
-				</div>
-			{/if}
-
-			<div class=" flex w-full justify-between">
-				<div class=" self-center text-xs font-medium">{$i18n.t('Hybrid Search')}</div>
-
-				<button
-					class="p-1 px-3 text-xs flex rounded-sm transition"
-					on:click={() => {
-						toggleHybridSearch();
-					}}
-					type="button"
-				>
-					{#if querySettings.hybrid === true}
-						<span class="ml-2 self-center">{$i18n.t('On')}</span>
-					{:else}
-						<span class="ml-2 self-center">{$i18n.t('Off')}</span>
+							<SensitiveInput
+								placeholder={$i18n.t('API Key')}
+								bind:value={OllamaKey}
+								required={false}
+							/>
+						</div>
 					{/if}
 					{/if}
-				</button>
-			</div>
-
-			<div class=" py-0.5 flex w-full justify-between">
-				<div class=" self-center text-xs font-medium">{$i18n.t('Full Context Mode')}</div>
-				<div class="flex items-center relative">
-					<Tooltip
-						content={RAG_FULL_CONTEXT
-							? 'Inject entire contents as context for comprehensive processing, this is recommended for complex queries.'
-							: 'Default to segmented retrieval for focused and relevant content extraction, this is recommended for most cases.'}
-					>
-						<Switch bind:state={RAG_FULL_CONTEXT} />
-					</Tooltip>
 				</div>
 				</div>
-			</div>
-		</div>
 
 
-		<hr class="border-gray-100 dark:border-gray-850" />
+				<div class="  mb-2.5 flex flex-col w-full">
+					<div class=" mb-1 text-xs font-medium">{$i18n.t('Embedding Model')}</div>
 
 
-		<div class="space-y-2" />
-		<div>
-			<div class=" mb-2 text-sm font-medium">{$i18n.t('Embedding Model')}</div>
+					<div class="">
+						{#if embeddingEngine === 'ollama'}
+							<div class="flex w-full">
+								<div class="flex-1 mr-2">
+									<input
+										class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
+										bind:value={embeddingModel}
+										placeholder={$i18n.t('Set embedding model')}
+										required
+									/>
+								</div>
+							</div>
+						{:else}
+							<div class="flex w-full">
+								<div class="flex-1 mr-2">
+									<input
+										class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
+										placeholder={$i18n.t('Set embedding model (e.g. {{model}})', {
+											model: embeddingModel.slice(-40)
+										})}
+										bind:value={embeddingModel}
+									/>
+								</div>
 
 
-			{#if embeddingEngine === 'ollama'}
-				<div class="flex w-full">
-					<div class="flex-1 mr-2">
-						<input
-							class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
-							bind:value={embeddingModel}
-							placeholder={$i18n.t('Set embedding model')}
-							required
-						/>
-					</div>
-				</div>
-			{:else}
-				<div class="flex w-full">
-					<div class="flex-1 mr-2">
-						<input
-							class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
-							placeholder={$i18n.t('Set embedding model (e.g. {{model}})', {
-								model: embeddingModel.slice(-40)
-							})}
-							bind:value={embeddingModel}
-						/>
+								{#if embeddingEngine === ''}
+									<button
+										class="px-2.5 bg-transparent text-gray-800 dark:bg-transparent 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>
+								{/if}
+							</div>
+						{/if}
 					</div>
 					</div>
 
 
-					{#if embeddingEngine === ''}
-						<button
-							class="px-2.5 bg-gray-50 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>
-					{/if}
+					<div class="mt-1 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>
 				</div>
 				</div>
-			{/if}
-
-			<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>
 
 
-			{#if querySettings.hybrid === true}
-				<div class=" ">
-					<div class=" mb-2 text-sm font-medium">{$i18n.t('Reranking Model')}</div>
+				{#if embeddingEngine === 'ollama' || embeddingEngine === 'openai'}
+					<div class="  mb-2.5 flex w-full justify-between">
+						<div class=" self-center text-xs font-medium">{$i18n.t('Embedding Batch Size')}</div>
 
 
-					<div class="flex w-full">
-						<div class="flex-1 mr-2">
+						<div class="">
 							<input
 							<input
-								class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
-								placeholder={$i18n.t('Set reranking model (e.g. {{model}})', {
-									model: 'BAAI/bge-reranker-v2-m3'
-								})}
-								bind:value={rerankingModel}
+								bind:value={embeddingBatchSize}
+								type="number"
+								class=" bg-transparent text-center w-14 outline-none"
+								min="-2"
+								max="16000"
+								step="1"
 							/>
 							/>
 						</div>
 						</div>
-						<button
-							class="px-2.5 bg-gray-50 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>
-				</div>
-			{/if}
-		</div>
-
-		<hr class=" border-gray-100 dark:border-gray-850" />
+				{/if}
 
 
-		<div class="">
-			<div class="text-sm font-medium mb-1">{$i18n.t('Content Extraction')}</div>
-
-			<div class="flex w-full justify-between">
-				<div class="self-center text-xs font-medium">{$i18n.t('Engine')}</div>
-				<div class="flex items-center relative">
-					<select
-						class="dark:bg-gray-900 w-fit pr-8 rounded-sm px-2 text-xs bg-transparent outline-hidden text-right"
-						bind:value={contentExtractionEngine}
-						on:change={(e) => {
-							showTikaServerUrl = e.target.value === 'tika';
-							showDocumentIntelligenceConfig = e.target.value === 'document_intelligence';
-						}}
-					>
-						<option value="">{$i18n.t('Default')} </option>
-						<option value="tika">{$i18n.t('Tika')}</option>
-						<option value="document_intelligence">{$i18n.t('Document Intelligence')}</option>
-					</select>
+				<div class="  mb-2.5 flex w-full justify-between">
+					<div class=" self-center text-xs font-medium">{$i18n.t('Full Context Mode')}</div>
+					<div class="flex items-center relative">
+						<Tooltip
+							content={RAG_FULL_CONTEXT
+								? 'Inject entire contents as context for comprehensive processing, this is recommended for complex queries.'
+								: 'Default to segmented retrieval for focused and relevant content extraction, this is recommended for most cases.'}
+						>
+							<Switch bind:state={RAG_FULL_CONTEXT} />
+						</Tooltip>
+					</div>
 				</div>
 				</div>
-			</div>
 
 
-			{#if showTikaServerUrl}
-				<div class="flex w-full mt-1">
-					<div class="flex-1 mr-2">
-						<input
-							class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
-							placeholder={$i18n.t('Enter Tika Server URL')}
-							bind:value={tikaServerUrl}
+				<div class="  mb-2.5 flex w-full justify-between">
+					<div class=" self-center text-xs font-medium">{$i18n.t('Hybrid Search')}</div>
+					<div class="flex items-center relative">
+						<Switch
+							bind:state={querySettings.hybrid}
+							on:change={() => {
+								toggleHybridSearch();
+							}}
 						/>
 						/>
 					</div>
 					</div>
 				</div>
 				</div>
-			{/if}
-
-			{#if showDocumentIntelligenceConfig}
-				<div class="my-0.5 flex gap-2 pr-2">
-					<input
-						class="flex-1 w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-none"
-						placeholder={$i18n.t('Enter Document Intelligence Endpoint')}
-						bind:value={documentIntelligenceEndpoint}
-					/>
-
-					<SensitiveInput
-						placeholder={$i18n.t('Enter Document Intelligence Key')}
-						bind:value={documentIntelligenceKey}
-					/>
-				</div>
-			{/if}
-		</div>
-
-		<hr class=" border-gray-100 dark:border-gray-850" />
-
-		<div class="text-sm font-medium mb-1">{$i18n.t('Google Drive')}</div>
-
-		<div class="">
-			<div class="flex justify-between items-center text-xs">
-				<div class="text-xs font-medium">{$i18n.t('Enable Google Drive')}</div>
-				<div>
-					<Switch bind:state={enableGoogleDriveIntegration} />
-				</div>
-			</div>
-		</div>
-
-		<div class="text-sm font-medium mb-1">{$i18n.t('OneDrive')}</div>
 
 
-		<div class="">
-			<div class="flex justify-between items-center text-xs">
-				<div class="text-xs font-medium">{$i18n.t('Enable OneDrive')}</div>
-				<div>
-					<Switch bind:state={enableOneDriveIntegration} />
-				</div>
+				{#if querySettings.hybrid === true}
+					<div class="  mb-2.5 flex flex-col w-full">
+						<div class=" mb-1 text-xs font-medium">{$i18n.t('Reranking Model')}</div>
+
+						<div class="">
+							<div class="flex w-full">
+								<div class="flex-1 mr-2">
+									<input
+										class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
+										placeholder={$i18n.t('Set reranking model (e.g. {{model}})', {
+											model: 'BAAI/bge-reranker-v2-m3'
+										})}
+										bind:value={rerankingModel}
+									/>
+								</div>
+								<button
+									class="px-2.5 bg-transparent text-gray-800 dark:bg-transparent 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>
+					</div>
+				{/if}
 			</div>
 			</div>
-		</div>
 
 
-		<hr class=" border-gray-100 dark:border-gray-850" />
+			<div class="mb-3">
+				<div class=" mb-2.5 text-base font-medium">{$i18n.t('Query')}</div>
 
 
-		<div class=" ">
-			<div class=" text-sm font-medium mb-1">{$i18n.t('Query Params')}</div>
+				<hr class=" border-gray-100 dark:border-gray-850 my-2" />
 
 
-			<div class=" flex gap-1.5">
-				<div class="flex flex-col w-full gap-1">
-					<div class=" text-xs font-medium w-full">{$i18n.t('Top K')}</div>
-
-					<div class="w-full">
+				<div class="  mb-2.5 flex w-full justify-between">
+					<div class=" self-center text-xs font-medium">{$i18n.t('Top K')}</div>
+					<div class="flex items-center relative">
 						<input
 						<input
-							class=" w-full rounded-lg py-1.5 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
+							class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
 							type="number"
 							type="number"
 							placeholder={$i18n.t('Enter Top K')}
 							placeholder={$i18n.t('Enter Top K')}
 							bind:value={querySettings.k}
 							bind:value={querySettings.k}
@@ -689,125 +601,167 @@
 				</div>
 				</div>
 
 
 				{#if querySettings.hybrid === true}
 				{#if querySettings.hybrid === true}
-					<div class=" flex flex-col w-full gap-1">
-						<div class="text-xs font-medium w-full">
-							{$i18n.t('Minimum Score')}
+					<div class="  mb-2.5 flex flex-col w-full justify-between">
+						<div class=" flex w-full justify-between">
+							<div class=" self-center text-xs font-medium">{$i18n.t('Minimum Score')}</div>
+							<div class="flex items-center relative">
+								<input
+									class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
+									type="number"
+									step="0.01"
+									placeholder={$i18n.t('Enter Score')}
+									bind:value={querySettings.r}
+									autocomplete="off"
+									min="0.0"
+									title={$i18n.t('The score should be a value between 0.0 (0%) and 1.0 (100%).')}
+								/>
+							</div>
 						</div>
 						</div>
-
-						<div class="w-full">
-							<input
-								class=" w-full rounded-lg py-1.5 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
-								type="number"
-								step="0.01"
-								placeholder={$i18n.t('Enter Score')}
-								bind:value={querySettings.r}
-								autocomplete="off"
-								min="0.0"
-								title={$i18n.t('The score should be a value between 0.0 (0%) and 1.0 (100%).')}
-							/>
+						<div class="mt-1 text-xs text-gray-400 dark:text-gray-500">
+							{$i18n.t(
+								'Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.'
+							)}
 						</div>
 						</div>
 					</div>
 					</div>
 				{/if}
 				{/if}
-			</div>
 
 
-			{#if querySettings.hybrid === true}
-				<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
-					{$i18n.t(
-						'Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.'
-					)}
+				<div class="  mb-2.5 flex flex-col w-full justify-between">
+					<div class=" mb-1 text-xs font-medium">{$i18n.t('RAG Template')}</div>
+					<div class="flex w-full items-center relative">
+						<Tooltip
+							content={$i18n.t('Leave empty to use the default prompt, or enter a custom prompt')}
+							placement="top-start"
+							className="w-full"
+						>
+							<Textarea
+								bind:value={querySettings.template}
+								placeholder={$i18n.t(
+									'Leave empty to use the default prompt, or enter a custom prompt'
+								)}
+							/>
+						</Tooltip>
+					</div>
 				</div>
 				</div>
-			{/if}
-
-			<div class="mt-2">
-				<div class=" mb-1 text-xs font-medium">{$i18n.t('RAG Template')}</div>
-				<Tooltip
-					content={$i18n.t('Leave empty to use the default prompt, or enter a custom prompt')}
-					placement="top-start"
-				>
-					<Textarea
-						bind:value={querySettings.template}
-						placeholder={$i18n.t('Leave empty to use the default prompt, or enter a custom prompt')}
-					/>
-				</Tooltip>
 			</div>
 			</div>
-		</div>
 
 
-		<hr class=" border-gray-100 dark:border-gray-850" />
-
-		<div class=" ">
-			<div class="mb-1 text-sm font-medium">{$i18n.t('Chunk Params')}</div>
-
-			<div class="flex w-full justify-between mb-1.5">
-				<div class="self-center text-xs font-medium">{$i18n.t('Text Splitter')}</div>
-				<div class="flex items-center relative">
-					<select
-						class="dark:bg-gray-900 w-fit pr-8 rounded-sm px-2 text-xs bg-transparent outline-hidden text-right"
-						bind:value={textSplitter}
-					>
-						<option value="">{$i18n.t('Default')} ({$i18n.t('Character')})</option>
-						<option value="token">{$i18n.t('Token')} ({$i18n.t('Tiktoken')})</option>
-					</select>
-				</div>
-			</div>
+			<div class="mb-3">
+				<div class=" mb-2.5 text-base font-medium">{$i18n.t('Content')}</div>
 
 
-			<div class=" flex gap-1.5">
-				<div class="  w-full justify-between">
-					<div class="self-center text-xs font-medium min-w-fit mb-1">
-						{$i18n.t('Chunk Size')}
-					</div>
-					<div class="self-center">
-						<input
-							class=" w-full rounded-lg py-1.5 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
-							type="number"
-							placeholder={$i18n.t('Enter Chunk Size')}
-							bind:value={chunkSize}
-							autocomplete="off"
-							min="0"
-						/>
+				<hr class=" border-gray-100 dark:border-gray-850 my-2" />
+
+				<div class="  mb-2.5 flex flex-col w-full justify-between">
+					<div class="flex w-full justify-between">
+						<div class=" self-center text-xs font-medium">
+							{$i18n.t('Content Extraction Engine')}
+						</div>
+
+						<div class="">
+							<select
+								class="dark:bg-gray-900 w-fit pr-8 rounded-sm px-2 text-xs bg-transparent outline-hidden text-right"
+								bind:value={contentExtractionEngine}
+								on:change={(e) => {
+									showDocumentIntelligenceConfig = e.target.value === 'document_intelligence';
+								}}
+							>
+								<option value="">{$i18n.t('Default')} </option>
+								<option value="tika">{$i18n.t('Tika')}</option>
+								<option value="document_intelligence">{$i18n.t('Document Intelligence')}</option>
+							</select>
+						</div>
 					</div>
 					</div>
+					{#if contentExtractionEngine === ''}
+						<div class="flex w-full mt-1">
+							<div class="flex w-full justify-between items-center text-xs">
+								<div class=" text-xs font-medium">{$i18n.t('PDF Extract Images (OCR)')}</div>
+
+								<div>
+									<Switch bind:state={pdfExtractImages} />
+								</div>
+							</div>
+						</div>
+					{:else if contentExtractionEngine === 'tika'}
+						<div class="flex w-full mt-1">
+							<div class="flex-1 mr-2">
+								<input
+									class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
+									placeholder={$i18n.t('Enter Tika Server URL')}
+									bind:value={tikaServerUrl}
+								/>
+							</div>
+						</div>
+					{:else if contentExtractionEngine === 'document_intelligence'}
+						<div class="my-0.5 flex gap-2 pr-2">
+							<input
+								class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
+								placeholder={$i18n.t('Enter Document Intelligence Endpoint')}
+								bind:value={documentIntelligenceEndpoint}
+							/>
+
+							<SensitiveInput
+								placeholder={$i18n.t('Enter Document Intelligence Key')}
+								bind:value={documentIntelligenceKey}
+							/>
+						</div>
+					{/if}
 				</div>
 				</div>
 
 
-				<div class="w-full">
-					<div class=" self-center text-xs font-medium min-w-fit mb-1">
-						{$i18n.t('Chunk Overlap')}
+				<div class="  mb-2.5 flex w-full justify-between">
+					<div class=" self-center text-xs font-medium">{$i18n.t('Text Splitter')}</div>
+					<div class="flex items-center relative">
+						<select
+							class="dark:bg-gray-900 w-fit pr-8 rounded-sm px-2 text-xs bg-transparent outline-hidden text-right"
+							bind:value={textSplitter}
+						>
+							<option value="">{$i18n.t('Default')} ({$i18n.t('Character')})</option>
+							<option value="token">{$i18n.t('Token')} ({$i18n.t('Tiktoken')})</option>
+						</select>
 					</div>
 					</div>
+				</div>
 
 
-					<div class="self-center">
-						<input
-							class="w-full rounded-lg py-1.5 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
-							type="number"
-							placeholder={$i18n.t('Enter Chunk Overlap')}
-							bind:value={chunkOverlap}
-							autocomplete="off"
-							min="0"
-						/>
+				<div class=" flex gap-1.5">
+					<div class="  w-full justify-between">
+						<div class="self-center text-xs font-medium min-w-fit mb-1">
+							{$i18n.t('Chunk Size')}
+						</div>
+						<div class="self-center">
+							<input
+								class=" w-full rounded-lg py-1.5 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
+								type="number"
+								placeholder={$i18n.t('Enter Chunk Size')}
+								bind:value={chunkSize}
+								autocomplete="off"
+								min="0"
+							/>
+						</div>
 					</div>
 					</div>
-				</div>
-			</div>
 
 
-			<div class="my-2">
-				<div class="flex justify-between items-center text-xs">
-					<div class=" text-xs font-medium">{$i18n.t('PDF Extract Images (OCR)')}</div>
+					<div class="w-full">
+						<div class=" self-center text-xs font-medium min-w-fit mb-1">
+							{$i18n.t('Chunk Overlap')}
+						</div>
 
 
-					<div>
-						<Switch bind:state={pdfExtractImages} />
+						<div class="self-center">
+							<input
+								class="w-full rounded-lg py-1.5 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
+								type="number"
+								placeholder={$i18n.t('Enter Chunk Overlap')}
+								bind:value={chunkOverlap}
+								autocomplete="off"
+								min="0"
+							/>
+						</div>
 					</div>
 					</div>
 				</div>
 				</div>
 			</div>
 			</div>
-		</div>
-
-		<hr class=" border-gray-100 dark:border-gray-850" />
 
 
-		<div class="">
-			<div class="text-sm font-medium mb-1">{$i18n.t('Files')}</div>
+			<div class="mb-3">
+				<div class=" mb-2.5 text-base font-medium">{$i18n.t('Files')}</div>
 
 
-			<div class=" flex gap-1.5">
-				<div class="w-full">
-					<div class=" self-center text-xs font-medium min-w-fit mb-1">
-						{$i18n.t('Max Upload Size')}
-					</div>
+				<hr class=" border-gray-100 dark:border-gray-850 my-2" />
 
 
-					<div class="self-center">
+				<div class="  mb-2.5 flex w-full justify-between">
+					<div class=" self-center text-xs font-medium">{$i18n.t('Max Upload Size')}</div>
+					<div class="flex items-center relative">
 						<Tooltip
 						<Tooltip
 							content={$i18n.t(
 							content={$i18n.t(
 								'The maximum file size in MB. If the file size exceeds this limit, the file will not be uploaded.'
 								'The maximum file size in MB. If the file size exceeds this limit, the file will not be uploaded.'
@@ -815,7 +769,7 @@
 							placement="top-start"
 							placement="top-start"
 						>
 						>
 							<input
 							<input
-								class="w-full rounded-lg py-1.5 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
+								class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
 								type="number"
 								type="number"
 								placeholder={$i18n.t('Leave empty for unlimited')}
 								placeholder={$i18n.t('Leave empty for unlimited')}
 								bind:value={fileMaxSize}
 								bind:value={fileMaxSize}
@@ -826,11 +780,9 @@
 					</div>
 					</div>
 				</div>
 				</div>
 
 
-				<div class="  w-full">
-					<div class="self-center text-xs font-medium min-w-fit mb-1">
-						{$i18n.t('Max Upload Count')}
-					</div>
-					<div class="self-center">
+				<div class="  mb-2.5 flex w-full justify-between">
+					<div class=" self-center text-xs font-medium">{$i18n.t('Max Upload Count')}</div>
+					<div class="flex items-center relative">
 						<Tooltip
 						<Tooltip
 							content={$i18n.t(
 							content={$i18n.t(
 								'The maximum number of files that can be used at once in chat. If the number of files exceeds this limit, the files will not be uploaded.'
 								'The maximum number of files that can be used at once in chat. If the number of files exceeds this limit, the files will not be uploaded.'
@@ -838,7 +790,7 @@
 							placement="top-start"
 							placement="top-start"
 						>
 						>
 							<input
 							<input
-								class=" w-full rounded-lg py-1.5 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
+								class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
 								type="number"
 								type="number"
 								placeholder={$i18n.t('Leave empty for unlimited')}
 								placeholder={$i18n.t('Leave empty for unlimited')}
 								bind:value={fileMaxCount}
 								bind:value={fileMaxCount}
@@ -849,63 +801,62 @@
 					</div>
 					</div>
 				</div>
 				</div>
 			</div>
 			</div>
-		</div>
 
 
-		<hr class=" border-gray-100 dark:border-gray-850" />
-
-		<div>
-			<button
-				class=" flex rounded-xl py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition"
-				on:click={() => {
-					showResetUploadDirConfirm = true;
-				}}
-				type="button"
-			>
-				<div class=" self-center mr-3">
-					<svg
-						xmlns="http://www.w3.org/2000/svg"
-						viewBox="0 0 24 24"
-						fill="currentColor"
-						class="size-4"
-					>
-						<path
-							fill-rule="evenodd"
-							d="M5.625 1.5H9a3.75 3.75 0 0 1 3.75 3.75v1.875c0 1.036.84 1.875 1.875 1.875H16.5a3.75 3.75 0 0 1 3.75 3.75v7.875c0 1.035-.84 1.875-1.875 1.875H5.625a1.875 1.875 0 0 1-1.875-1.875V3.375c0-1.036.84-1.875 1.875-1.875ZM9.75 14.25a.75.75 0 0 0 0 1.5H15a.75.75 0 0 0 0-1.5H9.75Z"
-							clip-rule="evenodd"
-						/>
-						<path
-							d="M14.25 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 16.5 7.5h-1.875a.375.375 0 0 1-.375-.375V5.25Z"
-						/>
-					</svg>
+			<div class="mb-3">
+				<div class=" mb-2.5 text-base font-medium">{$i18n.t('Integration')}</div>
+
+				<hr class=" border-gray-100 dark:border-gray-850 my-2" />
+
+				<div class="  mb-2.5 flex w-full justify-between">
+					<div class=" self-center text-xs font-medium">{$i18n.t('Google Drive')}</div>
+					<div class="flex items-center relative">
+						<Switch bind:state={enableGoogleDriveIntegration} />
+					</div>
 				</div>
 				</div>
-				<div class=" self-center text-sm font-medium">{$i18n.t('Reset Upload Directory')}</div>
-			</button>
-
-			<button
-				class=" flex rounded-xl py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition"
-				on:click={() => {
-					showResetConfirm = true;
-				}}
-				type="button"
-			>
-				<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 class="  mb-2.5 flex w-full justify-between">
+					<div class=" self-center text-xs font-medium">{$i18n.t('OneDrive')}</div>
+					<div class="flex items-center relative">
+						<Switch bind:state={enableOneDriveIntegration} />
+					</div>
+				</div>
+			</div>
+
+			<div class="mb-3">
+				<div class=" mb-2.5 text-base font-medium">{$i18n.t('Danger Zone')}</div>
+
+				<hr class=" border-gray-100 dark:border-gray-850 my-2" />
+
+				<div class="  mb-2.5 flex w-full justify-between">
+					<div class=" self-center text-xs font-medium">{$i18n.t('Reset Upload Directory')}</div>
+					<div class="flex items-center relative">
+						<button
+							class="text-xs"
+							on:click={() => {
+								showResetUploadDirConfirm = true;
+							}}
+						>
+							{$i18n.t('Reset')}
+						</button>
+					</div>
 				</div>
 				</div>
-				<div class=" self-center text-sm font-medium">
-					{$i18n.t('Reset Vector Storage/Knowledge')}
+
+				<div class="  mb-2.5 flex w-full justify-between">
+					<div class=" self-center text-xs font-medium">
+						{$i18n.t('Reset Vector Storage/Knowledge')}
+					</div>
+					<div class="flex items-center relative">
+						<button
+							class="text-xs"
+							on:click={() => {
+								showResetConfirm = true;
+							}}
+						>
+							{$i18n.t('Reset')}
+						</button>
+					</div>
 				</div>
 				</div>
-			</button>
+			</div>
 		</div>
 		</div>
 	</div>
 	</div>
 	<div class="flex justify-end pt-3 text-sm font-medium">
 	<div class="flex justify-end pt-3 text-sm font-medium">