Connections.svelte 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <script lang="ts">
  2. import { toast } from 'svelte-sonner';
  3. import { createEventDispatcher, onMount, getContext, tick } from 'svelte';
  4. import { getModels as _getModels } from '$lib/apis';
  5. const dispatch = createEventDispatcher();
  6. const i18n = getContext('i18n');
  7. import { models, settings, user } from '$lib/stores';
  8. import Switch from '$lib/components/common/Switch.svelte';
  9. import Spinner from '$lib/components/common/Spinner.svelte';
  10. import Tooltip from '$lib/components/common/Tooltip.svelte';
  11. import Plus from '$lib/components/icons/Plus.svelte';
  12. import Connection from './Connections/Connection.svelte';
  13. import AddConnectionModal from '$lib/components/AddConnectionModal.svelte';
  14. export let saveSettings: Function;
  15. let config = null;
  16. let showConnectionModal = false;
  17. const addConnectionHandler = async (connection) => {
  18. config.OPENAI_API_BASE_URLS.push(connection.url);
  19. config.OPENAI_API_KEYS.push(connection.key);
  20. config.OPENAI_API_CONFIGS[config.OPENAI_API_BASE_URLS.length - 1] = connection.config;
  21. await updateHandler();
  22. };
  23. const updateHandler = async () => {
  24. // Remove trailing slashes
  25. config.OPENAI_API_BASE_URLS = config.OPENAI_API_BASE_URLS.map((url) => url.replace(/\/$/, ''));
  26. // Check if API KEYS length is same than API URLS length
  27. if (config.OPENAI_API_KEYS.length !== config.OPENAI_API_BASE_URLS.length) {
  28. // if there are more keys than urls, remove the extra keys
  29. if (config.OPENAI_API_KEYS.length > config.OPENAI_API_BASE_URLS.length) {
  30. config.OPENAI_API_KEYS = config.OPENAI_API_KEYS.slice(
  31. 0,
  32. config.OPENAI_API_BASE_URLS.length
  33. );
  34. }
  35. // if there are more urls than keys, add empty keys
  36. if (config.OPENAI_API_KEYS.length < config.OPENAI_API_BASE_URLS.length) {
  37. const diff = config.OPENAI_API_BASE_URLS.length - config.OPENAI_API_KEYS.length;
  38. for (let i = 0; i < diff; i++) {
  39. config.OPENAI_API_KEYS.push('');
  40. }
  41. }
  42. }
  43. await saveSettings({
  44. directConnections: config
  45. });
  46. };
  47. onMount(async () => {
  48. config = $settings?.directConnections ?? {
  49. OPENAI_API_BASE_URLS: [],
  50. OPENAI_API_KEYS: [],
  51. OPENAI_API_CONFIGS: {}
  52. };
  53. });
  54. </script>
  55. <AddConnectionModal direct bind:show={showConnectionModal} onSubmit={addConnectionHandler} />
  56. <form
  57. class="flex flex-col h-full justify-between text-sm"
  58. on:submit|preventDefault={() => {
  59. updateHandler();
  60. }}
  61. >
  62. <div class=" overflow-y-scroll scrollbar-hidden h-full">
  63. {#if config !== null}
  64. <div class="">
  65. <div class="pr-1.5">
  66. <div class="">
  67. <div class="flex justify-between items-center mb-0.5">
  68. <div class="font-medium">{$i18n.t('Manage Direct Connections')}</div>
  69. <Tooltip content={$i18n.t(`Add Connection`)}>
  70. <button
  71. class="px-1"
  72. on:click={() => {
  73. showConnectionModal = true;
  74. }}
  75. type="button"
  76. >
  77. <Plus />
  78. </button>
  79. </Tooltip>
  80. </div>
  81. <div class="flex flex-col gap-1.5">
  82. {#each config?.OPENAI_API_BASE_URLS ?? [] as url, idx}
  83. <Connection
  84. bind:url
  85. bind:key={config.OPENAI_API_KEYS[idx]}
  86. bind:config={config.OPENAI_API_CONFIGS[idx]}
  87. onSubmit={() => {
  88. updateHandler();
  89. }}
  90. onDelete={() => {
  91. config.OPENAI_API_BASE_URLS = config.OPENAI_API_BASE_URLS.filter(
  92. (url, urlIdx) => idx !== urlIdx
  93. );
  94. config.OPENAI_API_KEYS = config.OPENAI_API_KEYS.filter(
  95. (key, keyIdx) => idx !== keyIdx
  96. );
  97. let newConfig = {};
  98. config.OPENAI_API_BASE_URLS.forEach((url, newIdx) => {
  99. newConfig[newIdx] =
  100. config.OPENAI_API_CONFIGS[newIdx < idx ? newIdx : newIdx + 1];
  101. });
  102. config.OPENAI_API_CONFIGS = newConfig;
  103. }}
  104. />
  105. {/each}
  106. </div>
  107. </div>
  108. <div class="my-1.5">
  109. <div class="text-xs text-gray-500">
  110. {$i18n.t('Connect to your own OpenAI compatible API endpoints.')}
  111. </div>
  112. </div>
  113. </div>
  114. </div>
  115. {:else}
  116. <div class="flex h-full justify-center">
  117. <div class="my-auto">
  118. <Spinner className="size-6" />
  119. </div>
  120. </div>
  121. {/if}
  122. </div>
  123. <div class="flex justify-end pt-3 text-sm font-medium">
  124. <button
  125. class="px-3.5 py-1.5 text-sm font-medium bg-black hover:bg-gray-900 text-white dark:bg-white dark:text-black dark:hover:bg-gray-100 transition rounded-full"
  126. type="submit"
  127. >
  128. {$i18n.t('Save')}
  129. </button>
  130. </div>
  131. </form>