feat: unified models integration

This commit is contained in:
Timothy J. Baek 2024-05-24 03:02:56 -07:00
parent e80e4c304a
commit 468c6398cd
9 changed files with 94 additions and 92 deletions

View File

@ -207,7 +207,7 @@ def merge_models_lists(model_lists):
[
{
**model,
"name": model["id"],
"name": model.get("name", model["id"]),
"owned_by": "openai",
"openai": model,
"urlIdx": idx,
@ -319,6 +319,8 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)):
body = body.decode("utf-8")
body = json.loads(body)
print(app.state.MODELS)
model = app.state.MODELS[body.get("model")]
idx = model["urlIdx"]

View File

@ -276,13 +276,11 @@ async def get_models(user=Depends(get_verified_user)):
if app.state.config.ENABLE_OPENAI_API:
openai_models = await get_openai_models()
openai_app.state.MODELS = openai_models
openai_models = openai_models["data"]
if app.state.config.ENABLE_OLLAMA_API:
ollama_models = await get_ollama_models()
ollama_app.state.MODELS = ollama_models
print(ollama_models)

View File

@ -27,7 +27,7 @@ export const getModels = async (token: string = '') => {
let models = res?.data ?? [];
models = models.filter((models) => models).reduce((a, e, i, arr) => a.concat(e), []);
models = models.filter((models) => models).sort((a, b) => (a.name > b.name ? 1 : -1));
console.log(models);
return models;

View File

@ -11,7 +11,6 @@
chats,
config,
type Model,
modelfiles,
models,
settings,
showSidebar,
@ -63,24 +62,6 @@
let selectedModels = [''];
let atSelectedModel: Model | undefined;
let selectedModelfile = null;
$: selectedModelfile =
selectedModels.length === 1 &&
$modelfiles.filter((modelfile) => modelfile.tagName === selectedModels[0]).length > 0
? $modelfiles.filter((modelfile) => modelfile.tagName === selectedModels[0])[0]
: null;
let selectedModelfiles = {};
$: selectedModelfiles = selectedModels.reduce((a, tagName, i, arr) => {
const modelfile =
$modelfiles.filter((modelfile) => modelfile.tagName === tagName)?.at(0) ?? undefined;
return {
...a,
...(modelfile && { [tagName]: modelfile })
};
}, {});
let chat = null;
let tags = [];
@ -345,6 +326,7 @@
const hasImages = messages.some((message) =>
message.files?.some((file) => file.type === 'image')
);
if (hasImages && !(model.custom_info?.meta.vision_capable ?? true)) {
toast.error(
$i18n.t('Model {{modelName}} is not vision capable', {
@ -362,7 +344,7 @@
role: 'assistant',
content: '',
model: model.id,
modelName: model.custom_info?.name ?? model.name ?? model.id,
modelName: model.name ?? model.id,
userContext: null,
timestamp: Math.floor(Date.now() / 1000) // Unix epoch
};
@ -407,7 +389,7 @@
}
responseMessage.userContext = userContext;
if (model?.external) {
if (model?.owned_by === 'openai') {
await sendPromptOpenAI(model, prompt, responseMessageId, _chatId);
} else if (model) {
await sendPromptOllama(model, prompt, responseMessageId, _chatId);
@ -956,10 +938,8 @@
) + ' {{prompt}}',
titleModelId,
userPrompt,
titleModel?.external ?? false
? titleModel?.source?.toLowerCase() === 'litellm'
? `${LITELLM_API_BASE_URL}/v1`
: `${OPENAI_API_BASE_URL}`
titleModel?.owned_by === 'openai' ?? false
? `${OPENAI_API_BASE_URL}`
: `${OLLAMA_API_BASE_URL}/v1`
);
@ -1046,16 +1026,12 @@
<Messages
chatId={$chatId}
{selectedModels}
{selectedModelfiles}
{processing}
bind:history
bind:messages
bind:autoScroll
bind:prompt
bottomPadding={files.length > 0}
suggestionPrompts={chatIdProp
? []
: selectedModelfile?.suggestionPrompts ?? $config.default_prompt_suggestions}
{sendPrompt}
{continueGeneration}
{regenerateResponse}

View File

@ -1,7 +1,7 @@
<script lang="ts">
import { v4 as uuidv4 } from 'uuid';
import { chats, config, modelfiles, settings, user as _user, mobile } from '$lib/stores';
import { chats, config, settings, user as _user, mobile } from '$lib/stores';
import { tick, getContext } from 'svelte';
import { toast } from 'svelte-sonner';
@ -26,7 +26,6 @@
export let user = $_user;
export let prompt;
export let suggestionPrompts = [];
export let processing = '';
export let bottomPadding = false;
export let autoScroll;
@ -34,7 +33,6 @@
export let messages = [];
export let selectedModels;
export let selectedModelfiles = [];
$: if (autoScroll && bottomPadding) {
(async () => {
@ -247,9 +245,7 @@
<div class="h-full flex mb-16">
{#if messages.length == 0}
<Placeholder
models={selectedModels}
modelfiles={selectedModelfiles}
{suggestionPrompts}
modelIds={selectedModels}
submitPrompt={async (p) => {
let text = p;
@ -316,7 +312,6 @@
{#key message.id}
<ResponseMessage
{message}
modelfiles={selectedModelfiles}
siblings={history.messages[message.parentId]?.childrenIds ?? []}
isLastMessage={messageIdx + 1 === messages.length}
{readOnly}
@ -348,7 +343,6 @@
{chatId}
parentMessage={history.messages[message.parentId]}
{messageIdx}
{selectedModelfiles}
{updateChatMessages}
{confirmEditResponseMessage}
{rateMessage}

View File

@ -1,6 +1,6 @@
<script lang="ts">
import { WEBUI_BASE_URL } from '$lib/constants';
import { user } from '$lib/stores';
import { config, user, models as _models } from '$lib/stores';
import { onMount, getContext } from 'svelte';
import { blur, fade } from 'svelte/transition';
@ -9,23 +9,21 @@
const i18n = getContext('i18n');
export let modelIds = [];
export let models = [];
export let modelfiles = [];
export let submitPrompt;
export let suggestionPrompts;
let mounted = false;
let modelfile = null;
let selectedModelIdx = 0;
$: modelfile =
models[selectedModelIdx] in modelfiles ? modelfiles[models[selectedModelIdx]] : null;
$: if (models.length > 0) {
$: if (modelIds.length > 0) {
selectedModelIdx = models.length - 1;
}
$: models = modelIds.map((id) => $_models.find((m) => m.id === id));
onMount(() => {
mounted = true;
});
@ -41,25 +39,14 @@
selectedModelIdx = modelIdx;
}}
>
{#if model in modelfiles}
<img
crossorigin="anonymous"
src={modelfiles[model]?.imageUrl ?? `${WEBUI_BASE_URL}/static/favicon.png`}
alt="modelfile"
class=" size-[2.7rem] rounded-full border-[1px] border-gray-200 dark:border-none"
draggable="false"
/>
{:else}
<img
crossorigin="anonymous"
src={$i18n.language === 'dg-DG'
? `/doge.png`
: `${WEBUI_BASE_URL}/static/favicon.png`}
class=" size-[2.7rem] rounded-full border-[1px] border-gray-200 dark:border-none"
alt="logo"
draggable="false"
/>
{/if}
<img
crossorigin="anonymous"
src={model?.info?.meta?.profile_image_url ??
($i18n.language === 'dg-DG' ? `/doge.png` : `${WEBUI_BASE_URL}/static/favicon.png`)}
class=" size-[2.7rem] rounded-full border-[1px] border-gray-200 dark:border-none"
alt="logo"
draggable="false"
/>
</button>
{/each}
</div>
@ -70,23 +57,32 @@
>
<div>
<div class=" capitalize line-clamp-1" in:fade={{ duration: 200 }}>
{#if modelfile}
{modelfile.title}
{#if models[selectedModelIdx]?.info}
{models[selectedModelIdx]?.info?.name}
{:else}
{$i18n.t('Hello, {{name}}', { name: $user.name })}
{/if}
</div>
<div in:fade={{ duration: 200, delay: 200 }}>
{#if modelfile}
{#if models[selectedModelIdx]?.info}
<div class="mt-0.5 text-base font-normal text-gray-500 dark:text-gray-400">
{modelfile.desc}
{models[selectedModelIdx]?.info?.meta?.description}
</div>
{#if modelfile.user}
{#if models[selectedModelIdx]?.info?.meta?.user}
<div class="mt-0.5 text-sm font-normal text-gray-400 dark:text-gray-500">
By <a href="https://openwebui.com/m/{modelfile.user.username}"
>{modelfile.user.name ? modelfile.user.name : `@${modelfile.user.username}`}</a
>
By
{#if models[selectedModelIdx]?.info?.meta?.user.community}
<a
href="https://openwebui.com/m/{models[selectedModelIdx]?.info?.meta?.user
.username}"
>{models[selectedModelIdx]?.info?.meta?.user.name
? models[selectedModelIdx]?.info?.meta?.user.name
: `@${models[selectedModelIdx]?.info?.meta?.user.username}`}</a
>
{:else}
{models[selectedModelIdx]?.info?.meta?.user.name}
{/if}
</div>
{/if}
{:else}
@ -99,7 +95,11 @@
</div>
<div class=" w-full" in:fade={{ duration: 200, delay: 300 }}>
<Suggestions {suggestionPrompts} {submitPrompt} />
<Suggestions
suggestionPrompts={models[selectedModelIdx]?.info?.meta?.suggestion_prompts ??
$config.default_prompt_suggestions}
{submitPrompt}
/>
</div>
</div>
{/key}

File diff suppressed because one or more lines are too long

View File

@ -45,13 +45,11 @@
<div class="mr-1 max-w-full">
<Selector
placeholder={$i18n.t('Select a model')}
items={$models
.filter((model) => model.name !== 'hr')
.map((model) => ({
value: model.id,
label: model.custom_info?.name ?? model.name,
info: model
}))}
items={$models.map((model) => ({
value: model.id,
label: model.name,
model: model
}))}
bind:value={selectedModel}
/>
</div>

View File

@ -249,15 +249,17 @@
<div class="line-clamp-1">
{item.label}
<span class=" text-xs font-medium text-gray-600 dark:text-gray-400"
>{item.info?.details?.parameter_size ?? ''}</span
>
{#if item.model.owned_by === 'ollama'}
<span class=" text-xs font-medium text-gray-600 dark:text-gray-400"
>{item.model.ollama?.details?.parameter_size ?? ''}</span
>
{/if}
</div>
<!-- {JSON.stringify(item.info)} -->
{#if item.info.external}
<Tooltip content={`${item.info?.source ?? 'External'}`}>
{#if item.model.owned_by === 'openai'}
<Tooltip content={`${'External'}`}>
<div class="">
<svg
xmlns="http://www.w3.org/2000/svg"
@ -278,13 +280,17 @@
</svg>
</div>
</Tooltip>
{:else}
{:else if item.model.owned_by === 'ollama'}
<Tooltip
content={`${
item.info?.details?.quantization_level
? item.info?.details?.quantization_level + ' '
item.model.ollama?.details?.quantization_level
? item.model.ollama?.details?.quantization_level + ' '
: ''
}${item.info.size ? `(${(item.info.size / 1024 ** 3).toFixed(1)}GB)` : ''}`}
}${
item.model.ollama?.size
? `(${(item.model.ollama?.size / 1024 ** 3).toFixed(1)}GB)`
: ''
}`}
>
<div class="">
<svg