mirror of
https://github.com/open-webui/open-webui
synced 2025-02-21 21:01:09 +00:00
commit
05c0423d6e
15
CHANGELOG.md
15
CHANGELOG.md
@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.3.19] - 2024-09-05
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **🌐 Translation Update**: Improved Chinese translations.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **📂 DATA_DIR Overriding**: Fixed an issue to avoid overriding DATA_DIR, preventing errors when directories are set identically, ensuring smoother operation and data management.
|
||||||
|
- **🛠️ Frontmatter Extraction**: Fixed the extraction process for frontmatter in tools and functions.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **🎨 UI Styling**: Refined the user interface styling for enhanced visual coherence and user experience.
|
||||||
|
|
||||||
## [0.3.18] - 2024-09-04
|
## [0.3.18] - 2024-09-04
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -152,29 +152,33 @@ async def get_pipe_models():
|
|||||||
|
|
||||||
# Check if function is a manifold
|
# Check if function is a manifold
|
||||||
if hasattr(function_module, "pipes"):
|
if hasattr(function_module, "pipes"):
|
||||||
manifold_pipes = []
|
sub_pipes = []
|
||||||
|
|
||||||
# Check if pipes is a function or a list
|
# Check if pipes is a function or a list
|
||||||
if callable(function_module.pipes):
|
|
||||||
manifold_pipes = function_module.pipes()
|
|
||||||
else:
|
|
||||||
manifold_pipes = function_module.pipes
|
|
||||||
|
|
||||||
for p in manifold_pipes:
|
try:
|
||||||
manifold_pipe_id = f'{pipe.id}.{p["id"]}'
|
if callable(function_module.pipes):
|
||||||
manifold_pipe_name = p["name"]
|
sub_pipes = function_module.pipes()
|
||||||
|
else:
|
||||||
|
sub_pipes = function_module.pipes
|
||||||
|
except Exception as e:
|
||||||
|
log.exception(e)
|
||||||
|
sub_pipes = []
|
||||||
|
|
||||||
|
print(sub_pipes)
|
||||||
|
|
||||||
|
for p in sub_pipes:
|
||||||
|
sub_pipe_id = f'{pipe.id}.{p["id"]}'
|
||||||
|
sub_pipe_name = p["name"]
|
||||||
|
|
||||||
if hasattr(function_module, "name"):
|
if hasattr(function_module, "name"):
|
||||||
manifold_pipe_name = f"{function_module.name}{manifold_pipe_name}"
|
sub_pipe_name = f"{function_module.name}{sub_pipe_name}"
|
||||||
|
|
||||||
pipe_flag = {"type": pipe.type}
|
pipe_flag = {"type": pipe.type}
|
||||||
if hasattr(function_module, "ChatValves"):
|
|
||||||
pipe_flag["valves_spec"] = function_module.ChatValves.schema()
|
|
||||||
|
|
||||||
pipe_models.append(
|
pipe_models.append(
|
||||||
{
|
{
|
||||||
"id": manifold_pipe_id,
|
"id": sub_pipe_id,
|
||||||
"name": manifold_pipe_name,
|
"name": sub_pipe_name,
|
||||||
"object": "model",
|
"object": "model",
|
||||||
"created": pipe.created_at,
|
"created": pipe.created_at,
|
||||||
"owned_by": "openai",
|
"owned_by": "openai",
|
||||||
@ -183,8 +187,6 @@ async def get_pipe_models():
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
pipe_flag = {"type": "pipe"}
|
pipe_flag = {"type": "pipe"}
|
||||||
if hasattr(function_module, "ChatValves"):
|
|
||||||
pipe_flag["valves_spec"] = function_module.ChatValves.schema()
|
|
||||||
|
|
||||||
pipe_models.append(
|
pipe_models.append(
|
||||||
{
|
{
|
||||||
|
@ -11,9 +11,9 @@ from open_webui.apps.webui.models.tools import Tools
|
|||||||
from open_webui.config import FUNCTIONS_DIR, TOOLS_DIR
|
from open_webui.config import FUNCTIONS_DIR, TOOLS_DIR
|
||||||
|
|
||||||
|
|
||||||
def extract_frontmatter(file_path):
|
def extract_frontmatter(content):
|
||||||
"""
|
"""
|
||||||
Extract frontmatter as a dictionary from the specified file path.
|
Extract frontmatter as a dictionary from the provided content string.
|
||||||
"""
|
"""
|
||||||
frontmatter = {}
|
frontmatter = {}
|
||||||
frontmatter_started = False
|
frontmatter_started = False
|
||||||
@ -21,29 +21,25 @@ def extract_frontmatter(file_path):
|
|||||||
frontmatter_pattern = re.compile(r"^\s*([a-z_]+):\s*(.*)\s*$", re.IGNORECASE)
|
frontmatter_pattern = re.compile(r"^\s*([a-z_]+):\s*(.*)\s*$", re.IGNORECASE)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(file_path, "r", encoding="utf-8") as file:
|
lines = content.splitlines()
|
||||||
first_line = file.readline()
|
if len(lines) < 1 or lines[0].strip() != '"""':
|
||||||
if first_line.strip() != '"""':
|
# The content doesn't start with triple quotes
|
||||||
# The file doesn't start with triple quotes
|
return {}
|
||||||
return {}
|
|
||||||
|
|
||||||
frontmatter_started = True
|
frontmatter_started = True
|
||||||
|
|
||||||
for line in file:
|
for line in lines[1:]:
|
||||||
if '"""' in line:
|
if '"""' in line:
|
||||||
if frontmatter_started:
|
if frontmatter_started:
|
||||||
frontmatter_ended = True
|
frontmatter_ended = True
|
||||||
break
|
break
|
||||||
|
|
||||||
if frontmatter_started and not frontmatter_ended:
|
if frontmatter_started and not frontmatter_ended:
|
||||||
match = frontmatter_pattern.match(line)
|
match = frontmatter_pattern.match(line)
|
||||||
if match:
|
if match:
|
||||||
key, value = match.groups()
|
key, value = match.groups()
|
||||||
frontmatter[key.strip()] = value.strip()
|
frontmatter[key.strip()] = value.strip()
|
||||||
|
|
||||||
except FileNotFoundError:
|
|
||||||
print(f"Error: The file {file_path} does not exist.")
|
|
||||||
return {}
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"An error occurred: {e}")
|
print(f"An error occurred: {e}")
|
||||||
return {}
|
return {}
|
||||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "open-webui",
|
"name": "open-webui",
|
||||||
"version": "0.3.18",
|
"version": "0.3.19",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "open-webui",
|
"name": "open-webui",
|
||||||
"version": "0.3.18",
|
"version": "0.3.19",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/lang-javascript": "^6.2.2",
|
"@codemirror/lang-javascript": "^6.2.2",
|
||||||
"@codemirror/lang-python": "^6.1.6",
|
"@codemirror/lang-python": "^6.1.6",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "open-webui",
|
"name": "open-webui",
|
||||||
"version": "0.3.18",
|
"version": "0.3.19",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "npm run pyodide:fetch && vite dev --host",
|
"dev": "npm run pyodide:fetch && vite dev --host",
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { mobile, showCallOverlay } from '$lib/stores';
|
import { mobile, showCallOverlay } from '$lib/stores';
|
||||||
import CallOverlay from './MessageInput/CallOverlay.svelte';
|
import CallOverlay from './MessageInput/CallOverlay.svelte';
|
||||||
|
import Drawer from '../common/Drawer.svelte';
|
||||||
|
|
||||||
export let show = false;
|
export let show = false;
|
||||||
|
|
||||||
@ -43,65 +44,60 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if largeScreen}
|
{#if !largeScreen}
|
||||||
{#if show}
|
{#if show}
|
||||||
<div class=" absolute bottom-0 right-0 z-20 h-full pointer-events-none">
|
<Drawer bind:show>
|
||||||
<div class="pr-4 pt-14 pb-8 w-[24rem] h-full" in:slide={{ duration: 200, axis: 'x' }}>
|
<div class=" px-6 py-4 h-full">
|
||||||
<div
|
<Controls
|
||||||
class="w-full h-full px-5 py-4 bg-white dark:shadow-lg dark:bg-gray-850 border border-gray-50 dark:border-gray-800 rounded-xl z-50 pointer-events-auto overflow-y-auto scrollbar-hidden"
|
on:close={() => {
|
||||||
>
|
show = false;
|
||||||
{#if $showCallOverlay}
|
}}
|
||||||
<CallOverlay
|
{models}
|
||||||
bind:files
|
bind:chatFiles
|
||||||
{submitPrompt}
|
bind:params
|
||||||
{stopResponse}
|
/>
|
||||||
{modelId}
|
</div>
|
||||||
{chatId}
|
</Drawer>
|
||||||
{eventTarget}
|
{/if}
|
||||||
/>
|
|
||||||
{:else}
|
{#if $showCallOverlay}
|
||||||
<Controls
|
<div class=" absolute w-full h-screen max-h-[100dvh] flex z-[999] overflow-hidden">
|
||||||
on:close={() => {
|
<div
|
||||||
show = false;
|
class="absolute w-full h-screen max-h-[100dvh] bg-white text-gray-700 dark:bg-black dark:text-gray-300 flex justify-center"
|
||||||
}}
|
>
|
||||||
{models}
|
<CallOverlay
|
||||||
bind:chatFiles
|
bind:files
|
||||||
bind:params
|
{submitPrompt}
|
||||||
/>
|
{stopResponse}
|
||||||
{/if}
|
{modelId}
|
||||||
</div>
|
{chatId}
|
||||||
|
{eventTarget}
|
||||||
|
on:close={() => {
|
||||||
|
show = false;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{:else if $showCallOverlay}
|
{:else if show}
|
||||||
<div class=" absolute w-full h-screen max-h-[100dvh] flex z-[999] overflow-hidden">
|
<div class=" absolute bottom-0 right-0 z-20 h-full pointer-events-none">
|
||||||
<div
|
<div class="pr-4 pt-14 pb-8 w-[24rem] h-full" in:slide={{ duration: 200, axis: 'x' }}>
|
||||||
class="absolute w-full h-screen max-h-[100dvh] bg-white text-gray-700 dark:bg-black dark:text-gray-300 flex justify-center"
|
<div
|
||||||
>
|
class="w-full h-full px-5 py-4 bg-white dark:shadow-lg dark:bg-gray-850 border border-gray-50 dark:border-gray-800 rounded-xl z-50 pointer-events-auto overflow-y-auto scrollbar-hidden"
|
||||||
<CallOverlay
|
>
|
||||||
bind:files
|
{#if $showCallOverlay}
|
||||||
{submitPrompt}
|
<CallOverlay bind:files {submitPrompt} {stopResponse} {modelId} {chatId} {eventTarget} />
|
||||||
{stopResponse}
|
{:else}
|
||||||
{modelId}
|
<Controls
|
||||||
{chatId}
|
on:close={() => {
|
||||||
{eventTarget}
|
show = false;
|
||||||
on:close={() => {
|
}}
|
||||||
show = false;
|
{models}
|
||||||
}}
|
bind:chatFiles
|
||||||
/>
|
bind:params
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
|
||||||
<Modal bind:show>
|
|
||||||
<div class=" px-6 py-4 h-full">
|
|
||||||
<Controls
|
|
||||||
on:close={() => {
|
|
||||||
show = false;
|
|
||||||
}}
|
|
||||||
{models}
|
|
||||||
bind:chatFiles
|
|
||||||
bind:params
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -34,9 +34,9 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#key mounted}
|
{#key mounted}
|
||||||
<div class="m-auto w-full max-w-6xl px-8 lg:px-20 pb-10">
|
<div class="m-auto w-full max-w-6xl px-8 lg:px-20">
|
||||||
<div class="flex justify-start">
|
<div class="flex justify-start">
|
||||||
<div class="flex -space-x-4 mb-1" in:fade={{ duration: 200 }}>
|
<div class="flex -space-x-4 mb-0.5" in:fade={{ duration: 200 }}>
|
||||||
{#each models as model, modelIdx}
|
{#each models as model, modelIdx}
|
||||||
<button
|
<button
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
|
@ -55,7 +55,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if selectedModelIdx === 0}
|
{#if selectedModelIdx === 0}
|
||||||
<div class=" self-center mr-2 disabled:text-gray-600 disabled:hover:text-gray-600">
|
<div
|
||||||
|
class=" self-center mx-1 disabled:text-gray-600 disabled:hover:text-gray-600 -translate-y-[0.5px]"
|
||||||
|
>
|
||||||
<Tooltip content={$i18n.t('Add Model')}>
|
<Tooltip content={$i18n.t('Add Model')}>
|
||||||
<button
|
<button
|
||||||
class=" "
|
class=" "
|
||||||
@ -79,7 +81,9 @@
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class=" self-center disabled:text-gray-600 disabled:hover:text-gray-600 mr-2">
|
<div
|
||||||
|
class=" self-center mx-1 disabled:text-gray-600 disabled:hover:text-gray-600 -translate-y-[0.5px]"
|
||||||
|
>
|
||||||
<Tooltip content={$i18n.t('Remove Model')}>
|
<Tooltip content={$i18n.t('Remove Model')}>
|
||||||
<button
|
<button
|
||||||
{disabled}
|
{disabled}
|
||||||
@ -95,7 +99,7 @@
|
|||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
class="size-3.5"
|
class="size-3"
|
||||||
>
|
>
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 12h-15" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 12h-15" />
|
||||||
</svg>
|
</svg>
|
||||||
@ -107,8 +111,8 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if showSetDefault && !$mobile}
|
{#if showSetDefault}
|
||||||
<div class="text-left mt-[1px] ml-1 text-[0.7rem] text-gray-500 font-primary">
|
<div class=" absolute text-left mt-[1px] ml-1 text-[0.7rem] text-gray-500 font-primary">
|
||||||
<button on:click={saveDefaultModel}> {$i18n.t('Set as default')}</button>
|
<button on:click={saveDefaultModel}> {$i18n.t('Set as default')}</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -302,7 +302,7 @@
|
|||||||
>
|
>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
{#if $mobile && (item?.model?.info?.meta?.tags ?? []).length > 0}
|
{#if $mobile && (item?.model?.info?.meta?.tags ?? []).length > 0}
|
||||||
<div class="flex gap-0.5 self-start h-full mb-0.5 -translate-x-1">
|
<div class="flex gap-0.5 self-start h-full mb-1.5 -translate-x-1">
|
||||||
{#each item.model?.info?.meta.tags as tag}
|
{#each item.model?.info?.meta.tags as tag}
|
||||||
<div
|
<div
|
||||||
class=" text-xs font-bold px-1 rounded uppercase line-clamp-1 bg-gray-500/20 text-gray-700 dark:text-gray-200"
|
class=" text-xs font-bold px-1 rounded uppercase line-clamp-1 bg-gray-500/20 text-gray-700 dark:text-gray-200"
|
||||||
@ -418,7 +418,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if value === item.value}
|
{#if value === item.value}
|
||||||
<div class="ml-auto pl-2">
|
<div class="ml-auto pl-2 pr-2 md:pr-0">
|
||||||
<Check />
|
<Check />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
94
src/lib/components/common/Drawer.svelte
Normal file
94
src/lib/components/common/Drawer.svelte
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { onDestroy, onMount, createEventDispatcher } from 'svelte';
|
||||||
|
import { flyAndScale } from '$lib/utils/transitions';
|
||||||
|
import { fade, fly, slide } from 'svelte/transition';
|
||||||
|
|
||||||
|
export let show = false;
|
||||||
|
export let size = 'md';
|
||||||
|
|
||||||
|
let modalElement = null;
|
||||||
|
let mounted = false;
|
||||||
|
|
||||||
|
const sizeToWidth = (size) => {
|
||||||
|
if (size === 'xs') {
|
||||||
|
return 'w-[16rem]';
|
||||||
|
} else if (size === 'sm') {
|
||||||
|
return 'w-[30rem]';
|
||||||
|
} else if (size === 'md') {
|
||||||
|
return 'w-[48rem]';
|
||||||
|
} else {
|
||||||
|
return 'w-[56rem]';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
|
if (event.key === 'Escape' && isTopModal()) {
|
||||||
|
console.log('Escape');
|
||||||
|
show = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isTopModal = () => {
|
||||||
|
const modals = document.getElementsByClassName('modal');
|
||||||
|
return modals.length && modals[modals.length - 1] === modalElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
mounted = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
$: if (show && modalElement) {
|
||||||
|
document.body.appendChild(modalElement);
|
||||||
|
window.addEventListener('keydown', handleKeyDown);
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
} else if (modalElement) {
|
||||||
|
window.removeEventListener('keydown', handleKeyDown);
|
||||||
|
document.body.removeChild(modalElement);
|
||||||
|
document.body.style.overflow = 'unset';
|
||||||
|
}
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
show = false;
|
||||||
|
if (modalElement) {
|
||||||
|
document.body.removeChild(modalElement);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={modalElement}
|
||||||
|
class="modal fixed right-0 left-0 bottom-0 bg-black/60 w-full min-h-screen h-screen flex justify-center z-[9999] overflow-hidden overscroll-contain"
|
||||||
|
in:fly={{ y: 100, duration: 100 }}
|
||||||
|
on:mousedown={() => {
|
||||||
|
show = false;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class=" mt-auto max-w-full w-full bg-gray-50 dark:bg-gray-900 max-h-[100dvh] overflow-y-auto scrollbar-hidden"
|
||||||
|
on:mousedown={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.modal-content {
|
||||||
|
animation: scaleUp 0.1s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scaleUp {
|
||||||
|
from {
|
||||||
|
transform: scale(0.985);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -261,7 +261,7 @@
|
|||||||
id="sidebar"
|
id="sidebar"
|
||||||
class="h-screen max-h-[100dvh] min-h-screen select-none {$showSidebar
|
class="h-screen max-h-[100dvh] min-h-screen select-none {$showSidebar
|
||||||
? 'md:relative w-[260px]'
|
? 'md:relative w-[260px]'
|
||||||
: '-translate-x-[260px] w-[0px]'} bg-gray-50 text-gray-900 dark:bg-gray-950 dark:text-gray-200 text-sm transition fixed z-50 top-0 left-0 rounded-r-2xl
|
: '-translate-x-[260px] w-[0px]'} bg-gray-50 text-gray-900 dark:bg-gray-950 dark:text-gray-200 text-sm transition fixed z-50 top-0 left-0
|
||||||
"
|
"
|
||||||
data-state={$showSidebar}
|
data-state={$showSidebar}
|
||||||
>
|
>
|
||||||
@ -273,7 +273,7 @@
|
|||||||
<div class="px-2.5 flex justify-between space-x-1 text-gray-600 dark:text-gray-400">
|
<div class="px-2.5 flex justify-between space-x-1 text-gray-600 dark:text-gray-400">
|
||||||
<a
|
<a
|
||||||
id="sidebar-new-chat-button"
|
id="sidebar-new-chat-button"
|
||||||
class="flex flex-1 justify-between rounded-xl px-2 py-2 hover:bg-gray-100 dark:hover:bg-gray-900 transition"
|
class="flex flex-1 justify-between rounded-xl px-2 h-full hover:bg-gray-100 dark:hover:bg-gray-900 transition"
|
||||||
href="/"
|
href="/"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
on:click={async () => {
|
on:click={async () => {
|
||||||
|
@ -248,8 +248,8 @@
|
|||||||
"Enter model tag (e.g. {{modelTag}})": "输入模型标签 (例如:{{modelTag}})",
|
"Enter model tag (e.g. {{modelTag}})": "输入模型标签 (例如:{{modelTag}})",
|
||||||
"Enter Number of Steps (e.g. 50)": "输入步骤数 (Steps) (例如:50)",
|
"Enter Number of Steps (e.g. 50)": "输入步骤数 (Steps) (例如:50)",
|
||||||
"Enter Score": "输入评分",
|
"Enter Score": "输入评分",
|
||||||
"Enter SearchApi API Key": "",
|
"Enter SearchApi API Key": "输入 SearchApi API 密钥",
|
||||||
"Enter SearchApi Engine": "",
|
"Enter SearchApi Engine": "输入 SearchApi 引擎",
|
||||||
"Enter Searxng Query URL": "输入 Searxng 查询地址",
|
"Enter Searxng Query URL": "输入 Searxng 查询地址",
|
||||||
"Enter Serper API Key": "输入 Serper API 密钥",
|
"Enter Serper API Key": "输入 Serper API 密钥",
|
||||||
"Enter Serply API Key": "输入 Serply API 密钥",
|
"Enter Serply API Key": "输入 Serply API 密钥",
|
||||||
@ -272,7 +272,7 @@
|
|||||||
"Export All Chats (All Users)": "导出所有用户对话",
|
"Export All Chats (All Users)": "导出所有用户对话",
|
||||||
"Export chat (.json)": "JSON 文件 (.json)",
|
"Export chat (.json)": "JSON 文件 (.json)",
|
||||||
"Export Chats": "导出对话",
|
"Export Chats": "导出对话",
|
||||||
"Export Config to JSON File": "",
|
"Export Config to JSON File": "导出配置信息至 JSON 文件中",
|
||||||
"Export Documents Mapping": "导出文档映射",
|
"Export Documents Mapping": "导出文档映射",
|
||||||
"Export Functions": "导出函数",
|
"Export Functions": "导出函数",
|
||||||
"Export LiteLLM config.yaml": "导出 LteLLM config.yaml 文件",
|
"Export LiteLLM config.yaml": "导出 LteLLM config.yaml 文件",
|
||||||
@ -337,7 +337,7 @@
|
|||||||
"Image Settings": "图像设置",
|
"Image Settings": "图像设置",
|
||||||
"Images": "图像",
|
"Images": "图像",
|
||||||
"Import Chats": "导入对话记录",
|
"Import Chats": "导入对话记录",
|
||||||
"Import Config from JSON File": "",
|
"Import Config from JSON File": "导入 JSON 文件中的配置信息",
|
||||||
"Import Documents Mapping": "导入文档映射",
|
"Import Documents Mapping": "导入文档映射",
|
||||||
"Import Functions": "导入函数",
|
"Import Functions": "导入函数",
|
||||||
"Import Models": "导入模型",
|
"Import Models": "导入模型",
|
||||||
@ -541,8 +541,8 @@
|
|||||||
"Search Query Generation Prompt Length Threshold": "搜索查询生成提示长度阈值",
|
"Search Query Generation Prompt Length Threshold": "搜索查询生成提示长度阈值",
|
||||||
"Search Result Count": "搜索结果数量",
|
"Search Result Count": "搜索结果数量",
|
||||||
"Search Tools": "搜索工具",
|
"Search Tools": "搜索工具",
|
||||||
"SearchApi API Key": "",
|
"SearchApi API Key": "SearchApi API 密钥",
|
||||||
"SearchApi Engine": "",
|
"SearchApi Engine": "SearchApi 引擎",
|
||||||
"Searched {{count}} sites_other": "搜索到 {{count}} 个结果",
|
"Searched {{count}} sites_other": "搜索到 {{count}} 个结果",
|
||||||
"Searching \"{{searchQuery}}\"": "搜索 \"{{searchQuery}}\" 中",
|
"Searching \"{{searchQuery}}\"": "搜索 \"{{searchQuery}}\" 中",
|
||||||
"Searching Knowledge for \"{{searchQuery}}\"": "检索有关 \"{{searchQuery}}\" 的知识中",
|
"Searching Knowledge for \"{{searchQuery}}\"": "检索有关 \"{{searchQuery}}\" 的知识中",
|
||||||
|
Loading…
Reference in New Issue
Block a user