Browse Source

feat: unified models integration

Timothy J. Baek 11 months ago
parent
commit
468c6398cd

+ 3 - 1
backend/apps/openai/main.py

@@ -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"]

+ 0 - 2
backend/main.py

@@ -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)
 

+ 1 - 1
src/lib/apis/index.ts

@@ -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;

+ 5 - 29
src/lib/components/chat/Chat.svelte

@@ -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}

+ 2 - 8
src/lib/components/chat/Messages.svelte

@@ -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}

+ 35 - 35
src/lib/components/chat/Messages/Placeholder.svelte

@@ -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 it is too large
+ 2 - 0
src/lib/components/chat/Messages/test.json


+ 5 - 7
src/lib/components/chat/ModelSelector.svelte

@@ -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>

+ 15 - 9
src/lib/components/chat/ModelSelector/Selector.svelte

@@ -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.model.ollama?.size
+											? `(${(item.model.ollama?.size / 1024 ** 3).toFixed(1)}GB)`
 											: ''
-									}${item.info.size ? `(${(item.info.size / 1024 ** 3).toFixed(1)}GB)` : ''}`}
+									}`}
 								>
 									<div class="">
 										<svg

Some files were not shown because too many files changed in this diff