浏览代码

feat: local/external connections

Timothy Jaeryang Baek 4 月之前
父节点
当前提交
08e4c163ea

+ 8 - 4
backend/open_webui/routers/ollama.py

@@ -340,6 +340,8 @@ async def get_all_models(request: Request, user: UserModel = None):
                     ),  # Legacy support
                     ),  # Legacy support
                 )
                 )
 
 
+                connection_type = api_config.get("connection_type", "local")
+
                 prefix_id = api_config.get("prefix_id", None)
                 prefix_id = api_config.get("prefix_id", None)
                 tags = api_config.get("tags", [])
                 tags = api_config.get("tags", [])
                 model_ids = api_config.get("model_ids", [])
                 model_ids = api_config.get("model_ids", [])
@@ -352,14 +354,16 @@ async def get_all_models(request: Request, user: UserModel = None):
                         )
                         )
                     )
                     )
 
 
-                if prefix_id:
-                    for model in response.get("models", []):
+                for model in response.get("models", []):
+                    if prefix_id:
                         model["model"] = f"{prefix_id}.{model['model']}"
                         model["model"] = f"{prefix_id}.{model['model']}"
 
 
-                if tags:
-                    for model in response.get("models", []):
+                    if tags:
                         model["tags"] = tags
                         model["tags"] = tags
 
 
+                    if connection_type:
+                        model["connection_type"] = connection_type
+
         def merge_models_lists(model_lists):
         def merge_models_lists(model_lists):
             merged_models = {}
             merged_models = {}
 
 

+ 10 - 8
backend/open_webui/routers/openai.py

@@ -353,21 +353,22 @@ async def get_all_models_responses(request: Request, user: UserModel) -> list:
                 ),  # Legacy support
                 ),  # Legacy support
             )
             )
 
 
+            connection_type = api_config.get("connection_type", "external")
             prefix_id = api_config.get("prefix_id", None)
             prefix_id = api_config.get("prefix_id", None)
             tags = api_config.get("tags", [])
             tags = api_config.get("tags", [])
 
 
-            if prefix_id:
-                for model in (
-                    response if isinstance(response, list) else response.get("data", [])
-                ):
+            for model in (
+                response if isinstance(response, list) else response.get("data", [])
+            ):
+                if prefix_id:
                     model["id"] = f"{prefix_id}.{model['id']}"
                     model["id"] = f"{prefix_id}.{model['id']}"
 
 
-            if tags:
-                for model in (
-                    response if isinstance(response, list) else response.get("data", [])
-                ):
+                if tags:
                     model["tags"] = tags
                     model["tags"] = tags
 
 
+                if connection_type:
+                    model["connection_type"] = connection_type
+
     log.debug(f"get_all_models:responses() {responses}")
     log.debug(f"get_all_models:responses() {responses}")
     return responses
     return responses
 
 
@@ -415,6 +416,7 @@ async def get_all_models(request: Request, user: UserModel) -> dict[str, list]:
                             "name": model.get("name", model["id"]),
                             "name": model.get("name", model["id"]),
                             "owned_by": "openai",
                             "owned_by": "openai",
                             "openai": model,
                             "openai": model,
+                            "connection_type": model.get("connection_type", "external"),
                             "urlIdx": idx,
                             "urlIdx": idx,
                         }
                         }
                         for model in models
                         for model in models

+ 1 - 0
backend/open_webui/utils/models.py

@@ -49,6 +49,7 @@ async def get_all_base_models(request: Request, user: UserModel = None):
                 "created": int(time.time()),
                 "created": int(time.time()),
                 "owned_by": "ollama",
                 "owned_by": "ollama",
                 "ollama": model,
                 "ollama": model,
+                "connection_type": model.get("connection_type", "local"),
                 "tags": model.get("tags", []),
                 "tags": model.get("tags", []),
             }
             }
             for model in ollama_models["models"]
             for model in ollama_models["models"]

+ 36 - 2
src/lib/components/AddConnectionModal.svelte

@@ -30,6 +30,9 @@
 	let url = '';
 	let url = '';
 	let key = '';
 	let key = '';
 
 
+	let connectionType = 'external';
+	let azure = false;
+
 	let prefixId = '';
 	let prefixId = '';
 	let enable = true;
 	let enable = true;
 	let tags = [];
 	let tags = [];
@@ -95,7 +98,9 @@
 				enable: enable,
 				enable: enable,
 				tags: tags,
 				tags: tags,
 				prefix_id: prefixId,
 				prefix_id: prefixId,
-				model_ids: modelIds
+				model_ids: modelIds,
+				connection_type: connectionType,
+				...(!ollama && azure ? { azure: true } : {})
 			}
 			}
 		};
 		};
 
 
@@ -120,6 +125,13 @@
 			tags = connection.config?.tags ?? [];
 			tags = connection.config?.tags ?? [];
 			prefixId = connection.config?.prefix_id ?? '';
 			prefixId = connection.config?.prefix_id ?? '';
 			modelIds = connection.config?.model_ids ?? [];
 			modelIds = connection.config?.model_ids ?? [];
+
+			if (ollama) {
+				connectionType = connection.config?.connection_type ?? 'local';
+			} else {
+				connectionType = connection.config?.connection_type ?? 'external';
+				azure = connection.config?.azure ?? false;
+			}
 		}
 		}
 	};
 	};
 
 
@@ -134,7 +146,7 @@
 
 
 <Modal size="sm" bind:show>
 <Modal size="sm" bind:show>
 	<div>
 	<div>
-		<div class=" flex justify-between dark:text-gray-100 px-5 pt-4 pb-2">
+		<div class=" flex justify-between dark:text-gray-100 px-5 pt-4 pb-1.5">
 			<div class=" text-lg font-medium self-center font-primary">
 			<div class=" text-lg font-medium self-center font-primary">
 				{#if edit}
 				{#if edit}
 					{$i18n.t('Edit Connection')}
 					{$i18n.t('Edit Connection')}
@@ -172,6 +184,28 @@
 				>
 				>
 					<div class="px-1">
 					<div class="px-1">
 						<div class="flex gap-2">
 						<div class="flex gap-2">
+							<div class="flex w-full justify-between items-center">
+								<div class=" text-xs text-gray-500">{$i18n.t('Connection Type')}</div>
+
+								<div class="">
+									<button
+										on:click={() => {
+											connectionType = connectionType === 'local' ? 'external' : 'local';
+										}}
+										type="button"
+										class=" text-xs text-gray-700 dark:text-gray-300"
+									>
+										{#if connectionType === 'local'}
+											{$i18n.t('Local')}
+										{:else}
+											{$i18n.t('External')}
+										{/if}
+									</button>
+								</div>
+							</div>
+						</div>
+
+						<div class="flex gap-2 mt-1.5">
 							<div class="flex flex-col w-full">
 							<div class="flex flex-col w-full">
 								<div class=" mb-0.5 text-xs text-gray-500">{$i18n.t('URL')}</div>
 								<div class=" mb-0.5 text-xs text-gray-500">{$i18n.t('URL')}</div>
 
 

+ 5 - 5
src/lib/components/admin/Settings/Interface.svelte

@@ -108,8 +108,8 @@
 
 
 				<hr class=" border-gray-100 dark:border-gray-850 my-2" />
 				<hr class=" border-gray-100 dark:border-gray-850 my-2" />
 
 
-				<div class=" mb-1 font-medium flex items-center">
-					<div class=" text-xs mr-1">{$i18n.t('Set Task Model')}</div>
+				<div class=" mb-2 font-medium flex items-center">
+					<div class=" text-xs mr-1">{$i18n.t('Task Model')}</div>
 					<Tooltip
 					<Tooltip
 						content={$i18n.t(
 						content={$i18n.t(
 							'A task model is used when performing tasks such as generating titles for chats and web search queries'
 							'A task model is used when performing tasks such as generating titles for chats and web search queries'
@@ -134,7 +134,7 @@
 
 
 				<div class=" mb-2.5 flex w-full gap-2">
 				<div class=" mb-2.5 flex w-full gap-2">
 					<div class="flex-1">
 					<div class="flex-1">
-						<div class=" text-xs mb-1">{$i18n.t('Local Models')}</div>
+						<div class=" text-xs mb-1">{$i18n.t('Local Task Model')}</div>
 						<select
 						<select
 							class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
 							class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
 							bind:value={taskConfig.TASK_MODEL}
 							bind:value={taskConfig.TASK_MODEL}
@@ -159,7 +159,7 @@
 							}}
 							}}
 						>
 						>
 							<option value="" selected>{$i18n.t('Current Model')}</option>
 							<option value="" selected>{$i18n.t('Current Model')}</option>
-							{#each models.filter((m) => m.owned_by === 'ollama') as model}
+							{#each models.filter((m) => m.connection_type === 'local') as model}
 								<option value={model.id} class="bg-gray-100 dark:bg-gray-700">
 								<option value={model.id} class="bg-gray-100 dark:bg-gray-700">
 									{model.name}
 									{model.name}
 								</option>
 								</option>
@@ -168,7 +168,7 @@
 					</div>
 					</div>
 
 
 					<div class="flex-1">
 					<div class="flex-1">
-						<div class=" text-xs mb-1">{$i18n.t('External Models')}</div>
+						<div class=" text-xs mb-1">{$i18n.t('External Task Model')}</div>
 						<select
 						<select
 							class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
 							class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
 							bind:value={taskConfig.TASK_MODEL_EXTERNAL}
 							bind:value={taskConfig.TASK_MODEL_EXTERNAL}

+ 14 - 14
src/lib/components/chat/ModelSelector/Selector.svelte

@@ -100,10 +100,10 @@
 					.filter((item) => {
 					.filter((item) => {
 						if (selectedConnectionType === '') {
 						if (selectedConnectionType === '') {
 							return true;
 							return true;
-						} else if (selectedConnectionType === 'ollama') {
-							return item.model?.owned_by === 'ollama';
-						} else if (selectedConnectionType === 'openai') {
-							return item.model?.owned_by === 'openai';
+						} else if (selectedConnectionType === 'local') {
+							return item.model?.connection_type === 'local';
+						} else if (selectedConnectionType === 'external') {
+							return item.model?.connection_type === 'external';
 						} else if (selectedConnectionType === 'direct') {
 						} else if (selectedConnectionType === 'direct') {
 							return item.model?.direct;
 							return item.model?.direct;
 						}
 						}
@@ -118,10 +118,10 @@
 					.filter((item) => {
 					.filter((item) => {
 						if (selectedConnectionType === '') {
 						if (selectedConnectionType === '') {
 							return true;
 							return true;
-						} else if (selectedConnectionType === 'ollama') {
-							return item.model?.owned_by === 'ollama';
-						} else if (selectedConnectionType === 'openai') {
-							return item.model?.owned_by === 'openai';
+						} else if (selectedConnectionType === 'local') {
+							return item.model?.connection_type === 'local';
+						} else if (selectedConnectionType === 'external') {
+							return item.model?.connection_type === 'external';
 						} else if (selectedConnectionType === 'direct') {
 						} else if (selectedConnectionType === 'direct') {
 							return item.model?.direct;
 							return item.model?.direct;
 						}
 						}
@@ -393,7 +393,7 @@
 							class="flex gap-1 w-fit text-center text-sm font-medium rounded-full bg-transparent px-1.5 pb-0.5"
 							class="flex gap-1 w-fit text-center text-sm font-medium rounded-full bg-transparent px-1.5 pb-0.5"
 							bind:this={tagsContainerElement}
 							bind:this={tagsContainerElement}
 						>
 						>
-							{#if (items.find((item) => item.model?.owned_by === 'ollama') && items.find((item) => item.model?.owned_by === 'openai')) || items.find((item) => item.model?.direct) || tags.length > 0}
+							{#if (items.find((item) => item.model?.connection_type === 'local') && items.find((item) => item.model?.connection_type === 'external')) || items.find((item) => item.model?.direct) || tags.length > 0}
 								<button
 								<button
 									class="min-w-fit outline-none p-1.5 {selectedTag === '' &&
 									class="min-w-fit outline-none p-1.5 {selectedTag === '' &&
 									selectedConnectionType === ''
 									selectedConnectionType === ''
@@ -408,25 +408,25 @@
 								</button>
 								</button>
 							{/if}
 							{/if}
 
 
-							{#if items.find((item) => item.model?.owned_by === 'ollama') && items.find((item) => item.model?.owned_by === 'openai')}
+							{#if items.find((item) => item.model?.connection_type === 'local') && items.find((item) => item.model?.connection_type === 'external')}
 								<button
 								<button
-									class="min-w-fit outline-none p-1.5 {selectedConnectionType === 'ollama'
+									class="min-w-fit outline-none p-1.5 {selectedConnectionType === 'local'
 										? ''
 										? ''
 										: 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition capitalize"
 										: 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition capitalize"
 									on:click={() => {
 									on:click={() => {
 										selectedTag = '';
 										selectedTag = '';
-										selectedConnectionType = 'ollama';
+										selectedConnectionType = 'local';
 									}}
 									}}
 								>
 								>
 									{$i18n.t('Local')}
 									{$i18n.t('Local')}
 								</button>
 								</button>
 								<button
 								<button
-									class="min-w-fit outline-none p-1.5 {selectedConnectionType === 'openai'
+									class="min-w-fit outline-none p-1.5 {selectedConnectionType === 'external'
 										? ''
 										? ''
 										: 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition capitalize"
 										: 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition capitalize"
 									on:click={() => {
 									on:click={() => {
 										selectedTag = '';
 										selectedTag = '';
-										selectedConnectionType = 'openai';
+										selectedConnectionType = 'external';
 									}}
 									}}
 								>
 								>
 									{$i18n.t('External')}
 									{$i18n.t('External')}