forked from open-webui/open-webui
feat: modelfile builder tagName field added
This commit is contained in:
parent
382827c71d
commit
12d7ae96b9
4 changed files with 141 additions and 31 deletions
|
@ -9,5 +9,6 @@ export const db = writable(undefined);
|
|||
export const chatId = writable('');
|
||||
export const chats = writable([]);
|
||||
export const models = writable([]);
|
||||
export const modelfiles = writable([]);
|
||||
export const settings = writable({});
|
||||
export const showSettings = writable(false);
|
||||
|
|
|
@ -4,7 +4,17 @@
|
|||
import { onMount, tick } from 'svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
import { config, user, showSettings, settings, models, db, chats, chatId } from '$lib/stores';
|
||||
import {
|
||||
config,
|
||||
user,
|
||||
showSettings,
|
||||
settings,
|
||||
models,
|
||||
db,
|
||||
chats,
|
||||
chatId,
|
||||
modelfiles
|
||||
} from '$lib/stores';
|
||||
|
||||
import SettingsModal from '$lib/components/chat/SettingsModal.svelte';
|
||||
import Sidebar from '$lib/components/layout/Sidebar.svelte';
|
||||
|
@ -78,7 +88,7 @@
|
|||
};
|
||||
|
||||
const getDB = async () => {
|
||||
const _db = await openDB('Chats', 1, {
|
||||
const DB = await openDB('Chats', 1, {
|
||||
upgrade(db) {
|
||||
const store = db.createObjectStore('chats', {
|
||||
keyPath: 'id',
|
||||
|
@ -89,7 +99,7 @@
|
|||
});
|
||||
|
||||
return {
|
||||
db: _db,
|
||||
db: DB,
|
||||
getChatById: async function (id) {
|
||||
return await this.db.get('chats', id);
|
||||
},
|
||||
|
@ -162,6 +172,14 @@
|
|||
let _db = await getDB();
|
||||
await db.set(_db);
|
||||
|
||||
await modelfiles.set(
|
||||
JSON.parse(localStorage.getItem('modelfiles') ?? JSON.stringify($modelfiles))
|
||||
);
|
||||
|
||||
modelfiles.subscribe(async () => {
|
||||
await models.set(await getModels());
|
||||
});
|
||||
|
||||
await tick();
|
||||
loaded = true;
|
||||
});
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
<script lang="ts">
|
||||
import { modelfiles } from '$lib/stores';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
onMount(() => {});
|
||||
</script>
|
||||
|
||||
<div class="min-h-screen w-full flex justify-center dark:text-white">
|
||||
<div class=" py-2.5 flex flex-col justify-between w-full">
|
||||
<div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10">
|
||||
<div class=" text-2xl font-semibold mb-6">My Modelfiles</div>
|
||||
|
||||
<a class=" flex space-x-3 cursor-pointer w-full mb-3" href="/modelfiles/create">
|
||||
<div class=" self-center">
|
||||
<a class=" flex space-x-4 cursor-pointer w-full mb-3" href="/modelfiles/create">
|
||||
<div class=" self-center w-10">
|
||||
<div
|
||||
class=" p-2 rounded-full bg-transparent dark:bg-gray-700 border border-dashed border-gray-200"
|
||||
class="w-full h-10 flex justify-center rounded-full bg-transparent dark:bg-gray-700 border border-dashed border-gray-200"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -29,12 +36,41 @@
|
|||
</div>
|
||||
</a>
|
||||
|
||||
<!-- <div class=" my-16">
|
||||
<div class=" text-2xl font-semibold mb-6">Made by Community</div>
|
||||
{#each $modelfiles as modelfile}
|
||||
<hr class=" dark:border-gray-700 my-2.5" />
|
||||
<a
|
||||
class=" flex space-x-4 cursor-pointer w-full mb-3"
|
||||
href={`/?models=${modelfile.tagName}`}
|
||||
>
|
||||
<div class=" self-center w-10">
|
||||
<div class=" rounded-full bg-stone-700">
|
||||
<img
|
||||
src={modelfile.imageUrl ?? '/user.png'}
|
||||
alt="modelfile profile"
|
||||
class=" rounded-full w-full h-auto object-cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a class=" flex space-x-3 cursor-pointer w-full mb-3" href="/presets/create">
|
||||
<div class=" self-center">
|
||||
<div class=" p-2 rounded-full bg-gray-700 border border-dashed border-gray-200">
|
||||
<div class=" flex-1 self-center">
|
||||
<div class=" font-bold">{modelfile.title}</div>
|
||||
<div class=" text-sm overflow-hidden text-ellipsis line-clamp-2">{modelfile.desc}</div>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
|
||||
<div class=" my-16">
|
||||
<div class=" text-2xl font-semibold mb-6">Made by OllamaHub Community</div>
|
||||
|
||||
<a
|
||||
class=" flex space-x-4 cursor-pointer w-full mb-3"
|
||||
href="https://ollamahub.com/"
|
||||
target="_blank"
|
||||
>
|
||||
<div class=" self-center w-10">
|
||||
<div
|
||||
class="w-full h-10 flex justify-center rounded-full bg-transparent dark:bg-gray-700 border border-dashed border-gray-200"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
|
@ -51,11 +87,11 @@
|
|||
</div>
|
||||
|
||||
<div class=" self-center">
|
||||
<div class=" font-bold">Create a preset</div>
|
||||
<div class=" text-sm">Customize Ollama models for a specific purpose</div>
|
||||
<div class=" font-bold">Discover a modelfile</div>
|
||||
<div class=" text-sm">Discover, download, and explore Ollama Modelfiles</div>
|
||||
</div>
|
||||
</a>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<script>
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { toast } from 'svelte-french-toast';
|
||||
import { goto } from '$app/navigation';
|
||||
import { OLLAMA_API_BASE_URL } from '$lib/constants';
|
||||
import { settings, db, user, config } from '$lib/stores';
|
||||
import { settings, db, user, config, modelfiles } from '$lib/stores';
|
||||
|
||||
import Advanced from '$lib/components/chat/Settings/Advanced.svelte';
|
||||
import { splitStream } from '$lib/utils';
|
||||
|
@ -21,6 +22,7 @@
|
|||
// ///////////
|
||||
|
||||
let title = '';
|
||||
let tagName = '';
|
||||
let desc = '';
|
||||
|
||||
let raw = true;
|
||||
|
@ -49,6 +51,8 @@
|
|||
num_ctx: ''
|
||||
};
|
||||
|
||||
$: tagName = title !== '' ? `${title.replace(/\s+/g, '-').toLowerCase()}:latest` : '';
|
||||
|
||||
$: if (!raw) {
|
||||
content = `FROM ${model}
|
||||
${template !== '' ? `TEMPLATE """${template}"""` : ''}
|
||||
|
@ -85,6 +89,11 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
|
|||
Business: false
|
||||
};
|
||||
|
||||
const saveModelfile = async (modelfile) => {
|
||||
await modelfiles.set([...$modelfiles, modelfile]);
|
||||
localStorage.setItem('modelfiles', JSON.stringify($modelfiles));
|
||||
};
|
||||
|
||||
const submitHandler = async () => {
|
||||
loading = true;
|
||||
|
||||
|
@ -108,7 +117,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
|
|||
...($user && { Authorization: `Bearer ${localStorage.token}` })
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: title.replace(/\s+/g, '-').toLowerCase(),
|
||||
name: tagName,
|
||||
modelfile: content
|
||||
})
|
||||
});
|
||||
|
@ -170,8 +179,22 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
await saveModelfile({
|
||||
tagName: tagName,
|
||||
imageUrl: imageUrl,
|
||||
title: title,
|
||||
desc: desc,
|
||||
content: content,
|
||||
suggestionPrompts: suggestions.filter((prompt) => prompt.content !== ''),
|
||||
categories: Object.keys(categories).filter((category) => categories[category])
|
||||
});
|
||||
await goto('/modelfiles');
|
||||
}
|
||||
}
|
||||
loading = false;
|
||||
success = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -196,15 +219,32 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
|
|||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// Set canvas dimensions to the original image dimensions
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
// Calculate the aspect ratio of the image
|
||||
const aspectRatio = img.width / img.height;
|
||||
|
||||
// Draw the original image on the canvas
|
||||
ctx.drawImage(img, 0, 0);
|
||||
// Calculate the new width and height to fit within 100x100
|
||||
let newWidth, newHeight;
|
||||
if (aspectRatio > 1) {
|
||||
newWidth = 100 * aspectRatio;
|
||||
newHeight = 100;
|
||||
} else {
|
||||
newWidth = 100;
|
||||
newHeight = 100 / aspectRatio;
|
||||
}
|
||||
|
||||
// Set the canvas size
|
||||
canvas.width = 100;
|
||||
canvas.height = 100;
|
||||
|
||||
// Calculate the position to center the image
|
||||
const offsetX = (100 - newWidth) / 2;
|
||||
const offsetY = (100 - newHeight) / 2;
|
||||
|
||||
// Draw the image on the canvas
|
||||
ctx.drawImage(img, offsetX, offsetY, newWidth, newHeight);
|
||||
|
||||
// Get the base64 representation of the compressed image
|
||||
const compressedSrc = canvas.toDataURL('image/jpeg', 0.1);
|
||||
const compressedSrc = canvas.toDataURL('image/jpeg');
|
||||
|
||||
// Display the compressed image
|
||||
imageUrl = compressedSrc;
|
||||
|
@ -293,7 +333,8 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-2">
|
||||
<div class="my-2 flex space-x-2">
|
||||
<div class="flex-1">
|
||||
<div class=" text-sm font-semibold mb-2">Name*</div>
|
||||
|
||||
<div>
|
||||
|
@ -306,6 +347,20 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1">
|
||||
<div class=" text-sm font-semibold mb-2">Model Tag Name*</div>
|
||||
|
||||
<div>
|
||||
<input
|
||||
class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
|
||||
placeholder="Add a model tag name"
|
||||
bind:value={tagName}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-2">
|
||||
<div class=" text-sm font-semibold mb-2">Description*</div>
|
||||
|
||||
|
|
Loading…
Reference in a new issue