Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
chenpangpang
open-webui
Commits
2e24c2d4
Commit
2e24c2d4
authored
Jun 02, 2024
by
Timothy J. Baek
Browse files
refac
parent
41442897
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
415 additions
and
391 deletions
+415
-391
src/lib/components/chat/Settings/Models.svelte
src/lib/components/chat/Settings/Models.svelte
+415
-391
No files found.
src/lib/components/chat/Settings/Models.svelte
View file @
2e24c2d4
...
@@ -9,7 +9,8 @@
...
@@ -9,7 +9,8 @@
getOllamaVersion,
getOllamaVersion,
pullModel,
pullModel,
cancelOllamaRequest,
cancelOllamaRequest,
uploadModel
uploadModel,
getOllamaConfig
} from '$lib/apis/ollama';
} from '$lib/apis/ollama';
import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants';
import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants';
...
@@ -28,6 +29,8 @@
...
@@ -28,6 +29,8 @@
// Models
// Models
let ollamaEnabled = null;
let OLLAMA_URLS = [];
let OLLAMA_URLS = [];
let selectedOllamaUrlIdx: string | null = null;
let selectedOllamaUrlIdx: string | null = null;
...
@@ -431,53 +434,138 @@
...
@@ -431,53 +434,138 @@
};
};
onMount(async () => {
onMount(async () => {
await Promise.all([
const ollamaConfig = await getOllamaConfig(localStorage.token);
(async () => {
OLLAMA_URLS = await getOllamaUrls(localStorage.token).catch((error) => {
toast.error(error);
return [];
});
if (OLLAMA_URLS.length > 0) {
if (ollamaConfig.ENABLE_OLLAMA_API) {
selectedOllamaUrlIdx = 0;
ollamaEnabled = true;
}
})(),
await Promise.all([
(async () => {
(async () => {
ollamaVersion = await getOllamaVersion(localStorage.token).catch((error) => false);
OLLAMA_URLS = await getOllamaUrls(localStorage.token).catch((error) => {
})()
toast.error(error);
]);
return [];
});
if (OLLAMA_URLS.length > 0) {
selectedOllamaUrlIdx = 0;
}
})(),
(async () => {
ollamaVersion = await getOllamaVersion(localStorage.token).catch((error) => false);
})()
]);
} else {
ollamaEnabled = false;
toast.error('Ollama API is disabled');
}
});
});
</script>
</script>
<div class="flex flex-col h-full justify-between text-sm">
<div class="flex flex-col h-full justify-between text-sm">
<div class=" space-y-3 pr-1.5 overflow-y-scroll h-[24rem]">
<div class=" space-y-3 pr-1.5 overflow-y-scroll h-[24rem]">
{#if ollamaVersion !== null}
{#if ollamaEnabled}
<div class="space-y-2 pr-1.5">
{#if ollamaVersion !== null}
<div class="text-sm font-medium">{$i18n.t('Manage Ollama Models')}</div>
<div class="space-y-2 pr-1.5">
<div class="text-sm font-medium">{$i18n.t('Manage Ollama Models')}</div>
{#if OLLAMA_URLS.length > 0}
<div class="flex gap-2">
{#if OLLAMA_URLS.length > 0}
<div class="flex-1 pb-1">
<div class="flex gap-2">
<select
<div class="flex-1 pb-1">
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
<select
bind:value={selectedOllamaUrlIdx}
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
placeholder={$i18n.t('Select an Ollama instance')}
bind:value={selectedOllamaUrlIdx}
>
placeholder={$i18n.t('Select an Ollama instance')}
{#each OLLAMA_URLS as url, idx}
>
<option value={idx} class="bg-gray-100 dark:bg-gray-700">{url}</option>
{#each OLLAMA_URLS as url, idx}
{/each}
<option value={idx} class="bg-gray-100 dark:bg-gray-700">{url}</option>
</select>
{/each}
</select>
</div>
<div>
<div class="flex w-full justify-end">
<Tooltip content="Update All Models" placement="top">
<button
class="p-2.5 flex gap-2 items-center 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={() => {
updateModelsHandler();
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
d="M7 1a.75.75 0 0 1 .75.75V6h-1.5V1.75A.75.75 0 0 1 7 1ZM6.25 6v2.94L5.03 7.72a.75.75 0 0 0-1.06 1.06l2.5 2.5a.75.75 0 0 0 1.06 0l2.5-2.5a.75.75 0 1 0-1.06-1.06L7.75 8.94V6H10a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2.25Z"
/>
<path
d="M4.268 14A2 2 0 0 0 6 15h6a2 2 0 0 0 2-2v-3a2 2 0 0 0-1-1.732V11a3 3 0 0 1-3 3H4.268Z"
/>
</svg>
</button>
</Tooltip>
</div>
</div>
</div>
</div>
{#if updateModelId}
Updating "{updateModelId}" {updateProgress ? `(${updateProgress}%)` : ''}
{/if}
{/if}
<div class="space-y-2">
<div>
<div>
<div class="flex w-full justify-end">
<div class=" mb-2 text-sm font-medium">{$i18n.t('Pull a model from Ollama.com')}</div>
<Tooltip content="Update All Models" placement="top">
<div class="flex w-full">
<button
<div class="flex-1 mr-2">
class="p-2.5 flex gap-2 items-center 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"
<input
on:click={() => {
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
updateModelsHandler();
placeholder={$i18n.t('Enter model tag (e.g. {{modelTag}})', {
}}
modelTag: 'mistral:7b'
>
})}
bind:value={modelTag}
/>
</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={() => {
pullModelHandler();
}}
disabled={modelTransferring}
>
{#if modelTransferring}
<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
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
viewBox="0 0 16 16"
...
@@ -485,74 +573,111 @@
...
@@ -485,74 +573,111 @@
class="w-4 h-4"
class="w-4 h-4"
>
>
<path
<path
d="M
7 1a.75.75 0 0 1 .75.75V6h-1.5V1.75A.75.75 0 0 1 7 1ZM6.25 6v2.94
L5.03
7.7
2a.75.75 0 0 0-1.06 1.06l
2
.5
2
.5a.75.75 0 0 0 1.06 0l
2
.5-
2
.5a.75.75 0
1
0-1.06-1.06L
7
.75 8.
94V6H10a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h
2.
2
5Z"
d="M
8.75 2.75a.75.75 0 0 0-1.5 0v5.69
L5.03
6.2
2a.75.75 0 0 0-1.06 1.06l
3
.5
3
.5a.75.75 0 0 0 1.06 0l
3
.5-
3
.5a.75.75 0
0
0-1.06-1.06L
8
.75 8.
44V
2.
7
5Z"
/>
/>
<path
<path
d="M
4.268 14A2 2
0 0 0
6
1
5
h6
a2 2 0 0 0 2-2v-3a2 2 0 0 0-1-1.732V11a3 3 0 0 1-3 3H4.268
Z"
d="M
3.5 9.75a.75.75 0 0 0-1.5 0v1.5A2.75 2.75
0 0 0
4.75
1
4
h6
.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.5
Z"
/>
/>
</svg>
</svg>
</button>
{/if}
</
Tooltip
>
</
button
>
</div>
</div>
</div>
</div>
{#if updateModelId}
<div class="mt-2 mb-1 text-xs text-gray-400 dark:text-gray-500">
Updating "{updateModelId}" {updateProgress ? `(${updateProgress}%)` : ''}
{$i18n.t('To access the available model names for downloading,')}
{/if}
<a
{/if}
class=" text-gray-500 dark:text-gray-300 font-medium underline"
href="https://ollama.com/library"
<div class="space-y-2">
target="_blank">{$i18n.t('click here.')}</a
<div>
>
<div class=" mb-2 text-sm font-medium">{$i18n.t('Pull a model from Ollama.com')}</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('Enter model tag (e.g. {{modelTag}})', {
modelTag: 'mistral:7b'
})}
bind:value={modelTag}
/>
</div>
</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"
{#if Object.keys($MODEL_DOWNLOAD_POOL).length > 0}
on:click={() => {
{#each Object.keys($MODEL_DOWNLOAD_POOL) as model}
pullModelHandler();
{#if 'pullProgress' in $MODEL_DOWNLOAD_POOL[model]}
}}
<div class="flex flex-col">
disabled={modelTransferring}
<div class="font-medium mb-1">{model}</div>
>
<div class="">
{#if modelTransferring}
<div class="flex flex-row justify-between space-x-4 pr-2">
<div class="self-center">
<div class=" flex-1">
<svg
<div
class=" w-4 h-4"
class="dark:bg-gray-600 bg-gray-500 text-xs font-medium text-gray-100 text-center p-0.5 leading-none rounded-full"
viewBox="0 0 24 24"
style="width: {Math.max(
fill="currentColor"
15,
xmlns="http://www.w3.org/2000/svg"
$MODEL_DOWNLOAD_POOL[model].pullProgress ?? 0
>
)}%"
<style>
>
.spinner_ajPY {
{$MODEL_DOWNLOAD_POOL[model].pullProgress ?? 0}%
transform-origin: center;
</div>
animation: spinner_AtaB 0.75s infinite linear;
</div>
}
<Tooltip content={$i18n.t('Cancel')}>
@keyframes spinner_AtaB {
<button
100% {
class="text-gray-800 dark:text-gray-100"
transform: rotate(360deg);
on:click={() => {
}
cancelModelPullHandler(model);
}
}}
</style>
>
<path
<svg
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"
class="w-4 h-4 text-gray-800 dark:text-white"
opacity=".25"
aria-hidden="true"
/>
xmlns="http://www.w3.org/2000/svg"
<path
width="24"
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"
height="24"
class="spinner_ajPY"
fill="currentColor"
/>
viewBox="0 0 24 24"
</svg>
>
</div>
<path
{:else}
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18 17.94 6M18 18 6.06 6"
/>
</svg>
</button>
</Tooltip>
</div>
{#if 'digest' in $MODEL_DOWNLOAD_POOL[model]}
<div class="mt-1 text-xs dark:text-gray-500" style="font-size: 0.5rem;">
{$MODEL_DOWNLOAD_POOL[model].digest}
</div>
{/if}
</div>
</div>
{/if}
{/each}
{/if}
</div>
<div>
<div class=" mb-2 text-sm font-medium">{$i18n.t('Delete a model')}</div>
<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={deleteModelTag}
placeholder={$i18n.t('Select a model')}
>
{#if !deleteModelTag}
<option value="" disabled selected>{$i18n.t('Select a model')}</option>
{/if}
{#each $models.filter((m) => !(m?.preset ?? false) && m.owned_by === 'ollama' && (selectedOllamaUrlIdx === null ? true : (m?.ollama?.urls ?? []).includes(selectedOllamaUrlIdx))) as model}
<option value={model.name} class="bg-gray-100 dark:bg-gray-700"
>{model.name +
' (' +
(model.ollama.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={() => {
deleteModelHandler();
}}
>
<svg
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
viewBox="0 0 16 16"
...
@@ -560,330 +685,229 @@
...
@@ -560,330 +685,229 @@
class="w-4 h-4"
class="w-4 h-4"
>
>
<path
<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"
fill-rule="evenodd"
/>
d="M5 3.25V4H2.75a.75.75 0 0 0 0 1.5h.3l.815 8.15A1.5 1.5 0 0 0 5.357 15h5.285a1.5 1.5 0 0 0 1.493-1.35l.815-8.15h.3a.75.75 0 0 0 0-1.5H11v-.75A2.25 2.25 0 0 0 8.75 1h-1.5A2.25 2.25 0 0 0 5 3.25Zm2.25-.75a.75.75 0 0 0-.75.75V4h3v-.75a.75.75 0 0 0-.75-.75h-1.5ZM6.05 6a.75.75 0 0 1 .787.713l.275 5.5a.75.75 0 0 1-1.498.075l-.275-5.5A.75.75 0 0 1 6.05 6Zm3.9 0a.75.75 0 0 1 .712.787l-.275 5.5a.75.75 0 0 1-1.498-.075l.275-5.5a.75.75 0 0 1 .786-.711Z"
<path
clip-rule="evenodd"
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>
</svg>
{/if}
</button>
</button>
</div>
</div>
<div class="mt-2 mb-1 text-xs text-gray-400 dark:text-gray-500">
{$i18n.t('To access the available model names for downloading,')}
<a
class=" text-gray-500 dark:text-gray-300 font-medium underline"
href="https://ollama.com/library"
target="_blank">{$i18n.t('click here.')}</a
>
</div>
</div>
{#if Object.keys($MODEL_DOWNLOAD_POOL).length > 0}
<div class="pt-1">
{#each Object.keys($MODEL_DOWNLOAD_POOL) as model}
<div class="flex justify-between items-center text-xs">
{#if 'pullProgress' in $MODEL_DOWNLOAD_POOL[model]}
<div class=" text-sm font-medium">{$i18n.t('Experimental')}</div>
<div class="flex flex-col">
<button
<div class="font-medium mb-1">{model}</div>
class=" text-xs font-medium text-gray-500"
<div class="">
type="button"
<div class="flex flex-row justify-between space-x-4 pr-2">
on:click={() => {
<div class=" flex-1">
showExperimentalOllama = !showExperimentalOllama;
<div
}}>{showExperimentalOllama ? $i18n.t('Hide') : $i18n.t('Show')}</button
class="dark:bg-gray-600 bg-gray-500 text-xs font-medium text-gray-100 text-center p-0.5 leading-none rounded-full"
style="width: {Math.max(
15,
$MODEL_DOWNLOAD_POOL[model].pullProgress ?? 0
)}%"
>
{$MODEL_DOWNLOAD_POOL[model].pullProgress ?? 0}%
</div>
</div>
<Tooltip content={$i18n.t('Cancel')}>
<button
class="text-gray-800 dark:text-gray-100"
on:click={() => {
cancelModelPullHandler(model);
}}
>
<svg
class="w-4 h-4 text-gray-800 dark:text-white"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
fill="currentColor"
viewBox="0 0 24 24"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18 17.94 6M18 18 6.06 6"
/>
</svg>
</button>
</Tooltip>
</div>
{#if 'digest' in $MODEL_DOWNLOAD_POOL[model]}
<div class="mt-1 text-xs dark:text-gray-500" style="font-size: 0.5rem;">
{$MODEL_DOWNLOAD_POOL[model].digest}
</div>
{/if}
</div>
</div>
{/if}
{/each}
{/if}
</div>
<div>
<div class=" mb-2 text-sm font-medium">{$i18n.t('Delete a model')}</div>
<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={deleteModelTag}
placeholder={$i18n.t('Select a model')}
>
>
{#if !deleteModelTag}
<option value="" disabled selected>{$i18n.t('Select a model')}</option>
{/if}
{#each $models.filter((m) => !(m?.preset ?? false) && m.owned_by === 'ollama' && (selectedOllamaUrlIdx === null ? true : (m?.ollama?.urls ?? []).includes(selectedOllamaUrlIdx))) as model}
<option value={model.name} class="bg-gray-100 dark:bg-gray-700"
>{model.name +
' (' +
(model.ollama.size / 1024 ** 3).toFixed(1) +
' GB)'}</option
>
{/each}
</select>
</div>
</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={() => {
deleteModelHandler();
}}
>
<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="M5 3.25V4H2.75a.75.75 0 0 0 0 1.5h.3l.815 8.15A1.5 1.5 0 0 0 5.357 15h5.285a1.5 1.5 0 0 0 1.493-1.35l.815-8.15h.3a.75.75 0 0 0 0-1.5H11v-.75A2.25 2.25 0 0 0 8.75 1h-1.5A2.25 2.25 0 0 0 5 3.25Zm2.25-.75a.75.75 0 0 0-.75.75V4h3v-.75a.75.75 0 0 0-.75-.75h-1.5ZM6.05 6a.75.75 0 0 1 .787.713l.275 5.5a.75.75 0 0 1-1.498.075l-.275-5.5A.75.75 0 0 1 6.05 6Zm3.9 0a.75.75 0 0 1 .712.787l-.275 5.5a.75.75 0 0 1-1.498-.075l.275-5.5a.75.75 0 0 1 .786-.711Z"
clip-rule="evenodd"
/>
</svg>
</button>
</div>
</div>
</div>
<div class="pt-1">
{#if showExperimentalOllama}
<div class="flex justify-between items-center text-xs">
<form
<div class=" text-sm font-medium">{$i18n.t('Experimental')}</div>
on:submit|preventDefault={() => {
<button
uploadModelHandler();
class=" text-xs font-medium text-gray-500"
}}
type="button"
on:click={() => {
showExperimentalOllama = !showExperimentalOllama;
}}>{showExperimentalOllama ? $i18n.t('Hide') : $i18n.t('Show')}</button
>
>
</div
>
<div class=" mb-2 flex w-full justify-between"
>
</div>
<div class=" text-sm font-medium">{$i18n.t('Upload a GGUF model')}
</div>
{#if showExperimentalOllama}
<button
<form
class="p-1 px-3 text-xs flex rounded transition"
on:submit|preventDefault={() => {
on:click={() => {
uploadModelHandler();
if (modelUploadMode === 'file') {
}}
modelUploadMode = 'url';
>
} else {
<div class=" mb-2 flex w-full justify-between">
modelUploadMode = 'file';
<div class=" text-sm font-medium">{$i18n.t('Upload a GGUF model')}</div>
}
}}
type="button"
>
{#if modelUploadMode === 'file'}
<span class="ml-2 self-center">{$i18n.t('File Mode')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('URL Mode')}</span>
{/if}
</button>
</div>
<
button
<
div class="flex w-full mb-1.5">
class="
p-1 px-3 text-xs flex rounded transition"
<div
class="
flex flex-col w-full">
on:click={() => {
{#if modelUploadMode === 'file'}
if (modelUploadMode === 'file') {
<div
modelUploadMode = 'url';
class="flex-1 {modelInputFile && modelInputFile.length > 0 ? 'mr-2' : ''}"
} else {
>
modelUploadMode = 'file';
<input
}
id="model-upload-input"
}
}
bind:this={modelUploadInputElement
}
type="
button
"
type="
file
"
>
bind:files={modelInputFile}
{#if modelUploadMode === 'file'}
on:change={() => {
<span class="ml-2 self-center">{$i18n.t('File Mode')}</span>
console.log(modelInputFile);
{:else
}
}
}
<span class="ml-2 self-center">{$i18n.t('URL Mode')}</span>
accept=".gguf,.safetensors"
{/if}
required
</button>
hidden
</div
>
/
>
<div class="flex w-full mb-1.5">
<button
<div class="flex flex-col w-full">
type="button"
{#if modelUploadMode === 'file'}
class="w-full rounded-lg text-left py-2 px-4 bg-white dark:text-gray-300 dark:bg-gray-850"
<div class="flex-1 {modelInputFile && modelInputFile.length > 0 ? 'mr-2' : ''}">
on:click={() => {
<input
modelUploadInputElement.click();
id="model-upload-input"
}}
bind:this={modelUploadInputElement}
>
type="file"
{#if modelInputFile && modelInputFile.length > 0}
bind:files={modelInputFile}
{modelInputFile[0].name}
on:change={() => {
{:else}
console.log(modelInputFile);
{$i18n.t('Click here to select')}
}}
{/if}
accept=".gguf,.safetensors"
</button>
required
</div>
hidden
{:else}
/>
<div class="flex-1 {modelFileUrl !== '' ? 'mr-2' : ''}">
<input
class="w-full rounded-lg text-left py-2 px-4 bg-white dark:text-gray-300 dark:bg-gray-850 outline-none {modelFileUrl !==
''
? 'mr-2'
: ''}"
type="url"
required
bind:value={modelFileUrl}
placeholder={$i18n.t('Type Hugging Face Resolve (Download) URL')}
/>
</div>
{/if}
</div>
<button
{#if (modelUploadMode === 'file' && modelInputFile && modelInputFile.length > 0) || (modelUploadMode === 'url' && modelFileUrl !== '')}
type="button"
<button
class="w-full rounded-lg text-left py-2 px-4 bg-white dark:text-gray-300 dark:bg-gray-850"
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 disabled:cursor-not-allowed transition"
on:click={() => {
type="submit"
modelUploadInputElement.click();
disabled={modelTransferring}
}}
>
>
{#if modelTransferring}
{#if modelInputFile && modelInputFile.length > 0}
<div class="self-center">
{modelInputFile[0].name}
<svg
{:else}
class=" w-4 h-4"
{$i18n.t('Click here to select')}
viewBox="0 0 24 24"
{/if}
fill="currentColor"
</button>
xmlns="http://www.w3.org/2000/svg"
</div>
>
{:else}
<style>
<div class="flex-1 {modelFileUrl !== '' ? 'mr-2' : ''}">
.spinner_ajPY {
<input
transform-origin: center;
class="w-full rounded-lg text-left py-2 px-4 bg-white dark:text-gray-300 dark:bg-gray-850 outline-none {modelFileUrl !==
animation: spinner_AtaB 0.75s infinite linear;
''
}
? 'mr-2'
: ''}"
type="url"
required
bind:value={modelFileUrl}
placeholder={$i18n.t('Type Hugging Face Resolve (Download) URL')}
/>
</div>
{/if}
</div>
{#if (modelUploadMode === 'file' && modelInputFile && modelInputFile.length > 0) || (modelUploadMode === 'url' && modelFileUrl !== '')}
@keyframes spinner_AtaB {
<button
100% {
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 disabled:cursor-not-allowed transition"
transform: rotate(360deg);
type="submit"
}
disabled={modelTransferring}
}
>
</style>
{#if modelTransferring}
<path
<div class="self-center">
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
<svg
class=" w-4 h-4"
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
>
<style>
.spinner_ajPY {
transform-origin: center;
animation: spinner_AtaB 0.75s infinite linear;
}
@keyframes spinner_AtaB {
100% {
transform: rotate(360deg);
}
}
</style>
<path
<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"
d="M7.25 10.25a.75.75 0 0 0 1.5 0V4.56l2.22 2.22a.75.75 0 1 0 1.06-1.06l-3.5-3.5a.75.75 0 0 0-1.06 0l-3.5 3.5a.75.75 0 0 0 1.06 1.06l2.22-2.22v5.69Z"
opacity=".25"
/>
/>
<path
<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"
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"
class="spinner_ajPY"
/>
/>
</svg>
</svg>
</div>
{/if}
{:else}
</button>
<svg
{/if}
xmlns="http://www.w3.org/2000/svg"
</div>
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
d="M7.25 10.25a.75.75 0 0 0 1.5 0V4.56l2.22 2.22a.75.75 0 1 0 1.06-1.06l-3.5-3.5a.75.75 0 0 0-1.06 0l-3.5 3.5a.75.75 0 0 0 1.06 1.06l2.22-2.22v5.69Z"
/>
<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 (modelUploadMode === 'file' && modelInputFile && modelInputFile.length > 0) || (modelUploadMode === 'url' && modelFileUrl !== '')}
{#if (modelUploadMode === 'file' && modelInputFile && modelInputFile.length > 0) || (modelUploadMode === 'url' && modelFileUrl !== '')}
<div>
<div>
<div>
<div class=" my-2.5 text-sm font-medium">{$i18n.t('Modelfile Content')}</div>
<div>
<textarea
<div class=" my-2.5 text-sm font-medium">{$i18n.t('Modelfile Content')}</div>
bind:value={modelFileContent}
<textarea
class="w-full rounded-lg py-2 px-4 text-sm bg-gray-100 dark:text-gray-100 dark:bg-gray-850 outline-none resize-none"
bind:value={modelFileContent}
rows="6"
class="w-full rounded-lg py-2 px-4 text-sm bg-gray-100 dark:text-gray-100 dark:bg-gray-850 outline-none resize-none"
/>
rows="6"
/>
</div>
</div>
</div>
{/if}
<div class=" mt-1 text-xs text-gray-400 dark:text-gray-500">
{$i18n.t('To access the GGUF models available for downloading,')}
<a
class=" text-gray-500 dark:text-gray-300 font-medium underline"
href="https://huggingface.co/models?search=gguf"
target="_blank">{$i18n.t('click here.')}</a
>
</div>
</div>
{/if}
<div class=" mt-1 text-xs text-gray-400 dark:text-gray-500">
{$i18n.t('To access the GGUF models available for downloading,')}
<a
class=" text-gray-500 dark:text-gray-300 font-medium underline"
href="https://huggingface.co/models?search=gguf"
target="_blank">{$i18n.t('click here.')}</a
>
</div>
{#if uploadMessage}
{#if uploadMessage}
<div class="mt-2">
<div class="mt-2">
<div class=" mb-2 text-xs">{$i18n.t('Upload Progress')}</div>
<div class=" mb-2 text-xs">{$i18n.t('Upload Progress')}</div>
<div class="w-full rounded-full dark:bg-gray-800">
<div class="w-full rounded-full dark:bg-gray-800">
<div
<div
class="dark:bg-gray-600 bg-gray-500 text-xs font-medium text-gray-100 text-center p-0.5 leading-none rounded-full"
class="dark:bg-gray-600 bg-gray-500 text-xs font-medium text-gray-100 text-center p-0.5 leading-none rounded-full"
style="width: 100%"
style="width: 100%"
>
>
{uploadMessage}
{uploadMessage}
</div>
</div>
</div>
</div>
<div class="mt-1 text-xs dark:text-gray-500" style="font-size: 0.5rem;">
<div class="mt-1 text-xs dark:text-gray-500" style="font-size: 0.5rem;">
{modelFileDigest}
{modelFileDigest}
</div>
</div>
{:else if uploadProgress !== null}
<div class="mt-2">
<div class=" mb-2 text-xs">{$i18n.t('Upload Progress')}</div>
<div class="w-full rounded-full dark:bg-gray-800">
<div
class="dark:bg-gray-600 bg-gray-500 text-xs font-medium text-gray-100 text-center p-0.5 leading-none rounded-full"
style="width: {Math.max(15, uploadProgress ?? 0)}%"
>
{uploadProgress ?? 0}%
</div>
</div>
</div>
</div>
<div class="mt-1 text-xs dark:text-gray-500" style="font-size: 0.5rem;">
{:else if uploadProgress !== null}
{modelFileDigest}
<div class="mt-2">
<div class=" mb-2 text-xs">{$i18n.t('Upload Progress')}</div>
<div class="w-full rounded-full dark:bg-gray-800">
<div
class="dark:bg-gray-600 bg-gray-500 text-xs font-medium text-gray-100 text-center p-0.5 leading-none rounded-full"
style="width: {Math.max(15, uploadProgress ?? 0)}%"
>
{uploadProgress ?? 0}%
</div>
</div>
<div class="mt-1 text-xs dark:text-gray-500" style="font-size: 0.5rem;">
{modelFileDigest}
</div>
</div>
</div>
</div>
{/if}
{/if}
</form>
</form>
{/if}
{/if}
</div>
</div>
</div>
</div>
{:else if ollamaVersion === false}
{:else if ollamaVersion === false}
<div>Ollama Not Detected</div>
<div>Ollama Not Detected</div>
{:else}
<div class="flex h-full justify-center">
<div class="my-auto">
<Spinner className="size-6" />
</div>
</div>
{/if}
{:else if ollamaEnabled === false}
<div>Ollama API is disabled</div>
{:else}
{:else}
<div class="flex h-full justify-center">
<div class="flex h-full justify-center">
<div class="my-auto">
<div class="my-auto">
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment