mirror of
https://github.com/open-webui/open-webui
synced 2025-03-19 11:38:22 +00:00
commit
d60f06608e
@ -19,8 +19,13 @@ from apps.webui.routers import (
|
||||
functions,
|
||||
)
|
||||
from apps.webui.models.functions import Functions
|
||||
from apps.webui.models.models import Models
|
||||
|
||||
from apps.webui.utils import load_function_module_by_id
|
||||
|
||||
from utils.misc import stream_message_template
|
||||
from utils.task import prompt_template
|
||||
|
||||
|
||||
from config import (
|
||||
WEBUI_BUILD_HASH,
|
||||
@ -186,6 +191,77 @@ async def get_pipe_models():
|
||||
|
||||
|
||||
async def generate_function_chat_completion(form_data, user):
|
||||
model_id = form_data.get("model")
|
||||
model_info = Models.get_model_by_id(model_id)
|
||||
|
||||
if model_info:
|
||||
if model_info.base_model_id:
|
||||
form_data["model"] = model_info.base_model_id
|
||||
|
||||
model_info.params = model_info.params.model_dump()
|
||||
|
||||
if model_info.params:
|
||||
if model_info.params.get("temperature", None) is not None:
|
||||
form_data["temperature"] = float(model_info.params.get("temperature"))
|
||||
|
||||
if model_info.params.get("top_p", None):
|
||||
form_data["top_p"] = int(model_info.params.get("top_p", None))
|
||||
|
||||
if model_info.params.get("max_tokens", None):
|
||||
form_data["max_tokens"] = int(model_info.params.get("max_tokens", None))
|
||||
|
||||
if model_info.params.get("frequency_penalty", None):
|
||||
form_data["frequency_penalty"] = int(
|
||||
model_info.params.get("frequency_penalty", None)
|
||||
)
|
||||
|
||||
if model_info.params.get("seed", None):
|
||||
form_data["seed"] = model_info.params.get("seed", None)
|
||||
|
||||
if model_info.params.get("stop", None):
|
||||
form_data["stop"] = (
|
||||
[
|
||||
bytes(stop, "utf-8").decode("unicode_escape")
|
||||
for stop in model_info.params["stop"]
|
||||
]
|
||||
if model_info.params.get("stop", None)
|
||||
else None
|
||||
)
|
||||
|
||||
system = model_info.params.get("system", None)
|
||||
if system:
|
||||
system = prompt_template(
|
||||
system,
|
||||
**(
|
||||
{
|
||||
"user_name": user.name,
|
||||
"user_location": (
|
||||
user.info.get("location") if user.info else None
|
||||
),
|
||||
}
|
||||
if user
|
||||
else {}
|
||||
),
|
||||
)
|
||||
# Check if the payload already has a system message
|
||||
# If not, add a system message to the payload
|
||||
if form_data.get("messages"):
|
||||
for message in form_data["messages"]:
|
||||
if message.get("role") == "system":
|
||||
message["content"] = system + message["content"]
|
||||
break
|
||||
else:
|
||||
form_data["messages"].insert(
|
||||
0,
|
||||
{
|
||||
"role": "system",
|
||||
"content": system,
|
||||
},
|
||||
)
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
async def job():
|
||||
pipe_id = form_data["model"]
|
||||
if "." in pipe_id:
|
||||
|
@ -198,7 +198,7 @@ class FunctionsTable:
|
||||
|
||||
try:
|
||||
user = Users.get_user_by_id(user_id)
|
||||
user_settings = user.settings.model_dump()
|
||||
user_settings = user.settings.model_dump() if user.settings else {}
|
||||
|
||||
# Check if user has "functions" and "valves" settings
|
||||
if "functions" not in user_settings:
|
||||
@ -217,7 +217,7 @@ class FunctionsTable:
|
||||
|
||||
try:
|
||||
user = Users.get_user_by_id(user_id)
|
||||
user_settings = user.settings.model_dump()
|
||||
user_settings = user.settings.model_dump() if user.settings else {}
|
||||
|
||||
# Check if user has "functions" and "valves" settings
|
||||
if "functions" not in user_settings:
|
||||
|
@ -149,7 +149,7 @@ class ToolsTable:
|
||||
) -> Optional[dict]:
|
||||
try:
|
||||
user = Users.get_user_by_id(user_id)
|
||||
user_settings = user.settings.model_dump()
|
||||
user_settings = user.settings.model_dump() if user.settings else {}
|
||||
|
||||
# Check if user has "tools" and "valves" settings
|
||||
if "tools" not in user_settings:
|
||||
@ -167,7 +167,7 @@ class ToolsTable:
|
||||
) -> Optional[dict]:
|
||||
try:
|
||||
user = Users.get_user_by_id(user_id)
|
||||
user_settings = user.settings.model_dump()
|
||||
user_settings = user.settings.model_dump() if user.settings else {}
|
||||
|
||||
# Check if user has "tools" and "valves" settings
|
||||
if "tools" not in user_settings:
|
||||
|
@ -999,12 +999,16 @@ async def get_all_models():
|
||||
model["info"] = custom_model.model_dump()
|
||||
else:
|
||||
owned_by = "openai"
|
||||
pipe = None
|
||||
|
||||
for model in models:
|
||||
if (
|
||||
custom_model.base_model_id == model["id"]
|
||||
or custom_model.base_model_id == model["id"].split(":")[0]
|
||||
):
|
||||
owned_by = model["owned_by"]
|
||||
if "pipe" in model:
|
||||
pipe = model["pipe"]
|
||||
break
|
||||
|
||||
models.append(
|
||||
@ -1016,11 +1020,11 @@ async def get_all_models():
|
||||
"owned_by": owned_by,
|
||||
"info": custom_model.model_dump(),
|
||||
"preset": True,
|
||||
**({"pipe": pipe} if pipe is not None else {}),
|
||||
}
|
||||
)
|
||||
|
||||
app.state.MODELS = {model["id"]: model for model in models}
|
||||
|
||||
webui_app.state.MODELS = app.state.MODELS
|
||||
|
||||
return models
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import { getContext, tick } from 'svelte';
|
||||
import { getContext, tick, onMount } from 'svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
|
||||
import Database from './Settings/Database.svelte';
|
||||
@ -21,11 +21,24 @@
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
let selectedTab = 'general';
|
||||
|
||||
onMount(() => {
|
||||
const containerElement = document.getElementById('admin-settings-tabs-container');
|
||||
|
||||
if (containerElement) {
|
||||
containerElement.addEventListener('wheel', function (event) {
|
||||
if (event.deltaY !== 0) {
|
||||
// Adjust horizontal scroll position based on vertical scroll
|
||||
containerElement.scrollLeft += event.deltaY;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col lg:flex-row w-full h-full py-2 lg:space-x-4">
|
||||
<div
|
||||
class="tabs flex flex-row overflow-x-auto space-x-1 max-w-full lg:space-x-0 lg:space-y-1 lg:flex-col lg:flex-none lg:w-44 dark:text-gray-200 text-xs text-left scrollbar-none"
|
||||
id="admin-settings-tabs-container" class="tabs flex flex-row overflow-x-auto space-x-1 max-w-full lg:space-x-0 lg:space-y-1 lg:flex-col lg:flex-none lg:w-44 dark:text-gray-200 text-xs text-left scrollbar-none"
|
||||
>
|
||||
<button
|
||||
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 lg:flex-none flex text-right transition {selectedTab ===
|
||||
|
@ -158,12 +158,14 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const [res, controller] = await pullModel(localStorage.token, sanitizedModelTag, '0').catch(
|
||||
(error) => {
|
||||
toast.error(error);
|
||||
return null;
|
||||
}
|
||||
);
|
||||
const [res, controller] = await pullModel(
|
||||
localStorage.token,
|
||||
sanitizedModelTag,
|
||||
selectedOllamaUrlIdx
|
||||
).catch((error) => {
|
||||
toast.error(error);
|
||||
return null;
|
||||
});
|
||||
|
||||
if (res) {
|
||||
const reader = res.body
|
||||
|
@ -126,21 +126,29 @@
|
||||
})();
|
||||
}
|
||||
|
||||
const chatEventHandler = async (data) => {
|
||||
if (data.chat_id === $chatId) {
|
||||
const chatEventHandler = async (event) => {
|
||||
if (event.chat_id === $chatId) {
|
||||
await tick();
|
||||
console.log(data);
|
||||
let message = history.messages[data.message_id];
|
||||
console.log(event);
|
||||
let message = history.messages[event.message_id];
|
||||
|
||||
const status = {
|
||||
done: data?.data?.done ?? null,
|
||||
description: data?.data?.status ?? null
|
||||
};
|
||||
const type = event?.data?.type ?? null;
|
||||
const data = event?.data?.data ?? null;
|
||||
|
||||
if (message.statusHistory) {
|
||||
message.statusHistory.push(status);
|
||||
if (type === 'status') {
|
||||
if (message.statusHistory) {
|
||||
message.statusHistory.push(data);
|
||||
} else {
|
||||
message.statusHistory = [data];
|
||||
}
|
||||
} else if (type === 'citation') {
|
||||
if (message.citations) {
|
||||
message.citations.push(data);
|
||||
} else {
|
||||
message.citations = [data];
|
||||
}
|
||||
} else {
|
||||
message.statusHistory = [status];
|
||||
console.log('Unknown message type', data);
|
||||
}
|
||||
|
||||
messages = messages;
|
||||
|
@ -2,32 +2,25 @@
|
||||
import ChevronDown from '$lib/components/icons/ChevronDown.svelte';
|
||||
import ChevronUp from '$lib/components/icons/ChevronUp.svelte';
|
||||
import MagnifyingGlass from '$lib/components/icons/MagnifyingGlass.svelte';
|
||||
import { Collapsible } from 'bits-ui';
|
||||
import { slide } from 'svelte/transition';
|
||||
import Collapsible from '$lib/components/common/Collapsible.svelte';
|
||||
|
||||
export let status = { urls: [], query: '' };
|
||||
let state = false;
|
||||
</script>
|
||||
|
||||
<Collapsible.Root class="w-full space-y-1" bind:open={state}>
|
||||
<Collapsible.Trigger>
|
||||
<div
|
||||
class="flex items-center gap-2 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition"
|
||||
>
|
||||
<slot />
|
||||
|
||||
{#if state}
|
||||
<ChevronUp strokeWidth="3.5" className="size-3.5 " />
|
||||
{:else}
|
||||
<ChevronDown strokeWidth="3.5" className="size-3.5 " />
|
||||
{/if}
|
||||
</div>
|
||||
</Collapsible.Trigger>
|
||||
|
||||
<Collapsible.Content
|
||||
class=" text-sm border border-gray-300/30 dark:border-gray-700/50 rounded-xl"
|
||||
transition={slide}
|
||||
<Collapsible bind:open={state} className="w-full space-y-1">
|
||||
<div
|
||||
class="flex items-center gap-2 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition"
|
||||
>
|
||||
<slot />
|
||||
|
||||
{#if state}
|
||||
<ChevronUp strokeWidth="3.5" className="size-3.5 " />
|
||||
{:else}
|
||||
<ChevronDown strokeWidth="3.5" className="size-3.5 " />
|
||||
{/if}
|
||||
</div>
|
||||
<div class="text-sm border border-gray-300/30 dark:border-gray-700/50 rounded-xl" slot="content">
|
||||
{#if status?.query}
|
||||
<a
|
||||
href="https://www.google.com/search?q={status.query}"
|
||||
@ -93,5 +86,5 @@
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</Collapsible.Content>
|
||||
</Collapsible.Root>
|
||||
</div>
|
||||
</Collapsible>
|
||||
|
@ -1,9 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
import { getContext, tick } from 'svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { models, settings, user } from '$lib/stores';
|
||||
|
||||
import { updateUserSettings } from '$lib/apis/users';
|
||||
import { getModels as _getModels } from '$lib/apis';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
import Modal from '../common/Modal.svelte';
|
||||
import Account from './Settings/Account.svelte';
|
||||
@ -14,8 +15,6 @@
|
||||
import Chats from './Settings/Chats.svelte';
|
||||
import User from '../icons/User.svelte';
|
||||
import Personalization from './Settings/Personalization.svelte';
|
||||
import { updateUserSettings } from '$lib/apis/users';
|
||||
import { goto } from '$app/navigation';
|
||||
import Valves from './Settings/Valves.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
@ -34,6 +33,37 @@
|
||||
};
|
||||
|
||||
let selectedTab = 'general';
|
||||
|
||||
// Function to handle sideways scrolling
|
||||
const scrollHandler = (event) => {
|
||||
const settingsTabsContainer = document.getElementById('settings-tabs-container');
|
||||
if (settingsTabsContainer) {
|
||||
event.preventDefault(); // Prevent default vertical scrolling
|
||||
settingsTabsContainer.scrollLeft += event.deltaY; // Scroll sideways
|
||||
}
|
||||
};
|
||||
|
||||
const addScrollListener = async () => {
|
||||
await tick();
|
||||
const settingsTabsContainer = document.getElementById('settings-tabs-container');
|
||||
if (settingsTabsContainer) {
|
||||
settingsTabsContainer.addEventListener('wheel', scrollHandler);
|
||||
}
|
||||
};
|
||||
|
||||
const removeScrollListener = async () => {
|
||||
await tick();
|
||||
const settingsTabsContainer = document.getElementById('settings-tabs-container');
|
||||
if (settingsTabsContainer) {
|
||||
settingsTabsContainer.removeEventListener('wheel', scrollHandler);
|
||||
}
|
||||
};
|
||||
|
||||
$: if (show) {
|
||||
addScrollListener();
|
||||
} else {
|
||||
removeScrollListener();
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal bind:show>
|
||||
@ -61,6 +91,7 @@
|
||||
|
||||
<div class="flex flex-col md:flex-row w-full p-4 md:space-x-4">
|
||||
<div
|
||||
id="settings-tabs-container"
|
||||
class="tabs flex flex-row overflow-x-auto space-x-1 md:space-x-0 md:space-y-1 md:flex-col flex-1 md:flex-none md:w-40 dark:text-gray-200 text-xs text-left mb-3 md:mb-0"
|
||||
>
|
||||
<button
|
||||
|
18
src/lib/components/common/Collapsible.svelte
Normal file
18
src/lib/components/common/Collapsible.svelte
Normal file
@ -0,0 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { slide } from 'svelte/transition';
|
||||
import { quintOut } from 'svelte/easing';
|
||||
export let open = false;
|
||||
export let className = '';
|
||||
</script>
|
||||
|
||||
<div class={className}>
|
||||
<button on:click={() => (open = !open)}>
|
||||
<slot />
|
||||
</button>
|
||||
|
||||
{#if open}
|
||||
<div transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }}>
|
||||
<slot name="content" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
@ -186,6 +186,7 @@
|
||||
goto('/');
|
||||
}
|
||||
await chats.set(await getChatList(localStorage.token));
|
||||
await pinnedChats.set(await getChatListByTagName(localStorage.token, 'pinned'));
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -126,7 +126,7 @@
|
||||
"Connections": "Connexions",
|
||||
"Contact Admin for WebUI Access": "Posat en contacte amb l'administrador per accedir a WebUI",
|
||||
"Content": "Contingut",
|
||||
"Content Extraction": "",
|
||||
"Content Extraction": "Extraccció de contingut",
|
||||
"Context Length": "Mida del context",
|
||||
"Continue Response": "Continuar la resposta",
|
||||
"Continue with {{provider}}": "Continuar amb {{provider}}",
|
||||
@ -213,7 +213,7 @@
|
||||
"Enable Community Sharing": "Activar l'ús compartit amb la comunitat",
|
||||
"Enable New Sign Ups": "Permetre nous registres",
|
||||
"Enable Web Search": "Activar la cerca web",
|
||||
"Engine": "",
|
||||
"Engine": "Motor",
|
||||
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "Assegura't que els teus fitxers CSV inclouen 4 columnes en aquest ordre: Nom, Correu electrònic, Contrasenya, Rol.",
|
||||
"Enter {{role}} message here": "Introdueix aquí el missatge de {{role}}",
|
||||
"Enter a detail about yourself for your LLMs to recall": "Introdueix un detall sobre tu què els teus models de llenguatge puguin recordar",
|
||||
@ -235,7 +235,7 @@
|
||||
"Enter Serpstack API Key": "Introdueix la clau API Serpstack",
|
||||
"Enter stop sequence": "Introdueix la seqüència de parada",
|
||||
"Enter Tavily API Key": "Introdueix la clau API de Tavily",
|
||||
"Enter Tika Server URL": "",
|
||||
"Enter Tika Server URL": "Introdueix l'URL del servidor Tika",
|
||||
"Enter Top K": "Introdueix Top K",
|
||||
"Enter URL (e.g. http://127.0.0.1:7860/)": "Introdueix l'URL (p. ex. http://127.0.0.1:7860/)",
|
||||
"Enter URL (e.g. http://localhost:11434)": "Introdueix l'URL (p. ex. http://localhost:11434)",
|
||||
@ -412,7 +412,7 @@
|
||||
"Open": "Obre",
|
||||
"Open AI (Dall-E)": "Open AI (Dall-E)",
|
||||
"Open new chat": "Obre un xat nou",
|
||||
"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
|
||||
"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "La versió d'Open WebUI (v{{OPEN_WEBUI_VERSION}}) és inferior a la versió requerida (v{{REQUIRED_VERSION}})",
|
||||
"OpenAI": "OpenAI",
|
||||
"OpenAI API": "API d'OpenAI",
|
||||
"OpenAI API Config": "Configuració de l'API d'OpenAI",
|
||||
@ -428,8 +428,8 @@
|
||||
"Permission denied when accessing microphone": "Permís denegat en accedir al micròfon",
|
||||
"Permission denied when accessing microphone: {{error}}": "Permís denegat en accedir al micròfon: {{error}}",
|
||||
"Personalization": "Personalització",
|
||||
"Pin": "",
|
||||
"Pinned": "",
|
||||
"Pin": "Fixar",
|
||||
"Pinned": "Fixat",
|
||||
"Pipeline deleted successfully": "Pipeline eliminada correctament",
|
||||
"Pipeline downloaded successfully": "Pipeline descarregada correctament",
|
||||
"Pipelines": "Pipelines",
|
||||
@ -580,8 +580,8 @@
|
||||
"This setting does not sync across browsers or devices.": "Aquesta preferència no es sincronitza entre navegadors ni dispositius.",
|
||||
"This will delete": "Això eliminarà",
|
||||
"Thorough explanation": "Explicació en detall",
|
||||
"Tika": "",
|
||||
"Tika Server URL required.": "",
|
||||
"Tika": "Tika",
|
||||
"Tika Server URL required.": "La URL del servidor Tika és obligatòria.",
|
||||
"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "Consell: Actualitza les diverses variables consecutivament prement la tecla de tabulació en l'entrada del xat després de cada reemplaçament.",
|
||||
"Title": "Títol",
|
||||
"Title (e.g. Tell me a fun fact)": "Títol (p. ex. Digues-me quelcom divertit)",
|
||||
@ -616,7 +616,7 @@
|
||||
"Uh-oh! There was an issue connecting to {{provider}}.": "Oh! Hi ha hagut un problema connectant a {{provider}}.",
|
||||
"UI": "UI",
|
||||
"Unknown file type '{{file_type}}'. Proceeding with the file upload anyway.": "Tipus de fitxer desconegut '{{file_type}}'. Continuant amb la càrrega del fitxer.",
|
||||
"Unpin": "",
|
||||
"Unpin": "Alliberar",
|
||||
"Update": "Actualitzar",
|
||||
"Update and Copy Link": "Actualitzar i copiar l'enllaç",
|
||||
"Update password": "Actualitzar la contrasenya",
|
||||
|
@ -126,7 +126,7 @@
|
||||
"Connections": "外部连接",
|
||||
"Contact Admin for WebUI Access": "请联系管理员以获取访问权限",
|
||||
"Content": "内容",
|
||||
"Content Extraction": "",
|
||||
"Content Extraction": "内容提取",
|
||||
"Context Length": "上下文长度",
|
||||
"Continue Response": "继续生成",
|
||||
"Continue with {{provider}}": "使用 {{provider}} 继续",
|
||||
@ -213,7 +213,7 @@
|
||||
"Enable Community Sharing": "启用分享至社区",
|
||||
"Enable New Sign Ups": "允许新用户注册",
|
||||
"Enable Web Search": "启用网络搜索",
|
||||
"Engine": "",
|
||||
"Engine": "引擎",
|
||||
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "确保您的 CSV 文件按以下顺序包含 4 列: 姓名、电子邮箱、密码、角色。",
|
||||
"Enter {{role}} message here": "在此处输入 {{role}} 信息",
|
||||
"Enter a detail about yourself for your LLMs to recall": "输入一个关于你自己的详细信息,方便你的大语言模型记住这些内容",
|
||||
@ -235,7 +235,7 @@
|
||||
"Enter Serpstack API Key": "输入 Serpstack API 密钥",
|
||||
"Enter stop sequence": "输入停止序列 (Stop Sequence)",
|
||||
"Enter Tavily API Key": "输入 Tavily API 密钥",
|
||||
"Enter Tika Server URL": "",
|
||||
"Enter Tika Server URL": "输入 Tika 服务器地址",
|
||||
"Enter Top K": "输入 Top K",
|
||||
"Enter URL (e.g. http://127.0.0.1:7860/)": "输入地址 (例如:http://127.0.0.1:7860/)",
|
||||
"Enter URL (e.g. http://localhost:11434)": "输入地址 (例如:http://localhost:11434)",
|
||||
@ -412,7 +412,7 @@
|
||||
"Open": "打开",
|
||||
"Open AI (Dall-E)": "Open AI (Dall-E)",
|
||||
"Open new chat": "打开新对话",
|
||||
"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
|
||||
"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "当前 Open WebUI 版本 (v{{OPEN_WEBUI_VERSION}}) 低于所需的版本 (v{{REQUIRED_VERSION}})",
|
||||
"OpenAI": "OpenAI",
|
||||
"OpenAI API": "OpenAI API",
|
||||
"OpenAI API Config": "OpenAI API 配置",
|
||||
@ -428,8 +428,8 @@
|
||||
"Permission denied when accessing microphone": "申请麦克风权限被拒绝",
|
||||
"Permission denied when accessing microphone: {{error}}": "申请麦克风权限被拒绝:{{error}}",
|
||||
"Personalization": "个性化",
|
||||
"Pin": "",
|
||||
"Pinned": "",
|
||||
"Pin": "置顶",
|
||||
"Pinned": "已置顶",
|
||||
"Pipeline deleted successfully": "Pipeline 删除成功",
|
||||
"Pipeline downloaded successfully": "Pipeline 下载成功",
|
||||
"Pipelines": "Pipeline",
|
||||
@ -578,8 +578,8 @@
|
||||
"This setting does not sync across browsers or devices.": "此设置不会在浏览器或设备之间同步。",
|
||||
"This will delete": "这将删除",
|
||||
"Thorough explanation": "解释较为详细",
|
||||
"Tika": "",
|
||||
"Tika Server URL required.": "",
|
||||
"Tika": "Tika",
|
||||
"Tika Server URL required.": "请输入 Tika 服务器地址。",
|
||||
"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "提示:在每次替换后,在对话输入中按 Tab 键可以连续更新多个变量。",
|
||||
"Title": "标题",
|
||||
"Title (e.g. Tell me a fun fact)": "标题(例如 给我讲一个有趣的事实)",
|
||||
@ -614,7 +614,7 @@
|
||||
"Uh-oh! There was an issue connecting to {{provider}}.": "糟糕!连接到 {{provider}} 时出现问题。",
|
||||
"UI": "界面",
|
||||
"Unknown file type '{{file_type}}'. Proceeding with the file upload anyway.": "未知文件类型“{{file_type}}”,将无视继续上传文件。",
|
||||
"Unpin": "",
|
||||
"Unpin": "取消置顶",
|
||||
"Update": "更新",
|
||||
"Update and Copy Link": "更新和复制链接",
|
||||
"Update password": "更新密码",
|
||||
|
Loading…
Reference in New Issue
Block a user