feat: local/external connections

This commit is contained in:
Timothy Jaeryang Baek 2025-05-17 01:47:48 +04:00
parent 000906cd99
commit 08e4c163ea
6 changed files with 74 additions and 33 deletions

View File

@ -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: if tags:
for model in response.get("models", []):
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 = {}

View File

@ -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 ( for model in (
response if isinstance(response, list) else response.get("data", []) 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: if tags:
for model in (
response if isinstance(response, list) else response.get("data", [])
):
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

View File

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

View File

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

View File

@ -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=" mb-2 font-medium flex items-center">
<div class=" text-xs mr-1">{$i18n.t('Set Task Model')}</div> <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}

View File

@ -100,10 +100,10 @@
.filter((item) => { .filter((item) => {
if (selectedConnectionType === '') { if (selectedConnectionType === '') {
return true; return true;
} else if (selectedConnectionType === 'ollama') { } else if (selectedConnectionType === 'local') {
return item.model?.owned_by === 'ollama'; return item.model?.connection_type === 'local';
} else if (selectedConnectionType === 'openai') { } else if (selectedConnectionType === 'external') {
return item.model?.owned_by === 'openai'; 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') { } else if (selectedConnectionType === 'local') {
return item.model?.owned_by === 'ollama'; return item.model?.connection_type === 'local';
} else if (selectedConnectionType === 'openai') { } else if (selectedConnectionType === 'external') {
return item.model?.owned_by === 'openai'; 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')}