mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-12 20:35:19 +00:00
Compare commits
12 commits
f26d0494ca
...
4c23243ace
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c23243ace | ||
|
|
2b1a29d44b | ||
|
|
f5fbbaf060 | ||
|
|
ba158d378f | ||
|
|
b02397e460 | ||
|
|
bcd50ed8f1 | ||
|
|
8cea0cf746 | ||
|
|
ce945a9334 | ||
|
|
3c8f1cf8e5 | ||
|
|
4d4ed743ae | ||
|
|
aa9c0389c3 | ||
|
|
86f33de9f3 |
17 changed files with 198 additions and 89 deletions
|
|
@ -635,6 +635,7 @@ OAUTH_AUDIENCE = PersistentConfig(
|
||||||
os.environ.get("OAUTH_AUDIENCE", ""),
|
os.environ.get("OAUTH_AUDIENCE", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def load_oauth_providers():
|
def load_oauth_providers():
|
||||||
OAUTH_PROVIDERS.clear()
|
OAUTH_PROVIDERS.clear()
|
||||||
if GOOGLE_CLIENT_ID.value and GOOGLE_CLIENT_SECRET.value:
|
if GOOGLE_CLIENT_ID.value and GOOGLE_CLIENT_SECRET.value:
|
||||||
|
|
@ -2999,6 +3000,12 @@ WEB_LOADER_CONCURRENT_REQUESTS = PersistentConfig(
|
||||||
int(os.getenv("WEB_LOADER_CONCURRENT_REQUESTS", "10")),
|
int(os.getenv("WEB_LOADER_CONCURRENT_REQUESTS", "10")),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
WEB_LOADER_TIMEOUT = PersistentConfig(
|
||||||
|
"WEB_LOADER_TIMEOUT",
|
||||||
|
"rag.web.loader.timeout",
|
||||||
|
os.getenv("WEB_LOADER_TIMEOUT", ""),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
ENABLE_WEB_LOADER_SSL_VERIFICATION = PersistentConfig(
|
ENABLE_WEB_LOADER_SSL_VERIFICATION = PersistentConfig(
|
||||||
"ENABLE_WEB_LOADER_SSL_VERIFICATION",
|
"ENABLE_WEB_LOADER_SSL_VERIFICATION",
|
||||||
|
|
|
||||||
|
|
@ -395,6 +395,13 @@ try:
|
||||||
except ValueError:
|
except ValueError:
|
||||||
REDIS_SENTINEL_MAX_RETRY_COUNT = 2
|
REDIS_SENTINEL_MAX_RETRY_COUNT = 2
|
||||||
|
|
||||||
|
|
||||||
|
REDIS_SOCKET_CONNECT_TIMEOUT = os.environ.get("REDIS_SOCKET_CONNECT_TIMEOUT", "")
|
||||||
|
try:
|
||||||
|
REDIS_SOCKET_CONNECT_TIMEOUT = float(REDIS_SOCKET_CONNECT_TIMEOUT)
|
||||||
|
except ValueError:
|
||||||
|
REDIS_SOCKET_CONNECT_TIMEOUT = None
|
||||||
|
|
||||||
####################################
|
####################################
|
||||||
# UVICORN WORKERS
|
# UVICORN WORKERS
|
||||||
####################################
|
####################################
|
||||||
|
|
@ -620,9 +627,16 @@ ENABLE_WEBSOCKET_SUPPORT = (
|
||||||
WEBSOCKET_MANAGER = os.environ.get("WEBSOCKET_MANAGER", "")
|
WEBSOCKET_MANAGER = os.environ.get("WEBSOCKET_MANAGER", "")
|
||||||
|
|
||||||
WEBSOCKET_REDIS_OPTIONS = os.environ.get("WEBSOCKET_REDIS_OPTIONS", "")
|
WEBSOCKET_REDIS_OPTIONS = os.environ.get("WEBSOCKET_REDIS_OPTIONS", "")
|
||||||
|
|
||||||
|
|
||||||
if WEBSOCKET_REDIS_OPTIONS == "":
|
if WEBSOCKET_REDIS_OPTIONS == "":
|
||||||
log.debug("No WEBSOCKET_REDIS_OPTIONS provided, defaulting to None")
|
if REDIS_SOCKET_CONNECT_TIMEOUT:
|
||||||
WEBSOCKET_REDIS_OPTIONS = None
|
WEBSOCKET_REDIS_OPTIONS = {
|
||||||
|
"socket_connect_timeout": REDIS_SOCKET_CONNECT_TIMEOUT
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
log.debug("No WEBSOCKET_REDIS_OPTIONS provided, defaulting to None")
|
||||||
|
WEBSOCKET_REDIS_OPTIONS = None
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
WEBSOCKET_REDIS_OPTIONS = json.loads(WEBSOCKET_REDIS_OPTIONS)
|
WEBSOCKET_REDIS_OPTIONS = json.loads(WEBSOCKET_REDIS_OPTIONS)
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,7 @@ from open_webui.config import (
|
||||||
FIRECRAWL_API_KEY,
|
FIRECRAWL_API_KEY,
|
||||||
WEB_LOADER_ENGINE,
|
WEB_LOADER_ENGINE,
|
||||||
WEB_LOADER_CONCURRENT_REQUESTS,
|
WEB_LOADER_CONCURRENT_REQUESTS,
|
||||||
|
WEB_LOADER_TIMEOUT,
|
||||||
WHISPER_MODEL,
|
WHISPER_MODEL,
|
||||||
WHISPER_VAD_FILTER,
|
WHISPER_VAD_FILTER,
|
||||||
WHISPER_LANGUAGE,
|
WHISPER_LANGUAGE,
|
||||||
|
|
@ -922,6 +923,7 @@ app.state.config.WEB_SEARCH_CONCURRENT_REQUESTS = WEB_SEARCH_CONCURRENT_REQUESTS
|
||||||
|
|
||||||
app.state.config.WEB_LOADER_ENGINE = WEB_LOADER_ENGINE
|
app.state.config.WEB_LOADER_ENGINE = WEB_LOADER_ENGINE
|
||||||
app.state.config.WEB_LOADER_CONCURRENT_REQUESTS = WEB_LOADER_CONCURRENT_REQUESTS
|
app.state.config.WEB_LOADER_CONCURRENT_REQUESTS = WEB_LOADER_CONCURRENT_REQUESTS
|
||||||
|
app.state.config.WEB_LOADER_TIMEOUT = WEB_LOADER_TIMEOUT
|
||||||
|
|
||||||
app.state.config.WEB_SEARCH_TRUST_ENV = WEB_SEARCH_TRUST_ENV
|
app.state.config.WEB_SEARCH_TRUST_ENV = WEB_SEARCH_TRUST_ENV
|
||||||
app.state.config.BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL = (
|
app.state.config.BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL = (
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ from open_webui.config import (
|
||||||
PLAYWRIGHT_WS_URL,
|
PLAYWRIGHT_WS_URL,
|
||||||
PLAYWRIGHT_TIMEOUT,
|
PLAYWRIGHT_TIMEOUT,
|
||||||
WEB_LOADER_ENGINE,
|
WEB_LOADER_ENGINE,
|
||||||
|
WEB_LOADER_TIMEOUT,
|
||||||
FIRECRAWL_API_BASE_URL,
|
FIRECRAWL_API_BASE_URL,
|
||||||
FIRECRAWL_API_KEY,
|
FIRECRAWL_API_KEY,
|
||||||
TAVILY_API_KEY,
|
TAVILY_API_KEY,
|
||||||
|
|
@ -674,6 +675,20 @@ def get_web_loader(
|
||||||
|
|
||||||
if WEB_LOADER_ENGINE.value == "" or WEB_LOADER_ENGINE.value == "safe_web":
|
if WEB_LOADER_ENGINE.value == "" or WEB_LOADER_ENGINE.value == "safe_web":
|
||||||
WebLoaderClass = SafeWebBaseLoader
|
WebLoaderClass = SafeWebBaseLoader
|
||||||
|
|
||||||
|
request_kwargs = {}
|
||||||
|
if WEB_LOADER_TIMEOUT.value:
|
||||||
|
try:
|
||||||
|
timeout_value = float(WEB_LOADER_TIMEOUT.value)
|
||||||
|
except ValueError:
|
||||||
|
timeout_value = None
|
||||||
|
|
||||||
|
if timeout_value:
|
||||||
|
request_kwargs["timeout"] = timeout_value
|
||||||
|
|
||||||
|
if request_kwargs:
|
||||||
|
web_loader_args["requests_kwargs"] = request_kwargs
|
||||||
|
|
||||||
if WEB_LOADER_ENGINE.value == "playwright":
|
if WEB_LOADER_ENGINE.value == "playwright":
|
||||||
WebLoaderClass = SafePlaywrightURLLoader
|
WebLoaderClass = SafePlaywrightURLLoader
|
||||||
web_loader_args["playwright_timeout"] = PLAYWRIGHT_TIMEOUT.value
|
web_loader_args["playwright_timeout"] = PLAYWRIGHT_TIMEOUT.value
|
||||||
|
|
|
||||||
|
|
@ -536,6 +536,7 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)):
|
||||||
"SOUGOU_API_SID": request.app.state.config.SOUGOU_API_SID,
|
"SOUGOU_API_SID": request.app.state.config.SOUGOU_API_SID,
|
||||||
"SOUGOU_API_SK": request.app.state.config.SOUGOU_API_SK,
|
"SOUGOU_API_SK": request.app.state.config.SOUGOU_API_SK,
|
||||||
"WEB_LOADER_ENGINE": request.app.state.config.WEB_LOADER_ENGINE,
|
"WEB_LOADER_ENGINE": request.app.state.config.WEB_LOADER_ENGINE,
|
||||||
|
"WEB_LOADER_TIMEOUT": request.app.state.config.WEB_LOADER_TIMEOUT,
|
||||||
"ENABLE_WEB_LOADER_SSL_VERIFICATION": request.app.state.config.ENABLE_WEB_LOADER_SSL_VERIFICATION,
|
"ENABLE_WEB_LOADER_SSL_VERIFICATION": request.app.state.config.ENABLE_WEB_LOADER_SSL_VERIFICATION,
|
||||||
"PLAYWRIGHT_WS_URL": request.app.state.config.PLAYWRIGHT_WS_URL,
|
"PLAYWRIGHT_WS_URL": request.app.state.config.PLAYWRIGHT_WS_URL,
|
||||||
"PLAYWRIGHT_TIMEOUT": request.app.state.config.PLAYWRIGHT_TIMEOUT,
|
"PLAYWRIGHT_TIMEOUT": request.app.state.config.PLAYWRIGHT_TIMEOUT,
|
||||||
|
|
@ -594,6 +595,7 @@ class WebConfig(BaseModel):
|
||||||
SOUGOU_API_SID: Optional[str] = None
|
SOUGOU_API_SID: Optional[str] = None
|
||||||
SOUGOU_API_SK: Optional[str] = None
|
SOUGOU_API_SK: Optional[str] = None
|
||||||
WEB_LOADER_ENGINE: Optional[str] = None
|
WEB_LOADER_ENGINE: Optional[str] = None
|
||||||
|
WEB_LOADER_TIMEOUT: Optional[str] = None
|
||||||
ENABLE_WEB_LOADER_SSL_VERIFICATION: Optional[bool] = None
|
ENABLE_WEB_LOADER_SSL_VERIFICATION: Optional[bool] = None
|
||||||
PLAYWRIGHT_WS_URL: Optional[str] = None
|
PLAYWRIGHT_WS_URL: Optional[str] = None
|
||||||
PLAYWRIGHT_TIMEOUT: Optional[int] = None
|
PLAYWRIGHT_TIMEOUT: Optional[int] = None
|
||||||
|
|
@ -1071,6 +1073,8 @@ async def update_rag_config(
|
||||||
|
|
||||||
# Web loader settings
|
# Web loader settings
|
||||||
request.app.state.config.WEB_LOADER_ENGINE = form_data.web.WEB_LOADER_ENGINE
|
request.app.state.config.WEB_LOADER_ENGINE = form_data.web.WEB_LOADER_ENGINE
|
||||||
|
request.app.state.config.WEB_LOADER_TIMEOUT = form_data.web.WEB_LOADER_TIMEOUT
|
||||||
|
|
||||||
request.app.state.config.ENABLE_WEB_LOADER_SSL_VERIFICATION = (
|
request.app.state.config.ENABLE_WEB_LOADER_SSL_VERIFICATION = (
|
||||||
form_data.web.ENABLE_WEB_LOADER_SSL_VERIFICATION
|
form_data.web.ENABLE_WEB_LOADER_SSL_VERIFICATION
|
||||||
)
|
)
|
||||||
|
|
@ -1206,6 +1210,7 @@ async def update_rag_config(
|
||||||
"SOUGOU_API_SID": request.app.state.config.SOUGOU_API_SID,
|
"SOUGOU_API_SID": request.app.state.config.SOUGOU_API_SID,
|
||||||
"SOUGOU_API_SK": request.app.state.config.SOUGOU_API_SK,
|
"SOUGOU_API_SK": request.app.state.config.SOUGOU_API_SK,
|
||||||
"WEB_LOADER_ENGINE": request.app.state.config.WEB_LOADER_ENGINE,
|
"WEB_LOADER_ENGINE": request.app.state.config.WEB_LOADER_ENGINE,
|
||||||
|
"WEB_LOADER_TIMEOUT": request.app.state.config.WEB_LOADER_TIMEOUT,
|
||||||
"ENABLE_WEB_LOADER_SSL_VERIFICATION": request.app.state.config.ENABLE_WEB_LOADER_SSL_VERIFICATION,
|
"ENABLE_WEB_LOADER_SSL_VERIFICATION": request.app.state.config.ENABLE_WEB_LOADER_SSL_VERIFICATION,
|
||||||
"PLAYWRIGHT_WS_URL": request.app.state.config.PLAYWRIGHT_WS_URL,
|
"PLAYWRIGHT_WS_URL": request.app.state.config.PLAYWRIGHT_WS_URL,
|
||||||
"PLAYWRIGHT_TIMEOUT": request.app.state.config.PLAYWRIGHT_TIMEOUT,
|
"PLAYWRIGHT_TIMEOUT": request.app.state.config.PLAYWRIGHT_TIMEOUT,
|
||||||
|
|
|
||||||
|
|
@ -391,6 +391,7 @@ async def update_user_info_by_session_user(
|
||||||
class UserActiveResponse(UserStatus):
|
class UserActiveResponse(UserStatus):
|
||||||
name: str
|
name: str
|
||||||
profile_image_url: Optional[str] = None
|
profile_image_url: Optional[str] = None
|
||||||
|
groups: Optional[list] = []
|
||||||
|
|
||||||
is_active: bool
|
is_active: bool
|
||||||
model_config = ConfigDict(extra="allow")
|
model_config = ConfigDict(extra="allow")
|
||||||
|
|
@ -412,11 +413,12 @@ async def get_user_by_id(user_id: str, user=Depends(get_verified_user)):
|
||||||
)
|
)
|
||||||
|
|
||||||
user = Users.get_user_by_id(user_id)
|
user = Users.get_user_by_id(user_id)
|
||||||
|
|
||||||
if user:
|
if user:
|
||||||
|
groups = Groups.get_groups_by_member_id(user_id)
|
||||||
return UserActiveResponse(
|
return UserActiveResponse(
|
||||||
**{
|
**{
|
||||||
**user.model_dump(),
|
**user.model_dump(),
|
||||||
|
"groups": [{"id": group.id, "name": group.name} for group in groups],
|
||||||
"is_active": Users.is_user_active(user_id),
|
"is_active": Users.is_user_active(user_id),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -716,17 +716,18 @@ async def chat_web_search_handler(
|
||||||
return form_data
|
return form_data
|
||||||
|
|
||||||
|
|
||||||
def get_last_images(message_list):
|
def get_images_from_messages(message_list):
|
||||||
images = []
|
images = []
|
||||||
|
|
||||||
for message in reversed(message_list):
|
for message in reversed(message_list):
|
||||||
images_flag = False
|
|
||||||
|
message_images = []
|
||||||
for file in message.get("files", []):
|
for file in message.get("files", []):
|
||||||
if file.get("type") == "image":
|
if file.get("type") == "image":
|
||||||
images.append(file.get("url"))
|
message_images.append(file.get("url"))
|
||||||
images_flag = True
|
|
||||||
|
|
||||||
if images_flag:
|
if message_images:
|
||||||
break
|
images.append(message_images)
|
||||||
|
|
||||||
return images
|
return images
|
||||||
|
|
||||||
|
|
@ -780,7 +781,16 @@ async def chat_image_generation_handler(
|
||||||
user_message = get_last_user_message(message_list)
|
user_message = get_last_user_message(message_list)
|
||||||
|
|
||||||
prompt = user_message
|
prompt = user_message
|
||||||
input_images = get_last_images(message_list)
|
message_images = get_images_from_messages(message_list)
|
||||||
|
|
||||||
|
# Limit to first 2 sets of images
|
||||||
|
# We may want to change this in the future to allow more images
|
||||||
|
input_images = []
|
||||||
|
for idx, images in enumerate(message_images):
|
||||||
|
if idx >= 2:
|
||||||
|
break
|
||||||
|
for image in images:
|
||||||
|
input_images.append(image)
|
||||||
|
|
||||||
system_message_content = ""
|
system_message_content = ""
|
||||||
|
|
||||||
|
|
@ -1540,10 +1550,15 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
||||||
if prompt is None:
|
if prompt is None:
|
||||||
raise Exception("No user message found")
|
raise Exception("No user message found")
|
||||||
|
|
||||||
|
model_rag_template = (
|
||||||
|
model.get("info", {}).get("params", {}).get("rag_template", "")
|
||||||
|
or request.app.state.config.RAG_TEMPLATE
|
||||||
|
)
|
||||||
|
|
||||||
if context_string != "":
|
if context_string != "":
|
||||||
form_data["messages"] = add_or_update_user_message(
|
form_data["messages"] = add_or_update_user_message(
|
||||||
rag_template(
|
rag_template(
|
||||||
request.app.state.config.RAG_TEMPLATE,
|
model_rag_template,
|
||||||
context_string,
|
context_string,
|
||||||
prompt,
|
prompt,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import redis
|
||||||
|
|
||||||
from open_webui.env import (
|
from open_webui.env import (
|
||||||
REDIS_CLUSTER,
|
REDIS_CLUSTER,
|
||||||
|
REDIS_SOCKET_CONNECT_TIMEOUT,
|
||||||
REDIS_SENTINEL_HOSTS,
|
REDIS_SENTINEL_HOSTS,
|
||||||
REDIS_SENTINEL_MAX_RETRY_COUNT,
|
REDIS_SENTINEL_MAX_RETRY_COUNT,
|
||||||
REDIS_SENTINEL_PORT,
|
REDIS_SENTINEL_PORT,
|
||||||
|
|
@ -162,6 +163,7 @@ def get_redis_connection(
|
||||||
username=redis_config["username"],
|
username=redis_config["username"],
|
||||||
password=redis_config["password"],
|
password=redis_config["password"],
|
||||||
decode_responses=decode_responses,
|
decode_responses=decode_responses,
|
||||||
|
socket_connect_timeout=REDIS_SOCKET_CONNECT_TIMEOUT,
|
||||||
)
|
)
|
||||||
connection = SentinelRedisProxy(
|
connection = SentinelRedisProxy(
|
||||||
sentinel,
|
sentinel,
|
||||||
|
|
@ -188,6 +190,7 @@ def get_redis_connection(
|
||||||
username=redis_config["username"],
|
username=redis_config["username"],
|
||||||
password=redis_config["password"],
|
password=redis_config["password"],
|
||||||
decode_responses=decode_responses,
|
decode_responses=decode_responses,
|
||||||
|
socket_connect_timeout=REDIS_SOCKET_CONNECT_TIMEOUT,
|
||||||
)
|
)
|
||||||
connection = SentinelRedisProxy(
|
connection = SentinelRedisProxy(
|
||||||
sentinel,
|
sentinel,
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
if (pipeline && (pipeline?.valves ?? false)) {
|
if (pipeline && (pipeline?.valves ?? false)) {
|
||||||
for (const property in valves_spec.properties) {
|
for (const property in valves_spec.properties) {
|
||||||
if (valves_spec.properties[property]?.type === 'array') {
|
if (valves_spec.properties[property]?.type === 'array') {
|
||||||
valves[property] = valves[property].split(',').map((v) => v.trim());
|
valves[property] = (valves[property] ?? '').split(',').map((v) => v.trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -767,6 +767,19 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if webConfig.WEB_LOADER_ENGINE === '' || webConfig.WEB_LOADER_ENGINE === 'safe_web'}
|
{#if webConfig.WEB_LOADER_ENGINE === '' || webConfig.WEB_LOADER_ENGINE === 'safe_web'}
|
||||||
|
<div class=" mb-2.5 flex w-full justify-between">
|
||||||
|
<div class=" self-center text-xs font-medium">
|
||||||
|
{$i18n.t('Timeout')}
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center relative">
|
||||||
|
<input
|
||||||
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
|
placeholder={$i18n.t('Timeout')}
|
||||||
|
bind:value={webConfig.WEB_LOADER_TIMEOUT}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class=" mb-2.5 flex w-full justify-between">
|
<div class=" mb-2.5 flex w-full justify-between">
|
||||||
<div class=" self-center text-xs font-medium">
|
<div class=" self-center text-xs font-medium">
|
||||||
{$i18n.t('Verify SSL Certificate')}
|
{$i18n.t('Verify SSL Certificate')}
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,18 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if (user?.groups ?? []).length > 0}
|
||||||
|
<div class="mx-3.5 mt-2 flex gap-0.5">
|
||||||
|
{#each user.groups as group}
|
||||||
|
<div
|
||||||
|
class="px-1.5 py-0.5 rounded-lg bg-gray-50 dark:text-white dark:bg-gray-900/50 text-black transition text-xs"
|
||||||
|
>
|
||||||
|
{group.name}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if $_user?.id !== user.id}
|
{#if $_user?.id !== user.id}
|
||||||
<hr class="border-gray-100/50 dark:border-gray-800/50 my-2.5" />
|
<hr class="border-gray-100/50 dark:border-gray-800/50 my-2.5" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,12 +75,11 @@
|
||||||
`<sup class="footnote-ref footnote-ref-text">${token.escapedText}</sup>`
|
`<sup class="footnote-ref footnote-ref-text">${token.escapedText}</sup>`
|
||||||
) || ''}
|
) || ''}
|
||||||
{:else if token.type === 'citation'}
|
{:else if token.type === 'citation'}
|
||||||
<SourceToken {id} {token} {sourceIds} onClick={onSourceClick} />
|
{#if (sourceIds ?? []).length > 0}
|
||||||
<!-- {#if token.ids && token.ids.length > 0}
|
<SourceToken {id} {token} {sourceIds} onClick={onSourceClick} />
|
||||||
{#each token.ids as sourceId}
|
{:else}
|
||||||
<Source id={sourceId - 1} title={sourceIds[sourceId - 1]} onClick={onSourceClick} />
|
<TextToken {token} {done} />
|
||||||
{/each}
|
{/if}
|
||||||
{/if} -->
|
|
||||||
{:else if token.type === 'text'}
|
{:else if token.type === 'text'}
|
||||||
<TextToken {token} {done} />
|
<TextToken {token} {done} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -39,37 +39,43 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if (token?.ids ?? []).length == 1}
|
{sourceIds}
|
||||||
<Source id={token.ids[0] - 1} title={sourceIds[token.ids[0] - 1]} {onClick} />
|
|
||||||
{:else}
|
{#if sourceIds}
|
||||||
<LinkPreview.Root openDelay={0} bind:open={openPreview}>
|
{#if (token?.ids ?? []).length == 1}
|
||||||
<LinkPreview.Trigger>
|
<Source id={token.ids[0] - 1} title={sourceIds[token.ids[0] - 1]} {onClick} />
|
||||||
<button
|
{:else}
|
||||||
class="text-[10px] w-fit translate-y-[2px] px-2 py-0.5 dark:bg-white/5 dark:text-white/80 dark:hover:text-white bg-gray-50 text-black/80 hover:text-black transition rounded-xl"
|
<LinkPreview.Root openDelay={0} bind:open={openPreview}>
|
||||||
on:click={() => {
|
<LinkPreview.Trigger>
|
||||||
openPreview = !openPreview;
|
<button
|
||||||
}}
|
class="text-[10px] w-fit translate-y-[2px] px-2 py-0.5 dark:bg-white/5 dark:text-white/80 dark:hover:text-white bg-gray-50 text-black/80 hover:text-black transition rounded-xl"
|
||||||
|
on:click={() => {
|
||||||
|
openPreview = !openPreview;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span class="line-clamp-1">
|
||||||
|
{getDisplayTitle(formattedTitle(decodeString(sourceIds[token.ids[0] - 1])))}
|
||||||
|
<span class="dark:text-white/50 text-black/50">+{(token?.ids ?? []).length - 1}</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</LinkPreview.Trigger>
|
||||||
|
<LinkPreview.Content
|
||||||
|
class="z-[999]"
|
||||||
|
align="start"
|
||||||
|
strategy="fixed"
|
||||||
|
sideOffset={6}
|
||||||
|
el={containerElement}
|
||||||
>
|
>
|
||||||
<span class="line-clamp-1">
|
<div class="bg-gray-50 dark:bg-gray-850 rounded-xl p-1 cursor-pointer">
|
||||||
{getDisplayTitle(formattedTitle(decodeString(sourceIds[token.ids[0] - 1])))}
|
{#each token.ids as sourceId}
|
||||||
<span class="dark:text-white/50 text-black/50">+{(token?.ids ?? []).length - 1}</span>
|
<div class="">
|
||||||
</span>
|
<Source id={sourceId - 1} title={sourceIds[sourceId - 1]} {onClick} />
|
||||||
</button>
|
</div>
|
||||||
</LinkPreview.Trigger>
|
{/each}
|
||||||
<LinkPreview.Content
|
</div>
|
||||||
class="z-[999]"
|
</LinkPreview.Content>
|
||||||
align="start"
|
</LinkPreview.Root>
|
||||||
strategy="fixed"
|
{/if}
|
||||||
sideOffset={6}
|
{:else}
|
||||||
el={containerElement}
|
<span>{token.raw}</span>
|
||||||
>
|
|
||||||
<div class="bg-gray-50 dark:bg-gray-850 rounded-xl p-1 cursor-pointer">
|
|
||||||
{#each token.ids as sourceId}
|
|
||||||
<div class="">
|
|
||||||
<Source id={sourceId - 1} title={sourceIds[sourceId - 1]} {onClick} />
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</LinkPreview.Content>
|
|
||||||
</LinkPreview.Root>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -1460,37 +1460,35 @@
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if isLastMessage}
|
{#each model?.actions ?? [] as action}
|
||||||
{#each model?.actions ?? [] as action}
|
<Tooltip content={action.name} placement="bottom">
|
||||||
<Tooltip content={action.name} placement="bottom">
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
aria-label={action.name}
|
||||||
aria-label={action.name}
|
class="{isLastMessage || ($settings?.highContrastMode ?? false)
|
||||||
class="{isLastMessage || ($settings?.highContrastMode ?? false)
|
? 'visible'
|
||||||
? 'visible'
|
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
|
||||||
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
|
on:click={() => {
|
||||||
on:click={() => {
|
actionMessage(action.id, message);
|
||||||
actionMessage(action.id, message);
|
}}
|
||||||
}}
|
>
|
||||||
>
|
{#if action?.icon}
|
||||||
{#if action?.icon}
|
<div class="size-4">
|
||||||
<div class="size-4">
|
<img
|
||||||
<img
|
src={action.icon}
|
||||||
src={action.icon}
|
class="w-4 h-4 {action.icon.includes('svg')
|
||||||
class="w-4 h-4 {action.icon.includes('svg')
|
? 'dark:invert-[80%]'
|
||||||
? 'dark:invert-[80%]'
|
: ''}"
|
||||||
: ''}"
|
style="fill: currentColor;"
|
||||||
style="fill: currentColor;"
|
alt={action.name}
|
||||||
alt={action.name}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
{:else}
|
||||||
{:else}
|
<Sparkles strokeWidth="2.1" className="size-4" />
|
||||||
<Sparkles strokeWidth="2.1" className="size-4" />
|
{/if}
|
||||||
{/if}
|
</button>
|
||||||
</button>
|
</Tooltip>
|
||||||
</Tooltip>
|
{/each}
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
let system = '';
|
let system = '';
|
||||||
|
let rag_template = '';
|
||||||
let info = {
|
let info = {
|
||||||
id: '',
|
id: '',
|
||||||
base_model_id: null,
|
base_model_id: null,
|
||||||
|
|
@ -78,12 +79,14 @@
|
||||||
tags: []
|
tags: []
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
system: ''
|
system: '',
|
||||||
|
rag_template: ''
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let params = {
|
let params: {
|
||||||
system: ''
|
system: '';
|
||||||
|
rag_template: '';
|
||||||
};
|
};
|
||||||
|
|
||||||
let knowledge = [];
|
let knowledge = [];
|
||||||
|
|
@ -207,6 +210,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
info.params.system = system.trim() === '' ? null : system;
|
info.params.system = system.trim() === '' ? null : system;
|
||||||
|
info.params.rag_template = rag_template.trim() === '' ? null : rag_template;
|
||||||
info.params.stop = params.stop ? params.stop.split(',').filter((s) => s.trim()) : null;
|
info.params.stop = params.stop ? params.stop.split(',').filter((s) => s.trim()) : null;
|
||||||
Object.keys(info.params).forEach((key) => {
|
Object.keys(info.params).forEach((key) => {
|
||||||
if (info.params[key] === '' || info.params[key] === null) {
|
if (info.params[key] === '' || info.params[key] === null) {
|
||||||
|
|
@ -254,6 +258,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
system = model?.params?.system ?? '';
|
system = model?.params?.system ?? '';
|
||||||
|
rag_template = model?.params?.rag_template ?? '';
|
||||||
|
|
||||||
params = { ...params, ...model?.params };
|
params = { ...params, ...model?.params };
|
||||||
params.stop = params?.stop
|
params.stop = params?.stop
|
||||||
|
|
@ -521,15 +526,15 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div class="shrink-0">
|
||||||
<button
|
<button
|
||||||
class="bg-gray-50 hover:bg-gray-100 text-black dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-white transition px-2 py-1 rounded-full flex gap-1 items-center"
|
class="bg-gray-50 shrink-0 hover:bg-gray-100 text-black dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-white transition px-2 py-1 rounded-full flex gap-1 items-center"
|
||||||
type="button"
|
type="button"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
showAccessControlModal = true;
|
showAccessControlModal = true;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<LockClosed strokeWidth="2.5" className="size-3.5" />
|
<LockClosed strokeWidth="2.5" className="size-3.5 shrink-0" />
|
||||||
|
|
||||||
<div class="text-sm font-medium shrink-0">
|
<div class="text-sm font-medium shrink-0">
|
||||||
{$i18n.t('Access')}
|
{$i18n.t('Access')}
|
||||||
|
|
@ -644,6 +649,18 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="my-1">
|
||||||
|
<div class=" text-xs font-semibold mb-2">{$i18n.t('RAG Template')}</div>
|
||||||
|
<div>
|
||||||
|
<Textarea
|
||||||
|
placeholder={$i18n.t(
|
||||||
|
'Leave empty to use the default prompt, or enter a custom prompt'
|
||||||
|
)}
|
||||||
|
bind:value={rag_template}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex w-full justify-between">
|
<div class="flex w-full justify-between">
|
||||||
<div class=" self-center text-xs font-medium">
|
<div class=" self-center text-xs font-medium">
|
||||||
{$i18n.t('Advanced Params')}
|
{$i18n.t('Advanced Params')}
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
window.addEventListener('message', async (event) => {
|
window.addEventListener('message', async (event) => {
|
||||||
if (
|
if (
|
||||||
!['https://openwebui.com', 'https://www.openwebui.com', 'http://localhost:5173'].includes(
|
!['https://openwebui.com', 'https://www.openwebui.com', 'http://localhost:9999'].includes(
|
||||||
event.origin
|
event.origin
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,9 @@
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
window.addEventListener('message', async (event) => {
|
window.addEventListener('message', async (event) => {
|
||||||
|
console.log(event);
|
||||||
if (
|
if (
|
||||||
!['https://openwebui.com', 'https://www.openwebui.com', 'http://localhost:5173'].includes(
|
!['https://openwebui.com', 'https://www.openwebui.com', 'http://localhost:9999'].includes(
|
||||||
event.origin
|
event.origin
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue