WebSearch.svelte 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. <script lang="ts">
  2. import { getRAGConfig, updateRAGConfig } from '$lib/apis/rag';
  3. import Switch from '$lib/components/common/Switch.svelte';
  4. import { documents, models } from '$lib/stores';
  5. import { onMount, getContext } from 'svelte';
  6. import { toast } from 'svelte-sonner';
  7. import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
  8. const i18n = getContext('i18n');
  9. export let saveHandler: Function;
  10. let webConfig = null;
  11. let webSearchEngines = [
  12. 'searxng',
  13. 'google_pse',
  14. 'brave',
  15. 'serpstack',
  16. 'serper',
  17. 'serply',
  18. 'duckduckgo',
  19. 'tavily',
  20. 'jina'
  21. ];
  22. let youtubeLanguage = 'en';
  23. let youtubeTranslation = null;
  24. const submitHandler = async () => {
  25. const res = await updateRAGConfig(localStorage.token, {
  26. web: webConfig,
  27. youtube: {
  28. language: youtubeLanguage.split(',').map((lang) => lang.trim()),
  29. translation: youtubeTranslation
  30. }
  31. });
  32. };
  33. onMount(async () => {
  34. const res = await getRAGConfig(localStorage.token);
  35. if (res) {
  36. webConfig = res.web;
  37. youtubeLanguage = res.youtube.language.join(',');
  38. youtubeTranslation = res.youtube.translation;
  39. }
  40. });
  41. </script>
  42. <form
  43. class="flex flex-col h-full justify-between space-y-3 text-sm"
  44. on:submit|preventDefault={async () => {
  45. await submitHandler();
  46. saveHandler();
  47. }}
  48. >
  49. <div class=" space-y-3 overflow-y-scroll scrollbar-hidden h-full">
  50. {#if webConfig}
  51. <div>
  52. <div class=" mb-1 text-sm font-medium">
  53. {$i18n.t('Web Search')}
  54. </div>
  55. <div>
  56. <div class=" py-0.5 flex w-full justify-between">
  57. <div class=" self-center text-xs font-medium">
  58. {$i18n.t('Enable Web Search')}
  59. </div>
  60. <Switch bind:state={webConfig.search.enabled} />
  61. </div>
  62. </div>
  63. <div class=" py-0.5 flex w-full justify-between">
  64. <div class=" self-center text-xs font-medium">{$i18n.t('Web Search Engine')}</div>
  65. <div class="flex items-center relative">
  66. <select
  67. class="dark:bg-gray-900 w-fit pr-8 rounded px-2 p-1 text-xs bg-transparent outline-none text-right"
  68. bind:value={webConfig.search.engine}
  69. placeholder={$i18n.t('Select a engine')}
  70. required
  71. >
  72. <option disabled selected value="">{$i18n.t('Select a engine')}</option>
  73. {#each webSearchEngines as engine}
  74. <option value={engine}>{engine}</option>
  75. {/each}
  76. </select>
  77. </div>
  78. </div>
  79. {#if webConfig.search.engine !== ''}
  80. <div class="mt-1.5">
  81. {#if webConfig.search.engine === 'searxng'}
  82. <div>
  83. <div class=" self-center text-xs font-medium mb-1">
  84. {$i18n.t('Searxng Query URL')}
  85. </div>
  86. <div class="flex w-full">
  87. <div class="flex-1">
  88. <input
  89. class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
  90. type="text"
  91. placeholder={$i18n.t('Enter Searxng Query URL')}
  92. bind:value={webConfig.search.searxng_query_url}
  93. autocomplete="off"
  94. />
  95. </div>
  96. </div>
  97. </div>
  98. {:else if webConfig.search.engine === 'google_pse'}
  99. <div>
  100. <div class=" self-center text-xs font-medium mb-1">
  101. {$i18n.t('Google PSE API Key')}
  102. </div>
  103. <SensitiveInput
  104. placeholder={$i18n.t('Enter Google PSE API Key')}
  105. bind:value={webConfig.search.google_pse_api_key}
  106. />
  107. </div>
  108. <div class="mt-1.5">
  109. <div class=" self-center text-xs font-medium mb-1">
  110. {$i18n.t('Google PSE Engine Id')}
  111. </div>
  112. <div class="flex w-full">
  113. <div class="flex-1">
  114. <input
  115. class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
  116. type="text"
  117. placeholder={$i18n.t('Enter Google PSE Engine Id')}
  118. bind:value={webConfig.search.google_pse_engine_id}
  119. autocomplete="off"
  120. />
  121. </div>
  122. </div>
  123. </div>
  124. {:else if webConfig.search.engine === 'brave'}
  125. <div>
  126. <div class=" self-center text-xs font-medium mb-1">
  127. {$i18n.t('Brave Search API Key')}
  128. </div>
  129. <SensitiveInput
  130. placeholder={$i18n.t('Enter Brave Search API Key')}
  131. bind:value={webConfig.search.brave_search_api_key}
  132. />
  133. </div>
  134. {:else if webConfig.search.engine === 'serpstack'}
  135. <div>
  136. <div class=" self-center text-xs font-medium mb-1">
  137. {$i18n.t('Serpstack API Key')}
  138. </div>
  139. <SensitiveInput
  140. placeholder={$i18n.t('Enter Serpstack API Key')}
  141. bind:value={webConfig.search.serpstack_api_key}
  142. />
  143. </div>
  144. {:else if webConfig.search.engine === 'serper'}
  145. <div>
  146. <div class=" self-center text-xs font-medium mb-1">
  147. {$i18n.t('Serper API Key')}
  148. </div>
  149. <SensitiveInput
  150. placeholder={$i18n.t('Enter Serper API Key')}
  151. bind:value={webConfig.search.serper_api_key}
  152. />
  153. </div>
  154. {:else if webConfig.search.engine === 'serply'}
  155. <div>
  156. <div class=" self-center text-xs font-medium mb-1">
  157. {$i18n.t('Serply API Key')}
  158. </div>
  159. <SensitiveInput
  160. placeholder={$i18n.t('Enter Serply API Key')}
  161. bind:value={webConfig.search.serply_api_key}
  162. />
  163. </div>
  164. {:else if webConfig.search.engine === 'tavily'}
  165. <div>
  166. <div class=" self-center text-xs font-medium mb-1">
  167. {$i18n.t('Tavily API Key')}
  168. </div>
  169. <SensitiveInput
  170. placeholder={$i18n.t('Enter Tavily API Key')}
  171. bind:value={webConfig.search.tavily_api_key}
  172. />
  173. </div>
  174. {/if}
  175. </div>
  176. {/if}
  177. {#if webConfig.search.enabled}
  178. <div class="mt-2 flex gap-2 mb-1">
  179. <div class="w-full">
  180. <div class=" self-center text-xs font-medium mb-1">
  181. {$i18n.t('Search Result Count')}
  182. </div>
  183. <input
  184. class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
  185. placeholder={$i18n.t('Search Result Count')}
  186. bind:value={webConfig.search.result_count}
  187. required
  188. />
  189. </div>
  190. <div class="w-full">
  191. <div class=" self-center text-xs font-medium mb-1">
  192. {$i18n.t('Concurrent Requests')}
  193. </div>
  194. <input
  195. class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
  196. placeholder={$i18n.t('Concurrent Requests')}
  197. bind:value={webConfig.search.concurrent_requests}
  198. required
  199. />
  200. </div>
  201. </div>
  202. {/if}
  203. </div>
  204. <hr class=" dark:border-gray-850 my-2" />
  205. <div>
  206. <div class=" mb-1 text-sm font-medium">
  207. {$i18n.t('Web Loader Settings')}
  208. </div>
  209. <div>
  210. <div class=" py-0.5 flex w-full justify-between">
  211. <div class=" self-center text-xs font-medium">
  212. {$i18n.t('Bypass SSL verification for Websites')}
  213. </div>
  214. <button
  215. class="p-1 px-3 text-xs flex rounded transition"
  216. on:click={() => {
  217. webConfig.ssl_verification = !webConfig.ssl_verification;
  218. submitHandler();
  219. }}
  220. type="button"
  221. >
  222. {#if webConfig.ssl_verification === true}
  223. <span class="ml-2 self-center">{$i18n.t('On')}</span>
  224. {:else}
  225. <span class="ml-2 self-center">{$i18n.t('Off')}</span>
  226. {/if}
  227. </button>
  228. </div>
  229. </div>
  230. <div class=" mt-2 mb-1 text-sm font-medium">
  231. {$i18n.t('Youtube Loader Settings')}
  232. </div>
  233. <div>
  234. <div class=" py-0.5 flex w-full justify-between">
  235. <div class=" w-20 text-xs font-medium self-center">{$i18n.t('Language')}</div>
  236. <div class=" flex-1 self-center">
  237. <input
  238. class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
  239. type="text"
  240. placeholder={$i18n.t('Enter language codes')}
  241. bind:value={youtubeLanguage}
  242. autocomplete="off"
  243. />
  244. </div>
  245. </div>
  246. </div>
  247. </div>
  248. {/if}
  249. </div>
  250. <div class="flex justify-end pt-3 text-sm font-medium">
  251. <button
  252. class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
  253. type="submit"
  254. >
  255. {$i18n.t('Save')}
  256. </button>
  257. </div>
  258. </form>