forked from open-webui/open-webui
feat: modelfile builder linked to api
This commit is contained in:
parent
b391c92036
commit
2fba5ed38e
1 changed files with 100 additions and 22 deletions
|
@ -1,13 +1,24 @@
|
||||||
<script>
|
<script>
|
||||||
import { toast } from 'svelte-french-toast';
|
import { toast } from 'svelte-french-toast';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
import { OLLAMA_API_BASE_URL } from '$lib/constants';
|
||||||
|
import { settings, db, user, config } from '$lib/stores';
|
||||||
|
|
||||||
import Advanced from '$lib/components/chat/Settings/Advanced.svelte';
|
import Advanced from '$lib/components/chat/Settings/Advanced.svelte';
|
||||||
|
import { splitStream } from '$lib/utils';
|
||||||
|
|
||||||
let loading = false;
|
let loading = false;
|
||||||
|
|
||||||
let filesInputElement;
|
let filesInputElement;
|
||||||
let inputFiles;
|
let inputFiles;
|
||||||
let imageUrl = null;
|
let imageUrl = null;
|
||||||
|
let digest = '';
|
||||||
|
let pullProgress = null;
|
||||||
|
let success = false;
|
||||||
|
|
||||||
|
// ///////////
|
||||||
|
// Modelfile
|
||||||
|
// ///////////
|
||||||
|
|
||||||
let title = '';
|
let title = '';
|
||||||
let desc = '';
|
let desc = '';
|
||||||
|
@ -54,8 +65,6 @@ ${options.top_p !== '' ? `PARAMETER top_p ${options.top_p}` : ''}
|
||||||
${options.tfs_z !== '' ? `PARAMETER tfs_z ${options.tfs_z}` : ''}
|
${options.tfs_z !== '' ? `PARAMETER tfs_z ${options.tfs_z}` : ''}
|
||||||
${options.num_ctx !== '' ? `PARAMETER num_ctx ${options.num_ctx}` : ''}
|
${options.num_ctx !== '' ? `PARAMETER num_ctx ${options.num_ctx}` : ''}
|
||||||
SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
|
SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
|
||||||
} else {
|
|
||||||
// content = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let suggestions = [
|
let suggestions = [
|
||||||
|
@ -91,31 +100,75 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
|
||||||
content !== '' &&
|
content !== '' &&
|
||||||
Object.keys(categories).filter((category) => categories[category]).length > 0
|
Object.keys(categories).filter((category) => categories[category]).length > 0
|
||||||
) {
|
) {
|
||||||
const res = await fetch(`/api/create`, {
|
const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/create`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'text/event-stream',
|
||||||
|
...($settings.authHeader && { Authorization: $settings.authHeader }),
|
||||||
|
...($user && { Authorization: `Bearer ${localStorage.token}` })
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
title: title,
|
name: title.replace(/\s+/g, '-').toLowerCase(),
|
||||||
desc: desc,
|
modelfile: content
|
||||||
content: content,
|
|
||||||
imageUrl: imageUrl,
|
|
||||||
categories: Object.keys(categories).filter((category) => categories[category])
|
|
||||||
})
|
})
|
||||||
})
|
});
|
||||||
.then(async (res) => {
|
|
||||||
if (!res.ok) throw await res.json();
|
|
||||||
return res.json();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.log(error);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res?.status ?? false) {
|
if (res) {
|
||||||
toast.success(`Success! Your model file is now available.`);
|
const reader = res.body
|
||||||
await goto(`/models/${res.id}`);
|
.pipeThrough(new TextDecoderStream())
|
||||||
|
.pipeThrough(splitStream('\n'))
|
||||||
|
.getReader();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const { value, done } = await reader.read();
|
||||||
|
if (done) break;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let lines = value.split('\n');
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
if (line !== '') {
|
||||||
|
console.log(line);
|
||||||
|
let data = JSON.parse(line);
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
if (data.error) {
|
||||||
|
throw data.error;
|
||||||
|
}
|
||||||
|
if (data.detail) {
|
||||||
|
throw data.detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.status) {
|
||||||
|
if (
|
||||||
|
!data.digest &&
|
||||||
|
!data.status.includes('writing') &&
|
||||||
|
!data.status.includes('sha256')
|
||||||
|
) {
|
||||||
|
toast.success(data.status);
|
||||||
|
|
||||||
|
if (data.status === 'success') {
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (data.digest) {
|
||||||
|
digest = data.digest;
|
||||||
|
|
||||||
|
if (data.completed) {
|
||||||
|
pullProgress = Math.round((data.completed / data.total) * 1000) / 10;
|
||||||
|
} else {
|
||||||
|
pullProgress = 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
toast.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loading = false;
|
loading = false;
|
||||||
|
@ -331,9 +384,17 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-1 text-xs text-gray-400 dark:text-gray-500">
|
||||||
|
To access the available model names for downloading, <a
|
||||||
|
class=" text-gray-500 dark:text-gray-300 font-medium"
|
||||||
|
href="https://ollama.ai/library"
|
||||||
|
target="_blank">click here.</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="my-2">
|
<div class="my-1">
|
||||||
<div class=" text-xs font-semibold mb-2">System Prompt</div>
|
<div class=" text-xs font-semibold mb-2">System Prompt</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
@ -459,6 +520,23 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{#if pullProgress !== null}
|
||||||
|
<div class="my-2">
|
||||||
|
<div class=" text-sm font-semibold mb-2">Pull Progress</div>
|
||||||
|
<div class="w-full rounded-full dark:bg-gray-800">
|
||||||
|
<div
|
||||||
|
class="dark:bg-gray-600 text-xs font-medium text-blue-100 text-center p-0.5 leading-none rounded-full"
|
||||||
|
style="width: {Math.max(15, pullProgress ?? 0)}%"
|
||||||
|
>
|
||||||
|
{pullProgress ?? 0}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-1 text-xs dark:text-gray-500" style="font-size: 0.5rem;">
|
||||||
|
{digest}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="my-2 flex justify-end">
|
<div class="my-2 flex justify-end">
|
||||||
<button
|
<button
|
||||||
class=" text-sm px-3 py-2 transition rounded-xl {loading
|
class=" text-sm px-3 py-2 transition rounded-xl {loading
|
||||||
|
|
Loading…
Reference in a new issue