Merge branch 'dev' into main

This commit is contained in:
Jarrod Lowe 2025-04-11 22:14:41 +12:00 committed by GitHub
commit a8bbaa61bd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
96 changed files with 1848 additions and 905 deletions

View file

@ -73,8 +73,15 @@ def serve(
os.environ["LD_LIBRARY_PATH"] = ":".join(LD_LIBRARY_PATH)
import open_webui.main # we need set environment variables before importing main
from open_webui.env import UVICORN_WORKERS # Import the workers setting
uvicorn.run(open_webui.main.app, host=host, port=port, forwarded_allow_ips="*")
uvicorn.run(
open_webui.main.app,
host=host,
port=port,
forwarded_allow_ips="*",
workers=UVICORN_WORKERS
)
@app.command()

View file

@ -201,6 +201,7 @@ def save_config(config):
T = TypeVar("T")
ENABLE_PERSISTENT_CONFIG = os.environ.get("ENABLE_PERSISTENT_CONFIG", "True").lower() == "true"
class PersistentConfig(Generic[T]):
def __init__(self, env_name: str, config_path: str, env_value: T):
@ -208,7 +209,7 @@ class PersistentConfig(Generic[T]):
self.config_path = config_path
self.env_value = env_value
self.config_value = get_config_value(config_path)
if self.config_value is not None:
if self.config_value is not None and ENABLE_PERSISTENT_CONFIG:
log.info(f"'{env_name}' loaded from the latest database entry")
self.value = self.config_value
else:
@ -456,6 +457,12 @@ OAUTH_SCOPES = PersistentConfig(
os.environ.get("OAUTH_SCOPES", "openid email profile"),
)
OAUTH_CODE_CHALLENGE_METHOD = PersistentConfig(
"OAUTH_CODE_CHALLENGE_METHOD",
"oauth.oidc.code_challenge_method",
os.environ.get("OAUTH_CODE_CHALLENGE_METHOD", None),
)
OAUTH_PROVIDER_NAME = PersistentConfig(
"OAUTH_PROVIDER_NAME",
"oauth.oidc.provider_name",
@ -560,7 +567,7 @@ def load_oauth_providers():
name="microsoft",
client_id=MICROSOFT_CLIENT_ID.value,
client_secret=MICROSOFT_CLIENT_SECRET.value,
server_metadata_url=f"https://login.microsoftonline.com/{MICROSOFT_CLIENT_TENANT_ID.value}/v2.0/.well-known/openid-configuration",
server_metadata_url=f"https://login.microsoftonline.com/{MICROSOFT_CLIENT_TENANT_ID.value}/v2.0/.well-known/openid-configuration?appid={MICROSOFT_CLIENT_ID.value}",
client_kwargs={
"scope": MICROSOFT_OAUTH_SCOPE.value,
},
@ -601,14 +608,21 @@ def load_oauth_providers():
):
def oidc_oauth_register(client):
client_kwargs = {
"scope": OAUTH_SCOPES.value,
}
if OAUTH_CODE_CHALLENGE_METHOD.value and OAUTH_CODE_CHALLENGE_METHOD.value == "S256":
client_kwargs["code_challenge_method"] = "S256"
elif OAUTH_CODE_CHALLENGE_METHOD.value:
raise Exception('Code challenge methods other than "%s" not supported. Given: "%s"' % ("S256", OAUTH_CODE_CHALLENGE_METHOD.value))
client.register(
name="oidc",
client_id=OAUTH_CLIENT_ID.value,
client_secret=OAUTH_CLIENT_SECRET.value,
server_metadata_url=OPENID_PROVIDER_URL.value,
client_kwargs={
"scope": OAUTH_SCOPES.value,
},
client_kwargs=client_kwargs,
redirect_uri=OPENID_REDIRECT_URI.value,
)
@ -2141,6 +2155,18 @@ PERPLEXITY_API_KEY = PersistentConfig(
os.getenv("PERPLEXITY_API_KEY", ""),
)
SOUGOU_API_SID = PersistentConfig(
"SOUGOU_API_SID",
"rag.web.search.sougou_api_sid",
os.getenv("SOUGOU_API_SID", ""),
)
SOUGOU_API_SK = PersistentConfig(
"SOUGOU_API_SK",
"rag.web.search.sougou_api_sk",
os.getenv("SOUGOU_API_SK", ""),
)
RAG_WEB_SEARCH_RESULT_COUNT = PersistentConfig(
"RAG_WEB_SEARCH_RESULT_COUNT",
"rag.web.search.result_count",
@ -2472,6 +2498,24 @@ AUDIO_STT_MODEL = PersistentConfig(
os.getenv("AUDIO_STT_MODEL", ""),
)
AUDIO_STT_AZURE_API_KEY = PersistentConfig(
"AUDIO_STT_AZURE_API_KEY",
"audio.stt.azure.api_key",
os.getenv("AUDIO_STT_AZURE_API_KEY", ""),
)
AUDIO_STT_AZURE_REGION = PersistentConfig(
"AUDIO_STT_AZURE_REGION",
"audio.stt.azure.region",
os.getenv("AUDIO_STT_AZURE_REGION", ""),
)
AUDIO_STT_AZURE_LOCALES = PersistentConfig(
"AUDIO_STT_AZURE_LOCALES",
"audio.stt.azure.locales",
os.getenv("AUDIO_STT_AZURE_LOCALES", ""),
)
AUDIO_TTS_OPENAI_API_BASE_URL = PersistentConfig(
"AUDIO_TTS_OPENAI_API_BASE_URL",
"audio.tts.openai.api_base_url",

View file

@ -31,6 +31,7 @@ class ERROR_MESSAGES(str, Enum):
USERNAME_TAKEN = (
"Uh-oh! This username is already registered. Please choose another username."
)
PASSWORD_TOO_LONG = "Uh-oh! The password you entered is too long. Please make sure your password is less than 72 bytes long."
COMMAND_TAKEN = "Uh-oh! This command is already registered. Please choose another command string."
FILE_EXISTS = "Uh-oh! This file is already registered. Please choose another file."

View file

@ -326,6 +326,20 @@ REDIS_URL = os.environ.get("REDIS_URL", "")
REDIS_SENTINEL_HOSTS = os.environ.get("REDIS_SENTINEL_HOSTS", "")
REDIS_SENTINEL_PORT = os.environ.get("REDIS_SENTINEL_PORT", "26379")
####################################
# UVICORN WORKERS
####################################
# Number of uvicorn worker processes for handling requests
UVICORN_WORKERS = os.environ.get("UVICORN_WORKERS", "1")
try:
UVICORN_WORKERS = int(UVICORN_WORKERS)
if UVICORN_WORKERS < 1:
UVICORN_WORKERS = 1
except ValueError:
UVICORN_WORKERS = 1
log.info(f"Invalid UVICORN_WORKERS value, defaulting to {UVICORN_WORKERS}")
####################################
# WEBUI_AUTH (Required for security)
####################################
@ -411,6 +425,21 @@ else:
except Exception:
AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = 10
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = os.environ.get(
"AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA", "10"
)
if AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA == "":
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = None
else:
try:
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = int(
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA
)
except Exception:
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = 10
####################################
# OFFLINE_MODE
####################################
@ -463,3 +492,10 @@ OTEL_TRACES_SAMPLER = os.environ.get(
PIP_OPTIONS = os.getenv("PIP_OPTIONS", "").split()
PIP_PACKAGE_INDEX_OPTIONS = os.getenv("PIP_PACKAGE_INDEX_OPTIONS", "").split()
####################################
# PROGRESSIVE WEB APP OPTIONS
####################################
EXTERNAL_PWA_MANIFEST_URL = os.environ.get("EXTERNAL_PWA_MANIFEST_URL")

View file

@ -148,6 +148,9 @@ from open_webui.config import (
AUDIO_STT_MODEL,
AUDIO_STT_OPENAI_API_BASE_URL,
AUDIO_STT_OPENAI_API_KEY,
AUDIO_STT_AZURE_API_KEY,
AUDIO_STT_AZURE_REGION,
AUDIO_STT_AZURE_LOCALES,
AUDIO_TTS_API_KEY,
AUDIO_TTS_ENGINE,
AUDIO_TTS_MODEL,
@ -225,6 +228,8 @@ from open_webui.config import (
BRAVE_SEARCH_API_KEY,
EXA_API_KEY,
PERPLEXITY_API_KEY,
SOUGOU_API_SID,
SOUGOU_API_SK,
KAGI_SEARCH_API_KEY,
MOJEEK_SEARCH_API_KEY,
BOCHA_SEARCH_API_KEY,
@ -341,6 +346,7 @@ from open_webui.env import (
RESET_CONFIG_ON_START,
OFFLINE_MODE,
ENABLE_OTEL,
EXTERNAL_PWA_MANIFEST_URL,
)
@ -427,6 +433,7 @@ async def lifespan(app: FastAPI):
app = FastAPI(
title="Open WebUI",
docs_url="/docs" if ENV == "dev" else None,
openapi_url="/openapi.json" if ENV == "dev" else None,
redoc_url=None,
@ -566,6 +573,7 @@ app.state.config.LDAP_CIPHERS = LDAP_CIPHERS
app.state.AUTH_TRUSTED_EMAIL_HEADER = WEBUI_AUTH_TRUSTED_EMAIL_HEADER
app.state.AUTH_TRUSTED_NAME_HEADER = WEBUI_AUTH_TRUSTED_NAME_HEADER
app.state.SIGNOUT_REDIRECT_URI = SIGNOUT_REDIRECT_URI
app.state.EXTERNAL_PWA_MANIFEST_URL = EXTERNAL_PWA_MANIFEST_URL
app.state.USER_COUNT = None
app.state.TOOLS = {}
@ -653,6 +661,8 @@ app.state.config.BING_SEARCH_V7_ENDPOINT = BING_SEARCH_V7_ENDPOINT
app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY = BING_SEARCH_V7_SUBSCRIPTION_KEY
app.state.config.EXA_API_KEY = EXA_API_KEY
app.state.config.PERPLEXITY_API_KEY = PERPLEXITY_API_KEY
app.state.config.SOUGOU_API_SID = SOUGOU_API_SID
app.state.config.SOUGOU_API_SK = SOUGOU_API_SK
app.state.config.RAG_WEB_SEARCH_RESULT_COUNT = RAG_WEB_SEARCH_RESULT_COUNT
app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS = RAG_WEB_SEARCH_CONCURRENT_REQUESTS
@ -780,6 +790,10 @@ app.state.config.STT_MODEL = AUDIO_STT_MODEL
app.state.config.WHISPER_MODEL = WHISPER_MODEL
app.state.config.DEEPGRAM_API_KEY = DEEPGRAM_API_KEY
app.state.config.AUDIO_STT_AZURE_API_KEY = AUDIO_STT_AZURE_API_KEY
app.state.config.AUDIO_STT_AZURE_REGION = AUDIO_STT_AZURE_REGION
app.state.config.AUDIO_STT_AZURE_LOCALES = AUDIO_STT_AZURE_LOCALES
app.state.config.TTS_OPENAI_API_BASE_URL = AUDIO_TTS_OPENAI_API_BASE_URL
app.state.config.TTS_OPENAI_API_KEY = AUDIO_TTS_OPENAI_API_KEY
app.state.config.TTS_ENGINE = AUDIO_TTS_ENGINE
@ -1055,6 +1069,7 @@ async def chat_completion(
model_item = form_data.pop("model_item", {})
tasks = form_data.pop("background_tasks", None)
metadata = {}
try:
if not model_item.get("direct", False):
model_id = form_data.get("model", None)
@ -1110,6 +1125,8 @@ async def chat_completion(
except Exception as e:
log.debug(f"Error processing chat payload: {e}")
if metadata.get("chat_id") and metadata.get("message_id"):
# Update the chat message with the error
Chats.upsert_message_to_chat_by_id_and_message_id(
metadata["chat_id"],
metadata["message_id"],
@ -1392,6 +1409,9 @@ async def oauth_callback(provider: str, request: Request, response: Response):
@app.get("/manifest.json")
async def get_manifest_json():
if app.state.EXTERNAL_PWA_MANIFEST_URL:
return requests.get(app.state.EXTERNAL_PWA_MANIFEST_URL).json()
else:
return {
"name": app.state.WEBUI_NAME,
"short_name": app.state.WEBUI_NAME,

View file

@ -110,7 +110,7 @@ class YoutubeLoader:
transcript = " ".join(
map(
lambda transcript_piece: transcript_piece["text"].strip(" "),
lambda transcript_piece: transcript_piece.text.strip(" "),
transcript_pieces,
)
)

View file

@ -77,6 +77,7 @@ def query_doc(
collection_name: str, query_embedding: list[float], k: int, user: UserModel = None
):
try:
log.debug(f"query_doc:doc {collection_name}")
result = VECTOR_DB_CLIENT.search(
collection_name=collection_name,
vectors=[query_embedding],
@ -94,6 +95,7 @@ def query_doc(
def get_doc(collection_name: str, user: UserModel = None):
try:
log.debug(f"get_doc:doc {collection_name}")
result = VECTOR_DB_CLIENT.get(collection_name=collection_name)
if result:
@ -116,6 +118,7 @@ def query_doc_with_hybrid_search(
r: float,
) -> dict:
try:
log.debug(f"query_doc_with_hybrid_search:doc {collection_name}")
bm25_retriever = BM25Retriever.from_texts(
texts=collection_result.documents[0],
metadatas=collection_result.metadatas[0],
@ -168,6 +171,7 @@ def query_doc_with_hybrid_search(
)
return result
except Exception as e:
log.exception(f"Error querying doc {collection_name} with hybrid search: {e}")
raise e
@ -257,6 +261,7 @@ def query_collection(
) -> dict:
results = []
for query in queries:
log.debug(f"query_collection:query {query}")
query_embedding = embedding_function(query, prefix=RAG_EMBEDDING_QUERY_PREFIX)
for collection_name in collection_names:
if collection_name:
@ -292,6 +297,7 @@ def query_collection_with_hybrid_search(
collection_results = {}
for collection_name in collection_names:
try:
log.debug(f"query_collection_with_hybrid_search:VECTOR_DB_CLIENT.get:collection {collection_name}")
collection_results[collection_name] = VECTOR_DB_CLIENT.get(
collection_name=collection_name
)
@ -613,6 +619,7 @@ def generate_openai_batch_embeddings(
user: UserModel = None,
) -> Optional[list[list[float]]]:
try:
log.debug(f"generate_openai_batch_embeddings:model {model} batch size: {len(texts)}")
json_data = {"input": texts, "model": model}
if isinstance(RAG_EMBEDDING_PREFIX_FIELD_NAME, str) and isinstance(prefix, str):
json_data[RAG_EMBEDDING_PREFIX_FIELD_NAME] = prefix
@ -655,6 +662,7 @@ def generate_ollama_batch_embeddings(
user: UserModel = None,
) -> Optional[list[list[float]]]:
try:
log.debug(f"generate_ollama_batch_embeddings:model {model} batch size: {len(texts)}")
json_data = {"input": texts, "model": model}
if isinstance(RAG_EMBEDDING_PREFIX_FIELD_NAME, str) and isinstance(prefix, str):
json_data[RAG_EMBEDDING_PREFIX_FIELD_NAME] = prefix

View file

@ -3,6 +3,7 @@ from typing import Optional
from open_webui.retrieval.web.main import SearchResult, get_filtered_results
from duckduckgo_search import DDGS
from duckduckgo_search.exceptions import RatelimitException
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
@ -22,16 +23,15 @@ def search_duckduckgo(
list[SearchResult]: A list of search results
"""
# Use the DDGS context manager to create a DDGS object
search_results = []
with DDGS() as ddgs:
# Use the ddgs.text() method to perform the search
ddgs_gen = ddgs.text(
query, safesearch="moderate", max_results=count, backend="api"
try:
search_results = ddgs.text(
query, safesearch="moderate", max_results=count, backend="lite"
)
# Check if there are search results
if ddgs_gen:
# Convert the search results into a list
search_results = [r for r in ddgs_gen]
except RatelimitException as e:
log.error(f"RatelimitException: {e}")
if filter_list:
search_results = get_filtered_results(search_results, filter_list)

View file

@ -0,0 +1,60 @@
import logging
import json
from typing import Optional, List
from open_webui.retrieval.web.main import SearchResult, get_filtered_results
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
def search_sougou(
sougou_api_sid: str,
sougou_api_sk: str,
query: str,
count: int,
filter_list: Optional[List[str]] = None,
) -> List[SearchResult]:
from tencentcloud.common.common_client import CommonClient
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import (
TencentCloudSDKException,
)
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
try:
cred = credential.Credential(sougou_api_sid, sougou_api_sk)
http_profile = HttpProfile()
http_profile.endpoint = "tms.tencentcloudapi.com"
client_profile = ClientProfile()
client_profile.http_profile = http_profile
params = json.dumps({"Query": query, "Cnt": 20})
common_client = CommonClient(
"tms", "2020-12-29", cred, "", profile=client_profile
)
results = [
json.loads(page)
for page in common_client.call_json("SearchPro", json.loads(params))[
"Response"
]["Pages"]
]
sorted_results = sorted(
results, key=lambda x: x.get("scour", 0.0), reverse=True
)
if filter_list:
sorted_results = get_filtered_results(sorted_results, filter_list)
return [
SearchResult(
link=result.get("url"),
title=result.get("title"),
snippet=result.get("passage"),
)
for result in sorted_results[:count]
]
except TencentCloudSDKException as err:
log.error(f"Error in Sougou search: {err}")
return []

View file

@ -50,6 +50,8 @@ router = APIRouter()
# Constants
MAX_FILE_SIZE_MB = 25
MAX_FILE_SIZE = MAX_FILE_SIZE_MB * 1024 * 1024 # Convert MB to bytes
AZURE_MAX_FILE_SIZE_MB = 200
AZURE_MAX_FILE_SIZE = AZURE_MAX_FILE_SIZE_MB * 1024 * 1024 # Convert MB to bytes
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["AUDIO"])
@ -68,8 +70,8 @@ from pydub import AudioSegment
from pydub.utils import mediainfo
def is_mp4_audio(file_path):
"""Check if the given file is an MP4 audio file."""
def get_audio_format(file_path):
"""Check if the given file needs to be converted to a different format."""
if not os.path.isfile(file_path):
log.error(f"File not found: {file_path}")
return False
@ -80,13 +82,17 @@ def is_mp4_audio(file_path):
and info.get("codec_type") == "audio"
and info.get("codec_tag_string") == "mp4a"
):
return True
return False
return "mp4"
elif info.get("format_name") == "ogg":
return "ogg"
elif info.get("format_name") == "matroska,webm":
return "webm"
return None
def convert_mp4_to_wav(file_path, output_path):
"""Convert MP4 audio file to WAV format."""
audio = AudioSegment.from_file(file_path, format="mp4")
def convert_audio_to_wav(file_path, output_path, conversion_type):
"""Convert MP4/OGG audio file to WAV format."""
audio = AudioSegment.from_file(file_path, format=conversion_type)
audio.export(output_path, format="wav")
log.info(f"Converted {file_path} to {output_path}")
@ -141,6 +147,9 @@ class STTConfigForm(BaseModel):
MODEL: str
WHISPER_MODEL: str
DEEPGRAM_API_KEY: str
AZURE_API_KEY: str
AZURE_REGION: str
AZURE_LOCALES: str
class AudioConfigUpdateForm(BaseModel):
@ -169,6 +178,9 @@ async def get_audio_config(request: Request, user=Depends(get_admin_user)):
"MODEL": request.app.state.config.STT_MODEL,
"WHISPER_MODEL": request.app.state.config.WHISPER_MODEL,
"DEEPGRAM_API_KEY": request.app.state.config.DEEPGRAM_API_KEY,
"AZURE_API_KEY": request.app.state.config.AUDIO_STT_AZURE_API_KEY,
"AZURE_REGION": request.app.state.config.AUDIO_STT_AZURE_REGION,
"AZURE_LOCALES": request.app.state.config.AUDIO_STT_AZURE_LOCALES,
},
}
@ -195,6 +207,9 @@ async def update_audio_config(
request.app.state.config.STT_MODEL = form_data.stt.MODEL
request.app.state.config.WHISPER_MODEL = form_data.stt.WHISPER_MODEL
request.app.state.config.DEEPGRAM_API_KEY = form_data.stt.DEEPGRAM_API_KEY
request.app.state.config.AUDIO_STT_AZURE_API_KEY = form_data.stt.AZURE_API_KEY
request.app.state.config.AUDIO_STT_AZURE_REGION = form_data.stt.AZURE_REGION
request.app.state.config.AUDIO_STT_AZURE_LOCALES = form_data.stt.AZURE_LOCALES
if request.app.state.config.STT_ENGINE == "":
request.app.state.faster_whisper_model = set_faster_whisper_model(
@ -220,6 +235,9 @@ async def update_audio_config(
"MODEL": request.app.state.config.STT_MODEL,
"WHISPER_MODEL": request.app.state.config.WHISPER_MODEL,
"DEEPGRAM_API_KEY": request.app.state.config.DEEPGRAM_API_KEY,
"AZURE_API_KEY": request.app.state.config.AUDIO_STT_AZURE_API_KEY,
"AZURE_REGION": request.app.state.config.AUDIO_STT_AZURE_REGION,
"AZURE_LOCALES": request.app.state.config.AUDIO_STT_AZURE_LOCALES,
},
}
@ -496,10 +514,15 @@ def transcribe(request: Request, file_path):
log.debug(data)
return data
elif request.app.state.config.STT_ENGINE == "openai":
if is_mp4_audio(file_path):
os.rename(file_path, file_path.replace(".wav", ".mp4"))
# Convert MP4 audio file to WAV format
convert_mp4_to_wav(file_path.replace(".wav", ".mp4"), file_path)
audio_format = get_audio_format(file_path)
if audio_format:
os.rename(file_path, file_path.replace(".wav", f".{audio_format}"))
# Convert unsupported audio file to WAV format
convert_audio_to_wav(
file_path.replace(".wav", f".{audio_format}"),
file_path,
audio_format,
)
r = None
try:
@ -598,6 +621,107 @@ def transcribe(request: Request, file_path):
detail = f"External: {e}"
raise Exception(detail if detail else "Open WebUI: Server Connection Error")
elif request.app.state.config.STT_ENGINE == "azure":
# Check file exists and size
if not os.path.exists(file_path):
raise HTTPException(
status_code=400,
detail="Audio file not found"
)
# Check file size (Azure has a larger limit of 200MB)
file_size = os.path.getsize(file_path)
if file_size > AZURE_MAX_FILE_SIZE:
raise HTTPException(
status_code=400,
detail=f"File size exceeds Azure's limit of {AZURE_MAX_FILE_SIZE_MB}MB",
)
api_key = request.app.state.config.AUDIO_STT_AZURE_API_KEY
region = request.app.state.config.AUDIO_STT_AZURE_REGION
locales = request.app.state.config.AUDIO_STT_AZURE_LOCALES
# IF NO LOCALES, USE DEFAULTS
if len(locales) < 2:
locales = ['en-US', 'es-ES', 'es-MX', 'fr-FR', 'hi-IN',
'it-IT','de-DE', 'en-GB', 'en-IN', 'ja-JP',
'ko-KR', 'pt-BR', 'zh-CN']
locales = ','.join(locales)
if not api_key or not region:
raise HTTPException(
status_code=400,
detail="Azure API key and region are required for Azure STT",
)
r = None
try:
# Prepare the request
data = {'definition': json.dumps({
"locales": locales.split(','),
"diarization": {"maxSpeakers": 3,"enabled": True}
} if locales else {}
)
}
url = f"https://{region}.api.cognitive.microsoft.com/speechtotext/transcriptions:transcribe?api-version=2024-11-15"
# Use context manager to ensure file is properly closed
with open(file_path, 'rb') as audio_file:
r = requests.post(
url=url,
files={'audio': audio_file},
data=data,
headers={
'Ocp-Apim-Subscription-Key': api_key,
},
)
r.raise_for_status()
response = r.json()
# Extract transcript from response
if not response.get('combinedPhrases'):
raise ValueError("No transcription found in response")
# Get the full transcript from combinedPhrases
transcript = response['combinedPhrases'][0].get('text', '').strip()
if not transcript:
raise ValueError("Empty transcript in response")
data = {"text": transcript}
# Save transcript to json file (consistent with other providers)
transcript_file = f"{file_dir}/{id}.json"
with open(transcript_file, "w") as f:
json.dump(data, f)
log.debug(data)
return data
except (KeyError, IndexError, ValueError) as e:
log.exception("Error parsing Azure response")
raise HTTPException(
status_code=500,
detail=f"Failed to parse Azure response: {str(e)}",
)
except requests.exceptions.RequestException as e:
log.exception(e)
detail = None
try:
if r is not None and r.status_code != 200:
res = r.json()
if "error" in res:
detail = f"External: {res['error'].get('message', '')}"
except Exception:
detail = f"External: {e}"
raise HTTPException(
status_code=getattr(r, 'status_code', 500) if r else 500,
detail=detail if detail else "Open WebUI: Server Connection Error",
)
def compress_audio(file_path):
if os.path.getsize(file_path) > MAX_FILE_SIZE:

View file

@ -231,11 +231,13 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm):
entry = connection_app.entries[0]
username = str(entry[f"{LDAP_ATTRIBUTE_FOR_USERNAME}"]).lower()
email = str(entry[f"{LDAP_ATTRIBUTE_FOR_MAIL}"])
if not email or email == "" or email == "[]":
email = entry[f"{LDAP_ATTRIBUTE_FOR_MAIL}"]
if not email:
raise HTTPException(400, "User does not have a valid email address.")
else:
elif isinstance(email, str):
email = email.lower()
elif isinstance(email, list):
email = email[0].lower()
cn = str(entry["cn"])
user_dn = entry.entry_dn
@ -455,6 +457,13 @@ async def signup(request: Request, response: Response, form_data: SignupForm):
# Disable signup after the first user is created
request.app.state.config.ENABLE_SIGNUP = False
# The password passed to bcrypt must be 72 bytes or fewer. If it is longer, it will be truncated before hashing.
if len(form_data.password.encode("utf-8")) > 72:
raise HTTPException(
status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.PASSWORD_TOO_LONG,
)
hashed = get_password_hash(form_data.password)
user = Auths.insert_new_auth(
form_data.email.lower(),

View file

@ -1,6 +1,7 @@
import logging
import os
import uuid
from fnmatch import fnmatch
from pathlib import Path
from typing import Optional
from urllib.parse import quote
@ -177,6 +178,47 @@ async def list_files(user=Depends(get_verified_user), content: bool = Query(True
return files
############################
# Search Files
############################
@router.get("/search", response_model=list[FileModelResponse])
async def search_files(
filename: str = Query(
...,
description="Filename pattern to search for. Supports wildcards such as '*.txt'",
),
content: bool = Query(True),
user=Depends(get_verified_user),
):
"""
Search for files by filename with support for wildcard patterns.
"""
# Get files according to user role
if user.role == "admin":
files = Files.get_files()
else:
files = Files.get_files_by_user_id(user.id)
# Get matching files
matching_files = [
file for file in files if fnmatch(file.filename.lower(), filename.lower())
]
if not matching_files:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="No files found matching the pattern.",
)
if not content:
for file in matching_files:
del file.data["content"]
return matching_files
############################
# Delete All Files
############################

View file

@ -161,6 +161,72 @@ async def create_new_knowledge(
)
############################
# ReindexKnowledgeFiles
############################
@router.post("/reindex", response_model=bool)
async def reindex_knowledge_files(
request: Request,
user=Depends(get_verified_user)
):
if user.role != "admin":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.UNAUTHORIZED,
)
knowledge_bases = Knowledges.get_knowledge_bases()
log.info(f"Starting reindexing for {len(knowledge_bases)} knowledge bases")
for knowledge_base in knowledge_bases:
try:
files = Files.get_files_by_ids(knowledge_base.data.get("file_ids", []))
try:
if VECTOR_DB_CLIENT.has_collection(collection_name=knowledge_base.id):
VECTOR_DB_CLIENT.delete_collection(
collection_name=knowledge_base.id
)
except Exception as e:
log.error(f"Error deleting collection {knowledge_base.id}: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Error deleting vector DB collection"
)
failed_files = []
for file in files:
try:
process_file(
request,
ProcessFileForm(file_id=file.id, collection_name=knowledge_base.id),
user=user,
)
except Exception as e:
log.error(f"Error processing file {file.filename} (ID: {file.id}): {str(e)}")
failed_files.append({"file_id": file.id, "error": str(e)})
continue
except Exception as e:
log.error(f"Error processing knowledge base {knowledge_base.id}: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Error processing knowledge base"
)
if failed_files:
log.warning(f"Failed to process {len(failed_files)} files in knowledge base {knowledge_base.id}")
for failed in failed_files:
log.warning(f"File ID: {failed['file_id']}, Error: {failed['error']}")
log.info("Reindexing completed successfully")
return True
############################
# GetKnowledgeById
############################
@ -676,3 +742,6 @@ def add_files_to_knowledge_batch(
return KnowledgeFilesResponse(
**knowledge.model_dump(), files=Files.get_files_by_ids(existing_file_ids)
)

View file

@ -60,6 +60,7 @@ from open_webui.retrieval.web.tavily import search_tavily
from open_webui.retrieval.web.bing import search_bing
from open_webui.retrieval.web.exa import search_exa
from open_webui.retrieval.web.perplexity import search_perplexity
from open_webui.retrieval.web.sougou import search_sougou
from open_webui.retrieval.utils import (
get_embedding_function,
@ -411,6 +412,8 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)):
"bing_search_v7_subscription_key": request.app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY,
"exa_api_key": request.app.state.config.EXA_API_KEY,
"perplexity_api_key": request.app.state.config.PERPLEXITY_API_KEY,
"sougou_api_sid": request.app.state.config.SOUGOU_API_SID,
"sougou_api_sk": request.app.state.config.SOUGOU_API_SK,
"result_count": request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
"trust_env": request.app.state.config.RAG_WEB_SEARCH_TRUST_ENV,
"concurrent_requests": request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS,
@ -478,6 +481,8 @@ class WebSearchConfig(BaseModel):
bing_search_v7_subscription_key: Optional[str] = None
exa_api_key: Optional[str] = None
perplexity_api_key: Optional[str] = None
sougou_api_sid: Optional[str] = None
sougou_api_sk: Optional[str] = None
result_count: Optional[int] = None
concurrent_requests: Optional[int] = None
trust_env: Optional[bool] = None
@ -640,6 +645,12 @@ async def update_rag_config(
request.app.state.config.PERPLEXITY_API_KEY = (
form_data.web.search.perplexity_api_key
)
request.app.state.config.SOUGOU_API_SID = (
form_data.web.search.sougou_api_sid
)
request.app.state.config.SOUGOU_API_SK = (
form_data.web.search.sougou_api_sk
)
request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT = (
form_data.web.search.result_count
@ -712,6 +723,8 @@ async def update_rag_config(
"bing_search_v7_subscription_key": request.app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY,
"exa_api_key": request.app.state.config.EXA_API_KEY,
"perplexity_api_key": request.app.state.config.PERPLEXITY_API_KEY,
"sougou_api_sid": request.app.state.config.SOUGOU_API_SID,
"sougou_api_sk": request.app.state.config.SOUGOU_API_SK,
"result_count": request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
"concurrent_requests": request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS,
"trust_env": request.app.state.config.RAG_WEB_SEARCH_TRUST_ENV,
@ -1267,6 +1280,7 @@ def search_web(request: Request, engine: str, query: str) -> list[SearchResult]:
- TAVILY_API_KEY
- EXA_API_KEY
- PERPLEXITY_API_KEY
- SOUGOU_API_SID + SOUGOU_API_SK
- SEARCHAPI_API_KEY + SEARCHAPI_ENGINE (by default `google`)
- SERPAPI_API_KEY + SERPAPI_ENGINE (by default `google`)
Args:
@ -1438,6 +1452,17 @@ def search_web(request: Request, engine: str, query: str) -> list[SearchResult]:
request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
request.app.state.config.RAG_WEB_SEARCH_DOMAIN_FILTER_LIST,
)
elif engine == 'sougou':
if request.app.state.config.SOUGOU_API_SID and request.app.state.config.SOUGOU_API_SK:
return search_sougou(
request.app.state.config.SOUGOU_API_SID,
request.app.state.config.SOUGOU_API_SK,
query,
request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
request.app.state.config.RAG_WEB_SEARCH_DOMAIN_FILTER_LIST,
)
else:
raise Exception("No SOUGOU_API_SID or SOUGOU_API_SK found in environment variables")
else:
raise Exception("No search engine API key found in environment variables")

View file

@ -10,11 +10,11 @@ from open_webui.models.tools import (
ToolUserResponse,
Tools,
)
from open_webui.utils.plugin import load_tools_module_by_id, replace_imports
from open_webui.utils.plugin import load_tool_module_by_id, replace_imports
from open_webui.config import CACHE_DIR
from open_webui.constants import ERROR_MESSAGES
from fastapi import APIRouter, Depends, HTTPException, Request, status
from open_webui.utils.tools import get_tools_specs
from open_webui.utils.tools import get_tool_specs
from open_webui.utils.auth import get_admin_user, get_verified_user
from open_webui.utils.access_control import has_access, has_permission
from open_webui.env import SRC_LOG_LEVELS
@ -45,7 +45,7 @@ async def get_tools(request: Request, user=Depends(get_verified_user)):
)
tools = Tools.get_tools()
for idx, server in enumerate(request.app.state.TOOL_SERVERS):
for server in request.app.state.TOOL_SERVERS:
tools.append(
ToolUserResponse(
**{
@ -60,7 +60,7 @@ async def get_tools(request: Request, user=Depends(get_verified_user)):
.get("description", ""),
},
"access_control": request.app.state.config.TOOL_SERVER_CONNECTIONS[
idx
server["idx"]
]
.get("config", {})
.get("access_control", None),
@ -137,15 +137,15 @@ async def create_new_tools(
if tools is None:
try:
form_data.content = replace_imports(form_data.content)
tools_module, frontmatter = load_tools_module_by_id(
tool_module, frontmatter = load_tool_module_by_id(
form_data.id, content=form_data.content
)
form_data.meta.manifest = frontmatter
TOOLS = request.app.state.TOOLS
TOOLS[form_data.id] = tools_module
TOOLS[form_data.id] = tool_module
specs = get_tools_specs(TOOLS[form_data.id])
specs = get_tool_specs(TOOLS[form_data.id])
tools = Tools.insert_new_tool(user.id, form_data, specs)
tool_cache_dir = CACHE_DIR / "tools" / form_data.id
@ -226,15 +226,13 @@ async def update_tools_by_id(
try:
form_data.content = replace_imports(form_data.content)
tools_module, frontmatter = load_tools_module_by_id(
id, content=form_data.content
)
tool_module, frontmatter = load_tool_module_by_id(id, content=form_data.content)
form_data.meta.manifest = frontmatter
TOOLS = request.app.state.TOOLS
TOOLS[id] = tools_module
TOOLS[id] = tool_module
specs = get_tools_specs(TOOLS[id])
specs = get_tool_specs(TOOLS[id])
updated = {
**form_data.model_dump(exclude={"id"}),
@ -332,7 +330,7 @@ async def get_tools_valves_spec_by_id(
if id in request.app.state.TOOLS:
tools_module = request.app.state.TOOLS[id]
else:
tools_module, _ = load_tools_module_by_id(id)
tools_module, _ = load_tool_module_by_id(id)
request.app.state.TOOLS[id] = tools_module
if hasattr(tools_module, "Valves"):
@ -375,7 +373,7 @@ async def update_tools_valves_by_id(
if id in request.app.state.TOOLS:
tools_module = request.app.state.TOOLS[id]
else:
tools_module, _ = load_tools_module_by_id(id)
tools_module, _ = load_tool_module_by_id(id)
request.app.state.TOOLS[id] = tools_module
if not hasattr(tools_module, "Valves"):
@ -431,7 +429,7 @@ async def get_tools_user_valves_spec_by_id(
if id in request.app.state.TOOLS:
tools_module = request.app.state.TOOLS[id]
else:
tools_module, _ = load_tools_module_by_id(id)
tools_module, _ = load_tool_module_by_id(id)
request.app.state.TOOLS[id] = tools_module
if hasattr(tools_module, "UserValves"):
@ -455,7 +453,7 @@ async def update_tools_user_valves_by_id(
if id in request.app.state.TOOLS:
tools_module = request.app.state.TOOLS[id]
else:
tools_module, _ = load_tools_module_by_id(id)
tools_module, _ = load_tool_module_by_id(id)
request.app.state.TOOLS[id] = tools_module
if hasattr(tools_module, "UserValves"):

View file

@ -897,12 +897,16 @@ async def process_chat_payload(request, form_data, user, metadata, model):
# If context is not empty, insert it into the messages
if len(sources) > 0:
context_string = ""
for source_idx, source in enumerate(sources):
citated_file_idx = {}
for _, source in enumerate(sources, 1):
if "document" in source:
for doc_idx, doc_context in enumerate(source["document"]):
context_string += (
f'<source id="{source_idx + 1}">{doc_context}</source>\n'
)
for doc_context, doc_meta in zip(
source["document"], source["metadata"]
):
file_id = doc_meta.get("file_id")
if file_id not in citated_file_idx:
citated_file_idx[file_id] = len(citated_file_idx) + 1
context_string += f'<source id="{citated_file_idx[file_id]}">{doc_context}</source>\n'
context_string = context_string.strip()
prompt = get_last_user_message(form_data["messages"])
@ -1609,6 +1613,9 @@ async def process_chat_response(
)
if data:
if "event" in data:
await event_emitter(data.get("event", {}))
if "selected_model_id" in data:
model_id = data["selected_model_id"]
Chats.upsert_message_to_chat_by_id_and_message_id(
@ -1653,14 +1660,27 @@ async def process_chat_response(
)
if tool_call_index is not None:
# Check if the tool call already exists
current_response_tool_call = None
for (
response_tool_call
) in response_tool_calls:
if (
len(response_tool_calls)
<= tool_call_index
response_tool_call.get("index")
== tool_call_index
):
current_response_tool_call = (
response_tool_call
)
break
if current_response_tool_call is None:
# Add the new tool call
response_tool_calls.append(
delta_tool_call
)
else:
# Update the existing tool call
delta_name = delta_tool_call.get(
"function", {}
).get("name")
@ -1671,16 +1691,14 @@ async def process_chat_response(
)
if delta_name:
response_tool_calls[
tool_call_index
]["function"][
"name"
] += delta_name
current_response_tool_call[
"function"
]["name"] += delta_name
if delta_arguments:
response_tool_calls[
tool_call_index
]["function"][
current_response_tool_call[
"function"
][
"arguments"
] += delta_arguments

View file

@ -68,7 +68,7 @@ def replace_imports(content):
return content
def load_tools_module_by_id(tool_id, content=None):
def load_tool_module_by_id(tool_id, content=None):
if content is None:
tool = Tools.get_tool_by_id(tool_id)

View file

@ -4,19 +4,39 @@ import re
import inspect
import aiohttp
import asyncio
import yaml
from typing import Any, Awaitable, Callable, get_type_hints, Dict, List, Union, Optional
from pydantic import BaseModel
from pydantic.fields import FieldInfo
from typing import (
Any,
Awaitable,
Callable,
get_type_hints,
get_args,
get_origin,
Dict,
List,
Tuple,
Union,
Optional,
Type,
)
from functools import update_wrapper, partial
from fastapi import Request
from pydantic import BaseModel, Field, create_model
from langchain_core.utils.function_calling import convert_to_openai_function
from langchain_core.utils.function_calling import (
convert_to_openai_function as convert_pydantic_model_to_openai_function_spec,
)
from open_webui.models.tools import Tools
from open_webui.models.users import UserModel
from open_webui.utils.plugin import load_tools_module_by_id
from open_webui.utils.plugin import load_tool_module_by_id
from open_webui.env import AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA
import copy
@ -55,7 +75,12 @@ def get_tools(
tool_server_connection = (
request.app.state.config.TOOL_SERVER_CONNECTIONS[server_idx]
)
tool_server_data = request.app.state.TOOL_SERVERS[server_idx]
tool_server_data = None
for server in request.app.state.TOOL_SERVERS:
if server["idx"] == server_idx:
tool_server_data = server
break
assert tool_server_data is not None
specs = tool_server_data.get("specs", [])
for spec in specs:
@ -112,7 +137,7 @@ def get_tools(
else:
module = request.app.state.TOOLS.get(tool_id, None)
if module is None:
module, _ = load_tools_module_by_id(tool_id)
module, _ = load_tool_module_by_id(tool_id)
request.app.state.TOOLS[tool_id] = module
extra_params["__id__"] = tool_id
@ -233,7 +258,7 @@ def parse_docstring(docstring):
return param_descriptions
def function_to_pydantic_model(func: Callable) -> type[BaseModel]:
def convert_function_to_pydantic_model(func: Callable) -> type[BaseModel]:
"""
Converts a Python function's type hints and docstring to a Pydantic model,
including support for nested types, default values, and descriptions.
@ -250,45 +275,57 @@ def function_to_pydantic_model(func: Callable) -> type[BaseModel]:
parameters = signature.parameters
docstring = func.__doc__
descriptions = parse_docstring(docstring)
tool_description = parse_description(docstring)
description = parse_description(docstring)
function_descriptions = parse_docstring(docstring)
field_defs = {}
for name, param in parameters.items():
type_hint = type_hints.get(name, Any)
default_value = param.default if param.default is not param.empty else ...
description = descriptions.get(name, None)
if not description:
field_defs[name] = type_hint, default_value
continue
description = function_descriptions.get(name, None)
if description:
field_defs[name] = type_hint, Field(default_value, description=description)
else:
field_defs[name] = type_hint, default_value
model = create_model(func.__name__, **field_defs)
model.__doc__ = tool_description
model.__doc__ = description
return model
def get_callable_attributes(tool: object) -> list[Callable]:
def get_functions_from_tool(tool: object) -> list[Callable]:
return [
getattr(tool, func)
for func in dir(tool)
if callable(getattr(tool, func))
and not func.startswith("__")
and not inspect.isclass(getattr(tool, func))
if callable(
getattr(tool, func)
) # checks if the attribute is callable (a method or function).
and not func.startswith(
"__"
) # filters out special (dunder) methods like init, str, etc. — these are usually built-in functions of an object that you might not need to use directly.
and not inspect.isclass(
getattr(tool, func)
) # ensures that the callable is not a class itself, just a method or function.
]
def get_tools_specs(tool_class: object) -> list[dict]:
function_model_list = map(
function_to_pydantic_model, get_callable_attributes(tool_class)
def get_tool_specs(tool_module: object) -> list[dict]:
function_models = map(
convert_function_to_pydantic_model, get_functions_from_tool(tool_module)
)
return [
convert_to_openai_function(function_model)
for function_model in function_model_list
specs = [
convert_pydantic_model_to_openai_function_spec(function_model)
for function_model in function_models
]
return specs
def resolve_schema(schema, components):
"""
@ -393,14 +430,21 @@ async def get_tool_server_data(token: str, url: str) -> Dict[str, Any]:
error = None
try:
async with aiohttp.ClientSession() as session:
timeout = aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA)
async with aiohttp.ClientSession(timeout=timeout) as session:
async with session.get(url, headers=headers) as response:
if response.status != 200:
error_body = await response.json()
raise Exception(error_body)
# Check if URL ends with .yaml or .yml to determine format
if url.lower().endswith((".yaml", ".yml")):
text_content = await response.text()
res = yaml.safe_load(text_content)
else:
res = await response.json()
except Exception as err:
print("Error:", err)
log.exception(f"Could not fetch tool server spec from {url}")
if isinstance(err, dict) and "detail" in err:
error = err["detail"]
else:

View file

@ -18,7 +18,7 @@ alembic==1.14.0
peewee==3.17.9
peewee-migrate==1.12.2
psycopg2-binary==2.9.9
pgvector==0.3.5
pgvector==0.4.0
PyMySQL==1.1.1
bcrypt==4.3.0
@ -44,7 +44,7 @@ langchain==0.3.19
langchain-community==0.3.18
fake-useragent==2.1.0
chromadb==0.6.2
chromadb==0.6.3
pymilvus==2.5.0
qdrant-client~=1.12.0
opensearch-py==2.8.0
@ -93,12 +93,12 @@ authlib==1.4.1
black==25.1.0
langfuse==2.44.0
youtube-transcript-api==0.6.3
youtube-transcript-api==1.0.3
pytube==15.0.0
extract_msg
pydub
duckduckgo-search~=7.3.2
duckduckgo-search~=8.0.0
## Google Drive
google-api-python-client
@ -113,7 +113,7 @@ pytest-docker~=3.1.1
googleapis-common-protos==1.63.2
google-cloud-storage==2.19.0
azure-identity==1.20.0
azure-identity==1.21.0
azure-storage-blob==12.24.1
@ -123,15 +123,18 @@ ldap3==2.9.1
## Firecrawl
firecrawl-py==1.12.0
# Sougou API SDK(Tencentcloud SDK)
tencentcloud-sdk-python==3.0.1336
## Trace
opentelemetry-api==1.30.0
opentelemetry-sdk==1.30.0
opentelemetry-exporter-otlp==1.30.0
opentelemetry-instrumentation==0.51b0
opentelemetry-instrumentation-fastapi==0.51b0
opentelemetry-instrumentation-sqlalchemy==0.51b0
opentelemetry-instrumentation-redis==0.51b0
opentelemetry-instrumentation-requests==0.51b0
opentelemetry-instrumentation-logging==0.51b0
opentelemetry-instrumentation-httpx==0.51b0
opentelemetry-instrumentation-aiohttp-client==0.51b0
opentelemetry-api==1.31.1
opentelemetry-sdk==1.31.1
opentelemetry-exporter-otlp==1.31.1
opentelemetry-instrumentation==0.52b1
opentelemetry-instrumentation-fastapi==0.52b1
opentelemetry-instrumentation-sqlalchemy==0.52b1
opentelemetry-instrumentation-redis==0.52b1
opentelemetry-instrumentation-requests==0.52b1
opentelemetry-instrumentation-logging==0.52b1
opentelemetry-instrumentation-httpx==0.52b1
opentelemetry-instrumentation-aiohttp-client==0.52b1

View file

@ -65,4 +65,4 @@ if [ -n "$SPACE_ID" ]; then
export WEBUI_URL=${SPACE_HOST}
fi
WEBUI_SECRET_KEY="$WEBUI_SECRET_KEY" exec uvicorn open_webui.main:app --host "$HOST" --port "$PORT" --forwarded-allow-ips '*'
WEBUI_SECRET_KEY="$WEBUI_SECRET_KEY" exec uvicorn open_webui.main:app --host "$HOST" --port "$PORT" --forwarded-allow-ips '*' --workers "${UVICORN_WORKERS:-1}"

View file

@ -41,5 +41,6 @@ IF "%WEBUI_SECRET_KEY%%WEBUI_JWT_SECRET_KEY%" == " " (
:: Execute uvicorn
SET "WEBUI_SECRET_KEY=%WEBUI_SECRET_KEY%"
uvicorn open_webui.main:app --host "%HOST%" --port "%PORT%" --forwarded-allow-ips '*' --ws auto
IF "%UVICORN_WORKERS%"=="" SET UVICORN_WORKERS=1
uvicorn open_webui.main:app --host "%HOST%" --port "%PORT%" --forwarded-allow-ips '*' --workers %UVICORN_WORKERS% --ws auto
:: For ssl user uvicorn open_webui.main:app --host "%HOST%" --port "%PORT%" --forwarded-allow-ips '*' --ssl-keyfile "key.pem" --ssl-certfile "cert.pem" --ws auto

86
package-lock.json generated
View file

@ -23,12 +23,13 @@
"@tiptap/extension-highlight": "^2.10.0",
"@tiptap/extension-placeholder": "^2.10.0",
"@tiptap/extension-typography": "^2.10.0",
"@tiptap/pm": "^2.10.0",
"@tiptap/pm": "^2.11.7",
"@tiptap/starter-kit": "^2.10.0",
"@xyflow/svelte": "^0.1.19",
"async": "^3.2.5",
"bits-ui": "^0.19.7",
"codemirror": "^6.0.1",
"codemirror-lang-elixir": "^4.0.0",
"codemirror-lang-hcl": "^0.0.0-beta.2",
"crc-32": "^1.2.2",
"dayjs": "^1.11.10",
@ -69,7 +70,8 @@
"turndown": "^7.2.0",
"undici": "^7.3.0",
"uuid": "^9.0.1",
"vite-plugin-static-copy": "^2.2.0"
"vite-plugin-static-copy": "^2.2.0",
"yaml": "^2.7.1"
},
"devDependencies": {
"@sveltejs/adapter-auto": "3.2.2",
@ -3042,9 +3044,9 @@
}
},
"node_modules/@tiptap/pm": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.10.0.tgz",
"integrity": "sha512-ohshlWf4MlW6D3rQkNQnhmiQ2w4pwRoQcJmTPt8UJoIDGkeKmZh494fQp4Aeh80XuGd81SsCv//1HJeyaeHJYQ==",
"version": "2.11.7",
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.11.7.tgz",
"integrity": "sha512-7gEEfz2Q6bYKXM07vzLUD0vqXFhC5geWRA6LCozTiLdVFDdHWiBrvb2rtkL5T7mfLq03zc1QhH7rI3F6VntOEA==",
"license": "MIT",
"dependencies": {
"prosemirror-changeset": "^2.2.1",
@ -3061,10 +3063,10 @@
"prosemirror-schema-basic": "^1.2.3",
"prosemirror-schema-list": "^1.4.1",
"prosemirror-state": "^1.4.3",
"prosemirror-tables": "^1.6.1",
"prosemirror-tables": "^1.6.4",
"prosemirror-trailing-node": "^3.0.0",
"prosemirror-transform": "^1.10.2",
"prosemirror-view": "^1.36.0"
"prosemirror-view": "^1.37.0"
},
"funding": {
"type": "github",
@ -4625,6 +4627,15 @@
"@codemirror/view": "^6.0.0"
}
},
"node_modules/codemirror-lang-elixir": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/codemirror-lang-elixir/-/codemirror-lang-elixir-4.0.0.tgz",
"integrity": "sha512-mzFesxo/t6KOxwnkqVd34R/q7yk+sMtHh6vUKGAvjwHmpL7bERHB+vQAsmU/nqrndkwVeJEHWGw/z/ybfdiudA==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"lezer-elixir": "^1.0.0"
}
},
"node_modules/codemirror-lang-hcl": {
"version": "0.0.0-beta.2",
"resolved": "https://registry.npmjs.org/codemirror-lang-hcl/-/codemirror-lang-hcl-0.0.0-beta.2.tgz",
@ -7611,6 +7622,15 @@
"node": ">= 0.8.0"
}
},
"node_modules/lezer-elixir": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/lezer-elixir/-/lezer-elixir-1.1.2.tgz",
"integrity": "sha512-K3yPMJcNhqCL6ugr5NkgOC1g37rcOM38XZezO9lBXy0LwWFd8zdWXfmRbY829vZVk0OGCQoI02yDWp9FF2OWZA==",
"dependencies": {
"@lezer/highlight": "^1.2.0",
"@lezer/lr": "^1.3.0"
}
},
"node_modules/lightningcss": {
"version": "1.29.1",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.1.tgz",
@ -9495,6 +9515,16 @@
"node": ">=10"
}
},
"node_modules/postcss-load-config/node_modules/yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">= 6"
}
},
"node_modules/postcss-safe-parser": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz",
@ -9783,9 +9813,10 @@
}
},
"node_modules/prosemirror-model": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.23.0.tgz",
"integrity": "sha512-Q/fgsgl/dlOAW9ILu4OOhYWQbc7TQd4BwKH/RwmUjyVf8682Be4zj3rOYdLnYEcGzyg8LL9Q5IWYKD8tdToreQ==",
"version": "1.25.0",
"resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.0.tgz",
"integrity": "sha512-/8XUmxWf0pkj2BmtqZHYJipTBMHIdVjuvFzMvEoxrtyGNmfvdhBiRwYt/eFwy2wA9DtBW3RLqvZnjurEkHaFCw==",
"license": "MIT",
"dependencies": {
"orderedmap": "^2.0.0"
}
@ -9819,16 +9850,16 @@
}
},
"node_modules/prosemirror-tables": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.6.1.tgz",
"integrity": "sha512-p8WRJNA96jaNQjhJolmbxTzd6M4huRE5xQ8OxjvMhQUP0Nzpo4zz6TztEiwk6aoqGBhz9lxRWR1yRZLlpQN98w==",
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.6.4.tgz",
"integrity": "sha512-TkDY3Gw52gRFRfRn2f4wJv5WOgAOXLJA2CQJYIJ5+kdFbfj3acR4JUW6LX2e1hiEBiUwvEhzH5a3cZ5YSztpIA==",
"license": "MIT",
"dependencies": {
"prosemirror-keymap": "^1.1.2",
"prosemirror-model": "^1.8.1",
"prosemirror-state": "^1.3.1",
"prosemirror-transform": "^1.2.1",
"prosemirror-view": "^1.13.3"
"prosemirror-keymap": "^1.2.2",
"prosemirror-model": "^1.24.1",
"prosemirror-state": "^1.4.3",
"prosemirror-transform": "^1.10.2",
"prosemirror-view": "^1.37.2"
}
},
"node_modules/prosemirror-trailing-node": {
@ -9856,9 +9887,9 @@
}
},
"node_modules/prosemirror-view": {
"version": "1.36.0",
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.36.0.tgz",
"integrity": "sha512-U0GQd5yFvV5qUtT41X1zCQfbw14vkbbKwLlQXhdylEmgpYVHkefXYcC4HHwWOfZa3x6Y8wxDLUBv7dxN5XQ3nA==",
"version": "1.39.1",
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.39.1.tgz",
"integrity": "sha512-GhLxH1xwnqa5VjhJ29LfcQITNDp+f1jzmMPXQfGW9oNrF0lfjPzKvV5y/bjIQkyKpwCX3Fp+GA4dBpMMk8g+ZQ==",
"license": "MIT",
"dependencies": {
"prosemirror-model": "^1.20.0",
@ -13011,12 +13042,15 @@
}
},
"node_modules/yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"dev": true,
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
"integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 6"
"node": ">= 14"
}
},
"node_modules/yauzl": {

View file

@ -66,13 +66,14 @@
"@tiptap/extension-highlight": "^2.10.0",
"@tiptap/extension-placeholder": "^2.10.0",
"@tiptap/extension-typography": "^2.10.0",
"@tiptap/pm": "^2.10.0",
"@tiptap/pm": "^2.11.7",
"@tiptap/starter-kit": "^2.10.0",
"@xyflow/svelte": "^0.1.19",
"async": "^3.2.5",
"bits-ui": "^0.19.7",
"codemirror": "^6.0.1",
"codemirror-lang-hcl": "^0.0.0-beta.2",
"codemirror-lang-elixir": "^4.0.0",
"crc-32": "^1.2.2",
"dayjs": "^1.11.10",
"dompurify": "^3.1.6",
@ -112,7 +113,8 @@
"turndown": "^7.2.0",
"undici": "^7.3.0",
"uuid": "^9.0.1",
"vite-plugin-static-copy": "^2.2.0"
"vite-plugin-static-copy": "^2.2.0",
"yaml": "^2.7.1"
},
"engines": {
"node": ">=18.13.0 <=22.x.x",

View file

@ -104,7 +104,7 @@ dependencies = [
"extract_msg",
"pydub",
"duckduckgo-search~=7.3.2",
"duckduckgo-search~=8.0.0",
"google-api-python-client",
"google-auth-httplib2",
@ -125,6 +125,8 @@ dependencies = [
"firecrawl-py==1.12.0",
"tencentcloud-sdk-python==3.0.1336",
"gcp-storage-emulator>=2024.8.3",
]
readme = "README.md"

View file

@ -91,10 +91,6 @@ textarea::placeholder {
-webkit-app-region: no-drag;
}
iframe {
@apply rounded-lg;
}
li p {
display: inline;
}

View file

@ -9,7 +9,7 @@
<link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png" />
<meta name="apple-mobile-web-app-title" content="Open WebUI" />
<link rel="manifest" href="/manifest.json" />
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover"

View file

@ -2,6 +2,7 @@ import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants';
import { convertOpenApiToToolPayload } from '$lib/utils';
import { getOpenAIModelsDirect } from './openai';
import { parse } from 'yaml';
import { toast } from 'svelte-sonner';
export const getModels = async (
@ -271,8 +272,15 @@ export const getToolServerData = async (token: string, url: string) => {
}
})
.then(async (res) => {
// Check if URL ends with .yaml or .yml to determine format
if (url.toLowerCase().endsWith('.yaml') || url.toLowerCase().endsWith('.yml')) {
if (!res.ok) throw await res.text();
const text = await res.text();
return parse(text);
} else {
if (!res.ok) throw await res.json();
return res.json();
}
})
.catch((err) => {
console.log(err);
@ -305,7 +313,7 @@ export const getToolServersData = async (i18n, servers: object[]) => {
.filter((server) => server?.config?.enable)
.map(async (server) => {
const data = await getToolServerData(
server?.key,
(server?.auth_type ?? 'bearer') === 'bearer' ? server?.key : localStorage.token,
server?.url + '/' + (server?.path ?? 'openapi.json')
).catch((err) => {
toast.error(

View file

@ -345,3 +345,32 @@ export const deleteKnowledgeById = async (token: string, id: string) => {
return res;
};
export const reindexKnowledgeFiles = async (token: string) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/knowledge/reindex`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
}
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};

View file

@ -39,6 +39,9 @@
let STT_ENGINE = '';
let STT_MODEL = '';
let STT_WHISPER_MODEL = '';
let STT_AZURE_API_KEY = '';
let STT_AZURE_REGION = '';
let STT_AZURE_LOCALES = '';
let STT_DEEPGRAM_API_KEY = '';
let STT_WHISPER_MODEL_LOADING = false;
@ -108,7 +111,10 @@
ENGINE: STT_ENGINE,
MODEL: STT_MODEL,
WHISPER_MODEL: STT_WHISPER_MODEL,
DEEPGRAM_API_KEY: STT_DEEPGRAM_API_KEY
DEEPGRAM_API_KEY: STT_DEEPGRAM_API_KEY,
AZURE_API_KEY: STT_AZURE_API_KEY,
AZURE_REGION: STT_AZURE_REGION,
AZURE_LOCALES: STT_AZURE_LOCALES
}
});
@ -148,6 +154,9 @@
STT_ENGINE = res.stt.ENGINE;
STT_MODEL = res.stt.MODEL;
STT_WHISPER_MODEL = res.stt.WHISPER_MODEL;
STT_AZURE_API_KEY = res.stt.AZURE_API_KEY;
STT_AZURE_REGION = res.stt.AZURE_REGION;
STT_AZURE_LOCALES = res.stt.AZURE_LOCALES;
STT_DEEPGRAM_API_KEY = res.stt.DEEPGRAM_API_KEY;
}
@ -180,6 +189,7 @@
<option value="openai">OpenAI</option>
<option value="web">{$i18n.t('Web API')}</option>
<option value="deepgram">Deepgram</option>
<option value="azure">Azure AI Speech</option>
</select>
</div>
</div>
@ -248,6 +258,33 @@
</a>
</div>
</div>
{:else if STT_ENGINE === 'azure'}
<div>
<div class="mt-1 flex gap-2 mb-1">
<SensitiveInput placeholder={$i18n.t('API Key')} bind:value={STT_AZURE_API_KEY} required />
<input
class="flex-1 w-full rounded-lg py-2 pl-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
placeholder={$i18n.t('Azure Region')}
bind:value={STT_AZURE_REGION}
required
/>
</div>
<hr class="border-gray-100 dark:border-gray-850 my-2" />
<div>
<div class=" mb-1.5 text-sm font-medium">{$i18n.t('Language Locales')}</div>
<div class="flex w-full">
<div class="flex-1">
<input
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={STT_AZURE_LOCALES}
placeholder={$i18n.t('e.g., en-US,ja-JP (leave blank for auto-detect)')}
/>
</div>
</div>
</div>
</div>
{:else if STT_ENGINE === ''}
<div>
<div class=" mb-1.5 text-sm font-medium">{$i18n.t('STT Model')}</div>

View file

@ -13,17 +13,16 @@
updateEmbeddingConfig,
getRerankingConfig,
updateRerankingConfig,
resetUploadDir,
getRAGConfig,
updateRAGConfig
} from '$lib/apis/retrieval';
import { knowledge, models } from '$lib/stores';
import { getKnowledgeBases } from '$lib/apis/knowledge';
import { uploadDir, deleteAllFiles, deleteFileById } from '$lib/apis/files';
import { reindexKnowledgeFiles} from '$lib/apis/knowledge';
import { deleteAllFiles } from '$lib/apis/files';
import ResetUploadDirConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
import ResetVectorDBConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
import ReindexKnowledgeFilesConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
import Tooltip from '$lib/components/common/Tooltip.svelte';
import Switch from '$lib/components/common/Switch.svelte';
@ -31,12 +30,12 @@
const i18n = getContext('i18n');
let scanDirLoading = false;
let updateEmbeddingModelLoading = false;
let updateRerankingModelLoading = false;
let showResetConfirm = false;
let showResetUploadDirConfirm = false;
let showReindexConfirm = false;
let embeddingEngine = '';
let embeddingModel = '';
@ -333,6 +332,21 @@
}}
/>
<ReindexKnowledgeFilesConfirmDialog
bind:show={showReindexConfirm}
on:confirm={async () => {
const res = await reindexKnowledgeFiles(localStorage.token).catch((error) => {
toast.error(`${error}`);
return null;
});
if (res) {
toast.success($i18n.t('Success'));
}
}}
/>
<form
class="flex flex-col h-full justify-between space-y-3 text-sm"
on:submit|preventDefault={() => {
@ -950,6 +964,21 @@
</button>
</div>
</div>
<div class=" mb-2.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">
{$i18n.t('Reindex Knowledge Base Vectors')}
</div>
<div class="flex items-center relative">
<button
class="text-xs"
on:click={() => {
showReindexConfirm = true;
}}
>
{$i18n.t('Reindex')}
</button>
</div>
</div>
</div>
</div>
</div>

View file

@ -30,7 +30,8 @@
'jina',
'bing',
'exa',
'perplexity'
'perplexity',
'sougou'
];
let youtubeLanguage = 'en';
@ -404,6 +405,31 @@
/>
</div>
</div>
{:else if webConfig.search.engine === 'sougou'}
<div class="mb-2.5 flex w-full flex-col">
<div>
<div class=" self-center text-xs font-medium mb-1">
{$i18n.t('Sougou Search API sID')}
</div>
<SensitiveInput
placeholder={$i18n.t('Enter Sougou Search API sID')}
bind:value={webConfig.search.sougou_api_sid}
/>
</div>
</div>
<div class="mb-2.5 flex w-full flex-col">
<div>
<div class=" self-center text-xs font-medium mb-1">
{$i18n.t('Sougou Search API SK')}
</div>
<SensitiveInput
placeholder={$i18n.t('Enter Sougou Search API SK')}
bind:value={webConfig.search.sougou_api_sk}
/>
</div>
</div>
{/if}
{/if}
@ -481,8 +507,12 @@
<div class="flex items-center relative">
<Tooltip
content={webConfig.search.trust_env
? 'Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents'
: 'Use no proxy to fetch page contents.'}
? $i18n.t(
'Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.'
)
: $i18n.t(
'Use no proxy to fetch page contents.'
)}
>
<Switch bind:state={webConfig.search.trust_env} />
</Tooltip>

View file

@ -401,6 +401,7 @@
if (!$chatId) {
chatIdUnsubscriber = chatId.subscribe(async (value) => {
if (!value) {
await tick(); // Wait for DOM updates
await initNewChat();
}
});
@ -1927,7 +1928,7 @@
: ' '} w-full max-w-full flex flex-col"
id="chat-container"
>
{#if chatIdProp === '' || (!loading && chatIdProp)}
{#if !loading}
{#if $settings?.backgroundImageUrl ?? null}
<div
class="absolute {$showSidebar
@ -1941,6 +1942,8 @@
/>
{/if}
<PaneGroup direction="horizontal" class="w-full h-full">
<Pane defaultSize={50} class="h-full flex relative max-w-full flex-col">
<Navbar
bind:this={navbarElement}
chat={{
@ -1960,8 +1963,6 @@
{initNewChat}
/>
<PaneGroup direction="horizontal" class="w-full h-full">
<Pane defaultSize={50} class="h-full flex w-full relative">
{#if !history.currentId && !$chatId && selectedModels.length <= 1 && ($banners.length > 0 || ($config?.license_metadata?.type ?? null) === 'trial' || (($config?.license_metadata?.seats ?? null) !== null && $config?.user_count > $config?.license_metadata?.seats))}
<div class="absolute top-12 left-0 right-0 w-full z-30">
<div class=" flex flex-col gap-1 w-full">

View file

@ -223,14 +223,14 @@
showControls.set(false);
}}
collapsible={true}
class="pt-8"
class=" z-10 "
>
{#if $showControls}
<div class="pr-4 pb-8 flex max-h-full min-h-full">
<div class="flex max-h-full min-h-full">
<div
class="w-full {($showOverview || $showArtifacts) && !$showCallOverlay
? ' '
: 'px-4 py-4 bg-white dark:shadow-lg dark:bg-gray-850 border border-gray-100 dark:border-gray-850'} rounded-xl z-40 pointer-events-auto overflow-y-auto scrollbar-hidden"
: 'px-4 py-4 bg-white dark:shadow-lg dark:bg-gray-850 border border-gray-100 dark:border-gray-850'} z-40 pointer-events-auto overflow-y-auto scrollbar-hidden"
>
{#if $showCallOverlay}
<div class="w-full h-full flex justify-center">

View file

@ -1033,7 +1033,7 @@
{/if}
</div>
<div class=" flex justify-between mt-1.5 mb-2.5 mx-0.5 max-w-full" dir="ltr">
<div class=" flex justify-between mt-1 mb-2.5 mx-0.5 max-w-full" dir="ltr">
<div class="ml-1 self-end flex items-center flex-1 max-w-[80%] gap-0.5">
<InputMenu
bind:selectedToolIds
@ -1102,7 +1102,7 @@
</button>
</InputMenu>
<div class="flex gap-[2px] items-center overflow-x-auto scrollbar-none flex-1">
<div class="flex gap-1 items-center overflow-x-auto scrollbar-none flex-1">
{#if toolServers.length + selectedToolIds.length > 0}
<Tooltip
content={$i18n.t('{{COUNT}} Available Tools', {
@ -1132,10 +1132,10 @@
<button
on:click|preventDefault={() => (webSearchEnabled = !webSearchEnabled)}
type="button"
class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden {webSearchEnabled ||
class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden border {webSearchEnabled ||
($settings?.webSearch ?? false) === 'always'
? 'bg-blue-100 dark:bg-blue-500/20 text-blue-500 dark:text-blue-400'
: 'bg-transparent text-gray-600 dark:text-gray-300 border-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800'}"
? 'bg-blue-100 dark:bg-blue-500/20 border-blue-400/20 text-blue-500 dark:text-blue-400'
: 'bg-transparent border-transparent text-gray-600 dark:text-gray-300 border-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800'}"
>
<GlobeAlt className="size-5" strokeWidth="1.75" />
<span
@ -1152,9 +1152,9 @@
on:click|preventDefault={() =>
(imageGenerationEnabled = !imageGenerationEnabled)}
type="button"
class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden {imageGenerationEnabled
? 'bg-gray-100 dark:bg-gray-500/20 text-gray-600 dark:text-gray-400'
: 'bg-transparent text-gray-600 dark:text-gray-300 border-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800 '}"
class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden border {imageGenerationEnabled
? 'bg-gray-50 dark:bg-gray-400/10 border-gray-100 dark:border-gray-700 text-gray-600 dark:text-gray-400'
: 'bg-transparent border-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 '}"
>
<Photo className="size-5" strokeWidth="1.75" />
<span
@ -1171,9 +1171,9 @@
on:click|preventDefault={() =>
(codeInterpreterEnabled = !codeInterpreterEnabled)}
type="button"
class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden {codeInterpreterEnabled
? 'bg-gray-100 dark:bg-gray-500/20 text-gray-600 dark:text-gray-400'
: 'bg-transparent text-gray-600 dark:text-gray-300 border-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800 '}"
class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden border {codeInterpreterEnabled
? 'bg-gray-50 dark:bg-gray-400/10 border-gray-100 dark:border-gray-700 text-gray-600 dark:text-gray-400 '
: 'bg-transparent border-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 '}"
>
<CommandLine className="size-5" strokeWidth="1.75" />
<span
@ -1242,10 +1242,7 @@
<div class=" flex items-center">
<Tooltip content={$i18n.t('Call')}>
<button
class=" {webSearchEnabled ||
($settings?.webSearch ?? false) === 'always'
? 'bg-blue-500 text-white hover:bg-blue-400 '
: 'bg-black text-white hover:bg-gray-900 dark:bg-white dark:text-black dark:hover:bg-gray-100'} transition rounded-full p-1.5 self-center"
class=" bg-black text-white hover:bg-gray-900 dark:bg-white dark:text-black dark:hover:bg-gray-100 transition rounded-full p-1.5 self-center"
type="button"
on:click={async () => {
if (selectedModels.length > 1) {
@ -1311,9 +1308,7 @@
<button
id="send-message-button"
class="{!(prompt === '' && files.length === 0)
? webSearchEnabled || ($settings?.webSearch ?? false) === 'always'
? 'bg-blue-500 text-white hover:bg-blue-400 '
: 'bg-black text-white hover:bg-gray-900 dark:bg-white dark:text-black dark:hover:bg-gray-100 '
? 'bg-black text-white hover:bg-gray-900 dark:bg-white dark:text-black dark:hover:bg-gray-100 '
: 'text-white bg-gray-200 dark:text-gray-900 dark:bg-gray-700 disabled'} transition rounded-full p-1.5 self-center"
type="submit"
disabled={prompt === '' && files.length === 0}

View file

@ -4,7 +4,7 @@
const dispatch = createEventDispatcher();
import Markdown from './Markdown.svelte';
import { chatId, mobile, showArtifacts, showControls, showOverview } from '$lib/stores';
import { chatId, mobile, settings, showArtifacts, showControls, showOverview } from '$lib/stores';
import FloatingButtons from '../ContentRenderer/FloatingButtons.svelte';
import { createMessagesList } from '$lib/utils';
@ -161,6 +161,7 @@
const { lang, code } = e.detail;
if (
($settings?.detectArtifacts ?? true) &&
(['html', 'svg'].includes(lang) || (lang === 'xml' && code.includes('svg'))) &&
!$mobile &&
$chatId

View file

@ -192,7 +192,7 @@
<div>
<button
id="save-edit-message-button"
class=" px-4 py-2 bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 border dark:border-gray-700 text-gray-700 dark:text-gray-200 transition rounded-3xl"
class=" px-4 py-2 bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 border border-gray-100 dark:border-gray-700 text-gray-700 dark:text-gray-200 transition rounded-3xl"
on:click={() => {
editMessageConfirmHandler(false);
}}

View file

@ -84,7 +84,8 @@
}
);
$: filteredItems = searchValue
$: filteredItems = (
searchValue
? fuse
.search(searchValue)
.map((e) => {
@ -124,7 +125,8 @@
} else if (selectedConnectionType === 'direct') {
return item.model?.direct;
}
});
})
).filter((item) => !(item.model?.info?.meta?.hidden ?? false));
$: if (selectedTag || selectedConnectionType) {
resetView();
@ -282,7 +284,10 @@
ollamaVersion = await getOllamaVersion(localStorage.token).catch((error) => false);
if (items) {
tags = items.flatMap((item) => item.model?.tags ?? []).map((tag) => tag.name);
tags = items
.filter((item) => !(item.model?.info?.meta?.hidden ?? false))
.flatMap((item) => item.model?.tags ?? [])
.map((tag) => tag.name);
// Remove duplicates and sort
tags = Array.from(new Set(tags)).sort((a, b) => a.localeCompare(b));
@ -373,7 +378,7 @@
</div>
{/if}
<div class="px-3 mb-2 max-h-64 overflow-y-auto scrollbar-hidden group relative">
<div class="px-3 max-h-64 overflow-y-auto scrollbar-hidden group relative">
{#if tags && items.filter((item) => !(item.model?.info?.meta?.hidden ?? false)).length > 0}
<div
class=" flex w-full sticky top-0 z-10 bg-white dark:bg-gray-850 overflow-x-auto scrollbar-none"
@ -388,6 +393,7 @@
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}
>
{#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}
<button
class="min-w-fit outline-none p-1.5 {selectedTag === '' &&
selectedConnectionType === ''
@ -400,6 +406,7 @@
>
{$i18n.t('All')}
</button>
{/if}
{#if items.find((item) => item.model?.owned_by === 'ollama') && items.find((item) => item.model?.owned_by === 'openai')}
<button
@ -457,7 +464,7 @@
</div>
{/if}
{#each filteredItems.filter((item) => !(item.model?.info?.meta?.hidden ?? false)) as item, index}
{#each filteredItems as item, index}
<button
aria-label="model-item"
class="flex w-full text-left font-medium line-clamp-1 select-none items-center rounded-button py-2 pl-3 pr-1.5 text-sm text-gray-700 dark:text-gray-100 outline-hidden transition-all duration-75 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg cursor-pointer data-highlighted:bg-muted {index ===
@ -739,9 +746,7 @@
</div>
{#if showTemporaryChatControl}
<hr class="border-gray-100 dark:border-gray-800" />
<div class="flex items-center mx-2 my-2">
<div class="flex items-center mx-2 mb-2">
<button
class="flex justify-between w-full font-medium line-clamp-1 select-none items-center rounded-button py-2 px-3 text-sm text-gray-700 dark:text-gray-100 outline-hidden transition-all duration-75 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg cursor-pointer data-highlighted:bg-muted"
on:click={async () => {

View file

@ -32,6 +32,8 @@
let showUsername = false;
let notificationSound = true;
let detectArtifacts = true;
let richTextInput = true;
let promptAutocomplete = false;
@ -176,6 +178,11 @@
saveSettings({ autoTags });
};
const toggleDetectArtifacts = async () => {
detectArtifacts = !detectArtifacts;
saveSettings({ detectArtifacts });
};
const toggleRichTextInput = async () => {
richTextInput = !richTextInput;
saveSettings({ richTextInput });
@ -242,6 +249,7 @@
titleAutoGenerate = $settings?.title?.auto ?? true;
autoTags = $settings.autoTags ?? true;
detectArtifacts = $settings.detectArtifacts ?? true;
responseAutoCopy = $settings.responseAutoCopy ?? false;
showUsername = $settings.showUsername ?? false;
@ -537,6 +545,28 @@
</div>
</div>
<div>
<div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs">
{$i18n.t('Detect Artifacts Automatically')}
</div>
<button
class="p-1 px-3 text-xs flex rounded-sm transition"
on:click={() => {
toggleDetectArtifacts();
}}
type="button"
>
{#if detectArtifacts === true}
<span class="ml-2 self-center">{$i18n.t('On')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Off')}</span>
{/if}
</button>
</div>
</div>
<div>
<div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs">

View file

@ -15,7 +15,7 @@
let selectedTools = [];
$: selectedTools = $tools.filter((tool) => selectedToolIds.includes(tool.id));
$: selectedTools = ($tools ?? []).filter((tool) => selectedToolIds.includes(tool.id));
const i18n = getContext('i18n');
</script>

View file

@ -98,6 +98,16 @@
}
})
);
languages.push(
LanguageDescription.of({
name: 'Elixir',
extensions: ['ex', 'exs'],
load() {
return import('codemirror-lang-elixir').then((m) => m.elixir());
}
})
);
const getLang = async () => {
const language = languages.find((l) => l.alias.includes(lang));
return await language?.load();
@ -232,4 +242,4 @@
});
</script>
<div id="code-textarea-{id}" class="h-full w-full" />
<div id="code-textarea-{id}" class="h-full w-full text-sm" />

View file

@ -73,7 +73,7 @@
return JSON.stringify(parsed, null, 2);
} else {
// It's a primitive value like a number, boolean, etc.
return String(parsed);
return `${JSON.stringify(String(parsed))}`;
}
} catch (e) {
// Not valid JSON, return as-is

View file

@ -83,6 +83,8 @@
currentChatPage.set(1);
await chats.set(await getChatList(localStorage.token, $currentChatPage));
await pinnedChats.set(await getPinnedChatList(localStorage.token));
dispatch('change');
}
};

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "رفض عندما لا ينبغي أن يكون",
"Regenerate": "تجديد",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "ملاحظات الإصدار",
"Relevance": "",
"Remove": "إزالة",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Gravatar أستخدم",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "Initials أستخدم",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (أولاما)",
"use_mmap (Ollama)": "use_mmap (أولاما)",
"user": "مستخدم",

View file

@ -878,6 +878,8 @@
"References from": "مراجع من",
"Refused when it shouldn't have": "رفض عندما لا ينبغي أن يكون",
"Regenerate": "تجديد",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "ملاحظات الإصدار",
"Relevance": "الصلة",
"Remove": "إزالة",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Gravatar أستخدم",
"Use groups to group your users and assign permissions.": "استخدم المجموعات لتجميع المستخدمين وتحديد الصلاحيات.",
"Use Initials": "Initials أستخدم",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (أولاما)",
"use_mmap (Ollama)": "use_mmap (أولاما)",
"user": "مستخدم",

View file

@ -878,6 +878,8 @@
"References from": "Препратки от",
"Refused when it shouldn't have": "Отказано, когато не трябва да бъде",
"Regenerate": "Регенериране",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Бележки по изданието",
"Relevance": "Релевантност",
"Remove": "Изтриване",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Използвайте Gravatar",
"Use groups to group your users and assign permissions.": "Използвайте групи, за да групирате вашите потребители и да присвоите разрешения.",
"Use Initials": "Използвайте инициали",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "потребител",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "যদি উপযুক্ত নয়, তবে রেজিগেনেট করা হচ্ছে",
"Regenerate": "রেজিগেনেট করুন",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "রিলিজ নোটসমূহ",
"Relevance": "",
"Remove": "রিমুভ করুন",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Gravatar ব্যবহার করুন",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "নামের আদ্যক্ষর ব্যবহার করুন",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (ওলামা)",
"use_mmap (Ollama)": "use_mmap (ওলামা)",
"user": "ব্যবহারকারী",

View file

@ -878,6 +878,8 @@
"References from": "ནས་ལུང་འདྲེན།",
"Refused when it shouldn't have": "མི་དགོས་དུས་ཁས་མ་བླངས།",
"Regenerate": "བསྐྱར་བཟོ།",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "འགྲེམས་སྤེལ་མཆན་བུ།",
"Relevance": "འབྲེལ་ཡོད་རང་བཞིན།",
"Remove": "འདོར་བ།",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Gravatar བེད་སྤྱོད།",
"Use groups to group your users and assign permissions.": "ཁྱེད་ཀྱི་བེད་སྤྱོད་མཁན་ཚོགས་པ་བཟོ་བ་དང་དབང་ཚད་སྤྲོད་པར་ཚོགས་པ་བེད་སྤྱོད་གཏོང་བ།",
"Use Initials": "མིང་གི་ཡིག་འབྲུ་མགོ་མ་བེད་སྤྱོད།",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "བེད་སྤྱོད་མཁན།",

View file

@ -6,7 +6,7 @@
"(latest)": "(últim)",
"(Ollama)": "(Ollama)",
"{{ models }}": "{{ models }}",
"{{COUNT}} Available Tools": "",
"{{COUNT}} Available Tools": "{{COUNT}} eines disponibles",
"{{COUNT}} hidden lines": "{{COUNT}} línies ocultes",
"{{COUNT}} Replies": "{{COUNT}} respostes",
"{{user}}'s Chats": "Els xats de {{user}}",
@ -108,10 +108,10 @@
"Attribute for Username": "Atribut per al Nom d'usuari",
"Audio": "Àudio",
"August": "Agost",
"Auth": "",
"Auth": "Autenticació",
"Authenticate": "Autenticar",
"Authentication": "Autenticació",
"Auto": "",
"Auto": "Automàtic",
"Auto-Copy Response to Clipboard": "Copiar la resposta automàticament al porta-retalls",
"Auto-playback response": "Reproduir la resposta automàticament",
"Autocomplete Generation": "Generació automàtica",
@ -121,7 +121,7 @@
"AUTOMATIC1111 Base URL": "URL Base d'AUTOMATIC1111",
"AUTOMATIC1111 Base URL is required.": "Es requereix l'URL Base d'AUTOMATIC1111.",
"Available list": "Llista de disponibles",
"Available Tools": "",
"Available Tools": "Eines disponibles",
"available!": "disponible!",
"Awful": "Terrible",
"Azure AI Speech": "Azure AI Speech",
@ -220,10 +220,10 @@
"Confirm your new password": "Confirma la teva nova contrasenya",
"Connect to your own OpenAI compatible API endpoints.": "Connecta als teus propis punts de connexió de l'API compatible amb OpenAI",
"Connect to your own OpenAPI compatible external tool servers.": "Connecta als teus propis servidors d'eines externs compatibles amb OpenAPI",
"Connection failed": "",
"Connection successful": "",
"Connection failed": "La connexió ha fallat",
"Connection successful": "Connexió correcta",
"Connections": "Connexions",
"Connections saved successfully": "",
"Connections saved successfully": "Les connexions s'han desat correctament",
"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort.": "Restringeix l'esforç de raonament dels models de raonament. Només aplicable a models de raonament de proveïdors específics que donen suport a l'esforç de raonament.",
"Contact Admin for WebUI Access": "Posat en contacte amb l'administrador per accedir a WebUI",
"Content": "Contingut",
@ -308,7 +308,7 @@
"Direct Connections": "Connexions directes",
"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "Les connexions directes permeten als usuaris connectar-se als seus propis endpoints d'API compatibles amb OpenAI.",
"Direct Connections settings updated": "Configuració de les connexions directes actualitzada",
"Direct Tool Servers": "",
"Direct Tool Servers": "Servidors d'eines directes",
"Disabled": "Deshabilitat",
"Discover a function": "Descobrir una funció",
"Discover a model": "Descobrir un model",
@ -385,7 +385,7 @@
"Enable Mirostat sampling for controlling perplexity.": "Permetre el mostreig de Mirostat per controlar la perplexitat",
"Enable New Sign Ups": "Permetre nous registres",
"Enabled": "Habilitat",
"Enforce Temporary Chat": "",
"Enforce Temporary Chat": "Forçar els xats temporals",
"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",
@ -418,7 +418,7 @@
"Enter Kagi Search API Key": "Introdueix la clau API de Kagi Search",
"Enter Key Behavior": "Introdueix el comportament de clau",
"Enter language codes": "Introdueix els codis de llenguatge",
"Enter Mistral API Key": "",
"Enter Mistral API Key": "Entra la clau API de Mistral",
"Enter Model ID": "Introdueix l'identificador del model",
"Enter model tag (e.g. {{modelTag}})": "Introdueix l'etiqueta del model (p. ex. {{modelTag}})",
"Enter Mojeek Search API Key": "Introdueix la clau API de Mojeek Search",
@ -443,7 +443,7 @@
"Enter server port": "Introdueix el port del servidor",
"Enter stop sequence": "Introdueix la seqüència de parada",
"Enter system prompt": "Introdueix la indicació de sistema",
"Enter system prompt here": "",
"Enter system prompt here": "Entra la indicació de sistema aquí",
"Enter Tavily API Key": "Introdueix la clau API de Tavily",
"Enter the public URL of your WebUI. This URL will be used to generate links in the notifications.": "Entra la URL pública de WebUI. Aquesta URL s'utilitzarà per generar els enllaços en les notificacions.",
"Enter Tika Server URL": "Introdueix l'URL del servidor Tika",
@ -457,7 +457,7 @@
"Enter Your Email": "Introdueix el teu correu electrònic",
"Enter Your Full Name": "Introdueix el teu nom complet",
"Enter your message": "Introdueix el teu missatge",
"Enter your name": "",
"Enter your name": "Entra el teu nom",
"Enter your new password": "Introdueix la teva nova contrasenya",
"Enter Your Password": "Introdueix la teva contrasenya",
"Enter Your Role": "Introdueix el teu rol",
@ -477,7 +477,7 @@
"Exceeded the number of seats in your license. Please contact support to increase the number of seats.": "S'ha superat el nombre de places a la vostra llicència. Poseu-vos en contacte amb el servei d'assistència per augmentar el nombre de places.",
"Exclude": "Excloure",
"Execute code for analysis": "Executar el codi per analitzar-lo",
"Executing **{{NAME}}**...": "",
"Executing **{{NAME}}**...": "Executant **{{NAME}}**...",
"Expand": "Expandir",
"Experimental": "Experimental",
"Explain": "Explicar",
@ -502,7 +502,7 @@
"Failed to create API Key.": "No s'ha pogut crear la clau API.",
"Failed to fetch models": "No s'han pogut obtenir els models",
"Failed to read clipboard contents": "No s'ha pogut llegir el contingut del porta-retalls",
"Failed to save connections": "",
"Failed to save connections": "No s'han pogut desar les connexions",
"Failed to save models configuration": "No s'ha pogut desar la configuració dels models",
"Failed to update settings": "No s'han pogut actualitzar les preferències",
"Failed to upload file.": "No s'ha pogut pujar l'arxiu.",
@ -535,7 +535,7 @@
"Forge new paths": "Crea nous camins",
"Form": "Formulari",
"Format your variables using brackets like this:": "Formata les teves variables utilitzant claudàtors així:",
"Forwards system user session credentials to authenticate": "",
"Forwards system user session credentials to authenticate": "Envia les credencials de l'usuari del sistema per autenticar",
"Frequency Penalty": "Penalització per freqüència",
"Full Context Mode": "Mode de context complert",
"Function": "Funció",
@ -581,7 +581,7 @@
"Hex Color": "Color hexadecimal",
"Hex Color - Leave empty for default color": "Color hexadecimal - Deixar buit per a color per defecte",
"Hide": "Amaga",
"Hide Model": "",
"Hide Model": "Amagar el model",
"Home": "Inici",
"Host": "Servidor",
"How can I help you today?": "Com et puc ajudar avui?",
@ -641,7 +641,7 @@
"Knowledge Access": "Accés al coneixement",
"Knowledge created successfully.": "Coneixement creat correctament.",
"Knowledge deleted successfully.": "Coneixement eliminat correctament.",
"Knowledge Public Sharing": "",
"Knowledge Public Sharing": "Compartir públicament el Coneixement",
"Knowledge reset successfully.": "Coneixement restablert correctament.",
"Knowledge updated successfully": "Coneixement actualitzat correctament.",
"Kokoro.js (Browser)": "Kokoro.js (Navegador)",
@ -655,7 +655,7 @@
"LDAP": "LDAP",
"LDAP server updated": "Servidor LDAP actualitzat",
"Leaderboard": "Tauler de classificació",
"Learn more about OpenAPI tool servers.": "",
"Learn more about OpenAPI tool servers.": "Aprèn més sobre els servidors d'eines OpenAPI",
"Leave empty for unlimited": "Deixar-ho buit per il·limitat",
"Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Deixar-ho buit per incloure tots els models del punt de connexió \"{{url}}/api/tags\"",
"Leave empty to include all models from \"{{url}}/models\" endpoint": "Deixar-ho buit per incloure tots els models del punt de connexió \"{{url}}/models\"",
@ -706,16 +706,16 @@
"Mirostat": "Mirostat",
"Mirostat Eta": "Eta de Mirostat",
"Mirostat Tau": "Tau de Mirostat",
"Mistral OCR": "",
"Mistral OCR API Key required.": "",
"Mistral OCR": "Mistral OCR",
"Mistral OCR API Key required.": "És necessària la clau API de Mistral OCR",
"Model": "Model",
"Model '{{modelName}}' has been successfully downloaded.": "El model '{{modelName}}' s'ha descarregat correctament.",
"Model '{{modelTag}}' is already in queue for downloading.": "El model '{{modelTag}}' ja està en cua per ser descarregat.",
"Model {{modelId}} not found": "No s'ha trobat el model {{modelId}}",
"Model {{modelName}} is not vision capable": "El model {{modelName}} no és capaç de visió",
"Model {{name}} is now {{status}}": "El model {{name}} ara és {{status}}",
"Model {{name}} is now hidden": "",
"Model {{name}} is now visible": "",
"Model {{name}} is now hidden": "El model {{name}} està ara amagat",
"Model {{name}} is now visible": "El model {{name}} està ara visible",
"Model accepts image inputs": "El model accepta entrades d'imatge",
"Model created successfully!": "Model creat correctament",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "S'ha detectat el camí del sistema de fitxers del model. És necessari un nom curt del model per actualitzar, no es pot continuar.",
@ -731,7 +731,7 @@
"Models": "Models",
"Models Access": "Accés als models",
"Models configuration saved successfully": "La configuració dels models s'ha desat correctament",
"Models Public Sharing": "",
"Models Public Sharing": "Compartició pública de models",
"Mojeek Search API Key": "Clau API de Mojeek Search",
"more": "més",
"More": "Més",
@ -794,7 +794,7 @@
"Open file": "Obrir arxiu",
"Open in full screen": "Obrir en pantalla complerta",
"Open new chat": "Obre un xat nou",
"Open WebUI can use tools provided by any OpenAPI server.": "",
"Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI pot utilitzar eines de servidors OpenAPI.",
"Open WebUI uses faster-whisper internally.": "Open WebUI utilitza faster-whisper internament.",
"Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI utilitza incrustacions de SpeechT5 i CMU Arctic.",
"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}})",
@ -804,7 +804,7 @@
"OpenAI API Key is required.": "Es requereix la clau API d'OpenAI.",
"OpenAI API settings updated": "Configuració de l'API d'OpenAI actualitzada",
"OpenAI URL/Key required.": "URL/Clau d'OpenAI requerides.",
"openapi.json Path": "",
"openapi.json Path": "openapi.json",
"or": "o",
"Organize your users": "Organitza els teus usuaris",
"Other": "Altres",
@ -836,8 +836,8 @@
"Please carefully review the following warnings:": "Si us plau, revisa els següents avisos amb cura:",
"Please do not close the settings page while loading the model.": "No tanquis la pàgina de configuració mentre carregues el model.",
"Please enter a prompt": "Si us plau, entra una indicació",
"Please enter a valid path": "",
"Please enter a valid URL": "",
"Please enter a valid path": "Si us plau, entra un camí vàlid",
"Please enter a valid URL": "Si us plau, entra una URL vàlida",
"Please fill in all fields.": "Emplena tots els camps, si us plau.",
"Please select a model first.": "Si us plau, selecciona un model primer",
"Please select a model.": "Si us plau, selecciona un model.",
@ -853,14 +853,14 @@
"Profile Image": "Imatge de perfil",
"Prompt": "Indicació",
"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "Indicació (p.ex. Digues-me quelcom divertit sobre l'Imperi Romà)",
"Prompt Autocompletion": "",
"Prompt Autocompletion": "Completar automàticament la indicació",
"Prompt Content": "Contingut de la indicació",
"Prompt created successfully": "Indicació creada correctament",
"Prompt suggestions": "Suggeriments d'indicacions",
"Prompt updated successfully": "Indicació actualitzada correctament",
"Prompts": "Indicacions",
"Prompts Access": "Accés a les indicacions",
"Prompts Public Sharing": "",
"Prompts Public Sharing": "Compartició pública de indicacions",
"Public": "Públic",
"Pull \"{{searchValue}}\" from Ollama.com": "Obtenir \"{{searchValue}}\" de Ollama.com",
"Pull a model from Ollama.com": "Obtenir un model d'Ollama.com",
@ -878,6 +878,8 @@
"References from": "Referències de",
"Refused when it shouldn't have": "Refusat quan no hauria d'haver estat",
"Regenerate": "Regenerar",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Notes de la versió",
"Relevance": "Rellevància",
"Remove": "Eliminar",
@ -993,11 +995,11 @@
"Share": "Compartir",
"Share Chat": "Compartir el xat",
"Share to Open WebUI Community": "Compartir amb la comunitat OpenWebUI",
"Sharing Permissions": "",
"Sharing Permissions": "Compartir els permisos",
"Show": "Mostrar",
"Show \"What's New\" modal on login": "Veure 'Què hi ha de nou' a l'entrada",
"Show Admin Details in Account Pending Overlay": "Mostrar els detalls de l'administrador a la superposició del compte pendent",
"Show Model": "",
"Show Model": "Mostrar el model",
"Show shortcuts": "Mostrar dreceres",
"Show your support!": "Mostra el teu suport!",
"Showcased creativity": "Creativitat mostrada",
@ -1060,7 +1062,7 @@
"Thinking...": "Pensant...",
"This action cannot be undone. Do you wish to continue?": "Aquesta acció no es pot desfer. Vols continuar?",
"This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Aquest canal es va crear el dia {{createdAt}}. Aquest és el començament del canal {{channelName}}.",
"This chat wont appear in history and your messages will not be saved.": "",
"This chat wont appear in history and your messages will not be saved.": "Aquest xat no apareixerà a l'historial i els teus missatges no es desaran.",
"This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "Això assegura que les teves converses valuoses queden desades de manera segura a la teva base de dades. Gràcies!",
"This is an experimental feature, it may not function as expected and is subject to change at any time.": "Aquesta és una funció experimental, és possible que no funcioni com s'espera i està subjecta a canvis en qualsevol moment.",
"This option controls how many tokens are preserved when refreshing the context. For example, if set to 2, the last 2 tokens of the conversation context will be retained. Preserving context can help maintain the continuity of a conversation, but it may reduce the ability to respond to new topics.": "Aquesta opció controla quants tokens es conserven en actualitzar el context. Per exemple, si s'estableix en 2, es conservaran els darrers 2 tokens del context de conversa. Preservar el context pot ajudar a mantenir la continuïtat d'una conversa, però pot reduir la capacitat de respondre a nous temes.",
@ -1108,7 +1110,7 @@
"Tool ID": "ID de l'eina",
"Tool imported successfully": "Eina importada correctament",
"Tool Name": "Nom de l'eina",
"Tool Servers": "",
"Tool Servers": "Servidors d'eines",
"Tool updated successfully": "Eina actualitzada correctament",
"Tools": "Eines",
"Tools Access": "Accés a les eines",
@ -1116,7 +1118,7 @@
"Tools Function Calling Prompt": "Indicació per a la crida de funcions",
"Tools have a function calling system that allows arbitrary code execution": "Les eines disposen d'un sistema de crida a funcions que permet execució de codi arbitrari",
"Tools have a function calling system that allows arbitrary code execution.": "Les eines disposen d'un sistema de crida a funcions que permet execució de codi arbitrari.",
"Tools Public Sharing": "",
"Tools Public Sharing": "Compartició pública d'eines",
"Top K": "Top K",
"Top K Reranker": "Top K Reranker",
"Top P": "Top P",
@ -1158,12 +1160,14 @@
"Use Gravatar": "Utilitzar Gravatar",
"Use groups to group your users and assign permissions.": "Utilitza grups per agrupar els usuaris i assignar permisos.",
"Use Initials": "Utilitzar inicials",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "usuari",
"User": "Usuari",
"User location successfully retrieved.": "Ubicació de l'usuari obtinguda correctament",
"User Webhooks": "",
"User Webhooks": "Webhooks d'usuari",
"Username": "Nom d'usuari",
"Users": "Usuaris",
"Using the default arena model with all models. Click the plus button to add custom models.": "S'utilitza el model d'Arena predeterminat amb tots els models. Clica el botó més per afegir models personalitzats.",
@ -1178,7 +1182,7 @@
"Version": "Versió",
"Version {{selectedVersion}} of {{totalVersions}}": "Versió {{selectedVersion}} de {{totalVersions}}",
"View Replies": "Veure les respostes",
"View Result from **{{NAME}}**": "",
"View Result from **{{NAME}}**": "Veure el resultat de **{{NAME}}**",
"Visibility": "Visibilitat",
"Voice": "Veu",
"Voice Input": "Entrada de veu",
@ -1196,7 +1200,7 @@
"Webhook URL": "URL del webhook",
"WebUI Settings": "Preferències de WebUI",
"WebUI URL": "URL de WebUI",
"WebUI will make requests to \"{{url}}\"": "",
"WebUI will make requests to \"{{url}}\"": "WebUI farà peticions a \"{{url}}\"",
"WebUI will make requests to \"{{url}}/api/chat\"": "WebUI farà peticions a \"{{url}}/api/chat\"",
"WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI farà peticions a \"{{url}}/chat/completions\"",
"What are you trying to achieve?": "Què intentes aconseguir?",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "",
"Regenerate": "",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Release Notes",
"Relevance": "",
"Remove": "",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Paggamit sa Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "",
"use_mmap (Ollama)": "",
"user": "tiggamit",

View file

@ -878,6 +878,8 @@
"References from": "Reference z",
"Refused when it shouldn't have": "Odmítnuto, když nemělo být.",
"Regenerate": "Regenerovat",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Záznamy o vydání",
"Relevance": "Relevance",
"Remove": "Odebrat",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Použití Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "Použijte iniciály",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "uživatel",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "Afvist, når den ikke burde have været det",
"Regenerate": "Regenerer",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Udgivelsesnoter",
"Relevance": "",
"Remove": "Fjern",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Brug Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "Brug initialer",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "bruger",

View file

@ -878,6 +878,8 @@
"References from": "Referenzen aus",
"Refused when it shouldn't have": "Abgelehnt, obwohl es nicht hätte abgelehnt werden sollen",
"Regenerate": "Neu generieren",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Veröffentlichungshinweise",
"Relevance": "Relevanz",
"Remove": "Entfernen",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Gravatar verwenden",
"Use groups to group your users and assign permissions.": "Nutzen Sie Gruppen, um Ihre Benutzer zu gruppieren und Berechtigungen zuzuweisen.",
"Use Initials": "Initialen verwenden",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "Benutzer",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "",
"Regenerate": "",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Release Borks",
"Relevance": "",
"Remove": "",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Use Gravatar much avatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "Use Initials much initial",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "",
"use_mmap (Ollama)": "",
"user": "user much user",

View file

@ -878,6 +878,8 @@
"References from": "Αναφορές από",
"Refused when it shouldn't have": "Αρνήθηκε όταν δεν έπρεπε",
"Regenerate": "Αναγεννήστε",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Σημειώσεις Έκδοσης",
"Relevance": "Σχετικότητα",
"Remove": "Αφαίρεση",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Χρησιμοποιήστε Gravatar",
"Use groups to group your users and assign permissions.": "Χρησιμοποιήστε ομάδες για να ομαδοποιήσετε τους χρήστες σας και να αναθέσετε δικαιώματα.",
"Use Initials": "Χρησιμοποιήστε Αρχικά",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "user",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "",
"Regenerate": "",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "",
"Relevance": "",
"Remove": "",
@ -1158,6 +1160,8 @@
"Use Gravatar": "",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "",
"use_mmap (Ollama)": "",
"user": "",

View file

@ -424,6 +424,8 @@
"Enter Mojeek Search API Key": "",
"Enter Number of Steps (e.g. 50)": "",
"Enter Perplexity API Key": "",
"Enter Sougou Search API sID": "",
"Enter Sougou Search API SK": "",
"Enter proxy URL (e.g. https://user:password@host:port)": "",
"Enter reasoning effort": "",
"Enter Sampler (e.g. Euler a)": "",
@ -822,6 +824,8 @@
"Permission denied when accessing microphone: {{error}}": "",
"Permissions": "",
"Perplexity API Key": "",
"Sougou Search API sID": "",
"Sougou Search API SK": "",
"Personalization": "",
"Pin": "",
"Pinned": "",
@ -878,6 +882,8 @@
"References from": "",
"Refused when it shouldn't have": "",
"Regenerate": "",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "",
"Relevance": "",
"Remove": "",
@ -1158,6 +1164,8 @@
"Use Gravatar": "",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "",
"use_mmap (Ollama)": "",
"user": "",

View file

@ -878,6 +878,8 @@
"References from": "Referencias desde",
"Refused when it shouldn't have": "Rechazado cuando no debería haberlo hecho",
"Regenerate": "Regenerar",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Notas de la Versión",
"Relevance": "Relevancia",
"Remove": "Eliminar",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Usar Gravatar",
"Use groups to group your users and assign permissions.": "Usar grupos para agrupar a usuarios y asignar permisos.",
"Use Initials": "Usar Iniciales",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "usuario",

View file

@ -878,6 +878,8 @@
"References from": "Viited allikast",
"Refused when it shouldn't have": "Keeldus, kui ei oleks pidanud",
"Regenerate": "Regenereeri",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Väljalaskemärkmed",
"Relevance": "Asjakohasus",
"Remove": "Eemalda",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Kasuta Gravatari",
"Use groups to group your users and assign permissions.": "Kasutage gruppe oma kasutajate grupeerimiseks ja õiguste määramiseks.",
"Use Initials": "Kasuta initsiaale",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "kasutaja",

View file

@ -878,6 +878,8 @@
"References from": "Erreferentziak hemendik",
"Refused when it shouldn't have": "Ukatu duenean ukatu behar ez zuenean",
"Regenerate": "Bersortu",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Bertsio oharrak",
"Relevance": "Garrantzia",
"Remove": "Kendu",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Erabili Gravatar",
"Use groups to group your users and assign permissions.": "Erabili taldeak zure erabiltzaileak taldekatu eta baimenak esleitzeko.",
"Use Initials": "Erabili inizialak",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "erabiltzailea",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "رد شده زمانی که باید نباشد",
"Regenerate": "ری\u200cسازی",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "یادداشت\u200cهای انتشار",
"Relevance": "ارتباط",
"Remove": "حذف",
@ -1158,6 +1160,8 @@
"Use Gravatar": "استفاده از گراواتار",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "استفاده از سرواژه",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (اولاما)",
"use_mmap (Ollama)": "use_mmap (اولاما)",
"user": "کاربر",

View file

@ -878,6 +878,8 @@
"References from": "Viitteet lähteistä",
"Refused when it shouldn't have": "Kieltäytyi, vaikka ei olisi pitänyt",
"Regenerate": "Uudelleentuota",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Julkaisutiedot",
"Relevance": "Relevanssi",
"Remove": "Poista",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Käytä Gravataria",
"Use groups to group your users and assign permissions.": "Käytä ryhmiä jäsentääksesi käyttäjiä ja antaaksesi käyttöoikeuksia.",
"Use Initials": "Käytä alkukirjaimia",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "käyttäjä",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "Refusé alors qu'il n'aurait pas dû l'être",
"Regenerate": "Regénérer",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Notes de publication",
"Relevance": "",
"Remove": "Retirer",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Utilisez Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "Utiliser les initiales",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "utiliser mmap (Ollama)",
"user": "utilisateur",

View file

@ -878,6 +878,8 @@
"References from": "Références de",
"Refused when it shouldn't have": "Refusé alors qu'il n'aurait pas dû l'être",
"Regenerate": "Regénérer",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Notes de mise à jour",
"Relevance": "Pertinence",
"Remove": "Retirer",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Utiliser Gravatar",
"Use groups to group your users and assign permissions.": "Utilisez des groupes pour regrouper vos utilisateurs et attribuer des permissions.",
"Use Initials": "Utiliser les initiales",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "Utiliser mlock (Ollama)",
"use_mmap (Ollama)": "Utiliser mmap (Ollama)",
"user": "utilisateur",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "נדחה כאשר לא היה צריך",
"Regenerate": "הפק מחדש",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "הערות שחרור",
"Relevance": "",
"Remove": "הסר",
@ -1158,6 +1160,8 @@
"Use Gravatar": "שימוש ב Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "שימוש ב initials",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (אולמה)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "משתמש",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "जब ऐसा नहीं होना चाहिए था तो मना कर दिया",
"Regenerate": "पुनः जेनरेट",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "रिलीज नोट्स",
"Relevance": "",
"Remove": "हटा दें",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Gravatar का प्रयोग करें",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "प्रथमाक्षर का प्रयोग करें",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (ओलामा)",
"use_mmap (Ollama)": "use_mmap (ओलामा)",
"user": "उपयोगकर्ता",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "Odbijen kada nije trebao biti",
"Regenerate": "Regeneriraj",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Bilješke o izdanju",
"Relevance": "",
"Remove": "Ukloni",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Koristi Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "Koristi inicijale",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "korisnik",

File diff suppressed because it is too large Load diff

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "Menolak ketika seharusnya tidak",
"Regenerate": "Regenerasi",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Catatan Rilis",
"Relevance": "",
"Remove": "Hapus",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Gunakan Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "Gunakan Inisial",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "pengguna",

View file

@ -878,6 +878,8 @@
"References from": "Tagairtí ó",
"Refused when it shouldn't have": "Diúltaíodh nuair nár chóir dó",
"Regenerate": "Athghiniúint",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Nótaí Scaoilte",
"Relevance": "Ábharthacht",
"Remove": "Bain",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Úsáid Gravatar",
"Use groups to group your users and assign permissions.": "Úsáid grúpaí chun d'úsáideoirí a ghrúpáil agus ceadanna a shannadh",
"Use Initials": "Úsáid ceannlitreacha",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "úsáideoir",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "Rifiutato quando non avrebbe dovuto",
"Regenerate": "Rigenera",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Note di rilascio",
"Relevance": "",
"Remove": "Rimuovi",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Usa Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "Usa iniziali",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "utente",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "拒否すべきでないのに拒否した",
"Regenerate": "再生成",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "リリースノート",
"Relevance": "",
"Remove": "削除",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Gravatar を使用する",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "初期値を使用する",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "",
"use_mmap (Ollama)": "",
"user": "ユーザー",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "უარა, როგორც უნდა იყოს",
"Regenerate": "თავიდან გენერაცია",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "გამოცემის შენიშვნები",
"Relevance": "შესაბამისობა",
"Remove": "წაშლა",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Gravatar-ის გამოყენება",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "ინიციალების გამოყენება",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "მომხმარებელი",

View file

@ -878,6 +878,8 @@
"References from": "출처",
"Refused when it shouldn't have": "허용되지 않았지만 허용되어야 합니다.",
"Regenerate": "재생성",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "릴리스 노트",
"Relevance": "관련도",
"Remove": "삭제",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Gravatar 사용",
"Use groups to group your users and assign permissions.": "그룹을 사용하여 사용자를 그룹화하고 권한을 할당하세요.",
"Use Initials": "초성 사용",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (올라마)",
"use_mmap (Ollama)": "use_mmap (올라마)",
"user": "사용자",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "Atmesta kai neturėtų būti atmesta",
"Regenerate": "Generuoti iš naujo",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Naujovės",
"Relevance": "",
"Remove": "Pašalinti",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Naudoti Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "Naudotojo inicialai",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "naudotojas",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "Menolak dimana ia tidak sepatutnya",
"Regenerate": "Jana semula",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Nota Keluaran",
"Relevance": "",
"Remove": "Hapuskan",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Gunakan Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "Gunakan nama pendek",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "se_mmap (Ollama)",
"user": "pengguna",

View file

@ -878,6 +878,8 @@
"References from": "Henviser fra",
"Refused when it shouldn't have": "Avvist når det ikke burde ha blitt det",
"Regenerate": "Generer på nytt",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Utgivelsesnotater",
"Relevance": "Relevans",
"Remove": "Fjern",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Bruk Gravatar",
"Use groups to group your users and assign permissions.": "Bruk grupper til å samle brukere og tildele tillatelser.",
"Use Initials": "Bruk initialer",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "bruker",

View file

@ -878,6 +878,8 @@
"References from": "Referenties van",
"Refused when it shouldn't have": "Geweigerd terwijl het niet had moeten",
"Regenerate": "Regenereren",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Release-opmerkingen",
"Relevance": "Relevantie",
"Remove": "Verwijderen",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Gebruik Gravatar",
"Use groups to group your users and assign permissions.": "Gebruik groepen om gebruikers te groeperen en rechten aan te wijzen",
"Use Initials": "Gebruik initialen",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "gebruiker",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "ਜਦੋਂ ਇਹ ਨਹੀਂ ਹੋਣਾ ਚਾਹੀਦਾ ਸੀ ਤਾਂ ਇਨਕਾਰ ਕੀਤਾ",
"Regenerate": "ਮੁੜ ਬਣਾਓ",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "ਰਿਲੀਜ਼ ਨੋਟਸ",
"Relevance": "",
"Remove": "ਹਟਾਓ",
@ -1158,6 +1160,8 @@
"Use Gravatar": "ਗ੍ਰਾਵਾਟਾਰ ਵਰਤੋ",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "ਸ਼ੁਰੂਆਤੀ ਅੱਖਰ ਵਰਤੋ",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (ਓਲਾਮਾ)",
"use_mmap (Ollama)": "use_mmap (ਓਲਾਮਾ)",
"user": "ਉਪਭੋਗਤਾ",

View file

@ -878,6 +878,8 @@
"References from": "Odniesienia do",
"Refused when it shouldn't have": "Odmówił, gdy nie powinien",
"Regenerate": "Wygeneruj ponownie",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Notatki do wydania",
"Relevance": "Trafność",
"Remove": "Usuń",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Użyj Gravatara",
"Use groups to group your users and assign permissions.": "Wykorzystaj grupy do grupowania użytkowników i przypisywania uprawnień.",
"Use Initials": "Użyj inicjałów",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "użyj_mlock (Ollama)",
"use_mmap (Ollama)": "użyj_mmap (Ollama)",
"user": "użytkownik",

View file

@ -878,6 +878,8 @@
"References from": "Referências de",
"Refused when it shouldn't have": "Recusado quando não deveria",
"Regenerate": "Gerar novamente",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Notas de Lançamento",
"Relevance": "Relevância",
"Remove": "Remover",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Usar Gravatar",
"Use groups to group your users and assign permissions.": "Use grupos para agrupar seus usuários e atribuir permissões.",
"Use Initials": "Usar Iniciais",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "usuário",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "Recusado quando não deveria",
"Regenerate": "Regenerar",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Notas de Lançamento",
"Relevance": "",
"Remove": "Remover",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Usar Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "Usar Iniciais",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "utilizador",

View file

@ -878,6 +878,8 @@
"References from": "Referințe din",
"Refused when it shouldn't have": "Refuzat când nu ar fi trebuit",
"Regenerate": "Regenerare",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Note de Lansare",
"Relevance": "Relevanță",
"Remove": "Înlătură",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Folosește Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "Folosește Inițialele",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "utilizator",

View file

@ -6,7 +6,7 @@
"(latest)": "(последняя)",
"(Ollama)": "",
"{{ models }}": "{{ модели }}",
"{{COUNT}} Available Tools": "",
"{{COUNT}} Available Tools": "{{COUNT}} доступных инструментов",
"{{COUNT}} hidden lines": "{{COUNT}} скрытых строк",
"{{COUNT}} Replies": "{{COUNT}} Ответов",
"{{user}}'s Chats": "Чаты {{user}}'а",
@ -49,10 +49,10 @@
"Adjusting these settings will apply changes universally to all users.": "Изменения в этих настройках будут применены для всех пользователей.",
"admin": "админ",
"Admin": "Админ",
"Admin Panel": "Админ панель",
"Admin Panel": "Панель администратора",
"Admin Settings": "Настройки администратора",
"Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Администраторы всегда имеют доступ ко всем инструментам; пользователям нужны инструменты, назначенные для каждой модели в рабочем пространстве.",
"Advanced Parameters": "Расширенные Параметры",
"Advanced Parameters": "Расширенные параметры",
"Advanced Params": "Расширенные параметры",
"All": "Все",
"All Documents": "Все документы",
@ -108,10 +108,10 @@
"Attribute for Username": "Атрибут для имени пользователя",
"Audio": "Аудио",
"August": "Август",
"Auth": "",
"Auth": "Вход",
"Authenticate": "Аутентификация",
"Authentication": "Аутентификация",
"Auto": "",
"Auto": "Автоматически",
"Auto-Copy Response to Clipboard": "Автоматическое копирование ответа в буфер обмена",
"Auto-playback response": "Автоматическое воспроизведение ответа",
"Autocomplete Generation": "Генерация автозаполнения",
@ -121,7 +121,7 @@
"AUTOMATIC1111 Base URL": "Базовый URL адрес AUTOMATIC1111",
"AUTOMATIC1111 Base URL is required.": "Необходим базовый адрес URL AUTOMATIC1111.",
"Available list": "Список доступных",
"Available Tools": "",
"Available Tools": "Доступные инструменты",
"available!": "доступно!",
"Awful": "Ужасно",
"Azure AI Speech": "Azure AI Speech",
@ -220,10 +220,10 @@
"Confirm your new password": "Подтвердите свой новый пароль",
"Connect to your own OpenAI compatible API endpoints.": "Подключитесь к своим собственным энд-поинтам API, совместимым с OpenAI.",
"Connect to your own OpenAPI compatible external tool servers.": "Подключитесь к вашим собственным внешним инструментальным серверам, совместимым с OpenAPI.",
"Connection failed": "",
"Connection successful": "",
"Connection failed": "Подключение не удалось",
"Connection successful": "Успешное подключение",
"Connections": "Подключения",
"Connections saved successfully": "",
"Connections saved successfully": "Подключение успешно сохранено",
"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort.": "Ограничивает усилия по обоснованию для моделей обоснования. Применимо только к моделям обоснования от конкретных поставщиков, которые поддерживают усилия по обоснованию.",
"Contact Admin for WebUI Access": "Обратитесь к администратору для получения доступа к WebUI",
"Content": "Содержание",
@ -254,7 +254,7 @@
"Create Admin Account": "Создать Аккаунт Администратора",
"Create Channel": "Создать Канал",
"Create Group": "Создать Группу",
"Create Knowledge": "Создать Знания",
"Create Knowledge": "Создать Знание",
"Create new key": "Создать новый ключ",
"Create new secret key": "Создать новый секретный ключ",
"Created at": "Создано",
@ -304,11 +304,11 @@
"Describe your knowledge base and objectives": "Опишите свою базу знаний и цели",
"Description": "Описание",
"Didn't fully follow instructions": "Не полностью следует инструкциям",
"Direct": "",
"Direct": "Прямое",
"Direct Connections": "Прямые подключения",
"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "Прямые подключения позволяют пользователям подключаться к своим собственным конечным точкам API, совместимым с OpenAI.",
"Direct Connections settings updated": "Настройки прямых подключений обновлены",
"Direct Tool Servers": "",
"Direct Tool Servers": "Прямые сервера инструментов",
"Disabled": "Отключено",
"Discover a function": "Найти функцию",
"Discover a model": "Найти модель",
@ -329,7 +329,7 @@
"Do not install functions from sources you do not fully trust.": "Не устанавливайте функции из источников, которым вы не полностью доверяете.",
"Do not install tools from sources you do not fully trust.": "Не устанавливайте инструменты из источников, которым вы не полностью доверяете.",
"Docling": "",
"Docling Server URL required.": "",
"Docling Server URL required.": "Необходим URL сервера Docling",
"Document": "Документ",
"Document Intelligence": "Интеллектуальный анализ документов",
"Document Intelligence endpoint and key required.": "Требуется энд-поинт анализа документов и ключ.",
@ -350,7 +350,7 @@
"Draw": "Рисовать",
"Drop any files here to add to the conversation": "Перетащите сюда файлы, чтобы добавить их в разговор",
"e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "например, '30s','10m'. Допустимые единицы времени: 's', 'm', 'h'.",
"e.g. \"json\" or a JSON schema": "",
"e.g. \"json\" or a JSON schema": "например, \"json\" или схему JSON",
"e.g. 60": "например, 60",
"e.g. A filter to remove profanity from text": "например, фильтр для удаления ненормативной лексики из текста",
"e.g. My Filter": "например, мой фильтр",
@ -385,7 +385,7 @@
"Enable Mirostat sampling for controlling perplexity.": "Включите выборку Mirostat для контроля путаницы.",
"Enable New Sign Ups": "Разрешить новые регистрации",
"Enabled": "Включено",
"Enforce Temporary Chat": "",
"Enforce Temporary Chat": "Принудительный временный чат",
"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": "Введите детали о себе, чтобы LLMs могли запомнить",
@ -402,7 +402,7 @@
"Enter Chunk Size": "Введите размер фрагмента",
"Enter comma-seperated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Введите пары \"token:bias_value\", разделенные запятыми (пример: 5432:100, 413:-100).",
"Enter description": "Введите описание",
"Enter Docling Server URL": "",
"Enter Docling Server URL": "Введите URL сервера Docling",
"Enter Document Intelligence Endpoint": "Введите энд-поинт анализа документов",
"Enter Document Intelligence Key": "Введите ключ для анализа документов",
"Enter domains separated by commas (e.g., example.com,site.org)": "Введите домены, разделенные запятыми (например, example.com,site.org)",
@ -418,7 +418,7 @@
"Enter Kagi Search API Key": "Введите ключ API поиска Kagi",
"Enter Key Behavior": "Введите ключ поведения",
"Enter language codes": "Введите коды языков",
"Enter Mistral API Key": "",
"Enter Mistral API Key": "Введите ключ API для Mistral",
"Enter Model ID": "Введите ID модели",
"Enter model tag (e.g. {{modelTag}})": "Введите тег модели (например, {{modelTag}})",
"Enter Mojeek Search API Key": "Введите ключ API поиска Mojeek",
@ -443,21 +443,21 @@
"Enter server port": "Введите порт сервера",
"Enter stop sequence": "Введите последовательность остановки",
"Enter system prompt": "Введите системный промпт",
"Enter system prompt here": "",
"Enter system prompt here": "Введите системный промпт здесь",
"Enter Tavily API Key": "Введите ключ API Tavily",
"Enter the public URL of your WebUI. This URL will be used to generate links in the notifications.": "Введите общедоступный URL вашего WebUI. Этот URL будет использоваться для создания ссылок в уведомлениях.",
"Enter Tika Server URL": "Введите URL-адрес сервера Tika",
"Enter timeout in seconds": "Введите время ожидания в секундах",
"Enter to Send": "Enter для отправки",
"Enter Top K": "Введите Top K",
"Enter Top K Reranker": "",
"Enter Top K Reranker": "Введите Top K переоценщика",
"Enter URL (e.g. http://127.0.0.1:7860/)": "Введите URL-адрес (например, http://127.0.0.1:7860/)",
"Enter URL (e.g. http://localhost:11434)": "Введите URL-адрес (например, http://localhost:11434)",
"Enter your current password": "Введите ваш текущий пароль",
"Enter Your Email": "Введите вашу электронную почту",
"Enter Your Full Name": "Введите ваше полное имя",
"Enter your message": "Введите ваше сообщение",
"Enter your name": "",
"Enter your name": "Введите ваше имя",
"Enter your new password": "Введите свой новый пароль",
"Enter Your Password": "Введите ваш пароль",
"Enter Your Role": "Введите вашу роль",
@ -477,7 +477,7 @@
"Exceeded the number of seats in your license. Please contact support to increase the number of seats.": "Превышено количество мест в вашей лицензии. Пожалуйста, свяжитесь со службой поддержки, чтобы увеличить количество мест.",
"Exclude": "Исключать",
"Execute code for analysis": "Выполнить код для анализа",
"Executing **{{NAME}}**...": "",
"Executing **{{NAME}}**...": "Выполняю **{{NAME}}**...",
"Expand": "Расширить",
"Experimental": "Экспериментальное",
"Explain": "Объяснить",
@ -495,14 +495,14 @@
"Export Prompts": "Экспортировать промпты",
"Export to CSV": "Экспортировать в CSV",
"Export Tools": "Экспортировать инструменты",
"External": "",
"External": "Внешнее",
"External Models": "Внешние модели",
"Failed to add file.": "Не удалось добавить файл.",
"Failed to connect to {{URL}} OpenAPI tool server": "",
"Failed to connect to {{URL}} OpenAPI tool server": "Не удалось подключиться к серверу инструмента OpenAI {{URL}}",
"Failed to create API Key.": "Не удалось создать ключ API.",
"Failed to fetch models": "Не удалось получить модели",
"Failed to read clipboard contents": "Не удалось прочитать содержимое буфера обмена",
"Failed to save connections": "",
"Failed to save connections": "Не удалось сохранить подключения",
"Failed to save models configuration": "Не удалось сохранить конфигурацию моделей",
"Failed to update settings": "Не удалось обновить настройки",
"Failed to upload file.": "Не удалось загрузить файл.",
@ -535,7 +535,7 @@
"Forge new paths": "Прокладывайте новые пути",
"Form": "Форма",
"Format your variables using brackets like this:": "Отформатируйте переменные, используя такие : скобки",
"Forwards system user session credentials to authenticate": "",
"Forwards system user session credentials to authenticate": "Перенаправляет учетные данные сеанса системного пользователя для проверки подлинности",
"Frequency Penalty": "Штраф за частоту",
"Full Context Mode": "Режим полного контекста",
"Function": "Функция",
@ -581,7 +581,7 @@
"Hex Color": "Цвет Hex",
"Hex Color - Leave empty for default color": "Цвет Hex - оставьте пустым значение цвета по умолчанию",
"Hide": "Скрыть",
"Hide Model": "",
"Hide Model": "Скрыть модель",
"Home": "Домой",
"Host": "Хост",
"How can I help you today?": "Чем я могу помочь вам сегодня?",
@ -612,14 +612,14 @@
"Include `--api` flag when running stable-diffusion-webui": "Добавьте флаг `--api` при запуске stable-diffusion-webui",
"Influences how quickly the algorithm responds to feedback from the generated text. A lower learning rate will result in slower adjustments, while a higher learning rate will make the algorithm more responsive.": "Влияет на то, насколько быстро алгоритм реагирует на обратную связь из сгенерированного текста. Более низкая скорость обучения приведет к более медленной корректировке, в то время как более высокая скорость обучения сделает алгоритм более отзывчивым.",
"Info": "Информация",
"Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "",
"Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Вводите весь контент в качестве контекста для комплексной обработки, это рекомендуется для сложных запросов.",
"Input commands": "Введите команды",
"Install from Github URL": "Установка с URL-адреса Github",
"Instant Auto-Send After Voice Transcription": "Мгновенная автоматическая отправка после расшифровки голоса",
"Integration": "Интеграция",
"Interface": "Интерфейс",
"Invalid file format.": "Неверный формат файла.",
"Invalid JSON schema": "",
"Invalid JSON schema": "Недопустимая схема JSON",
"Invalid Tag": "Недопустимый тег",
"is typing...": "печатает...",
"January": "Январь",
@ -641,7 +641,7 @@
"Knowledge Access": "Доступ к Знаниям",
"Knowledge created successfully.": "Знания созданы успешно.",
"Knowledge deleted successfully.": "Знания успешно удалены.",
"Knowledge Public Sharing": "",
"Knowledge Public Sharing": "Публичный обмен знаниями",
"Knowledge reset successfully.": "Знания успешно сброшены.",
"Knowledge updated successfully": "Знания успешно обновлены",
"Kokoro.js (Browser)": "Kokoro.js (Браузер)",
@ -655,10 +655,10 @@
"LDAP": "",
"LDAP server updated": "LDAP сервер обновлен",
"Leaderboard": "Таблица Лидеров",
"Learn more about OpenAPI tool servers.": "",
"Learn more about OpenAPI tool servers.": "Узнайте больше о серверах инструментов OpenAPI.",
"Leave empty for unlimited": "Оставьте пустым для неограниченного",
"Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "",
"Leave empty to include all models from \"{{url}}/models\" endpoint": "",
"Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Оставьте пустым, чтобы включить все модели из конечной точки \"{{url}}/api/tags\"",
"Leave empty to include all models from \"{{url}}/models\" endpoint": "Оставьте поле пустым, чтобы включить все модели из конечной точки \"{{url}}/models\"",
"Leave empty to include all models or select specific models": "Оставьте поле пустым, чтобы включить все модели или выбрать конкретные модели",
"Leave empty to use the default prompt, or enter a custom prompt": "Оставьте пустым, чтобы использовать промпт по умолчанию, или введите пользовательский промпт",
"Leave model field empty to use the default model.": "Оставьте поле model пустым, чтобы использовать модель по умолчанию.",
@ -668,8 +668,8 @@
"Llama.cpp": "",
"LLMs can make mistakes. Verify important information.": "LLMs могут допускать ошибки. Проверяйте важную информацию.",
"Loader": "Загрузчик",
"Loading Kokoro.js...": "",
"Local": "",
"Loading Kokoro.js...": "Загрузка Kokoro.js",
"Local": "Локально",
"Local Models": "Локальные модели",
"Location access not allowed": "Доступ к местоположению запрещен",
"Logit Bias": "",
@ -707,15 +707,15 @@
"Mirostat Eta": "Mirostat Eta",
"Mirostat Tau": "Mirostat Tau",
"Mistral OCR": "",
"Mistral OCR API Key required.": "",
"Mistral OCR API Key required.": "Требуется API ключ Mistral OCR.",
"Model": "Модель",
"Model '{{modelName}}' has been successfully downloaded.": "Модель '{{modelName}}' успешно загружена.",
"Model '{{modelTag}}' is already in queue for downloading.": "Модель '{{modelTag}}' уже находится в очереди на загрузку.",
"Model {{modelId}} not found": "Модель {{modelId}} не найдена",
"Model {{modelName}} is not vision capable": "Модель {{modelName}} не поддерживает зрение",
"Model {{name}} is now {{status}}": "Модель {{name}} теперь {{status}}",
"Model {{name}} is now hidden": "",
"Model {{name}} is now visible": "",
"Model {{name}} is now hidden": "Модель {{name}} теперь скрыта",
"Model {{name}} is now visible": "Модель {{name}} теперь видна",
"Model accepts image inputs": "Модель принимает изображения как входные данные",
"Model created successfully!": "Модель успешно создана!",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "Обнаружен путь к файловой системе модели. Для обновления требуется краткое имя модели, не удается продолжить.",
@ -731,7 +731,7 @@
"Models": "Модели",
"Models Access": "Доступ к Моделям",
"Models configuration saved successfully": "Конфигурация модели успешно сохранена.",
"Models Public Sharing": "",
"Models Public Sharing": "Публичный обмен моделями",
"Mojeek Search API Key": "Ключ API для поиска Mojeek",
"more": "больше",
"More": "Больше",
@ -794,7 +794,7 @@
"Open file": "Открыть файл",
"Open in full screen": "Открыть на весь экран",
"Open new chat": "Открыть новый чат",
"Open WebUI can use tools provided by any OpenAPI server.": "",
"Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI может использовать инструменты, предоставляемые любым сервером OpenAPI.",
"Open WebUI uses faster-whisper internally.": "Open WebUI использует более быстрый внутренний интерфейс whisper.",
"Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "В Open WebUI используются встраиваемые движки генерации речи SpeechT5 и CMU Arctic.",
"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Версия Open WebUI (v{{OPEN_WEBUI_VERSION}}) ниже требуемой версии (v{{REQUIRED_VERSION}})",
@ -804,7 +804,7 @@
"OpenAI API Key is required.": "Требуется ключ API OpenAI.",
"OpenAI API settings updated": "Настройки OpenAI API обновлены",
"OpenAI URL/Key required.": "Требуется URL-адрес API OpenAI или ключ API.",
"openapi.json Path": "",
"openapi.json Path": "Путь openapi.json",
"or": "или",
"Organize your users": "Организуйте своих пользователей",
"Other": "Прочее",
@ -836,8 +836,8 @@
"Please carefully review the following warnings:": "Пожалуйста, внимательно ознакомьтесь со следующими предупреждениями:",
"Please do not close the settings page while loading the model.": "Пожалуйста, не закрывайте страницу настроек во время загрузки модели.",
"Please enter a prompt": "Пожалуйста, введите подсказку",
"Please enter a valid path": "",
"Please enter a valid URL": "",
"Please enter a valid path": "Пожалуйста, введите правильный путь",
"Please enter a valid URL": "Пожалуйста, введите правильный URL",
"Please fill in all fields.": "Пожалуйста, заполните все поля.",
"Please select a model first.": "Пожалуйста, сначала выберите модель.",
"Please select a model.": "Пожалуйста, выберите модель.",
@ -849,7 +849,7 @@
"Presence Penalty": "Штраф за присутствие",
"Previous 30 days": "Предыдущие 30 дней",
"Previous 7 days": "Предыдущие 7 дней",
"Private": "",
"Private": "Частное",
"Profile Image": "Изображение профиля",
"Prompt": "Промпт",
"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "Промпт (например, Расскажи мне интересный факт о Римской империи)",
@ -860,8 +860,8 @@
"Prompt updated successfully": "Промпт успешно обновлён",
"Prompts": "Промпты",
"Prompts Access": "Доступ к промптам",
"Prompts Public Sharing": "",
"Public": "",
"Prompts Public Sharing": "Публичный обмен промптами",
"Public": "Публичное",
"Pull \"{{searchValue}}\" from Ollama.com": "Загрузить \"{{searchValue}}\" с Ollama.com",
"Pull a model from Ollama.com": "Загрузить модель с Ollama.com",
"Query Generation Prompt": "Запрос на генерацию промпта",
@ -878,6 +878,8 @@
"References from": "Отсылки к",
"Refused when it shouldn't have": "Отказано в доступе, когда это не должно было произойти",
"Regenerate": "Перегенерировать",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Примечания к выпуску",
"Relevance": "Актуальность",
"Remove": "Удалить",
@ -993,11 +995,11 @@
"Share": "Поделиться",
"Share Chat": "Поделиться чатом",
"Share to Open WebUI Community": "Поделиться с сообществом OpenWebUI",
"Sharing Permissions": "",
"Sharing Permissions": "Разрешения на общий доступ",
"Show": "Показать",
"Show \"What's New\" modal on login": "Показывать окно «Что нового» при входе в систему",
"Show Admin Details in Account Pending Overlay": "Показывать данные администратора в оверлее ожидающей учетной записи",
"Show Model": "",
"Show Model": "Показать модель",
"Show shortcuts": "Показать горячие клавиши",
"Show your support!": "Поддержите нас!",
"Showcased creativity": "Продемонстрирован творческий подход",
@ -1024,11 +1026,11 @@
"Suggested": "Предложено",
"Support": "Поддержать",
"Support this plugin:": "Поддержите этот плагин",
"Sync directory": "",
"Sync directory": "Каталог синхронизации",
"System": "Система",
"System Instructions": "Системные инструкции",
"System Prompt": "Системный промпт",
"Tags": "",
"Tags": "Теги",
"Tags Generation": "Генерация тегов",
"Tags Generation Prompt": "Промпт для генерации тегов",
"Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting.": "Выборка без хвостов используется для уменьшения влияния менее вероятных токенов на выходные данные. Более высокое значение (например, 2.0) еще больше уменьшит влияние, в то время как значение 1.0 отключает эту настройку.",
@ -1059,8 +1061,8 @@
"Theme": "Тема",
"Thinking...": "Думаю...",
"This action cannot be undone. Do you wish to continue?": "Это действие нельзя отменить. Вы хотите продолжить?",
"This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "",
"This chat wont appear in history and your messages will not be saved.": "",
"This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Этот канал был создан {{createdAt}}. Это самое начало канала {{channelName}}.",
"This chat wont appear in history and your messages will not be saved.": "Этот чат не появится в истории, и ваши сообщения не будут сохранены.",
"This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "Это обеспечивает сохранение ваших ценных разговоров в безопасной базе данных на вашем сервере. Спасибо!",
"This is an experimental feature, it may not function as expected and is subject to change at any time.": "Это экспериментальная функция, она может работать не так, как ожидалось, и может быть изменена в любое время.",
"This option controls how many tokens are preserved when refreshing the context. For example, if set to 2, the last 2 tokens of the conversation context will be retained. Preserving context can help maintain the continuity of a conversation, but it may reduce the ability to respond to new topics.": "Этот параметр определяет, сколько токенов сохраняется при обновлении контекста. Например, если задано значение 2, будут сохранены последние 2 токена контекста беседы. Сохранение контекста может помочь сохранить непрерывность беседы, но может уменьшить возможность отвечать на новые темы.",
@ -1074,7 +1076,7 @@
"This will reset the knowledge base and sync all files. Do you wish to continue?": "Это сбросит базу знаний и синхронизирует все файлы. Хотите продолжить?",
"Thorough explanation": "Подробное объяснение",
"Thought for {{DURATION}}": "Рассуждаю {{DURATION}}",
"Thought for {{DURATION}} seconds": "Рассуждаю {{DURATION}} секунд(ы)",
"Thought for {{DURATION}} seconds": "Рассуждал {{DURATION}} секунд",
"Tika": "Tika",
"Tika Server URL required.": "Требуется URL-адрес сервера Tika.",
"Tiktoken": "",
@ -1108,7 +1110,7 @@
"Tool ID": "ID Инструмента",
"Tool imported successfully": "Инструмент успешно импортирован",
"Tool Name": "Имя Инструмента",
"Tool Servers": "",
"Tool Servers": "Сервер Инструмента",
"Tool updated successfully": "Инструмент успешно обновлен",
"Tools": "Инструменты",
"Tools Access": "Доступ к инструментам",
@ -1116,7 +1118,7 @@
"Tools Function Calling Prompt": "Промпт на вызов функции Инструменты",
"Tools have a function calling system that allows arbitrary code execution": "Инструменты имеют систему вызова функций, которая позволяет выполнять произвольный код",
"Tools have a function calling system that allows arbitrary code execution.": "Инструменты имеют систему вызова функций, которая позволяет выполнять произвольный код.",
"Tools Public Sharing": "",
"Tools Public Sharing": "Публичный обмен инструментами",
"Top K": "Top K",
"Top K Reranker": "",
"Top P": "Top P",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Использовать Gravatar",
"Use groups to group your users and assign permissions.": "Используйте группы, чтобы группировать пользователей и назначать разрешения.",
"Use Initials": "Использовать инициалы",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "пользователь",
@ -1174,11 +1178,11 @@
"Valves updated successfully": "Вентили успешно обновлены",
"variable": "переменная",
"variable to have them replaced with clipboard content.": "переменную, чтобы заменить их содержимым буфера обмена.",
"Verify Connection": "",
"Verify Connection": "Проверить подключение",
"Version": "Версия",
"Version {{selectedVersion}} of {{totalVersions}}": "Версия {{selectedVersion}} из {{totalVersions}}",
"View Replies": "С ответами",
"View Result from **{{NAME}}**": "",
"View Result from **{{NAME}}**": "Просмотр результата от **{{NAME}}**",
"Visibility": "Видимость",
"Voice": "Голос",
"Voice Input": "Ввод голоса",
@ -1196,7 +1200,7 @@
"Webhook URL": "URL-адрес веб-хука",
"WebUI Settings": "Настройки WebUI",
"WebUI URL": "",
"WebUI will make requests to \"{{url}}\"": "",
"WebUI will make requests to \"{{url}}\"": "WebUI будет отправлять запросы к \"{{url}}\"",
"WebUI will make requests to \"{{url}}/api/chat\"": "WebUI будет отправлять запросы к \"{{url}}/api/chat\"",
"WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI будет отправлять запросы к \"{{url}}/chat/completions\"",
"What are you trying to achieve?": "Чего вы пытаетесь достичь?",

View file

@ -878,6 +878,8 @@
"References from": "Referencie z",
"Refused when it shouldn't have": "Odmietnuté, keď nemalo byť.",
"Regenerate": "Regenerovať",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Záznamy o vydaní",
"Relevance": "Relevancia",
"Remove": "Odstrániť",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Použiť Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "Použiť iniciály",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "používateľ",

View file

@ -878,6 +878,8 @@
"References from": "Референце од",
"Refused when it shouldn't have": "Одбијено када није требало",
"Regenerate": "Поново створи",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Напомене о издању",
"Relevance": "Примењивост",
"Remove": "Уклони",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Користи Граватар",
"Use groups to group your users and assign permissions.": "Користите групе да бисте разврстали ваше кориснике и доделили овлашћења.",
"Use Initials": "Користи иницијале",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "корисник",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "Avvisades när det inte borde ha gjort det",
"Regenerate": "Regenerera",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Versionsinformation",
"Relevance": "",
"Remove": "Ta bort",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Använd Gravatar",
"Use groups to group your users and assign permissions.": "Använd grupper för att gruppera dina användare och tilldela behörigheter.",
"Use Initials": "Använd initialer",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "användare",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "ปฏิเสธเมื่อไม่ควรทำ",
"Regenerate": "สร้างใหม่",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "บันทึกรุ่น",
"Relevance": "",
"Remove": "ลบ",
@ -1158,6 +1160,8 @@
"Use Gravatar": "ใช้ Gravatar",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "ใช้ตัวย่อ",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "ผู้ใช้",

View file

@ -878,6 +878,8 @@
"References from": "",
"Refused when it shouldn't have": "",
"Regenerate": "",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "",
"Relevance": "",
"Remove": "",
@ -1158,6 +1160,8 @@
"Use Gravatar": "",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "",
"use_mmap (Ollama)": "",
"user": "",

View file

@ -878,6 +878,8 @@
"References from": "Referanslar arasından",
"Refused when it shouldn't have": "Reddedilmemesi gerekirken reddedildi",
"Regenerate": "Tekrar Oluştur",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Sürüm Notları",
"Relevance": "İlgili",
"Remove": "Kaldır",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Gravatar Kullan",
"Use groups to group your users and assign permissions.": "Kullanıcılarınızı gruplamak ve izinler atamak için grupları kullanın.",
"Use Initials": "Baş Harfleri Kullan",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "kullanıcı",

View file

@ -878,6 +878,8 @@
"References from": "Посилання з",
"Refused when it shouldn't have": "Відмовив, коли не мав би",
"Regenerate": "Регенерувати",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Нотатки до випуску",
"Relevance": "Актуальність",
"Remove": "Видалити",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Змінити аватар",
"Use groups to group your users and assign permissions.": "Використовуйте групи, щоб об’єднувати користувачів і призначати дозволи.",
"Use Initials": "Використовувати ініціали",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "користувач",

View file

@ -878,6 +878,8 @@
"References from": "سے حوالہ جات",
"Refused when it shouldn't have": "جب انکار نہیں ہونا چاہیے تھا، انکار کر دیا",
"Regenerate": "دوبارہ تخلیق کریں",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "ریلیز نوٹس",
"Relevance": "موزونیت",
"Remove": "ہٹا دیں",
@ -1158,6 +1160,8 @@
"Use Gravatar": "گراویٹر استعمال کریں",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "ابتدائیات استعمال کریں",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "استعمال کریں_mlock (Ollama)",
"use_mmap (Ollama)": "استعمال_mmap (Ollama)",
"user": "صارف",

View file

@ -878,6 +878,8 @@
"References from": "Tham khảo từ",
"Refused when it shouldn't have": "Từ chối trả lời mà nhẽ không nên làm vậy",
"Regenerate": "Tạo sinh lại câu trả lời",
"Reindex": "",
"Reindex Knowledge Base Vectors": "",
"Release Notes": "Mô tả những cập nhật mới",
"Relevance": "Mức độ liên quan",
"Remove": "Xóa",
@ -1158,6 +1160,8 @@
"Use Gravatar": "Sử dụng Gravatar",
"Use groups to group your users and assign permissions.": "Sử dụng nhóm để nhóm người dùng của bạn và gán quyền.",
"Use Initials": "Sử dụng tên viết tắt",
"Use no proxy to fetch page contents.": "",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "",
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "Người sử dụng",

View file

@ -111,11 +111,11 @@
"Auth": "授权",
"Authenticate": "认证",
"Authentication": "身份验证",
"Auto": "",
"Auto": "自动",
"Auto-Copy Response to Clipboard": "自动复制回复到剪贴板",
"Auto-playback response": "自动念出回复内容",
"Autocomplete Generation": "输入框内容猜测补全",
"Autocomplete Generation Input Max Length": "输入框内容猜测补全输入最大长度",
"Autocomplete Generation": "输入框内容自动补全",
"Autocomplete Generation Input Max Length": "输入框内容自动补全输入最大长度",
"Automatic1111": "Automatic1111",
"AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api 鉴权字符串",
"AUTOMATIC1111 Base URL": "AUTOMATIC1111 基础地址",
@ -154,7 +154,7 @@
"Channel Name": "频道名称",
"Channels": "频道",
"Character": "字符",
"Character limit for autocomplete generation input": "输入框内容猜测补全输入的字符限制",
"Character limit for autocomplete generation input": "输入框内容自动补全输入的字符限制",
"Chart new frontiers": "开拓新领域",
"Chat": "对话",
"Chat Background Image": "对话背景图片",
@ -375,7 +375,7 @@
"Embedding Model Engine": "语义向量模型引擎",
"Embedding model set to \"{{embedding_model}}\"": "语义向量模型设置为 \"{{embedding_model}}\"",
"Enable API Key": "启用 API 密钥",
"Enable autocomplete generation for chat messages": "启用聊天消息的输入框内容猜测补全",
"Enable autocomplete generation for chat messages": "启用聊天消息的输入框内容自动补全",
"Enable Code Execution": "启用代码执行",
"Enable Code Interpreter": "启用代码解释器",
"Enable Community Sharing": "启用分享至社区",
@ -424,6 +424,8 @@
"Enter Mojeek Search API Key": "输入 Mojeek Search API 密钥",
"Enter Number of Steps (e.g. 50)": "输入步骤数 (Steps) (例如50)",
"Enter Perplexity API Key": "输入 Perplexity API 密钥",
"Enter Sougou Search API sID": "输入搜狗搜索 API 的 Secret ID",
"Enter Sougou Search API SK": "输入搜狗搜索 API 的 Secret Key",
"Enter proxy URL (e.g. https://user:password@host:port)": "输入代理 URL (例如https://用户名:密码@主机名:端口)",
"Enter reasoning effort": "设置推理努力",
"Enter Sampler (e.g. Euler a)": "输入 Sampler (例如Euler a)",
@ -655,7 +657,7 @@
"LDAP": "LDAP",
"LDAP server updated": "LDAP 服务器已更新",
"Leaderboard": "排行榜",
"Learn more about OpenAPI tool servers.": "",
"Learn more about OpenAPI tool servers.": "进一步了解 OpenAPI 工具服务器。",
"Leave empty for unlimited": "留空表示无限制",
"Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "留空以包含来自 \"{{url}}/api/tags\" 端点的所有模型",
"Leave empty to include all models from \"{{url}}/models\" endpoint": "留空以包含来自 \"{{url}}/models\" 端点的所有模型",
@ -771,7 +773,7 @@
"Notifications": "桌面通知",
"November": "十一月",
"num_gpu (Ollama)": "num_gpu (Ollama)",
"num_thread (Ollama)": "num_threadOllama",
"num_thread (Ollama)": "num_thread (Ollama)",
"OAuth ID": "OAuth ID",
"October": "十月",
"Off": "关闭",
@ -794,7 +796,7 @@
"Open file": "打开文件",
"Open in full screen": "全屏打开",
"Open new chat": "打开新对话",
"Open WebUI can use tools provided by any OpenAPI server.": "",
"Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI 可使用任何 OpenAPI 服务器提供的工具。",
"Open WebUI uses faster-whisper internally.": "Open WebUI 使用内置 faster-whisper。",
"Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI 使用 SpeechT5 和 CMU Arctic speaker embedding。",
"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "当前 Open WebUI 版本 (v{{OPEN_WEBUI_VERSION}}) 低于所需的版本 (v{{REQUIRED_VERSION}})",
@ -822,6 +824,8 @@
"Permission denied when accessing microphone: {{error}}": "申请麦克风权限被拒绝:{{error}}",
"Permissions": "权限",
"Perplexity API Key": "Perplexity API 密钥",
"Sougou Search API sID": "搜狗搜索 API 的 Secret ID",
"Sougou Search API SK": "搜狗搜索 API 的 Secret Key",
"Personalization": "个性化",
"Pin": "置顶",
"Pinned": "已置顶",
@ -846,7 +850,7 @@
"Positive attitude": "积极的态度",
"Prefix ID": "Prefix ID",
"Prefix ID is used to avoid conflicts with other connections by adding a prefix to the model IDs - leave empty to disable": "Prefix ID 用于通过为模型 ID 添加前缀来避免与其他连接发生冲突 - 留空则禁用此功能",
"Presence Penalty": "重复惩罚Presence Penalty",
"Presence Penalty": "重复惩罚 (Presence Penalty)",
"Previous 30 days": "过去 30 天",
"Previous 7 days": "过去 7 天",
"Private": "私有",
@ -878,6 +882,8 @@
"References from": "来自",
"Refused when it shouldn't have": "无理拒绝",
"Regenerate": "重新生成",
"Reindex": "重建索引",
"Reindex Knowledge Base Vectors": "重建知识库向量",
"Release Notes": "更新日志",
"Relevance": "相关性",
"Remove": "移除",
@ -885,7 +891,7 @@
"Rename": "重命名",
"Reorder Models": "重新排序模型",
"Repeat Last N": "重复最后 N 次",
"Repeat Penalty (Ollama)": "重复惩罚Ollama",
"Repeat Penalty (Ollama)": "重复惩罚 (Ollama)",
"Reply in Thread": "在主题中回复",
"Request Mode": "请求模式",
"Reranking Model": "重排模型",
@ -1158,6 +1164,8 @@
"Use Gravatar": "使用来自 Gravatar 的头像",
"Use groups to group your users and assign permissions.": "使用权限组来组织用户并分配权限。",
"Use Initials": "使用首个字符作为头像",
"Use no proxy to fetch page contents.": "不使用代理获取页面内容。",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "使用由 http_proxy 和 https_proxy 环境变量指定的代理获取页面内容。",
"use_mlock (Ollama)": "use_mlockOllama",
"use_mmap (Ollama)": "use_mmap Ollama",
"user": "用户",

View file

@ -878,6 +878,8 @@
"References from": "引用來源",
"Refused when it shouldn't have": "不應拒絕時拒絕了",
"Regenerate": "重新產生",
"Reindex": "重新索引",
"Reindex Knowledge Base Vectors": "重新索引知識庫向量",
"Release Notes": "釋出説明",
"Relevance": "相關性",
"Remove": "移除",
@ -1158,6 +1160,8 @@
"Use Gravatar": "使用 Gravatar",
"Use groups to group your users and assign permissions.": "使用群組來組織您的使用者並分配權限。",
"Use Initials": "使用姓名縮寫",
"Use no proxy to fetch page contents.": "不使用代理擷取頁面內容。",
"Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "使用 http_proxy 和 https_proxy 環境變數指定的代理擷取頁面內容。",
"use_mlock (Ollama)": "使用 mlock (Ollama)",
"use_mmap (Ollama)": "使用 mmap (Ollama)",
"user": "使用者",

View file

@ -45,6 +45,7 @@
import AccountPending from '$lib/components/layout/Overlay/AccountPending.svelte';
import UpdateInfoToast from '$lib/components/layout/UpdateInfoToast.svelte';
import { get } from 'svelte/store';
import Spinner from '$lib/components/common/Spinner.svelte';
const i18n = getContext('i18n');
@ -254,7 +255,6 @@
<div
class=" text-gray-700 dark:text-gray-100 bg-white dark:bg-gray-900 h-screen max-h-[100dvh] overflow-auto flex flex-row justify-end"
>
{#if loaded}
{#if !['user', 'admin'].includes($user?.role)}
<AccountPending />
{:else if localDBChats.length > 0}
@ -312,7 +312,13 @@
{/if}
<Sidebar />
{#if loaded}
<slot />
{:else}
<div class="w-full flex-1 h-full flex items-center justify-center">
<Spinner />
</div>
{/if}
</div>
</div>

View file

@ -211,8 +211,9 @@
console.log('executeTool', data, toolServer);
if (toolServer) {
console.log(toolServer);
const res = await executeToolServer(
toolServer.key,
(toolServer?.auth_type ?? 'bearer') === 'bearer' ? toolServer?.key : localStorage.token,
toolServer.url,
data?.name,
data?.params,