Merge remote-tracking branch 'upstream/dev' into feat/oauth

This commit is contained in:
Jun Siang Cheah 2024-06-24 18:46:48 +08:00
commit f26d80dcae
81 changed files with 4112 additions and 1214 deletions

View file

@ -77,6 +77,7 @@ from apps.rag.search.serpstack import search_serpstack
from apps.rag.search.serply import search_serply
from apps.rag.search.duckduckgo import search_duckduckgo
from apps.rag.search.tavily import search_tavily
from apps.rag.search.jina_search import search_jina
from utils.misc import (
calculate_sha256,
@ -856,6 +857,8 @@ def search_web(engine: str, query: str) -> list[SearchResult]:
)
else:
raise Exception("No TAVILY_API_KEY found in environment variables")
elif engine == "jina":
return search_jina(query, app.state.config.RAG_WEB_SEARCH_RESULT_COUNT)
else:
raise Exception("No search engine API key found in environment variables")

View file

@ -0,0 +1,41 @@
import logging
import requests
from yarl import URL
from apps.rag.search.main import SearchResult
from config import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
def search_jina(query: str, count: int) -> list[SearchResult]:
"""
Search using Jina's Search API and return the results as a list of SearchResult objects.
Args:
query (str): The query to search for
count (int): The number of results to return
Returns:
List[SearchResult]: A list of search results
"""
jina_search_endpoint = "https://s.jina.ai/"
headers = {
"Accept": "application/json",
}
url = str(URL(jina_search_endpoint + query))
response = requests.get(url, headers=headers)
response.raise_for_status()
data = response.json()
results = []
for result in data["data"][:count]:
results.append(
SearchResult(
link=result["url"],
title=result.get("title"),
snippet=result.get("content"),
)
)
return results

View file

@ -0,0 +1,50 @@
"""Peewee migrations -- 009_add_models.py.
Some examples (model - class or model name)::
> Model = migrator.orm['table_name'] # Return model in current state by name
> Model = migrator.ModelClass # Return model in current state by name
> migrator.sql(sql) # Run custom SQL
> migrator.run(func, *args, **kwargs) # Run python function with the given args
> migrator.create_model(Model) # Create a model (could be used as decorator)
> migrator.remove_model(model, cascade=True) # Remove a model
> migrator.add_fields(model, **fields) # Add fields to a model
> migrator.change_fields(model, **fields) # Change fields
> migrator.remove_fields(model, *field_names, cascade=True)
> migrator.rename_field(model, old_field_name, new_field_name)
> migrator.rename_table(model, new_table_name)
> migrator.add_index(model, *col_names, unique=False)
> migrator.add_not_null(model, *field_names)
> migrator.add_default(model, field_name, default)
> migrator.add_constraint(model, name, sql)
> migrator.drop_index(model, *col_names)
> migrator.drop_not_null(model, *field_names)
> migrator.drop_constraints(model, *constraints)
"""
from contextlib import suppress
import peewee as pw
from peewee_migrate import Migrator
with suppress(ImportError):
import playhouse.postgres_ext as pw_pext
def migrate(migrator: Migrator, database: pw.Database, *, fake=False):
"""Write your migrations here."""
migrator.add_fields("tool", valves=pw.TextField(null=True))
migrator.add_fields("function", valves=pw.TextField(null=True))
migrator.add_fields("function", is_active=pw.BooleanField(default=False))
def rollback(migrator: Migrator, database: pw.Database, *, fake=False):
"""Write your rollback migrations here."""
migrator.remove_fields("tool", "valves")
migrator.remove_fields("function", "valves")
migrator.remove_fields("function", "is_active")

View file

@ -105,13 +105,15 @@ async def get_status():
async def get_pipe_models():
pipes = Functions.get_functions_by_type("pipe")
pipes = Functions.get_functions_by_type("pipe", active_only=True)
pipe_models = []
for pipe in pipes:
# Check if function is already loaded
if pipe.id not in app.state.FUNCTIONS:
function_module, function_type = load_function_module_by_id(pipe.id)
function_module, function_type, frontmatter = load_function_module_by_id(
pipe.id
)
app.state.FUNCTIONS[pipe.id] = function_module
else:
function_module = app.state.FUNCTIONS[pipe.id]
@ -132,7 +134,9 @@ async def get_pipe_models():
manifold_pipe_name = p["name"]
if hasattr(function_module, "name"):
manifold_pipe_name = f"{pipe.name}{manifold_pipe_name}"
manifold_pipe_name = (
f"{function_module.name}{manifold_pipe_name}"
)
pipe_models.append(
{

View file

@ -5,8 +5,11 @@ from typing import List, Union, Optional
import time
import logging
from apps.webui.internal.db import DB, JSONField
from apps.webui.models.users import Users
import json
import copy
from config import SRC_LOG_LEVELS
@ -25,6 +28,8 @@ class Function(Model):
type = TextField()
content = TextField()
meta = JSONField()
valves = JSONField()
is_active = BooleanField(default=False)
updated_at = BigIntegerField()
created_at = BigIntegerField()
@ -34,6 +39,7 @@ class Function(Model):
class FunctionMeta(BaseModel):
description: Optional[str] = None
manifest: Optional[dict] = {}
class FunctionModel(BaseModel):
@ -43,6 +49,7 @@ class FunctionModel(BaseModel):
type: str
content: str
meta: FunctionMeta
is_active: bool = False
updated_at: int # timestamp in epoch
created_at: int # timestamp in epoch
@ -58,6 +65,7 @@ class FunctionResponse(BaseModel):
type: str
name: str
meta: FunctionMeta
is_active: bool
updated_at: int # timestamp in epoch
created_at: int # timestamp in epoch
@ -69,6 +77,10 @@ class FunctionForm(BaseModel):
meta: FunctionMeta
class FunctionValves(BaseModel):
valves: Optional[dict] = None
class FunctionsTable:
def __init__(self, db):
self.db = db
@ -104,16 +116,98 @@ class FunctionsTable:
except:
return None
def get_functions(self) -> List[FunctionModel]:
return [
FunctionModel(**model_to_dict(function)) for function in Function.select()
]
def get_functions(self, active_only=False) -> List[FunctionModel]:
if active_only:
return [
FunctionModel(**model_to_dict(function))
for function in Function.select().where(Function.is_active == True)
]
else:
return [
FunctionModel(**model_to_dict(function))
for function in Function.select()
]
def get_functions_by_type(self, type: str) -> List[FunctionModel]:
return [
FunctionModel(**model_to_dict(function))
for function in Function.select().where(Function.type == type)
]
def get_functions_by_type(
self, type: str, active_only=False
) -> List[FunctionModel]:
if active_only:
return [
FunctionModel(**model_to_dict(function))
for function in Function.select().where(
Function.type == type, Function.is_active == True
)
]
else:
return [
FunctionModel(**model_to_dict(function))
for function in Function.select().where(Function.type == type)
]
def get_function_valves_by_id(self, id: str) -> Optional[dict]:
try:
function = Function.get(Function.id == id)
return function.valves if function.valves else {}
except Exception as e:
print(f"An error occurred: {e}")
return None
def update_function_valves_by_id(
self, id: str, valves: dict
) -> Optional[FunctionValves]:
try:
query = Function.update(
**{"valves": valves},
updated_at=int(time.time()),
).where(Function.id == id)
query.execute()
function = Function.get(Function.id == id)
return FunctionValves(**model_to_dict(function))
except:
return None
def get_user_valves_by_id_and_user_id(
self, id: str, user_id: str
) -> Optional[dict]:
try:
user = Users.get_user_by_id(user_id)
user_settings = user.settings.model_dump()
# Check if user has "functions" and "valves" settings
if "functions" not in user_settings:
user_settings["functions"] = {}
if "valves" not in user_settings["functions"]:
user_settings["functions"]["valves"] = {}
return user_settings["functions"]["valves"].get(id, {})
except Exception as e:
print(f"An error occurred: {e}")
return None
def update_user_valves_by_id_and_user_id(
self, id: str, user_id: str, valves: dict
) -> Optional[dict]:
try:
user = Users.get_user_by_id(user_id)
user_settings = user.settings.model_dump()
# Check if user has "functions" and "valves" settings
if "functions" not in user_settings:
user_settings["functions"] = {}
if "valves" not in user_settings["functions"]:
user_settings["functions"]["valves"] = {}
user_settings["functions"]["valves"][id] = valves
# Update the user settings in the database
query = Users.update_user_by_id(user_id, {"settings": user_settings})
query.execute()
return user_settings["functions"]["valves"][id]
except Exception as e:
print(f"An error occurred: {e}")
return None
def update_function_by_id(self, id: str, updated: dict) -> Optional[FunctionModel]:
try:
@ -128,6 +222,19 @@ class FunctionsTable:
except:
return None
def deactivate_all_functions(self) -> Optional[bool]:
try:
query = Function.update(
**{"is_active": False},
updated_at=int(time.time()),
)
query.execute()
return True
except:
return None
def delete_function_by_id(self, id: str) -> bool:
try:
query = Function.delete().where((Function.id == id))

View file

@ -5,8 +5,11 @@ from typing import List, Union, Optional
import time
import logging
from apps.webui.internal.db import DB, JSONField
from apps.webui.models.users import Users
import json
import copy
from config import SRC_LOG_LEVELS
@ -25,6 +28,7 @@ class Tool(Model):
content = TextField()
specs = JSONField()
meta = JSONField()
valves = JSONField()
updated_at = BigIntegerField()
created_at = BigIntegerField()
@ -34,6 +38,7 @@ class Tool(Model):
class ToolMeta(BaseModel):
description: Optional[str] = None
manifest: Optional[dict] = {}
class ToolModel(BaseModel):
@ -68,6 +73,10 @@ class ToolForm(BaseModel):
meta: ToolMeta
class ToolValves(BaseModel):
valves: Optional[dict] = None
class ToolsTable:
def __init__(self, db):
self.db = db
@ -106,6 +115,69 @@ class ToolsTable:
def get_tools(self) -> List[ToolModel]:
return [ToolModel(**model_to_dict(tool)) for tool in Tool.select()]
def get_tool_valves_by_id(self, id: str) -> Optional[dict]:
try:
tool = Tool.get(Tool.id == id)
return tool.valves if tool.valves else {}
except Exception as e:
print(f"An error occurred: {e}")
return None
def update_tool_valves_by_id(self, id: str, valves: dict) -> Optional[ToolValves]:
try:
query = Tool.update(
**{"valves": valves},
updated_at=int(time.time()),
).where(Tool.id == id)
query.execute()
tool = Tool.get(Tool.id == id)
return ToolValves(**model_to_dict(tool))
except:
return None
def get_user_valves_by_id_and_user_id(
self, id: str, user_id: str
) -> Optional[dict]:
try:
user = Users.get_user_by_id(user_id)
user_settings = user.settings.model_dump()
# Check if user has "tools" and "valves" settings
if "tools" not in user_settings:
user_settings["tools"] = {}
if "valves" not in user_settings["tools"]:
user_settings["tools"]["valves"] = {}
return user_settings["tools"]["valves"].get(id, {})
except Exception as e:
print(f"An error occurred: {e}")
return None
def update_user_valves_by_id_and_user_id(
self, id: str, user_id: str, valves: dict
) -> Optional[dict]:
try:
user = Users.get_user_by_id(user_id)
user_settings = user.settings.model_dump()
# Check if user has "tools" and "valves" settings
if "tools" not in user_settings:
user_settings["tools"] = {}
if "valves" not in user_settings["tools"]:
user_settings["tools"]["valves"] = {}
user_settings["tools"]["valves"][id] = valves
# Update the user settings in the database
query = Users.update_user_by_id(user_id, {"settings": user_settings})
query.execute()
return user_settings["tools"]["valves"][id]
except Exception as e:
print(f"An error occurred: {e}")
return None
def update_tool_by_id(self, id: str, updated: dict) -> Optional[ToolModel]:
try:
query = Tool.update(

View file

@ -194,6 +194,29 @@ async def get_file_content_by_id(id: str, user=Depends(get_verified_user)):
)
@router.get("/{id}/content/{file_name}", response_model=Optional[FileModel])
async def get_file_content_by_id(id: str, user=Depends(get_verified_user)):
file = Files.get_file_by_id(id)
if file:
file_path = Path(file.meta["path"])
# Check if the file already exists in the cache
if file_path.is_file():
print(f"file_path: {file_path}")
return FileResponse(file_path)
else:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=ERROR_MESSAGES.NOT_FOUND,
)
else:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=ERROR_MESSAGES.NOT_FOUND,
)
############################
# Delete File By Id
############################

View file

@ -69,7 +69,10 @@ async def create_new_function(
with open(function_path, "w") as function_file:
function_file.write(form_data.content)
function_module, function_type = load_function_module_by_id(form_data.id)
function_module, function_type, frontmatter = load_function_module_by_id(
form_data.id
)
form_data.meta.manifest = frontmatter
FUNCTIONS = request.app.state.FUNCTIONS
FUNCTIONS[form_data.id] = function_module
@ -117,13 +120,40 @@ async def get_function_by_id(id: str, user=Depends(get_admin_user)):
)
############################
# ToggleFunctionById
############################
@router.post("/id/{id}/toggle", response_model=Optional[FunctionModel])
async def toggle_function_by_id(id: str, user=Depends(get_admin_user)):
function = Functions.get_function_by_id(id)
if function:
function = Functions.update_function_by_id(
id, {"is_active": not function.is_active}
)
if function:
return function
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT("Error updating function"),
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
############################
# UpdateFunctionById
############################
@router.post("/id/{id}/update", response_model=Optional[FunctionModel])
async def update_toolkit_by_id(
async def update_function_by_id(
request: Request, id: str, form_data: FunctionForm, user=Depends(get_admin_user)
):
function_path = os.path.join(FUNCTIONS_DIR, f"{id}.py")
@ -132,7 +162,8 @@ async def update_toolkit_by_id(
with open(function_path, "w") as function_file:
function_file.write(form_data.content)
function_module, function_type = load_function_module_by_id(id)
function_module, function_type, frontmatter = load_function_module_by_id(id)
form_data.meta.manifest = frontmatter
FUNCTIONS = request.app.state.FUNCTIONS
FUNCTIONS[id] = function_module
@ -178,3 +209,188 @@ async def delete_function_by_id(
os.remove(function_path)
return result
############################
# GetFunctionValves
############################
@router.get("/id/{id}/valves", response_model=Optional[dict])
async def get_function_valves_by_id(id: str, user=Depends(get_admin_user)):
function = Functions.get_function_by_id(id)
if function:
try:
valves = Functions.get_function_valves_by_id(id)
return valves
except Exception as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
############################
# GetFunctionValvesSpec
############################
@router.get("/id/{id}/valves/spec", response_model=Optional[dict])
async def get_function_valves_spec_by_id(
request: Request, id: str, user=Depends(get_admin_user)
):
function = Functions.get_function_by_id(id)
if function:
if id in request.app.state.FUNCTIONS:
function_module = request.app.state.FUNCTIONS[id]
else:
function_module, function_type, frontmatter = load_function_module_by_id(id)
request.app.state.FUNCTIONS[id] = function_module
if hasattr(function_module, "Valves"):
Valves = function_module.Valves
return Valves.schema()
return None
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
############################
# UpdateFunctionValves
############################
@router.post("/id/{id}/valves/update", response_model=Optional[dict])
async def update_function_valves_by_id(
request: Request, id: str, form_data: dict, user=Depends(get_admin_user)
):
function = Functions.get_function_by_id(id)
if function:
if id in request.app.state.FUNCTIONS:
function_module = request.app.state.FUNCTIONS[id]
else:
function_module, function_type, frontmatter = load_function_module_by_id(id)
request.app.state.FUNCTIONS[id] = function_module
if hasattr(function_module, "Valves"):
Valves = function_module.Valves
try:
form_data = {k: v for k, v in form_data.items() if v is not None}
valves = Valves(**form_data)
Functions.update_function_valves_by_id(id, valves.model_dump())
return valves.model_dump()
except Exception as e:
print(e)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
############################
# FunctionUserValves
############################
@router.get("/id/{id}/valves/user", response_model=Optional[dict])
async def get_function_user_valves_by_id(id: str, user=Depends(get_verified_user)):
function = Functions.get_function_by_id(id)
if function:
try:
user_valves = Functions.get_user_valves_by_id_and_user_id(id, user.id)
return user_valves
except Exception as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
@router.get("/id/{id}/valves/user/spec", response_model=Optional[dict])
async def get_function_user_valves_spec_by_id(
request: Request, id: str, user=Depends(get_verified_user)
):
function = Functions.get_function_by_id(id)
if function:
if id in request.app.state.FUNCTIONS:
function_module = request.app.state.FUNCTIONS[id]
else:
function_module, function_type, frontmatter = load_function_module_by_id(id)
request.app.state.FUNCTIONS[id] = function_module
if hasattr(function_module, "UserValves"):
UserValves = function_module.UserValves
return UserValves.schema()
return None
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
@router.post("/id/{id}/valves/user/update", response_model=Optional[dict])
async def update_function_user_valves_by_id(
request: Request, id: str, form_data: dict, user=Depends(get_verified_user)
):
function = Functions.get_function_by_id(id)
if function:
if id in request.app.state.FUNCTIONS:
function_module = request.app.state.FUNCTIONS[id]
else:
function_module, function_type, frontmatter = load_function_module_by_id(id)
request.app.state.FUNCTIONS[id] = function_module
if hasattr(function_module, "UserValves"):
UserValves = function_module.UserValves
try:
form_data = {k: v for k, v in form_data.items() if v is not None}
user_valves = UserValves(**form_data)
Functions.update_user_valves_by_id_and_user_id(
id, user.id, user_valves.model_dump()
)
return user_valves.model_dump()
except Exception as e:
print(e)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)

View file

@ -6,10 +6,12 @@ from fastapi import APIRouter
from pydantic import BaseModel
import json
from apps.webui.models.users import Users
from apps.webui.models.tools import Tools, ToolForm, ToolModel, ToolResponse
from apps.webui.utils import load_toolkit_module_by_id
from utils.utils import get_current_user, get_admin_user
from utils.utils import get_admin_user, get_verified_user
from utils.tools import get_tools_specs
from constants import ERROR_MESSAGES
@ -32,7 +34,7 @@ router = APIRouter()
@router.get("/", response_model=List[ToolResponse])
async def get_toolkits(user=Depends(get_current_user)):
async def get_toolkits(user=Depends(get_verified_user)):
toolkits = [toolkit for toolkit in Tools.get_tools()]
return toolkits
@ -72,7 +74,8 @@ async def create_new_toolkit(
with open(toolkit_path, "w") as tool_file:
tool_file.write(form_data.content)
toolkit_module = load_toolkit_module_by_id(form_data.id)
toolkit_module, frontmatter = load_toolkit_module_by_id(form_data.id)
form_data.meta.manifest = frontmatter
TOOLS = request.app.state.TOOLS
TOOLS[form_data.id] = toolkit_module
@ -136,7 +139,8 @@ async def update_toolkit_by_id(
with open(toolkit_path, "w") as tool_file:
tool_file.write(form_data.content)
toolkit_module = load_toolkit_module_by_id(id)
toolkit_module, frontmatter = load_toolkit_module_by_id(id)
form_data.meta.manifest = frontmatter
TOOLS = request.app.state.TOOLS
TOOLS[id] = toolkit_module
@ -185,3 +189,187 @@ async def delete_toolkit_by_id(request: Request, id: str, user=Depends(get_admin
os.remove(toolkit_path)
return result
############################
# GetToolValves
############################
@router.get("/id/{id}/valves", response_model=Optional[dict])
async def get_toolkit_valves_by_id(id: str, user=Depends(get_admin_user)):
toolkit = Tools.get_tool_by_id(id)
if toolkit:
try:
valves = Tools.get_tool_valves_by_id(id)
return valves
except Exception as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
############################
# GetToolValvesSpec
############################
@router.get("/id/{id}/valves/spec", response_model=Optional[dict])
async def get_toolkit_valves_spec_by_id(
request: Request, id: str, user=Depends(get_admin_user)
):
toolkit = Tools.get_tool_by_id(id)
if toolkit:
if id in request.app.state.TOOLS:
toolkit_module = request.app.state.TOOLS[id]
else:
toolkit_module, frontmatter = load_toolkit_module_by_id(id)
request.app.state.TOOLS[id] = toolkit_module
if hasattr(toolkit_module, "Valves"):
Valves = toolkit_module.Valves
return Valves.schema()
return None
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
############################
# UpdateToolValves
############################
@router.post("/id/{id}/valves/update", response_model=Optional[dict])
async def update_toolkit_valves_by_id(
request: Request, id: str, form_data: dict, user=Depends(get_admin_user)
):
toolkit = Tools.get_tool_by_id(id)
if toolkit:
if id in request.app.state.TOOLS:
toolkit_module = request.app.state.TOOLS[id]
else:
toolkit_module, frontmatter = load_toolkit_module_by_id(id)
request.app.state.TOOLS[id] = toolkit_module
if hasattr(toolkit_module, "Valves"):
Valves = toolkit_module.Valves
try:
form_data = {k: v for k, v in form_data.items() if v is not None}
valves = Valves(**form_data)
Tools.update_tool_valves_by_id(id, valves.model_dump())
return valves.model_dump()
except Exception as e:
print(e)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
############################
# ToolUserValves
############################
@router.get("/id/{id}/valves/user", response_model=Optional[dict])
async def get_toolkit_user_valves_by_id(id: str, user=Depends(get_verified_user)):
toolkit = Tools.get_tool_by_id(id)
if toolkit:
try:
user_valves = Tools.get_user_valves_by_id_and_user_id(id, user.id)
return user_valves
except Exception as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
@router.get("/id/{id}/valves/user/spec", response_model=Optional[dict])
async def get_toolkit_user_valves_spec_by_id(
request: Request, id: str, user=Depends(get_verified_user)
):
toolkit = Tools.get_tool_by_id(id)
if toolkit:
if id in request.app.state.TOOLS:
toolkit_module = request.app.state.TOOLS[id]
else:
toolkit_module, frontmatter = load_toolkit_module_by_id(id)
request.app.state.TOOLS[id] = toolkit_module
if hasattr(toolkit_module, "UserValves"):
UserValves = toolkit_module.UserValves
return UserValves.schema()
return None
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
@router.post("/id/{id}/valves/user/update", response_model=Optional[dict])
async def update_toolkit_user_valves_by_id(
request: Request, id: str, form_data: dict, user=Depends(get_verified_user)
):
toolkit = Tools.get_tool_by_id(id)
if toolkit:
if id in request.app.state.TOOLS:
toolkit_module = request.app.state.TOOLS[id]
else:
toolkit_module, frontmatter = load_toolkit_module_by_id(id)
request.app.state.TOOLS[id] = toolkit_module
if hasattr(toolkit_module, "UserValves"):
UserValves = toolkit_module.UserValves
try:
form_data = {k: v for k, v in form_data.items() if v is not None}
user_valves = UserValves(**form_data)
Tools.update_user_valves_by_id_and_user_id(
id, user.id, user_valves.model_dump()
)
return user_valves.model_dump()
except Exception as e:
print(e)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)

View file

@ -1,19 +1,56 @@
from importlib import util
import os
import re
from config import TOOLS_DIR, FUNCTIONS_DIR
def extract_frontmatter(file_path):
"""
Extract frontmatter as a dictionary from the specified file path.
"""
frontmatter = {}
frontmatter_started = False
frontmatter_ended = False
frontmatter_pattern = re.compile(r"^\s*([a-z_]+):\s*(.*)\s*$", re.IGNORECASE)
try:
with open(file_path, "r", encoding="utf-8") as file:
for line in file:
if '"""' in line:
if not frontmatter_started:
frontmatter_started = True
continue # skip the line with the opening triple quotes
else:
frontmatter_ended = True
break
if frontmatter_started and not frontmatter_ended:
match = frontmatter_pattern.match(line)
if match:
key, value = match.groups()
frontmatter[key.strip()] = value.strip()
except FileNotFoundError:
print(f"Error: The file {file_path} does not exist.")
return {}
except Exception as e:
print(f"An error occurred: {e}")
return {}
return frontmatter
def load_toolkit_module_by_id(toolkit_id):
toolkit_path = os.path.join(TOOLS_DIR, f"{toolkit_id}.py")
spec = util.spec_from_file_location(toolkit_id, toolkit_path)
module = util.module_from_spec(spec)
frontmatter = extract_frontmatter(toolkit_path)
try:
spec.loader.exec_module(module)
print(f"Loaded module: {module.__name__}")
if hasattr(module, "Tools"):
return module.Tools()
return module.Tools(), frontmatter
else:
raise Exception("No Tools class found")
except Exception as e:
@ -28,14 +65,15 @@ def load_function_module_by_id(function_id):
spec = util.spec_from_file_location(function_id, function_path)
module = util.module_from_spec(spec)
frontmatter = extract_frontmatter(function_path)
try:
spec.loader.exec_module(module)
print(f"Loaded module: {module.__name__}")
if hasattr(module, "Pipe"):
return module.Pipe(), "pipe"
return module.Pipe(), "pipe", frontmatter
elif hasattr(module, "Filter"):
return module.Filter(), "filter"
return module.Filter(), "filter", frontmatter
else:
raise Exception("No Function class found")
except Exception as e:

View file

@ -167,6 +167,12 @@ for version in soup.find_all("h2"):
CHANGELOG = changelog_json
####################################
# SAFE_MODE
####################################
SAFE_MODE = os.environ.get("SAFE_MODE", "false").lower() == "true"
####################################
# WEBUI_BUILD_HASH
####################################

View file

@ -62,9 +62,7 @@ from apps.webui.models.functions import Functions
from apps.webui.models.users import Users
from apps.webui.utils import load_toolkit_module_by_id, load_function_module_by_id
from apps.webui.utils import load_toolkit_module_by_id
from utils.misc import parse_duration
from utils.utils import (
get_admin_user,
get_verified_user,
@ -82,6 +80,7 @@ from utils.misc import (
get_last_user_message,
add_or_update_system_message,
stream_message_template,
parse_duration,
)
from apps.rag.utils import get_rag_context, rag_template
@ -113,6 +112,7 @@ from config import (
SEARCH_QUERY_GENERATION_PROMPT_TEMPLATE,
SEARCH_QUERY_PROMPT_LENGTH_THRESHOLD,
TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE,
SAFE_MODE,
OAUTH_PROVIDERS,
ENABLE_OAUTH_SIGNUP,
OAUTH_MERGE_ACCOUNTS_BY_EMAIL,
@ -124,6 +124,11 @@ from config import (
from constants import ERROR_MESSAGES, WEBHOOK_MESSAGES
from utils.webhook import post_webhook
if SAFE_MODE:
print("SAFE MODE ENABLED")
Functions.deactivate_all_functions()
logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL)
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["MAIN"])
@ -271,7 +276,7 @@ async def get_function_call_response(
if tool_id in webui_app.state.TOOLS:
toolkit_module = webui_app.state.TOOLS[tool_id]
else:
toolkit_module = load_toolkit_module_by_id(tool_id)
toolkit_module, frontmatter = load_toolkit_module_by_id(tool_id)
webui_app.state.TOOLS[tool_id] = toolkit_module
file_handler = False
@ -280,6 +285,14 @@ async def get_function_call_response(
file_handler = True
print("file_handler: ", file_handler)
if hasattr(toolkit_module, "valves") and hasattr(
toolkit_module, "Valves"
):
valves = Tools.get_tool_valves_by_id(tool_id)
toolkit_module.valves = toolkit_module.Valves(
**(valves if valves else {})
)
function = getattr(toolkit_module, result["name"])
function_result = None
try:
@ -289,16 +302,24 @@ async def get_function_call_response(
if "__user__" in sig.parameters:
# Call the function with the '__user__' parameter included
params = {
**params,
"__user__": {
"id": user.id,
"email": user.email,
"name": user.name,
"role": user.role,
},
__user__ = {
"id": user.id,
"email": user.email,
"name": user.name,
"role": user.role,
}
try:
if hasattr(toolkit_module, "UserValves"):
__user__["valves"] = toolkit_module.UserValves(
**Tools.get_user_valves_by_id_and_user_id(
tool_id, user.id
)
)
except Exception as e:
print(e)
params = {**params, "__user__": __user__}
if "__messages__" in sig.parameters:
# Call the function with the '__messages__' parameter included
params = {
@ -386,54 +407,94 @@ class ChatCompletionMiddleware(BaseHTTPMiddleware):
)
model = app.state.MODELS[model_id]
def get_priority(function_id):
function = Functions.get_function_by_id(function_id)
if function is not None and hasattr(function, "valves"):
return (function.valves if function.valves else {}).get(
"priority", 0
)
return 0
filter_ids = [
function.id
for function in Functions.get_functions_by_type(
"filter", active_only=True
)
]
# Check if the model has any filters
if "info" in model and "meta" in model["info"]:
for filter_id in model["info"]["meta"].get("filterIds", []):
filter = Functions.get_function_by_id(filter_id)
if filter:
if filter_id in webui_app.state.FUNCTIONS:
function_module = webui_app.state.FUNCTIONS[filter_id]
else:
function_module, function_type = load_function_module_by_id(
filter_id
)
webui_app.state.FUNCTIONS[filter_id] = function_module
filter_ids.extend(model["info"]["meta"].get("filterIds", []))
filter_ids = list(set(filter_ids))
# Check if the function has a file_handler variable
if hasattr(function_module, "file_handler"):
skip_files = function_module.file_handler
filter_ids.sort(key=get_priority)
for filter_id in filter_ids:
filter = Functions.get_function_by_id(filter_id)
if filter:
if filter_id in webui_app.state.FUNCTIONS:
function_module = webui_app.state.FUNCTIONS[filter_id]
else:
function_module, function_type, frontmatter = (
load_function_module_by_id(filter_id)
)
webui_app.state.FUNCTIONS[filter_id] = function_module
try:
if hasattr(function_module, "inlet"):
inlet = function_module.inlet
# Check if the function has a file_handler variable
if hasattr(function_module, "file_handler"):
skip_files = function_module.file_handler
if inspect.iscoroutinefunction(inlet):
data = await inlet(
data,
{
"id": user.id,
"email": user.email,
"name": user.name,
"role": user.role,
},
)
else:
data = inlet(
data,
{
"id": user.id,
"email": user.email,
"name": user.name,
"role": user.role,
},
)
if hasattr(function_module, "valves") and hasattr(
function_module, "Valves"
):
valves = Functions.get_function_valves_by_id(filter_id)
function_module.valves = function_module.Valves(
**(valves if valves else {})
)
except Exception as e:
print(f"Error: {e}")
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"detail": str(e)},
)
try:
if hasattr(function_module, "inlet"):
inlet = function_module.inlet
# Get the signature of the function
sig = inspect.signature(inlet)
params = {"body": data}
if "__user__" in sig.parameters:
__user__ = {
"id": user.id,
"email": user.email,
"name": user.name,
"role": user.role,
}
try:
if hasattr(function_module, "UserValves"):
__user__["valves"] = function_module.UserValves(
**Functions.get_user_valves_by_id_and_user_id(
filter_id, user.id
)
)
except Exception as e:
print(e)
params = {**params, "__user__": __user__}
if "__id__" in sig.parameters:
params = {
**params,
"__id__": filter_id,
}
if inspect.iscoroutinefunction(inlet):
data = await inlet(**params)
else:
data = inlet(**params)
except Exception as e:
print(f"Error: {e}")
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"detail": str(e)},
)
# Set the task model
task_model_id = data["model"]
@ -857,12 +918,6 @@ async def generate_chat_completions(form_data: dict, user=Depends(get_verified_u
pipe = model.get("pipe")
if pipe:
form_data["user"] = {
"id": user.id,
"email": user.email,
"name": user.name,
"role": user.role,
}
async def job():
pipe_id = form_data["model"]
@ -870,14 +925,62 @@ async def generate_chat_completions(form_data: dict, user=Depends(get_verified_u
pipe_id, sub_pipe_id = pipe_id.split(".", 1)
print(pipe_id)
pipe = webui_app.state.FUNCTIONS[pipe_id].pipe
# Check if function is already loaded
if pipe_id not in webui_app.state.FUNCTIONS:
function_module, function_type, frontmatter = (
load_function_module_by_id(pipe_id)
)
webui_app.state.FUNCTIONS[pipe_id] = function_module
else:
function_module = webui_app.state.FUNCTIONS[pipe_id]
if hasattr(function_module, "valves") and hasattr(
function_module, "Valves"
):
valves = Functions.get_function_valves_by_id(pipe_id)
function_module.valves = function_module.Valves(
**(valves if valves else {})
)
pipe = function_module.pipe
# Get the signature of the function
sig = inspect.signature(pipe)
params = {"body": form_data}
if "__user__" in sig.parameters:
__user__ = {
"id": user.id,
"email": user.email,
"name": user.name,
"role": user.role,
}
try:
if hasattr(function_module, "UserValves"):
__user__["valves"] = function_module.UserValves(
**Functions.get_user_valves_by_id_and_user_id(
pipe_id, user.id
)
)
except Exception as e:
print(e)
params = {**params, "__user__": __user__}
if form_data["stream"]:
async def stream_content():
if inspect.iscoroutinefunction(pipe):
res = await pipe(body=form_data)
else:
res = pipe(body=form_data)
try:
if inspect.iscoroutinefunction(pipe):
res = await pipe(**params)
else:
res = pipe(**params)
except Exception as e:
print(f"Error: {e}")
yield f"data: {json.dumps({'error': {'detail':str(e)}})}\n\n"
return
if isinstance(res, str):
message = stream_message_template(form_data["model"], res)
@ -922,10 +1025,20 @@ async def generate_chat_completions(form_data: dict, user=Depends(get_verified_u
stream_content(), media_type="text/event-stream"
)
else:
try:
if inspect.iscoroutinefunction(pipe):
res = await pipe(**params)
else:
res = pipe(**params)
except Exception as e:
print(f"Error: {e}")
return {"error": {"detail": str(e)}}
if inspect.iscoroutinefunction(pipe):
res = await pipe(body=form_data)
res = await pipe(**params)
else:
res = pipe(body=form_data)
res = pipe(**params)
if isinstance(res, dict):
return res
@ -1008,7 +1121,12 @@ async def chat_completed(form_data: dict, user=Depends(get_verified_user)):
f"{url}/{filter['id']}/filter/outlet",
headers=headers,
json={
"user": {"id": user.id, "name": user.name, "role": user.role},
"user": {
"id": user.id,
"name": user.name,
"email": user.email,
"role": user.role,
},
"body": data,
},
)
@ -1033,49 +1151,88 @@ async def chat_completed(form_data: dict, user=Depends(get_verified_user)):
else:
pass
def get_priority(function_id):
function = Functions.get_function_by_id(function_id)
if function is not None and hasattr(function, "valves"):
return (function.valves if function.valves else {}).get("priority", 0)
return 0
filter_ids = [
function.id
for function in Functions.get_functions_by_type("filter", active_only=True)
]
# Check if the model has any filters
if "info" in model and "meta" in model["info"]:
for filter_id in model["info"]["meta"].get("filterIds", []):
filter = Functions.get_function_by_id(filter_id)
if filter:
if filter_id in webui_app.state.FUNCTIONS:
function_module = webui_app.state.FUNCTIONS[filter_id]
else:
function_module, function_type = load_function_module_by_id(
filter_id
)
webui_app.state.FUNCTIONS[filter_id] = function_module
filter_ids.extend(model["info"]["meta"].get("filterIds", []))
filter_ids = list(set(filter_ids))
try:
if hasattr(function_module, "outlet"):
outlet = function_module.outlet
if inspect.iscoroutinefunction(outlet):
data = await outlet(
data,
{
"id": user.id,
"email": user.email,
"name": user.name,
"role": user.role,
},
)
else:
data = outlet(
data,
{
"id": user.id,
"email": user.email,
"name": user.name,
"role": user.role,
},
)
# Sort filter_ids by priority, using the get_priority function
filter_ids.sort(key=get_priority)
except Exception as e:
print(f"Error: {e}")
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"detail": str(e)},
)
for filter_id in filter_ids:
filter = Functions.get_function_by_id(filter_id)
if filter:
if filter_id in webui_app.state.FUNCTIONS:
function_module = webui_app.state.FUNCTIONS[filter_id]
else:
function_module, function_type, frontmatter = (
load_function_module_by_id(filter_id)
)
webui_app.state.FUNCTIONS[filter_id] = function_module
if hasattr(function_module, "valves") and hasattr(
function_module, "Valves"
):
valves = Functions.get_function_valves_by_id(filter_id)
function_module.valves = function_module.Valves(
**(valves if valves else {})
)
try:
if hasattr(function_module, "outlet"):
outlet = function_module.outlet
# Get the signature of the function
sig = inspect.signature(outlet)
params = {"body": data}
if "__user__" in sig.parameters:
__user__ = {
"id": user.id,
"email": user.email,
"name": user.name,
"role": user.role,
}
try:
if hasattr(function_module, "UserValves"):
__user__["valves"] = function_module.UserValves(
**Functions.get_user_valves_by_id_and_user_id(
filter_id, user.id
)
)
except Exception as e:
print(e)
params = {**params, "__user__": __user__}
if "__id__" in sig.parameters:
params = {
**params,
"__id__": filter_id,
}
if inspect.iscoroutinefunction(outlet):
data = await outlet(**params)
else:
data = outlet(**params)
except Exception as e:
print(f"Error: {e}")
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"detail": str(e)},
)
return data
@ -1989,7 +2146,6 @@ async def get_manifest_json():
"start_url": "/",
"display": "standalone",
"background_color": "#343541",
"theme_color": "#343541",
"orientation": "portrait-primary",
"icons": [{"src": "/static/logo.png", "type": "image/png", "sizes": "500x500"}],
}

View file

@ -17,7 +17,9 @@ peewee-migrate==1.12.2
psycopg2-binary==2.9.9
PyMySQL==1.1.1
bcrypt==4.1.3
SQLAlchemy
pymongo
redis
boto3==1.34.110
argon2-cffi==23.1.0

View file

@ -20,7 +20,9 @@ def get_tools_specs(tools) -> List[dict]:
function_list = [
{"name": func, "function": getattr(tools, func)}
for func in dir(tools)
if callable(getattr(tools, func)) and not func.startswith("__")
if callable(getattr(tools, func))
and not func.startswith("__")
and not inspect.isclass(getattr(tools, func))
]
specs = []
@ -65,6 +67,7 @@ def get_tools_specs(tools) -> List[dict]:
function
).parameters.items()
if param.default is param.empty
and not (name.startswith("__") and name.endswith("__"))
],
},
}

View file

@ -32,6 +32,10 @@ math {
@apply underline;
}
iframe {
@apply rounded-lg;
}
ol > li {
counter-increment: list-number;
display: block;

View file

@ -191,3 +191,233 @@ export const deleteFunctionById = async (token: string, id: string) => {
return res;
};
export const toggleFunctionById = async (token: string, id: string) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/functions/id/${id}/toggle`, {
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();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const getFunctionValvesById = async (token: string, id: string) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/functions/id/${id}/valves`, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
}
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const getFunctionValvesSpecById = async (token: string, id: string) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/functions/id/${id}/valves/spec`, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
}
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const updateFunctionValvesById = async (token: string, id: string, valves: object) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/functions/id/${id}/valves/update`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
},
body: JSON.stringify({
...valves
})
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const getUserValvesById = async (token: string, id: string) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/functions/id/${id}/valves/user`, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
}
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const getUserValvesSpecById = async (token: string, id: string) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/functions/id/${id}/valves/user/spec`, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
}
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const updateUserValvesById = async (token: string, id: string, valves: object) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/functions/id/${id}/valves/user/update`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
},
body: JSON.stringify({
...valves
})
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};

View file

@ -191,3 +191,201 @@ export const deleteToolById = async (token: string, id: string) => {
return res;
};
export const getToolValvesById = async (token: string, id: string) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/tools/id/${id}/valves`, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
}
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const getToolValvesSpecById = async (token: string, id: string) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/tools/id/${id}/valves/spec`, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
}
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const updateToolValvesById = async (token: string, id: string, valves: object) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/tools/id/${id}/valves/update`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
},
body: JSON.stringify({
...valves
})
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const getUserValvesById = async (token: string, id: string) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/tools/id/${id}/valves/user`, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
}
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const getUserValvesSpecById = async (token: string, id: string) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/tools/id/${id}/valves/user/spec`, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
}
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const updateUserValvesById = async (token: string, id: string, valves: object) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/tools/id/${id}/valves/user/update`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
},
body: JSON.stringify({
...valves
})
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};

View file

@ -19,7 +19,8 @@
'serper',
'serply',
'duckduckgo',
'tavily'
'tavily',
'jina'
];
let youtubeLanguage = 'en';

View file

@ -1,43 +0,0 @@
<script>
import { getContext } from 'svelte';
import Modal from '../common/Modal.svelte';
import Database from './Settings/Database.svelte';
import General from './Settings/General.svelte';
import Users from './Settings/Users.svelte';
import Banners from '$lib/components/admin/Settings/Banners.svelte';
import { toast } from 'svelte-sonner';
import Pipelines from './Settings/Pipelines.svelte';
const i18n = getContext('i18n');
export let show = false;
let selectedTab = 'general';
</script>
<Modal bind:show>
<div>
<div class=" flex justify-between dark:text-gray-300 px-5 pt-4 pb-2">
<div class=" text-lg font-medium self-center">{$i18n.t('Admin Settings')}</div>
<button
class="self-center"
on:click={() => {
show = false;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-5 h-5"
>
<path
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
/>
</svg>
</button>
</div>
</div>
</Modal>

View file

@ -127,6 +127,42 @@
}
onMount(async () => {
const onMessageHandler = async (event) => {
if (event.origin === window.origin) {
// Replace with your iframe's origin
console.log('Message received from iframe:', event.data);
if (event.data.type === 'input:prompt') {
console.log(event.data.text);
const inputElement = document.getElementById('chat-textarea');
if (inputElement) {
prompt = event.data.text;
inputElement.focus();
}
}
if (event.data.type === 'action:submit') {
console.log(event.data.text);
if (prompt !== '') {
await tick();
submitPrompt(prompt);
}
}
if (event.data.type === 'input:prompt:submit') {
console.log(event.data.text);
if (prompt !== '') {
await tick();
submitPrompt(event.data.text);
}
}
}
};
window.addEventListener('message', onMessageHandler);
if (!$chatId) {
chatId.subscribe(async (value) => {
if (!value) {
@ -138,6 +174,10 @@
await goto('/');
}
}
return () => {
window.removeEventListener('message', onMessageHandler);
};
});
//////////////////////////
@ -600,10 +640,14 @@
files = model.info.meta.knowledge;
}
const lastUserMessage = messages.filter((message) => message.role === 'user').at(-1);
files = [
...files,
...(lastUserMessage?.files?.filter((item) =>
['doc', 'file', 'collection', 'web_search_results'].includes(item.type)
) ?? []),
...(responseMessage?.files?.filter((item) =>
['doc', 'file', 'collection', 'web_search_results'].includes(item.type)
) ?? [])
].filter(
// Remove duplicates
@ -844,6 +888,9 @@
...files,
...(lastUserMessage?.files?.filter((item) =>
['doc', 'file', 'collection', 'web_search_results'].includes(item.type)
) ?? []),
...(responseMessage?.files?.filter((item) =>
['doc', 'file', 'collection', 'web_search_results'].includes(item.type)
) ?? [])
].filter(
// Remove duplicates
@ -1213,6 +1260,7 @@
const getWebSearchResults = async (model: string, parentId: string, responseId: string) => {
const responseMessage = history.messages[responseId];
const userMessage = history.messages[parentId];
responseMessage.statusHistory = [
{
@ -1223,7 +1271,7 @@
];
messages = messages;
const prompt = history.messages[parentId].content;
const prompt = userMessage.content;
let searchQuery = await generateSearchQuery(localStorage.token, model, messages, prompt).catch(
(error) => {
console.log(error);

View file

@ -321,9 +321,11 @@
<div class="flex flex-col max-w-6xl px-2.5 md:px-6 w-full">
<div class="relative">
{#if autoScroll === false && messages.length > 0}
<div class=" absolute -top-12 left-0 right-0 flex justify-center z-30">
<div
class=" absolute -top-12 left-0 right-0 flex justify-center z-30 pointer-events-none"
>
<button
class=" bg-white border border-gray-100 dark:border-none dark:bg-white/20 p-1.5 rounded-full"
class=" bg-white border border-gray-100 dark:border-none dark:bg-white/20 p-1.5 rounded-full pointer-events-auto"
on:click={() => {
autoScroll = true;
scrollToBottom();

View file

@ -271,7 +271,7 @@
return;
}
if (assistantSpeaking) {
if (assistantSpeaking && !($settings?.voiceInterruption ?? false)) {
// Mute the audio if the assistant is speaking
analyser.maxDecibels = 0;
analyser.minDecibels = -1;

View file

@ -33,7 +33,7 @@
</script>
{#key mounted}
<div class="m-auto w-full max-w-6xl px-8 lg:px-24 pb-10">
<div class="m-auto w-full max-w-6xl px-8 lg:px-20 pb-10">
<div class="flex justify-start">
<div class="flex -space-x-4 mb-1" in:fade={{ duration: 200 }}>
{#each models as model, modelIdx}

View file

@ -32,6 +32,7 @@
let chatDirection: 'LTR' | 'RTL' = 'LTR';
let showEmojiInCall = false;
let voiceInterruption = false;
const toggleSplitLargeChunks = async () => {
splitLargeChunks = !splitLargeChunks;
@ -58,6 +59,11 @@
saveSettings({ showEmojiInCall: showEmojiInCall });
};
const toggleVoiceInterruption = async () => {
voiceInterruption = !voiceInterruption;
saveSettings({ voiceInterruption: voiceInterruption });
};
const toggleUserLocation = async () => {
userLocation = !userLocation;
@ -128,6 +134,7 @@
showUsername = $settings.showUsername ?? false;
showEmojiInCall = $settings.showEmojiInCall ?? false;
voiceInterruption = $settings.voiceInterruption ?? false;
chatBubble = $settings.chatBubble ?? true;
widescreenMode = $settings.widescreenMode ?? false;
@ -399,6 +406,26 @@
<div class=" my-1.5 text-sm font-medium">{$i18n.t('Voice')}</div>
<div>
<div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs">{$i18n.t('Allow Voice Interruption in Call')}</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
on:click={() => {
toggleVoiceInterruption();
}}
type="button"
>
{#if voiceInterruption === 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">{$i18n.t('Display Emoji in Call')}</div>

View file

@ -31,7 +31,7 @@
dispatch('save');
}}
>
<div class=" pr-1.5 overflow-y-scroll max-h-[25rem]">
<div class=" pr-1.5 py-1 overflow-y-scroll max-h-[25rem]">
<div>
<div class="flex items-center justify-between mb-1">
<Tooltip
@ -46,7 +46,7 @@
</div>
</Tooltip>
<div class="mt-1">
<div class="">
<Switch
bind:state={enableMemory}
on:change={async () => {

View file

@ -0,0 +1,245 @@
<script lang="ts">
import { toast } from 'svelte-sonner';
import { config, functions, models, settings, tools, user } from '$lib/stores';
import { createEventDispatcher, onMount, getContext, tick } from 'svelte';
import {
getUserValvesSpecById as getToolUserValvesSpecById,
getUserValvesById as getToolUserValvesById,
updateUserValvesById as updateToolUserValvesById
} from '$lib/apis/tools';
import {
getUserValvesSpecById as getFunctionUserValvesSpecById,
getUserValvesById as getFunctionUserValvesById,
updateUserValvesById as updateFunctionUserValvesById
} from '$lib/apis/functions';
import ManageModal from './Personalization/ManageModal.svelte';
import Tooltip from '$lib/components/common/Tooltip.svelte';
import Spinner from '$lib/components/common/Spinner.svelte';
const dispatch = createEventDispatcher();
const i18n = getContext('i18n');
export let saveSettings: Function;
let tab = 'tools';
let selectedId = '';
let loading = false;
let valvesSpec = null;
let valves = {};
const getUserValves = async () => {
loading = true;
if (tab === 'tools') {
valves = await getToolUserValvesById(localStorage.token, selectedId);
valvesSpec = await getToolUserValvesSpecById(localStorage.token, selectedId);
} else if (tab === 'functions') {
valves = await getFunctionUserValvesById(localStorage.token, selectedId);
valvesSpec = await getFunctionUserValvesSpecById(localStorage.token, selectedId);
}
if (valvesSpec) {
// Convert array to string
for (const property in valvesSpec.properties) {
if (valvesSpec.properties[property]?.type === 'array') {
valves[property] = (valves[property] ?? []).join(',');
}
}
}
loading = false;
};
const submitHandler = async () => {
if (valvesSpec) {
// Convert string to array
for (const property in valvesSpec.properties) {
if (valvesSpec.properties[property]?.type === 'array') {
valves[property] = (valves[property] ?? '').split(',').map((v) => v.trim());
}
}
if (tab === 'tools') {
const res = await updateToolUserValvesById(localStorage.token, selectedId, valves).catch(
(error) => {
toast.error(error);
return null;
}
);
if (res) {
toast.success('Valves updated');
valves = res;
}
} else if (tab === 'functions') {
const res = await updateFunctionUserValvesById(
localStorage.token,
selectedId,
valves
).catch((error) => {
toast.error(error);
return null;
});
if (res) {
toast.success('Valves updated');
valves = res;
}
}
}
};
$: if (tab) {
selectedId = '';
}
$: if (selectedId) {
getUserValves();
}
</script>
<form
class="flex flex-col h-full justify-between space-y-3 text-sm"
on:submit|preventDefault={() => {
submitHandler();
dispatch('save');
}}
>
<div class="flex flex-col pr-1.5 overflow-y-scroll max-h-[25rem]">
<div>
<div class="flex items-center justify-between mb-2">
<Tooltip content="">
<div class="text-sm font-medium">
{$i18n.t('Manage Valves')}
</div>
</Tooltip>
<div class=" self-end">
<select
class=" dark:bg-gray-900 w-fit pr-8 rounded text-xs bg-transparent outline-none text-right"
bind:value={tab}
placeholder="Select"
>
<option value="tools">{$i18n.t('Tools')}</option>
<option value="functions">{$i18n.t('Functions')}</option>
</select>
</div>
</div>
</div>
<div class="space-y-1">
<div class="flex gap-2">
<div class="flex-1">
<select
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
bind:value={selectedId}
on:change={async () => {
await tick();
}}
>
{#if tab === 'tools'}
<option value="" selected disabled class="bg-gray-100 dark:bg-gray-700"
>{$i18n.t('Select a tool')}</option
>
{#each $tools as tool, toolIdx}
<option value={tool.id} class="bg-gray-100 dark:bg-gray-700">{tool.name}</option>
{/each}
{:else if tab === 'functions'}
<option value="" selected disabled class="bg-gray-100 dark:bg-gray-700"
>{$i18n.t('Select a function')}</option
>
{#each $functions as func, funcIdx}
<option value={func.id} class="bg-gray-100 dark:bg-700">{func.name}</option>
{/each}
{/if}
</select>
</div>
</div>
</div>
{#if selectedId}
<hr class="dark:border-gray-800 my-3 w-full" />
<div>
{#if !loading}
{#if valvesSpec}
{#each Object.keys(valvesSpec.properties) as property, idx}
<div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">
{valvesSpec.properties[property].title}
{#if (valvesSpec?.required ?? []).includes(property)}
<span class=" text-gray-500">*required</span>
{/if}
</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
valves[property] = (valves[property] ?? null) === null ? '' : null;
}}
>
{#if (valves[property] ?? null) === null}
<span class="ml-2 self-center">
{#if (valvesSpec?.required ?? []).includes(property)}
{$i18n.t('None')}
{:else}
{$i18n.t('Default')}
{/if}
</span>
{:else}
<span class="ml-2 self-center"> {$i18n.t('Custom')} </span>
{/if}
</button>
</div>
{#if (valves[property] ?? null) !== null}
<div class="flex mt-0.5 mb-1.5 space-x-2">
<div class=" flex-1">
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="text"
placeholder={valvesSpec.properties[property].title}
bind:value={valves[property]}
autocomplete="off"
required
/>
</div>
</div>
{/if}
{#if (valvesSpec.properties[property]?.description ?? null) !== null}
<div class="text-xs text-gray-500">
{valvesSpec.properties[property].description}
</div>
{/if}
</div>
{/each}
{:else}
<div>No valves</div>
{/if}
{:else}
<Spinner className="size-5" />
{/if}
</div>
{/if}
</div>
<div class="flex justify-end text-sm font-medium">
<button
class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
type="submit"
>
{$i18n.t('Save')}
</button>
</div>
</form>

View file

@ -16,6 +16,7 @@
import Personalization from './Settings/Personalization.svelte';
import { updateUserSettings } from '$lib/apis/users';
import { goto } from '$app/navigation';
import Valves from './Settings/Valves.svelte';
const i18n = getContext('i18n');
@ -65,8 +66,8 @@
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'general'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
? 'bg-gray-200 dark:bg-gray-800'
: ' hover:bg-gray-100 dark:hover:bg-gray-850'}"
on:click={() => {
selectedTab = 'general';
}}
@ -91,8 +92,8 @@
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'interface'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
? 'bg-gray-200 dark:bg-gray-800'
: ' hover:bg-gray-100 dark:hover:bg-gray-850'}"
on:click={() => {
selectedTab = 'interface';
}}
@ -117,8 +118,8 @@
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'personalization'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
? 'bg-gray-200 dark:bg-gray-800'
: ' hover:bg-gray-100 dark:hover:bg-gray-850'}"
on:click={() => {
selectedTab = 'personalization';
}}
@ -132,8 +133,8 @@
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'audio'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
? 'bg-gray-200 dark:bg-gray-800'
: ' hover:bg-gray-100 dark:hover:bg-gray-850'}"
on:click={() => {
selectedTab = 'audio';
}}
@ -156,11 +157,35 @@
<div class=" self-center">{$i18n.t('Audio')}</div>
</button>
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'valves'
? 'bg-gray-200 dark:bg-gray-800'
: ' hover:bg-gray-100 dark:hover:bg-gray-850'}"
on:click={() => {
selectedTab = 'valves';
}}
>
<div class=" self-center mr-2">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="size-4"
>
<path
d="M18.75 12.75h1.5a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5ZM12 6a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 12 6ZM12 18a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 12 18ZM3.75 6.75h1.5a.75.75 0 1 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5ZM5.25 18.75h-1.5a.75.75 0 0 1 0-1.5h1.5a.75.75 0 0 1 0 1.5ZM3 12a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 3 12ZM9 3.75a2.25 2.25 0 1 0 0 4.5 2.25 2.25 0 0 0 0-4.5ZM12.75 12a2.25 2.25 0 1 1 4.5 0 2.25 2.25 0 0 1-4.5 0ZM9 15.75a2.25 2.25 0 1 0 0 4.5 2.25 2.25 0 0 0 0-4.5Z"
/>
</svg>
</div>
<div class=" self-center">{$i18n.t('Valves')}</div>
</button>
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'chats'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
? 'bg-gray-200 dark:bg-gray-800'
: ' hover:bg-gray-100 dark:hover:bg-gray-850'}"
on:click={() => {
selectedTab = 'chats';
}}
@ -185,8 +210,8 @@
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'account'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
? 'bg-gray-200 dark:bg-gray-800'
: ' hover:bg-gray-100 dark:hover:bg-gray-850'}"
on:click={() => {
selectedTab = 'account';
}}
@ -212,8 +237,8 @@
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'admin'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
? 'bg-gray-200 dark:bg-gray-800'
: ' hover:bg-gray-100 dark:hover:bg-gray-850'}"
on:click={async () => {
await goto('/admin/settings');
show = false;
@ -240,8 +265,8 @@
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'about'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
? 'bg-gray-200 dark:bg-gray-800'
: ' hover:bg-gray-100 dark:hover:bg-gray-850'}"
on:click={() => {
selectedTab = 'about';
}}
@ -293,6 +318,13 @@
toast.success($i18n.t('Settings saved successfully!'));
}}
/>
{:else if selectedTab === 'valves'}
<Valves
{saveSettings}
on:save={() => {
toast.success($i18n.t('Settings saved successfully!'));
}}
/>
{:else if selectedTab === 'chats'}
<Chats {saveSettings} />
{:else if selectedTab === 'account'}

View file

@ -0,0 +1,19 @@
<script lang="ts">
export let className = 'size-4';
export let strokeWidth = '1.5';
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width={strokeWidth}
stroke="currentColor"
class={className}
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12Z"
/>
</svg>

View file

@ -538,7 +538,9 @@
documentsImportInputElement.click();
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Import Documents Mapping')}</div>
<div class=" self-center mr-2 font-medium line-clamp-1">
{$i18n.t('Import Documents Mapping')}
</div>
<div class=" self-center">
<svg
@ -565,7 +567,9 @@
saveAs(blob, `documents-mapping-export-${Date.now()}.json`);
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Export Documents Mapping')}</div>
<div class=" self-center mr-2 font-medium line-clamp-1">
{$i18n.t('Export Documents Mapping')}
</div>
<div class=" self-center">
<svg

View file

@ -13,13 +13,20 @@
deleteFunctionById,
exportFunctions,
getFunctionById,
getFunctions
getFunctions,
toggleFunctionById
} from '$lib/apis/functions';
import ArrowDownTray from '../icons/ArrowDownTray.svelte';
import Tooltip from '../common/Tooltip.svelte';
import ConfirmDialog from '../common/ConfirmDialog.svelte';
import { getModels } from '$lib/apis';
import FunctionMenu from './Functions/FunctionMenu.svelte';
import EllipsisHorizontal from '../icons/EllipsisHorizontal.svelte';
import Switch from '../common/Switch.svelte';
import ValvesModal from './common/ValvesModal.svelte';
import ManifestModal from './common/ManifestModal.svelte';
import Heart from '../icons/Heart.svelte';
const i18n = getContext('i18n');
@ -28,6 +35,58 @@
let showConfirm = false;
let query = '';
let showManifestModal = false;
let showValvesModal = false;
let selectedFunction = null;
const shareHandler = async (tool) => {
console.log(tool);
};
const cloneHandler = async (func) => {
const _function = await getFunctionById(localStorage.token, func.id).catch((error) => {
toast.error(error);
return null;
});
if (_function) {
sessionStorage.function = JSON.stringify({
..._function,
id: `${_function.id}_clone`,
name: `${_function.name} (Clone)`
});
goto('/workspace/functions/create');
}
};
const exportHandler = async (func) => {
const _function = await getFunctionById(localStorage.token, func.id).catch((error) => {
toast.error(error);
return null;
});
if (_function) {
let blob = new Blob([JSON.stringify([_function])], {
type: 'application/json'
});
saveAs(blob, `function-${_function.id}-export-${Date.now()}.json`);
}
};
const deleteHandler = async (func) => {
const res = await deleteFunctionById(localStorage.token, func.id).catch((error) => {
toast.error(error);
return null;
});
if (res) {
toast.success('Function deleted successfully');
functions.set(await getFunctions(localStorage.token));
models.set(await getModels(localStorage.token));
}
};
</script>
<svelte:head>
@ -87,18 +146,14 @@
{#each $functions.filter((f) => query === '' || f.name
.toLowerCase()
.includes(query.toLowerCase()) || f.id.toLowerCase().includes(query.toLowerCase())) as func}
<button
<div
class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl"
type="button"
on:click={() => {
goto(`/workspace/functions/edit?id=${encodeURIComponent(func.id)}`);
}}
>
<div class=" flex flex-1 space-x-4 cursor-pointer w-full">
<a
href={`/workspace/functions/edit?id=${encodeURIComponent(func.id)}`}
class="flex items-center text-left"
>
<a
class=" flex flex-1 space-x-3.5 cursor-pointer w-full"
href={`/workspace/functions/edit?id=${encodeURIComponent(func.id)}`}
>
<div class="flex items-center text-left">
<div class=" flex-1 self-center pl-1">
<div class=" font-semibold flex items-center gap-1.5">
<div
@ -107,150 +162,113 @@
{func.type}
</div>
<div>
{#if func?.meta?.manifest?.version}
<div
class="text-xs font-black px-1 rounded line-clamp-1 bg-gray-500/20 text-gray-700 dark:text-gray-200"
>
v{func?.meta?.manifest?.version ?? ''}
</div>
{/if}
<div class=" line-clamp-1">
{func.name}
</div>
</div>
<div class="flex gap-1.5 px-1">
<div class=" text-gray-500 text-xs font-medium">{func.id}</div>
<div class=" text-gray-500 text-xs font-medium flex-shrink-0">{func.id}</div>
<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1">
{func.meta.description}
</div>
</div>
</div>
</a>
</div>
</a>
<div class="flex flex-row gap-0.5 self-center">
{#if func?.meta?.manifest?.funding_url ?? false}
<Tooltip content="Support">
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
selectedFunction = func;
showManifestModal = true;
}}
>
<Heart />
</button>
</Tooltip>
{/if}
<Tooltip content="Valves">
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
selectedFunction = func;
showValvesModal = true;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="size-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z"
/>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
/>
</svg>
</button>
</Tooltip>
<FunctionMenu
editHandler={() => {
goto(`/workspace/functions/edit?id=${encodeURIComponent(func.id)}`);
}}
shareHandler={() => {
shareHandler(func);
}}
cloneHandler={() => {
cloneHandler(func);
}}
exportHandler={() => {
exportHandler(func);
}}
deleteHandler={async () => {
deleteHandler(func);
}}
onClose={() => {}}
>
<button
class="self-center w-fit text-sm p-1.5 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
>
<EllipsisHorizontal className="size-5" />
</button>
</FunctionMenu>
<div class=" self-center mx-1">
<Switch
bind:state={func.is_active}
on:change={async (e) => {
toggleFunctionById(localStorage.token, func.id);
models.set(await getModels(localStorage.token));
}}
/>
</div>
</div>
<div class="flex flex-row space-x-1 self-center">
<Tooltip content="Edit">
<a
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
href={`/workspace/functions/edit?id=${encodeURIComponent(func.id)}`}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
/>
</svg>
</a>
</Tooltip>
<Tooltip content="Clone">
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={async (e) => {
e.stopPropagation();
const _function = await getFunctionById(localStorage.token, func.id).catch(
(error) => {
toast.error(error);
return null;
}
);
if (_function) {
sessionStorage.function = JSON.stringify({
..._function,
id: `${_function.id}_clone`,
name: `${_function.name} (Clone)`
});
goto('/workspace/functions/create');
}
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 0 1-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 0 1 1.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 0 0-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 0 1-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H9.75"
/>
</svg>
</button>
</Tooltip>
<Tooltip content="Export">
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={async (e) => {
e.stopPropagation();
const _function = await getFunctionById(localStorage.token, func.id).catch(
(error) => {
toast.error(error);
return null;
}
);
if (_function) {
let blob = new Blob([JSON.stringify([_function])], {
type: 'application/json'
});
saveAs(blob, `function-${_function.id}-export-${Date.now()}.json`);
}
}}
>
<ArrowDownTray />
</button>
</Tooltip>
<Tooltip content="Delete">
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={async (e) => {
e.stopPropagation();
const res = await deleteFunctionById(localStorage.token, func.id).catch((error) => {
toast.error(error);
return null;
});
if (res) {
toast.success('Function deleted successfully');
functions.set(await getFunctions(localStorage.token));
models.set(await getModels(localStorage.token));
}
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
/>
</svg>
</button>
</Tooltip>
</div>
</button>
</div>
{/each}
</div>
@ -281,7 +299,7 @@
functionsImportInputElement.click();
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Import Functions')}</div>
<div class=" self-center mr-2 font-medium line-clamp-1">{$i18n.t('Import Functions')}</div>
<div class=" self-center">
<svg
@ -315,7 +333,7 @@
}
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Export Functions')}</div>
<div class=" self-center mr-2 font-medium line-clamp-1">{$i18n.t('Export Functions')}</div>
<div class=" self-center">
<svg
@ -335,6 +353,42 @@
</div>
</div>
<div class=" my-16">
<div class=" text-lg font-semibold mb-3 line-clamp-1">
{$i18n.t('Made by OpenWebUI Community')}
</div>
<a
class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2"
href="https://openwebui.com/"
target="_blank"
>
<div class=" self-center w-10 flex-shrink-0">
<div
class="w-full h-10 flex justify-center rounded-full bg-transparent dark:bg-gray-700 border border-dashed border-gray-200"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6">
<path
fill-rule="evenodd"
d="M12 3.75a.75.75 0 01.75.75v6.75h6.75a.75.75 0 010 1.5h-6.75v6.75a.75.75 0 01-1.5 0v-6.75H4.5a.75.75 0 010-1.5h6.75V4.5a.75.75 0 01.75-.75z"
clip-rule="evenodd"
/>
</svg>
</div>
</div>
<div class=" self-center">
<div class=" font-bold line-clamp-1">{$i18n.t('Discover a function')}</div>
<div class=" text-sm line-clamp-1">
{$i18n.t('Discover, download, and explore custom functions')}
</div>
</div>
</a>
</div>
<ManifestModal bind:show={showManifestModal} manifest={selectedFunction?.meta?.manifest ?? {}} />
<ValvesModal bind:show={showValvesModal} type="function" id={selectedFunction?.id ?? null} />
<ConfirmDialog
bind:show={showConfirm}
on:confirm={() => {

View file

@ -0,0 +1,117 @@
<script lang="ts">
import { DropdownMenu } from 'bits-ui';
import { flyAndScale } from '$lib/utils/transitions';
import { getContext } from 'svelte';
import Dropdown from '$lib/components/common/Dropdown.svelte';
import GarbageBin from '$lib/components/icons/GarbageBin.svelte';
import Pencil from '$lib/components/icons/Pencil.svelte';
import Tooltip from '$lib/components/common/Tooltip.svelte';
import Tags from '$lib/components/chat/Tags.svelte';
import Share from '$lib/components/icons/Share.svelte';
import ArchiveBox from '$lib/components/icons/ArchiveBox.svelte';
import DocumentDuplicate from '$lib/components/icons/DocumentDuplicate.svelte';
import ArrowDownTray from '$lib/components/icons/ArrowDownTray.svelte';
const i18n = getContext('i18n');
export let editHandler: Function;
export let shareHandler: Function;
export let cloneHandler: Function;
export let exportHandler: Function;
export let deleteHandler: Function;
export let onClose: Function;
let show = false;
</script>
<Dropdown
bind:show
on:change={(e) => {
if (e.detail === false) {
onClose();
}
}}
>
<Tooltip content={$i18n.t('More')}>
<slot />
</Tooltip>
<div slot="content">
<DropdownMenu.Content
class="w-full max-w-[160px] rounded-xl px-1 py-1.5 border border-gray-300/30 dark:border-gray-700/50 z-50 bg-white dark:bg-gray-850 dark:text-white shadow"
sideOffset={-2}
side="bottom"
align="start"
transition={flyAndScale}
>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
editHandler();
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
/>
</svg>
<div class="flex items-center">{$i18n.t('Edit')}</div>
</DropdownMenu.Item>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
shareHandler();
}}
>
<Share />
<div class="flex items-center">{$i18n.t('Share')}</div>
</DropdownMenu.Item>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
cloneHandler();
}}
>
<DocumentDuplicate />
<div class="flex items-center">{$i18n.t('Clone')}</div>
</DropdownMenu.Item>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
exportHandler();
}}
>
<ArrowDownTray />
<div class="flex items-center">{$i18n.t('Export')}</div>
</DropdownMenu.Item>
<hr class="border-gray-100 dark:border-gray-800 my-1" />
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
deleteHandler();
}}
>
<GarbageBin strokeWidth="2" />
<div class="flex items-center">{$i18n.t('Delete')}</div>
</DropdownMenu.Item>
</DropdownMenu.Content>
</div>
</Dropdown>

View file

@ -256,7 +256,7 @@
<hr class=" dark:border-gray-850 my-2.5" />
<a class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2" href="/workspace/models/create">
<div class=" self-center w-10">
<div class=" self-center w-10 flex-shrink-0">
<div
class="w-full h-10 flex justify-center rounded-full bg-transparent dark:bg-gray-700 border border-dashed border-gray-200"
>
@ -271,8 +271,8 @@
</div>
<div class=" self-center">
<div class=" font-bold">{$i18n.t('Create a model')}</div>
<div class=" text-sm">{$i18n.t('Customize models for a specific purpose')}</div>
<div class=" font-bold line-clamp-1">{$i18n.t('Create a model')}</div>
<div class=" text-sm line-clamp-1">{$i18n.t('Customize models for a specific purpose')}</div>
</div>
</a>
@ -412,7 +412,7 @@
modelsImportInputElement.click();
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Import Models')}</div>
<div class=" self-center mr-2 font-medium line-clamp-1">{$i18n.t('Import Models')}</div>
<div class=" self-center">
<svg
@ -436,7 +436,7 @@
downloadModels($models);
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Export Models')}</div>
<div class=" self-center mr-2 font-medium line-clamp-1">{$i18n.t('Export Models')}</div>
<div class=" self-center">
<svg
@ -494,14 +494,16 @@
</div>
<div class=" my-16">
<div class=" text-lg font-semibold mb-3">{$i18n.t('Made by OpenWebUI Community')}</div>
<div class=" text-lg font-semibold mb-3 line-clamp-1">
{$i18n.t('Made by OpenWebUI Community')}
</div>
<a
class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2"
href="https://openwebui.com/"
target="_blank"
>
<div class=" self-center w-10">
<div class=" self-center w-10 flex-shrink-0">
<div
class="w-full h-10 flex justify-center rounded-full bg-transparent dark:bg-gray-700 border border-dashed border-gray-200"
>
@ -516,8 +518,10 @@
</div>
<div class=" self-center">
<div class=" font-bold">{$i18n.t('Discover a model')}</div>
<div class=" text-sm">{$i18n.t('Discover, download, and explore model presets')}</div>
<div class=" font-bold line-clamp-1">{$i18n.t('Discover a model')}</div>
<div class=" text-sm line-clamp-1">
{$i18n.t('Discover, download, and explore model presets')}
</div>
</div>
</a>
</div>

View file

@ -8,13 +8,16 @@
import { createNewPrompt, deletePromptByCommand, getPrompts } from '$lib/apis/prompts';
import { error } from '@sveltejs/kit';
import { goto } from '$app/navigation';
import PromptMenu from './Prompts/PromptMenu.svelte';
import EllipsisHorizontal from '../icons/EllipsisHorizontal.svelte';
const i18n = getContext('i18n');
let importFiles = '';
let query = '';
let promptsImportInputElement: HTMLInputElement;
const sharePrompt = async (prompt) => {
const shareHandler = async (prompt) => {
toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
const url = 'https://openwebui.com';
@ -32,7 +35,20 @@
);
};
const deletePrompt = async (command) => {
const cloneHandler = async (prompt) => {
sessionStorage.prompt = JSON.stringify(prompt);
goto('/workspace/prompts/create');
};
const exportHandler = async (prompt) => {
let blob = new Blob([JSON.stringify([prompt])], {
type: 'application/json'
});
saveAs(blob, `prompt-export-${Date.now()}.json`);
};
const deleteHandler = async (prompt) => {
const command = prompt.command;
await deletePromptByCommand(localStorage.token, command);
await prompts.set(await getPrompts(localStorage.token));
};
@ -99,14 +115,14 @@
<div class=" flex flex-1 space-x-4 cursor-pointer w-full">
<a href={`/workspace/prompts/edit?command=${encodeURIComponent(prompt.command)}`}>
<div class=" flex-1 self-center pl-5">
<div class=" font-bold">{prompt.command}</div>
<div class=" font-bold line-clamp-1">{prompt.command}</div>
<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1">
{prompt.title}
</div>
</div>
</a>
</div>
<div class="flex flex-row space-x-1 self-center">
<div class="flex flex-row gap-0.5 self-center">
<a
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
@ -128,76 +144,28 @@
</svg>
</a>
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
// console.log(modelfile);
sessionStorage.prompt = JSON.stringify(prompt);
goto('/workspace/prompts/create');
<PromptMenu
shareHandler={() => {
shareHandler(prompt);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 0 1-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 0 1 1.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 0 0-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 0 1-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H9.75"
/>
</svg>
</button>
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
sharePrompt(prompt);
cloneHandler={() => {
cloneHandler(prompt);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M7.217 10.907a2.25 2.25 0 100 2.186m0-2.186c.18.324.283.696.283 1.093s-.103.77-.283 1.093m0-2.186l9.566-5.314m-9.566 7.5l9.566 5.314m0 0a2.25 2.25 0 103.935 2.186 2.25 2.25 0 00-3.935-2.186zm0-12.814a2.25 2.25 0 103.933-2.185 2.25 2.25 0 00-3.933 2.185z"
/>
</svg>
</button>
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
deletePrompt(prompt.command);
exportHandler={() => {
exportHandler(prompt);
}}
deleteHandler={async () => {
deleteHandler(prompt);
}}
onClose={() => {}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
<button
class="self-center w-fit text-sm p-1.5 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
/>
</svg>
</button>
<EllipsisHorizontal className="size-5" />
</button>
</PromptMenu>
</div>
</div>
{/each}
@ -245,7 +213,7 @@
promptsImportInputElement.click();
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Import Prompts')}</div>
<div class=" self-center mr-2 font-medium line-clamp-1">{$i18n.t('Import Prompts')}</div>
<div class=" self-center">
<svg
@ -273,7 +241,7 @@
saveAs(blob, `prompts-export-${Date.now()}.json`);
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Export Prompts')}</div>
<div class=" self-center mr-2 font-medium line-clamp-1">{$i18n.t('Export Prompts')}</div>
<div class=" self-center">
<svg
@ -302,14 +270,16 @@
</div>
<div class=" my-16">
<div class=" text-lg font-semibold mb-3">{$i18n.t('Made by OpenWebUI Community')}</div>
<div class=" text-lg font-semibold mb-3 line-clamp-1">
{$i18n.t('Made by OpenWebUI Community')}
</div>
<a
class=" flex space-x-4 cursor-pointer w-full mb-3 px-3 py-2"
href="https://openwebui.com/?type=prompts"
class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2"
href="https://openwebui.com/"
target="_blank"
>
<div class=" self-center w-10">
<div class=" self-center w-10 flex-shrink-0">
<div
class="w-full h-10 flex justify-center rounded-full bg-transparent dark:bg-gray-700 border border-dashed border-gray-200"
>
@ -324,8 +294,10 @@
</div>
<div class=" self-center">
<div class=" font-bold">{$i18n.t('Discover a prompt')}</div>
<div class=" text-sm">{$i18n.t('Discover, download, and explore custom prompts')}</div>
<div class=" font-bold line-clamp-1">{$i18n.t('Discover a prompt')}</div>
<div class=" text-sm line-clamp-1">
{$i18n.t('Discover, download, and explore custom prompts')}
</div>
</div>
</a>
</div>

View file

@ -0,0 +1,92 @@
<script lang="ts">
import { DropdownMenu } from 'bits-ui';
import { flyAndScale } from '$lib/utils/transitions';
import { getContext } from 'svelte';
import Dropdown from '$lib/components/common/Dropdown.svelte';
import GarbageBin from '$lib/components/icons/GarbageBin.svelte';
import Pencil from '$lib/components/icons/Pencil.svelte';
import Tooltip from '$lib/components/common/Tooltip.svelte';
import Tags from '$lib/components/chat/Tags.svelte';
import Share from '$lib/components/icons/Share.svelte';
import ArchiveBox from '$lib/components/icons/ArchiveBox.svelte';
import DocumentDuplicate from '$lib/components/icons/DocumentDuplicate.svelte';
import ArrowDownTray from '$lib/components/icons/ArrowDownTray.svelte';
const i18n = getContext('i18n');
export let shareHandler: Function;
export let cloneHandler: Function;
export let exportHandler: Function;
export let deleteHandler: Function;
export let onClose: Function;
let show = false;
</script>
<Dropdown
bind:show
on:change={(e) => {
if (e.detail === false) {
onClose();
}
}}
>
<Tooltip content={$i18n.t('More')}>
<slot />
</Tooltip>
<div slot="content">
<DropdownMenu.Content
class="w-full max-w-[160px] rounded-xl px-1 py-1.5 border border-gray-300/30 dark:border-gray-700/50 z-50 bg-white dark:bg-gray-850 dark:text-white shadow"
sideOffset={-2}
side="bottom"
align="start"
transition={flyAndScale}
>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
shareHandler();
}}
>
<Share />
<div class="flex items-center">{$i18n.t('Share')}</div>
</DropdownMenu.Item>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
cloneHandler();
}}
>
<DocumentDuplicate />
<div class="flex items-center">{$i18n.t('Clone')}</div>
</DropdownMenu.Item>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
exportHandler();
}}
>
<ArrowDownTray />
<div class="flex items-center">{$i18n.t('Export')}</div>
</DropdownMenu.Item>
<hr class="border-gray-100 dark:border-gray-800 my-1" />
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
deleteHandler();
}}
>
<GarbageBin strokeWidth="2" />
<div class="flex items-center">{$i18n.t('Delete')}</div>
</DropdownMenu.Item>
</DropdownMenu.Content>
</div>
</Dropdown>

View file

@ -18,6 +18,11 @@
import ArrowDownTray from '../icons/ArrowDownTray.svelte';
import Tooltip from '../common/Tooltip.svelte';
import ConfirmDialog from '../common/ConfirmDialog.svelte';
import ToolMenu from './Tools/ToolMenu.svelte';
import EllipsisHorizontal from '../icons/EllipsisHorizontal.svelte';
import ValvesModal from './common/ValvesModal.svelte';
import ManifestModal from './common/ManifestModal.svelte';
import Heart from '../icons/Heart.svelte';
const i18n = getContext('i18n');
@ -26,6 +31,56 @@
let showConfirm = false;
let query = '';
let showManifestModal = false;
let showValvesModal = false;
let selectedTool = null;
const shareHandler = async (tool) => {
console.log(tool);
};
const cloneHandler = async (tool) => {
const _tool = await getToolById(localStorage.token, tool.id).catch((error) => {
toast.error(error);
return null;
});
if (_tool) {
sessionStorage.tool = JSON.stringify({
..._tool,
id: `${_tool.id}_clone`,
name: `${_tool.name} (Clone)`
});
goto('/workspace/tools/create');
}
};
const exportHandler = async (tool) => {
const _tool = await getToolById(localStorage.token, tool.id).catch((error) => {
toast.error(error);
return null;
});
if (_tool) {
let blob = new Blob([JSON.stringify([_tool])], {
type: 'application/json'
});
saveAs(blob, `tool-${_tool.id}-export-${Date.now()}.json`);
}
};
const deleteHandler = async (tool) => {
const res = await deleteToolById(localStorage.token, tool.id).catch((error) => {
toast.error(error);
return null;
});
if (res) {
toast.success('Tool deleted successfully');
tools.set(await getTools(localStorage.token));
}
};
</script>
<svelte:head>
@ -85,18 +140,14 @@
{#each $tools.filter((t) => query === '' || t.name
.toLowerCase()
.includes(query.toLowerCase()) || t.id.toLowerCase().includes(query.toLowerCase())) as tool}
<button
<div
class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl"
type="button"
on:click={() => {
goto(`/workspace/tools/edit?id=${encodeURIComponent(tool.id)}`);
}}
>
<div class=" flex flex-1 space-x-4 cursor-pointer w-full">
<a
href={`/workspace/tools/edit?id=${encodeURIComponent(tool.id)}`}
class="flex items-center text-left"
>
<a
class=" flex flex-1 space-x-3.5 cursor-pointer w-full"
href={`/workspace/tools/edit?id=${encodeURIComponent(tool.id)}`}
>
<div class="flex items-center text-left">
<div class=" flex-1 self-center pl-1">
<div class=" font-semibold flex items-center gap-1.5">
<div
@ -105,144 +156,103 @@
TOOL
</div>
<div>
{#if tool?.meta?.manifest?.version}
<div
class="text-xs font-black px-1 rounded line-clamp-1 bg-gray-500/20 text-gray-700 dark:text-gray-200"
>
v{tool?.meta?.manifest?.version ?? ''}
</div>
{/if}
<div class="line-clamp-1">
{tool.name}
</div>
</div>
<div class="flex gap-1.5 px-1">
<div class=" text-gray-500 text-xs font-medium">{tool.id}</div>
<div class=" text-gray-500 text-xs font-medium flex-shrink-0">{tool.id}</div>
<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1">
{tool.meta.description}
</div>
</div>
</div>
</a>
</div>
</a>
<div class="flex flex-row gap-0.5 self-center">
{#if tool?.meta?.manifest?.funding_url ?? false}
<Tooltip content="Support">
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
selectedTool = tool;
showManifestModal = true;
}}
>
<Heart />
</button>
</Tooltip>
{/if}
<Tooltip content="Valves">
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
selectedTool = tool;
showValvesModal = true;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="size-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z"
/>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
/>
</svg>
</button>
</Tooltip>
<ToolMenu
editHandler={() => {
goto(`/workspace/tools/edit?id=${encodeURIComponent(tool.id)}`);
}}
shareHandler={() => {
shareHandler(tool);
}}
cloneHandler={() => {
cloneHandler(tool);
}}
exportHandler={() => {
exportHandler(tool);
}}
deleteHandler={async () => {
deleteHandler(tool);
}}
onClose={() => {}}
>
<button
class="self-center w-fit text-sm p-1.5 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
>
<EllipsisHorizontal className="size-5" />
</button>
</ToolMenu>
</div>
<div class="flex flex-row space-x-1 self-center">
<Tooltip content="Edit">
<a
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
href={`/workspace/tools/edit?id=${encodeURIComponent(tool.id)}`}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
/>
</svg>
</a>
</Tooltip>
<Tooltip content="Clone">
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={async (e) => {
e.stopPropagation();
const _tool = await getToolById(localStorage.token, tool.id).catch((error) => {
toast.error(error);
return null;
});
if (_tool) {
sessionStorage.tool = JSON.stringify({
..._tool,
id: `${_tool.id}_clone`,
name: `${_tool.name} (Clone)`
});
goto('/workspace/tools/create');
}
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 0 1-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 0 1 1.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 0 0-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 0 1-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H9.75"
/>
</svg>
</button>
</Tooltip>
<Tooltip content="Export">
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={async (e) => {
e.stopPropagation();
const _tool = await getToolById(localStorage.token, tool.id).catch((error) => {
toast.error(error);
return null;
});
if (_tool) {
let blob = new Blob([JSON.stringify([_tool])], {
type: 'application/json'
});
saveAs(blob, `tool-${_tool.id}-export-${Date.now()}.json`);
}
}}
>
<ArrowDownTray />
</button>
</Tooltip>
<Tooltip content="Delete">
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={async (e) => {
e.stopPropagation();
const res = await deleteToolById(localStorage.token, tool.id).catch((error) => {
toast.error(error);
return null;
});
if (res) {
toast.success('Tool deleted successfully');
tools.set(await getTools(localStorage.token));
}
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
/>
</svg>
</button>
</Tooltip>
</div>
</button>
</div>
{/each}
</div>
@ -273,7 +283,7 @@
toolsImportInputElement.click();
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Import Tools')}</div>
<div class=" self-center mr-2 font-medium line-clamp-1">{$i18n.t('Import Tools')}</div>
<div class=" self-center">
<svg
@ -307,7 +317,7 @@
}
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Export Tools')}</div>
<div class=" self-center mr-2 font-medium line-clamp-1">{$i18n.t('Export Tools')}</div>
<div class=" self-center">
<svg
@ -327,6 +337,42 @@
</div>
</div>
<div class=" my-16">
<div class=" text-lg font-semibold mb-3 line-clamp-1">
{$i18n.t('Made by OpenWebUI Community')}
</div>
<a
class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2"
href="https://openwebui.com/"
target="_blank"
>
<div class=" self-center w-10 flex-shrink-0">
<div
class="w-full h-10 flex justify-center rounded-full bg-transparent dark:bg-gray-700 border border-dashed border-gray-200"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6">
<path
fill-rule="evenodd"
d="M12 3.75a.75.75 0 01.75.75v6.75h6.75a.75.75 0 010 1.5h-6.75v6.75a.75.75 0 01-1.5 0v-6.75H4.5a.75.75 0 010-1.5h6.75V4.5a.75.75 0 01.75-.75z"
clip-rule="evenodd"
/>
</svg>
</div>
</div>
<div class=" self-center">
<div class=" font-bold line-clamp-1">{$i18n.t('Discover a tool')}</div>
<div class=" text-sm line-clamp-1">
{$i18n.t('Discover, download, and explore custom tools')}
</div>
</div>
</a>
</div>
<ValvesModal bind:show={showValvesModal} type="tool" id={selectedTool?.id ?? null} />
<ManifestModal bind:show={showManifestModal} manifest={selectedTool?.meta?.manifest ?? {}} />
<ConfirmDialog
bind:show={showConfirm}
on:confirm={() => {

View file

@ -0,0 +1,117 @@
<script lang="ts">
import { DropdownMenu } from 'bits-ui';
import { flyAndScale } from '$lib/utils/transitions';
import { getContext } from 'svelte';
import Dropdown from '$lib/components/common/Dropdown.svelte';
import GarbageBin from '$lib/components/icons/GarbageBin.svelte';
import Pencil from '$lib/components/icons/Pencil.svelte';
import Tooltip from '$lib/components/common/Tooltip.svelte';
import Tags from '$lib/components/chat/Tags.svelte';
import Share from '$lib/components/icons/Share.svelte';
import ArchiveBox from '$lib/components/icons/ArchiveBox.svelte';
import DocumentDuplicate from '$lib/components/icons/DocumentDuplicate.svelte';
import ArrowDownTray from '$lib/components/icons/ArrowDownTray.svelte';
const i18n = getContext('i18n');
export let editHandler: Function;
export let shareHandler: Function;
export let cloneHandler: Function;
export let exportHandler: Function;
export let deleteHandler: Function;
export let onClose: Function;
let show = false;
</script>
<Dropdown
bind:show
on:change={(e) => {
if (e.detail === false) {
onClose();
}
}}
>
<Tooltip content={$i18n.t('More')}>
<slot />
</Tooltip>
<div slot="content">
<DropdownMenu.Content
class="w-full max-w-[160px] rounded-xl px-1 py-1.5 border border-gray-300/30 dark:border-gray-700/50 z-50 bg-white dark:bg-gray-850 dark:text-white shadow"
sideOffset={-2}
side="bottom"
align="start"
transition={flyAndScale}
>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
editHandler();
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
/>
</svg>
<div class="flex items-center">{$i18n.t('Edit')}</div>
</DropdownMenu.Item>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
shareHandler();
}}
>
<Share />
<div class="flex items-center">{$i18n.t('Share')}</div>
</DropdownMenu.Item>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
cloneHandler();
}}
>
<DocumentDuplicate />
<div class="flex items-center">{$i18n.t('Clone')}</div>
</DropdownMenu.Item>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
exportHandler();
}}
>
<ArrowDownTray />
<div class="flex items-center">{$i18n.t('Export')}</div>
</DropdownMenu.Item>
<hr class="border-gray-100 dark:border-gray-800 my-1" />
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
deleteHandler();
}}
>
<GarbageBin strokeWidth="2" />
<div class="flex items-center">{$i18n.t('Delete')}</div>
</DropdownMenu.Item>
</DropdownMenu.Content>
</div>
</Dropdown>

View file

@ -0,0 +1,102 @@
<script lang="ts">
import { toast } from 'svelte-sonner';
import { createEventDispatcher } from 'svelte';
import { onMount, getContext } from 'svelte';
import Modal from '../../common/Modal.svelte';
const i18n = getContext('i18n');
const dispatch = createEventDispatcher();
export let show = false;
export let manifest = {};
</script>
<Modal size="sm" bind:show>
<div>
<div class=" flex justify-between dark:text-gray-300 px-5 pt-4 pb-2">
<div class=" text-lg font-medium self-center">{$i18n.t('Show your support!')}</div>
<button
class="self-center"
on:click={() => {
show = false;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-5 h-5"
>
<path
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
/>
</svg>
</button>
</div>
<div class="flex flex-col md:flex-row w-full px-5 pb-4 md:space-x-4 dark:text-gray-200">
<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6">
<form
class="flex flex-col w-full"
on:submit|preventDefault={() => {
show = false;
}}
>
<div class="px-1 text-sm">
<div class=" my-2">
The developers behind this plugin are passionate volunteers from the community. If you
find this plugin helpful, please consider contributing to its development.
</div>
<div class=" my-2">
Your entire contribution will go directly to the plugin developer; Open WebUI does not
take any percentage. However, the chosen funding platform might have its own fees.
</div>
<hr class=" dark:border-gray-800 my-3" />
<div class="my-2">
Support this plugin: <a
href={manifest.funding_url}
target="_blank"
class=" underline text-blue-400 hover:text-blue-300">{manifest.funding_url}</a
>
</div>
</div>
<div class="flex justify-end pt-3 text-sm font-medium">
<button
class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg flex flex-row space-x-1 items-center"
type="submit"
>
{$i18n.t('Done')}
</button>
</div>
</form>
</div>
</div>
</div>
</Modal>
<style>
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
/* display: none; <- Crashes Chrome on hover */
-webkit-appearance: none;
margin: 0; /* <-- Apparently some margin are still there even though it's hidden */
}
.tabs::-webkit-scrollbar {
display: none; /* for Chrome, Safari and Opera */
}
.tabs {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
input[type='number'] {
-moz-appearance: textfield; /* Firefox */
}
</style>

View file

@ -0,0 +1,256 @@
<script lang="ts">
import { toast } from 'svelte-sonner';
import { createEventDispatcher } from 'svelte';
import { onMount, getContext } from 'svelte';
import { addUser } from '$lib/apis/auths';
import Modal from '../../common/Modal.svelte';
import {
getFunctionValvesById,
getFunctionValvesSpecById,
updateFunctionValvesById
} from '$lib/apis/functions';
import { getToolValvesById, getToolValvesSpecById, updateToolValvesById } from '$lib/apis/tools';
import Spinner from '../../common/Spinner.svelte';
const i18n = getContext('i18n');
const dispatch = createEventDispatcher();
export let show = false;
export let type = 'tool';
export let id = null;
let saving = false;
let loading = false;
let valvesSpec = null;
let valves = {};
const submitHandler = async () => {
saving = true;
if (valvesSpec) {
// Convert string to array
for (const property in valvesSpec.properties) {
if (valvesSpec.properties[property]?.type === 'array') {
valves[property] = (valves[property] ?? '').split(',').map((v) => v.trim());
}
}
let res = null;
if (type === 'tool') {
res = await updateToolValvesById(localStorage.token, id, valves).catch((error) => {
toast.error(error);
});
} else if (type === 'function') {
res = await updateFunctionValvesById(localStorage.token, id, valves).catch((error) => {
toast.error(error);
});
}
if (res) {
toast.success('Valves updated successfully');
}
}
saving = false;
};
const initHandler = async () => {
loading = true;
valves = {};
valvesSpec = null;
if (type === 'tool') {
valves = await getToolValvesById(localStorage.token, id);
valvesSpec = await getToolValvesSpecById(localStorage.token, id);
} else if (type === 'function') {
valves = await getFunctionValvesById(localStorage.token, id);
valvesSpec = await getFunctionValvesSpecById(localStorage.token, id);
}
if (!valves) {
valves = {};
}
if (valvesSpec) {
// Convert array to string
for (const property in valvesSpec.properties) {
if (valvesSpec.properties[property]?.type === 'array') {
valves[property] = (valves[property] ?? []).join(',');
}
}
}
loading = false;
};
$: if (show) {
initHandler();
}
</script>
<Modal size="sm" bind:show>
<div>
<div class=" flex justify-between dark:text-gray-300 px-5 pt-4 pb-2">
<div class=" text-lg font-medium self-center">{$i18n.t('Valves')}</div>
<button
class="self-center"
on:click={() => {
show = false;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-5 h-5"
>
<path
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
/>
</svg>
</button>
</div>
<div class="flex flex-col md:flex-row w-full px-5 pb-4 md:space-x-4 dark:text-gray-200">
<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6">
<form
class="flex flex-col w-full"
on:submit|preventDefault={() => {
submitHandler();
}}
>
<div class="px-1">
{#if !loading}
{#if valvesSpec}
{#each Object.keys(valvesSpec.properties) as property, idx}
<div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">
{valvesSpec.properties[property].title}
{#if (valvesSpec?.required ?? []).includes(property)}
<span class=" text-gray-500">*required</span>
{/if}
</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
valves[property] = (valves[property] ?? null) === null ? '' : null;
}}
>
{#if (valves[property] ?? null) === null}
<span class="ml-2 self-center">
{#if (valvesSpec?.required ?? []).includes(property)}
{$i18n.t('None')}
{:else}
{$i18n.t('Default')}
{/if}
</span>
{:else}
<span class="ml-2 self-center"> {$i18n.t('Custom')} </span>
{/if}
</button>
</div>
{#if (valves[property] ?? null) !== null}
<div class="flex mt-0.5 mb-1.5 space-x-2">
<div class=" flex-1">
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="text"
placeholder={valvesSpec.properties[property].title}
bind:value={valves[property]}
autocomplete="off"
required
/>
</div>
</div>
{/if}
{#if (valvesSpec.properties[property]?.description ?? null) !== null}
<div class="text-xs text-gray-500">
{valvesSpec.properties[property].description}
</div>
{/if}
</div>
{/each}
{:else}
<div class="text-sm">No valves</div>
{/if}
{:else}
<Spinner className="size-5" />
{/if}
</div>
<div class="flex justify-end pt-3 text-sm font-medium">
<button
class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg flex flex-row space-x-1 items-center {saving
? ' cursor-not-allowed'
: ''}"
type="submit"
disabled={saving}
>
{$i18n.t('Save')}
{#if saving}
<div class="ml-2 self-center">
<svg
class=" w-4 h-4"
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
><style>
.spinner_ajPY {
transform-origin: center;
animation: spinner_AtaB 0.75s infinite linear;
}
@keyframes spinner_AtaB {
100% {
transform: rotate(360deg);
}
}
</style><path
d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
opacity=".25"
/><path
d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
class="spinner_ajPY"
/></svg
>
</div>
{/if}
</button>
</div>
</form>
</div>
</div>
</div>
</Modal>
<style>
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
/* display: none; <- Crashes Chrome on hover */
-webkit-appearance: none;
margin: 0; /* <-- Apparently some margin are still there even though it's hidden */
}
.tabs::-webkit-scrollbar {
display: none; /* for Chrome, Safari and Opera */
}
.tabs {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
input[type='number'] {
-moz-appearance: textfield; /* Firefox */
}
</style>

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "يستطيع حذف المحادثات",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "الأحرف الأبجدية الرقمية والواصلات",
"Already have an account?": "هل تملك حساب ؟",
"an assistant": "مساعد",
@ -165,9 +166,13 @@
"Deleted {{name}}": "حذف {{name}}",
"Description": "وصف",
"Didn't fully follow instructions": "لم أتبع التعليمات بشكل كامل",
"Discover a function": "",
"Discover a model": "اكتشف نموذجا",
"Discover a prompt": "اكتشاف موجه",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "اكتشاف وتنزيل واستكشاف المطالبات المخصصة",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "اكتشاف وتنزيل واستكشاف الإعدادات المسبقة للنموذج",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "لا تسمح بذلك",
"Don't have an account?": "ليس لديك حساب؟",
"Don't like the style": "لا أحب النمط",
"Done": "",
"Download": "تحميل",
"Download canceled": "تم اللغاء التحميل",
"Download Database": "تحميل قاعدة البيانات",
@ -312,6 +318,7 @@
"Manage Models": "إدارة النماذج",
"Manage Ollama Models": "Ollama إدارة موديلات ",
"Manage Pipelines": "إدارة خطوط الأنابيب",
"Manage Valves": "",
"March": "مارس",
"Max Tokens (num_predict)": "ماكس توكنز (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "يمكن تنزيل 3 نماذج كحد أقصى في وقت واحد. الرجاء معاودة المحاولة في وقت لاحق.",
@ -463,10 +470,12 @@
"Seed": "Seed",
"Select a base model": "حدد نموذجا أساسيا",
"Select a engine": "",
"Select a function": "",
"Select a mode": "أختار موديل",
"Select a model": "أختار الموديل",
"Select a pipeline": "حدد مسارا",
"Select a pipeline url": "حدد عنوان URL لخط الأنابيب",
"Select a tool": "",
"Select an Ollama instance": "أختار سيرفر ",
"Select Documents": "",
"Select model": " أختار موديل",
@ -499,6 +508,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "إظهار الاختصارات",
"Show your support!": "",
"Showcased creativity": "أظهر الإبداع",
"sidebar": "الشريط الجانبي",
"Sign in": "تسجيل الدخول",
@ -587,6 +597,7 @@
"Users": "المستخدمين",
"Utilize": "يستخدم",
"Valid time units:": "وحدات زمنية صالحة:",
"Valves": "",
"variable": "المتغير",
"variable to have them replaced with clipboard content.": "متغير لاستبدالها بمحتوى الحافظة.",
"Version": "إصدار",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Позволи Изтриване на Чат",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "алфанумерични знаци и тире",
"Already have an account?": "Вече имате акаунт? ",
"an assistant": "асистент",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Изтрито {{име}}",
"Description": "Описание",
"Didn't fully follow instructions": "Не следва инструкциите",
"Discover a function": "",
"Discover a model": "Открийте модел",
"Discover a prompt": "Откриване на промпт",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Откриване, сваляне и преглед на персонализирани промптове",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Откриване, сваляне и преглед на пресетове на модели",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Не Позволявай",
"Don't have an account?": "Нямате акаунт?",
"Don't like the style": "Не харесваш стила?",
"Done": "",
"Download": "Изтегляне отменено",
"Download canceled": "Изтегляне отменено",
"Download Database": "Сваляне на база данни",
@ -312,6 +318,7 @@
"Manage Models": "Управление на Моделите",
"Manage Ollama Models": "Управление на Ollama Моделите",
"Manage Pipelines": "Управление на тръбопроводи",
"Manage Valves": "",
"March": "Март",
"Max Tokens (num_predict)": "Макс токени (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Максимум 3 модели могат да бъдат сваляни едновременно. Моля, опитайте отново по-късно.",
@ -459,10 +466,12 @@
"Seed": "Seed",
"Select a base model": "Изберете базов модел",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Изберете режим",
"Select a model": "Изберете модел",
"Select a pipeline": "Изберете тръбопровод",
"Select a pipeline url": "Избор на URL адрес на канал",
"Select a tool": "",
"Select an Ollama instance": "Изберете Ollama инстанция",
"Select Documents": "",
"Select model": "Изберете модел",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Покажи",
"Show your support!": "",
"Showcased creativity": "Показана креативност",
"sidebar": "sidebar",
"Sign in": "Вписване",
@ -583,6 +593,7 @@
"Users": "Потребители",
"Utilize": "Използване",
"Valid time units:": "Валидни единици за време:",
"Valves": "",
"variable": "променлива",
"variable to have them replaced with clipboard content.": "променливи да се заменят съдържанието от клипборд.",
"Version": "Версия",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "চ্যাট ডিলিট করতে দিন",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "ইংরেজি অক্ষর, সংখ্যা এবং হাইফেন",
"Already have an account?": "আগে থেকেই একাউন্ট আছে?",
"an assistant": "একটা এসিস্ট্যান্ট",
@ -165,9 +166,13 @@
"Deleted {{name}}": "{{name}} মোছা হয়েছে",
"Description": "বিবরণ",
"Didn't fully follow instructions": "ইনস্ট্রাকশন সম্পূর্ণ অনুসরণ করা হয়নি",
"Discover a function": "",
"Discover a model": "একটি মডেল আবিষ্কার করুন",
"Discover a prompt": "একটি প্রম্পট খুঁজে বের করুন",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "কাস্টম প্রম্পটগুলো আবিস্কার, ডাউনলোড এবং এক্সপ্লোর করুন",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "মডেল প্রিসেটগুলো আবিস্কার, ডাউনলোড এবং এক্সপ্লোর করুন",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "অনুমোদন দেবেন না",
"Don't have an account?": "একাউন্ট নেই?",
"Don't like the style": "স্টাইল পছন্দ করেন না",
"Done": "",
"Download": "ডাউনলোড",
"Download canceled": "ডাউনলোড বাতিল করা হয়েছে",
"Download Database": "ডেটাবেজ ডাউনলোড করুন",
@ -312,6 +318,7 @@
"Manage Models": "মডেলসমূহ ব্যবস্থাপনা করুন",
"Manage Ollama Models": "Ollama মডেলসূহ ব্যবস্থাপনা করুন",
"Manage Pipelines": "পাইপলাইন পরিচালনা করুন",
"Manage Valves": "",
"March": "মার্চ",
"Max Tokens (num_predict)": "সর্বোচ্চ টোকেন (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "একসঙ্গে সর্বোচ্চ তিনটি মডেল ডাউনলোড করা যায়। দয়া করে পরে আবার চেষ্টা করুন।",
@ -459,10 +466,12 @@
"Seed": "সীড",
"Select a base model": "একটি বেস মডেল নির্বাচন করুন",
"Select a engine": "",
"Select a function": "",
"Select a mode": "একটি মডেল নির্বাচন করুন",
"Select a model": "একটি মডেল নির্বাচন করুন",
"Select a pipeline": "একটি পাইপলাইন নির্বাচন করুন",
"Select a pipeline url": "একটি পাইপলাইন URL নির্বাচন করুন",
"Select a tool": "",
"Select an Ollama instance": "একটি Ollama ইন্সট্যান্স নির্বাচন করুন",
"Select Documents": "",
"Select model": "মডেল নির্বাচন করুন",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "শর্টকাটগুলো দেখান",
"Show your support!": "",
"Showcased creativity": "সৃজনশীলতা প্রদর্শন",
"sidebar": "সাইডবার",
"Sign in": "সাইন ইন",
@ -583,6 +593,7 @@
"Users": "ব্যাবহারকারীগণ",
"Utilize": "ইউটিলাইজ",
"Valid time units:": "সময়ের গ্রহণযোগ্য এককসমূহ:",
"Valves": "",
"variable": "ভেরিয়েবল",
"variable to have them replaced with clipboard content.": "ক্লিপবোর্ডের কন্টেন্ট দিয়ে যেই ভেরিয়েবল রিপ্লেস করা যাবে।",
"Version": "ভার্সন",

File diff suppressed because it is too large Load diff

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Tugoti nga mapapas ang mga chat",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "alphanumeric nga mga karakter ug hyphen",
"Already have an account?": "Naa na kay account ?",
"an assistant": "usa ka katabang",
@ -165,9 +166,13 @@
"Deleted {{name}}": "",
"Description": "Deskripsyon",
"Didn't fully follow instructions": "",
"Discover a function": "",
"Discover a model": "",
"Discover a prompt": "Pagkaplag usa ka prompt",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Pagdiskubre, pag-download ug pagsuhid sa mga naandan nga pag-aghat",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Pagdiskobre, pag-download, ug pagsuhid sa mga preset sa template",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Dili tugotan",
"Don't have an account?": "Wala kay account ?",
"Don't like the style": "",
"Done": "",
"Download": "",
"Download canceled": "",
"Download Database": "I-download ang database",
@ -312,6 +318,7 @@
"Manage Models": "Pagdumala sa mga templates",
"Manage Ollama Models": "Pagdumala sa mga modelo sa Ollama",
"Manage Pipelines": "",
"Manage Valves": "",
"March": "",
"Max Tokens (num_predict)": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Ang labing taas nga 3 nga mga disenyo mahimong ma-download nga dungan. ",
@ -459,10 +466,12 @@
"Seed": "Binhi",
"Select a base model": "",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Pagpili og mode",
"Select a model": "Pagpili og modelo",
"Select a pipeline": "",
"Select a pipeline url": "",
"Select a tool": "",
"Select an Ollama instance": "Pagpili usa ka pananglitan sa Ollama",
"Select Documents": "",
"Select model": "Pagpili og modelo",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Ipakita ang mga shortcut",
"Show your support!": "",
"Showcased creativity": "",
"sidebar": "lateral bar",
"Sign in": "Para maka log in",
@ -583,6 +593,7 @@
"Users": "Mga tiggamit",
"Utilize": "Sa paggamit",
"Valid time units:": "Balido nga mga yunit sa oras:",
"Valves": "",
"variable": "variable",
"variable to have them replaced with clipboard content.": "variable aron pulihan kini sa mga sulud sa clipboard.",
"Version": "Bersyon",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Chat Löschung erlauben",
"Allow non-local voices": "Nicht-lokale Stimmen erlauben",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "alphanumerische Zeichen und Bindestriche",
"Already have an account?": "Hast du vielleicht schon ein Account?",
"an assistant": "ein Assistent",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Gelöscht {{name}}",
"Description": "Beschreibung",
"Didn't fully follow instructions": "Nicht genau den Answeisungen gefolgt",
"Discover a function": "",
"Discover a model": "Entdecken Sie ein Modell",
"Discover a prompt": "Einen Prompt entdecken",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Benutzerdefinierte Prompts entdecken, herunterladen und erkunden",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Modellvorgaben entdecken, herunterladen und erkunden",
"Dismissible": "ausblendbar",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Nicht erlauben",
"Don't have an account?": "Hast du vielleicht noch kein Konto?",
"Don't like the style": "Dir gefällt der Style nicht",
"Done": "",
"Download": "Herunterladen",
"Download canceled": "Download abgebrochen",
"Download Database": "Datenbank herunterladen",
@ -312,6 +318,7 @@
"Manage Models": "Modelle verwalten",
"Manage Ollama Models": "Ollama-Modelle verwalten",
"Manage Pipelines": "Verwalten von Pipelines",
"Manage Valves": "",
"March": "März",
"Max Tokens (num_predict)": "Max. Token (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Es können maximal 3 Modelle gleichzeitig heruntergeladen werden. Bitte versuche es später erneut.",
@ -459,10 +466,12 @@
"Seed": "Seed",
"Select a base model": "Wählen Sie ein Basismodell",
"Select a engine": "Wähle eine Engine",
"Select a function": "",
"Select a mode": "Einen Modus auswählen",
"Select a model": "Ein Modell auswählen",
"Select a pipeline": "Wählen Sie eine Pipeline aus",
"Select a pipeline url": "Auswählen einer Pipeline-URL",
"Select a tool": "",
"Select an Ollama instance": "Eine Ollama Instanz auswählen",
"Select Documents": "",
"Select model": "Modell auswählen",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "Admin-Details im Account-Pending-Overlay anzeigen",
"Show Model": "",
"Show shortcuts": "Verknüpfungen anzeigen",
"Show your support!": "",
"Showcased creativity": "Kreativität zur Schau gestellt",
"sidebar": "Seitenleiste",
"Sign in": "Anmelden",
@ -583,6 +593,7 @@
"Users": "Benutzer",
"Utilize": "Nutze die",
"Valid time units:": "Gültige Zeiteinheiten:",
"Valves": "",
"variable": "Variable",
"variable to have them replaced with clipboard content.": "Variable, um den Inhalt der Zwischenablage beim Nutzen des Prompts zu ersetzen.",
"Version": "Version",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Allow Delete Chats",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "so alpha, many hyphen",
"Already have an account?": "Such account exists?",
"an assistant": "such assistant",
@ -165,9 +166,13 @@
"Deleted {{name}}": "",
"Description": "Description",
"Didn't fully follow instructions": "",
"Discover a function": "",
"Discover a model": "",
"Discover a prompt": "Discover a prompt",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Discover, download, and explore custom prompts",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Discover, download, and explore model presets",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Don't Allow",
"Don't have an account?": "No account? Much sad.",
"Don't like the style": "",
"Done": "",
"Download": "",
"Download canceled": "",
"Download Database": "Download Database",
@ -312,6 +318,7 @@
"Manage Models": "Manage Wowdels",
"Manage Ollama Models": "Manage Ollama Wowdels",
"Manage Pipelines": "",
"Manage Valves": "",
"March": "",
"Max Tokens (num_predict)": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maximum of 3 models can be downloaded simultaneously. Please try again later.",
@ -461,10 +468,12 @@
"Seed": "Seed very plant",
"Select a base model": "",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Select a mode very choose",
"Select a model": "Select a model much choice",
"Select a pipeline": "",
"Select a pipeline url": "",
"Select a tool": "",
"Select an Ollama instance": "Select an Ollama instance very choose",
"Select Documents": "",
"Select model": "Select model much choice",
@ -497,6 +506,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Show shortcuts much shortcut",
"Show your support!": "",
"Showcased creativity": "",
"sidebar": "sidebar much side",
"Sign in": "Sign in very sign",
@ -585,6 +595,7 @@
"Users": "Users much users",
"Utilize": "Utilize very use",
"Valid time units:": "Valid time units: much time",
"Valves": "",
"variable": "variable very variable",
"variable to have them replaced with clipboard content.": "variable to have them replaced with clipboard content. Very replace.",
"Version": "Version much version",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "",
"Already have an account?": "",
"an assistant": "",
@ -165,9 +166,13 @@
"Deleted {{name}}": "",
"Description": "",
"Didn't fully follow instructions": "",
"Discover a function": "",
"Discover a model": "",
"Discover a prompt": "",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "",
"Don't have an account?": "",
"Don't like the style": "",
"Done": "",
"Download": "",
"Download canceled": "",
"Download Database": "",
@ -312,6 +318,7 @@
"Manage Models": "",
"Manage Ollama Models": "",
"Manage Pipelines": "",
"Manage Valves": "",
"March": "",
"Max Tokens (num_predict)": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "",
@ -459,10 +466,12 @@
"Seed": "",
"Select a base model": "",
"Select a engine": "",
"Select a function": "",
"Select a mode": "",
"Select a model": "",
"Select a pipeline": "",
"Select a pipeline url": "",
"Select a tool": "",
"Select an Ollama instance": "",
"Select Documents": "",
"Select model": "",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "",
"Show your support!": "",
"Showcased creativity": "",
"sidebar": "",
"Sign in": "",
@ -583,6 +593,7 @@
"Users": "",
"Utilize": "",
"Valid time units:": "",
"Valves": "",
"variable": "",
"variable to have them replaced with clipboard content.": "",
"Version": "",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "",
"Already have an account?": "",
"an assistant": "",
@ -165,9 +166,13 @@
"Deleted {{name}}": "",
"Description": "",
"Didn't fully follow instructions": "",
"Discover a function": "",
"Discover a model": "",
"Discover a prompt": "",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "",
"Don't have an account?": "",
"Don't like the style": "",
"Done": "",
"Download": "",
"Download canceled": "",
"Download Database": "",
@ -312,6 +318,7 @@
"Manage Models": "",
"Manage Ollama Models": "",
"Manage Pipelines": "",
"Manage Valves": "",
"March": "",
"Max Tokens (num_predict)": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "",
@ -459,10 +466,12 @@
"Seed": "",
"Select a base model": "",
"Select a engine": "",
"Select a function": "",
"Select a mode": "",
"Select a model": "",
"Select a pipeline": "",
"Select a pipeline url": "",
"Select a tool": "",
"Select an Ollama instance": "",
"Select Documents": "",
"Select model": "",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "",
"Show your support!": "",
"Showcased creativity": "",
"sidebar": "",
"Sign in": "",
@ -583,6 +593,7 @@
"Users": "",
"Utilize": "",
"Valid time units:": "",
"Valves": "",
"variable": "",
"variable to have them replaced with clipboard content.": "",
"Version": "",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Permitir Borrar Chats",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "caracteres alfanuméricos y guiones",
"Already have an account?": "¿Ya tienes una cuenta?",
"an assistant": "un asistente",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Eliminado {{nombre}}",
"Description": "Descripción",
"Didn't fully follow instructions": "No siguió las instrucciones",
"Discover a function": "",
"Discover a model": "Descubrir un modelo",
"Discover a prompt": "Descubre un Prompt",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Descubre, descarga, y explora Prompts personalizados",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Descubre, descarga y explora ajustes preestablecidos de modelos",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "No Permitir",
"Don't have an account?": "¿No tienes una cuenta?",
"Don't like the style": "No te gusta el estilo?",
"Done": "",
"Download": "Descargar",
"Download canceled": "Descarga cancelada",
"Download Database": "Descarga la Base de Datos",
@ -312,6 +318,7 @@
"Manage Models": "Administrar Modelos",
"Manage Ollama Models": "Administrar Modelos Ollama",
"Manage Pipelines": "Administrar canalizaciones",
"Manage Valves": "",
"March": "Marzo",
"Max Tokens (num_predict)": "Máximo de fichas (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Se pueden descargar un máximo de 3 modelos simultáneamente. Por favor, inténtelo de nuevo más tarde.",
@ -460,10 +467,12 @@
"Seed": "Seed",
"Select a base model": "Seleccionar un modelo base",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Selecciona un modo",
"Select a model": "Selecciona un modelo",
"Select a pipeline": "Selección de una canalización",
"Select a pipeline url": "Selección de una dirección URL de canalización",
"Select a tool": "",
"Select an Ollama instance": "Seleccione una instancia de Ollama",
"Select Documents": "",
"Select model": "Selecciona un modelo",
@ -496,6 +505,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Mostrar atajos",
"Show your support!": "",
"Showcased creativity": "Mostrar creatividad",
"sidebar": "barra lateral",
"Sign in": "Iniciar sesión",
@ -584,6 +594,7 @@
"Users": "Usuarios",
"Utilize": "Utilizar",
"Valid time units:": "Unidades válidas de tiempo:",
"Valves": "",
"variable": "variable",
"variable to have them replaced with clipboard content.": "variable para reemplazarlos con el contenido del portapapeles.",
"Version": "Versión",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "اجازه حذف گپ",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "حروف الفبایی و خط فاصله",
"Already have an account?": "از قبل حساب کاربری دارید؟",
"an assistant": "یک دستیار",
@ -165,9 +166,13 @@
"Deleted {{name}}": "حذف شده {{name}}",
"Description": "توضیحات",
"Didn't fully follow instructions": "نمی تواند دستورالعمل را کامل پیگیری کند",
"Discover a function": "",
"Discover a model": "کشف یک مدل",
"Discover a prompt": "یک اعلان را کشف کنید",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "پرامپت\u200cهای سفارشی را کشف، دانلود و کاوش کنید",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "پیش تنظیمات مدل را کشف، دانلود و کاوش کنید",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "اجازه نده",
"Don't have an account?": "حساب کاربری ندارید؟",
"Don't like the style": "نظری ندارید؟",
"Done": "",
"Download": "دانلود کن",
"Download canceled": "دانلود لغو شد",
"Download Database": "دانلود پایگاه داده",
@ -312,6 +318,7 @@
"Manage Models": "مدیریت مدل\u200cها",
"Manage Ollama Models": "مدیریت مدل\u200cهای اولاما",
"Manage Pipelines": "مدیریت خطوط لوله",
"Manage Valves": "",
"March": "مارچ",
"Max Tokens (num_predict)": "توکنهای بیشینه (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "حداکثر 3 مدل را می توان به طور همزمان دانلود کرد. لطفاً بعداً دوباره امتحان کنید.",
@ -459,10 +466,12 @@
"Seed": "Seed",
"Select a base model": "انتخاب یک مدل پایه",
"Select a engine": "",
"Select a function": "",
"Select a mode": "یک حالت انتخاب کنید",
"Select a model": "انتخاب یک مدل",
"Select a pipeline": "انتخاب یک خط لوله",
"Select a pipeline url": "یک ادرس خط لوله را انتخاب کنید",
"Select a tool": "",
"Select an Ollama instance": "انتخاب یک نمونه از اولاما",
"Select Documents": "",
"Select model": "انتخاب یک مدل",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "نمایش میانبرها",
"Show your support!": "",
"Showcased creativity": "ایده\u200cآفرینی",
"sidebar": "نوار کناری",
"Sign in": "ورود",
@ -583,6 +593,7 @@
"Users": "کاربران",
"Utilize": "استفاده کنید",
"Valid time units:": "واحدهای زمانی معتبر:",
"Valves": "",
"variable": "متغیر",
"variable to have them replaced with clipboard content.": "متغیر برای جایگزینی آنها با محتوای کلیپ بورد.",
"Version": "نسخه",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Salli keskustelujen poisto",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "kirjaimia, numeroita ja väliviivoja",
"Already have an account?": "Onko sinulla jo tili?",
"an assistant": "avustaja",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Poistettu {{nimi}}",
"Description": "Kuvaus",
"Didn't fully follow instructions": "Ei noudattanut ohjeita täysin",
"Discover a function": "",
"Discover a model": "Tutustu malliin",
"Discover a prompt": "Löydä kehote",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Löydä ja lataa mukautettuja kehotteita",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Löydä ja lataa mallien esiasetuksia",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Älä salli",
"Don't have an account?": "Eikö sinulla ole tiliä?",
"Don't like the style": "En pidä tyylistä",
"Done": "",
"Download": "Lataa",
"Download canceled": "Lataus peruutettu",
"Download Database": "Lataa tietokanta",
@ -312,6 +318,7 @@
"Manage Models": "Hallitse malleja",
"Manage Ollama Models": "Hallitse Ollama-malleja",
"Manage Pipelines": "Hallitse putkia",
"Manage Valves": "",
"March": "maaliskuu",
"Max Tokens (num_predict)": "Tokenien enimmäismäärä (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Enintään 3 mallia voidaan ladata samanaikaisesti. Yritä myöhemmin uudelleen.",
@ -459,10 +466,12 @@
"Seed": "Siemen",
"Select a base model": "Valitse perusmalli",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Valitse tila",
"Select a model": "Valitse malli",
"Select a pipeline": "Valitse putki",
"Select a pipeline url": "Valitse putken URL-osoite",
"Select a tool": "",
"Select an Ollama instance": "Valitse Ollama-instanssi",
"Select Documents": "",
"Select model": "Valitse malli",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Näytä pikanäppäimet",
"Show your support!": "",
"Showcased creativity": "Näytti luovuutta",
"sidebar": "sivupalkki",
"Sign in": "Kirjaudu sisään",
@ -583,6 +593,7 @@
"Users": "Käyttäjät",
"Utilize": "Käytä",
"Valid time units:": "Kelvolliset aikayksiköt:",
"Valves": "",
"variable": "muuttuja",
"variable to have them replaced with clipboard content.": "muuttuja korvataan leikepöydän sisällöllä.",
"Version": "Versio",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Autoriser la suppression des discussions",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "caractères alphanumériques et tirets",
"Already have an account?": "Vous avez déjà un compte ?",
"an assistant": "un assistant",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Supprimé {{nom}}",
"Description": "Description",
"Didn't fully follow instructions": "Ne suit pas les instructions",
"Discover a function": "",
"Discover a model": "Découvrez un modèle",
"Discover a prompt": "Découvrir un prompt",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Découvrir, télécharger et explorer des prompts personnalisés",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Découvrir, télécharger et explorer des préconfigurations de modèles",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Ne pas autoriser",
"Don't have an account?": "Vous n'avez pas de compte ?",
"Don't like the style": "Vous n'aimez pas le style ?",
"Done": "",
"Download": "Télécharger",
"Download canceled": "Téléchargement annulé",
"Download Database": "Télécharger la base de données",
@ -312,6 +318,7 @@
"Manage Models": "Gérer les modèles",
"Manage Ollama Models": "Gérer les modèles Ollama",
"Manage Pipelines": "Gérer les pipelines",
"Manage Valves": "",
"March": "Mars",
"Max Tokens (num_predict)": "Max Tokens (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Un maximum de 3 modèles peut être téléchargé simultanément. Veuillez réessayer plus tard.",
@ -460,10 +467,12 @@
"Seed": "Graine",
"Select a base model": "Sélectionner un modèle de base",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Sélectionnez un mode",
"Select a model": "Sélectionnez un modèle",
"Select a pipeline": "Sélectionner un pipeline",
"Select a pipeline url": "Sélectionnez une URL de pipeline",
"Select a tool": "",
"Select an Ollama instance": "Sélectionner une instance Ollama",
"Select Documents": "",
"Select model": "Sélectionnez un modèle",
@ -496,6 +505,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Afficher les raccourcis",
"Show your support!": "",
"Showcased creativity": "Créativité affichée",
"sidebar": "barre latérale",
"Sign in": "Se connecter",
@ -584,6 +594,7 @@
"Users": "Utilisateurs",
"Utilize": "Utiliser",
"Valid time units:": "Unités de temps valides :",
"Valves": "",
"variable": "variable",
"variable to have them replaced with clipboard content.": "variable pour les remplacer par le contenu du presse-papiers.",
"Version": "Version",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Autoriser la suppression du chat",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "caractères alphanumériques et tirets",
"Already have an account?": "Vous avez déjà un compte ?",
"an assistant": "un assistant",
@ -165,9 +166,13 @@
"Deleted {{name}}": "{{name}} supprimé",
"Description": "Description",
"Didn't fully follow instructions": "N'a pas suivi entièrement les instructions",
"Discover a function": "",
"Discover a model": "Découvrir un modèle",
"Discover a prompt": "Découvrir un prompt",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Découvrir, télécharger et explorer des prompts personnalisés",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Découvrir, télécharger et explorer des préconfigurations de modèles",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Ne pas autoriser",
"Don't have an account?": "Vous n'avez pas de compte ?",
"Don't like the style": "N'aime pas le style",
"Done": "",
"Download": "Télécharger",
"Download canceled": "Téléchargement annulé",
"Download Database": "Télécharger la base de données",
@ -312,6 +318,7 @@
"Manage Models": "Gérer les modèles",
"Manage Ollama Models": "Gérer les modèles Ollama",
"Manage Pipelines": "Gérer les pipelines",
"Manage Valves": "",
"March": "Mars",
"Max Tokens (num_predict)": "Tokens maximaux (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Un maximum de 3 modèles peut être téléchargé simultanément. Veuillez réessayer plus tard.",
@ -460,10 +467,12 @@
"Seed": "Graine",
"Select a base model": "Sélectionner un modèle de base",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Sélectionner un mode",
"Select a model": "Sélectionner un modèle",
"Select a pipeline": "Sélectionner un pipeline",
"Select a pipeline url": "Sélectionnez une URL de pipeline",
"Select a tool": "",
"Select an Ollama instance": "Sélectionner une instance Ollama",
"Select Documents": "",
"Select model": "Sélectionner un modèle",
@ -496,6 +505,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Afficher les raccourcis",
"Show your support!": "",
"Showcased creativity": "Créativité affichée",
"sidebar": "barre latérale",
"Sign in": "Se connecter",
@ -584,6 +594,7 @@
"Users": "Utilisateurs",
"Utilize": "Utiliser",
"Valid time units:": "Unités de temps valides :",
"Valves": "",
"variable": "variable",
"variable to have them replaced with clipboard content.": "variable pour les remplacer par le contenu du presse-papiers.",
"Version": "Version",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "אפשר מחיקת צ'אט",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "תווים אלפאנומריים ומקפים",
"Already have an account?": "כבר יש לך חשבון?",
"an assistant": "עוזר",
@ -165,9 +166,13 @@
"Deleted {{name}}": "נמחק {{name}}",
"Description": "תיאור",
"Didn't fully follow instructions": "לא עקב אחרי ההוראות באופן מלא",
"Discover a function": "",
"Discover a model": "גלה מודל",
"Discover a prompt": "גלה פקודה",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "גלה, הורד, וחקור פקודות מותאמות אישית",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "גלה, הורד, וחקור הגדרות מודל מוגדרות מראש",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "אל תאפשר",
"Don't have an account?": "אין לך חשבון?",
"Don't like the style": "לא אוהב את הסגנון",
"Done": "",
"Download": "הורד",
"Download canceled": "ההורדה בוטלה",
"Download Database": "הורד מסד נתונים",
@ -312,6 +318,7 @@
"Manage Models": "נהל מודלים",
"Manage Ollama Models": "נהל מודלים של Ollama",
"Manage Pipelines": "ניהול צינורות",
"Manage Valves": "",
"March": "מרץ",
"Max Tokens (num_predict)": "מקסימום אסימונים (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "ניתן להוריד מקסימום 3 מודלים בו זמנית. אנא נסה שוב מאוחר יותר.",
@ -460,10 +467,12 @@
"Seed": "זרע",
"Select a base model": "בחירת מודל בסיס",
"Select a engine": "",
"Select a function": "",
"Select a mode": "בחר מצב",
"Select a model": "בחר מודל",
"Select a pipeline": "בחר קו צינור",
"Select a pipeline url": "בחר כתובת URL של קו צינור",
"Select a tool": "",
"Select an Ollama instance": "בחר מופע של Ollama",
"Select Documents": "",
"Select model": "בחר מודל",
@ -496,6 +505,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "הצג קיצורי דרך",
"Show your support!": "",
"Showcased creativity": "הצגת יצירתיות",
"sidebar": "סרגל צד",
"Sign in": "הירשם",
@ -584,6 +594,7 @@
"Users": "משתמשים",
"Utilize": "שימוש",
"Valid time units:": "יחידות זמן תקינות:",
"Valves": "",
"variable": "משתנה",
"variable to have them replaced with clipboard content.": "משתנה להחליפו ב- clipboard תוכן.",
"Version": "גרסה",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "चैट हटाने की अनुमति दें",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "अल्फ़ान्यूमेरिक वर्ण और हाइफ़न",
"Already have an account?": "क्या आपके पास पहले से एक खाता मौजूद है?",
"an assistant": "एक सहायक",
@ -165,9 +166,13 @@
"Deleted {{name}}": "{{name}} हटा दिया गया",
"Description": "विवरण",
"Didn't fully follow instructions": "निर्देशों का पूरी तरह से पालन नहीं किया",
"Discover a function": "",
"Discover a model": "एक मॉडल की खोज करें",
"Discover a prompt": "प्रॉम्प्ट खोजें",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "कस्टम प्रॉम्प्ट को खोजें, डाउनलोड करें और एक्सप्लोर करें",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "मॉडल प्रीसेट खोजें, डाउनलोड करें और एक्सप्लोर करें",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "अनुमति न दें",
"Don't have an account?": "कोई खाता नहीं है?",
"Don't like the style": "शैली पसंद नहीं है",
"Done": "",
"Download": "डाउनलोड",
"Download canceled": "डाउनलोड रद्द किया गया",
"Download Database": "डेटाबेस डाउनलोड करें",
@ -312,6 +318,7 @@
"Manage Models": "मॉडल प्रबंधित करें",
"Manage Ollama Models": "Ollama मॉडल प्रबंधित करें",
"Manage Pipelines": "पाइपलाइनों का प्रबंधन करें",
"Manage Valves": "",
"March": "मार्च",
"Max Tokens (num_predict)": "अधिकतम टोकन (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "अधिकतम 3 मॉडल एक साथ डाउनलोड किये जा सकते हैं। कृपया बाद में पुन: प्रयास करें।",
@ -459,10 +466,12 @@
"Seed": "सीड्\u200c",
"Select a base model": "एक आधार मॉडल का चयन करें",
"Select a engine": "",
"Select a function": "",
"Select a mode": "एक मोड चुनें",
"Select a model": "एक मॉडल चुनें",
"Select a pipeline": "एक पाइपलाइन का चयन करें",
"Select a pipeline url": "एक पाइपलाइन url चुनें",
"Select a tool": "",
"Select an Ollama instance": "एक Ollama Instance चुनें",
"Select Documents": "",
"Select model": "मॉडल चुनें",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "शॉर्टकट दिखाएँ",
"Show your support!": "",
"Showcased creativity": "रचनात्मकता का प्रदर्शन किया",
"sidebar": "साइड बार",
"Sign in": "साइन इन",
@ -583,6 +593,7 @@
"Users": "उपयोगकर्ताओं",
"Utilize": "उपयोग करें",
"Valid time units:": "मान्य समय इकाइयाँ:",
"Valves": "",
"variable": "वेरिएबल",
"variable to have them replaced with clipboard content.": "उन्हें क्लिपबोर्ड सामग्री से बदलने के लिए वेरिएबल।",
"Version": "संस्करण",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Dopusti brisanje razgovora",
"Allow non-local voices": "Dopusti nelokalne glasove",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "alfanumerički znakovi i crtice",
"Already have an account?": "Već imate račun?",
"an assistant": "asistent",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Izbrisano {{name}}",
"Description": "Opis",
"Didn't fully follow instructions": "Nije u potpunosti slijedio upute",
"Discover a function": "",
"Discover a model": "Otkrijte model",
"Discover a prompt": "Otkrijte prompt",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Otkrijte, preuzmite i istražite prilagođene prompte",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Otkrijte, preuzmite i istražite unaprijed postavljene modele",
"Dismissible": "Odbaciti",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Ne dopuštaj",
"Don't have an account?": "Nemate račun?",
"Don't like the style": "Ne sviđa mi se stil",
"Done": "",
"Download": "Preuzimanje",
"Download canceled": "Preuzimanje otkazano",
"Download Database": "Preuzmi bazu podataka",
@ -312,6 +318,7 @@
"Manage Models": "Upravljanje modelima",
"Manage Ollama Models": "Upravljanje Ollama modelima",
"Manage Pipelines": "Upravljanje cjevovodima",
"Manage Valves": "",
"March": "Ožujak",
"Max Tokens (num_predict)": "Maksimalan broj tokena (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maksimalno 3 modela se mogu preuzeti istovremeno. Pokušajte ponovo kasnije.",
@ -460,10 +467,12 @@
"Seed": "Sjeme",
"Select a base model": "Odabir osnovnog modela",
"Select a engine": "Odaberite pogon",
"Select a function": "",
"Select a mode": "Odaberite način",
"Select a model": "Odaberite model",
"Select a pipeline": "Odabir kanala",
"Select a pipeline url": "Odabir URL-a kanala",
"Select a tool": "",
"Select an Ollama instance": "Odaberite Ollama instancu",
"Select Documents": "Odaberite dokumente",
"Select model": "Odaberite model",
@ -496,6 +505,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Pokaži prečace",
"Show your support!": "",
"Showcased creativity": "Prikazana kreativnost",
"sidebar": "bočna traka",
"Sign in": "Prijava",
@ -584,6 +594,7 @@
"Users": "Korisnici",
"Utilize": "Iskoristi",
"Valid time units:": "Važeće vremenske jedinice:",
"Valves": "",
"variable": "varijabla",
"variable to have them replaced with clipboard content.": "varijabla za zamjenu sadržajem međuspremnika.",
"Version": "Verzija",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Consenti l'eliminazione della chat",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "caratteri alfanumerici e trattini",
"Already have an account?": "Hai già un account?",
"an assistant": "un assistente",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Eliminato {{name}}",
"Description": "Descrizione",
"Didn't fully follow instructions": "Non ha seguito completamente le istruzioni",
"Discover a function": "",
"Discover a model": "Scopri un modello",
"Discover a prompt": "Scopri un prompt",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Scopri, scarica ed esplora prompt personalizzati",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Scopri, scarica ed esplora i preset del modello",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Non consentire",
"Don't have an account?": "Non hai un account?",
"Don't like the style": "Non ti piace lo stile",
"Done": "",
"Download": "Scarica",
"Download canceled": "Scaricamento annullato",
"Download Database": "Scarica database",
@ -312,6 +318,7 @@
"Manage Models": "Gestisci modelli",
"Manage Ollama Models": "Gestisci modelli Ollama",
"Manage Pipelines": "Gestire le pipeline",
"Manage Valves": "",
"March": "Marzo",
"Max Tokens (num_predict)": "Numero massimo di gettoni (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "È possibile scaricare un massimo di 3 modelli contemporaneamente. Riprova più tardi.",
@ -460,10 +467,12 @@
"Seed": "Seme",
"Select a base model": "Selezionare un modello di base",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Seleziona una modalità",
"Select a model": "Seleziona un modello",
"Select a pipeline": "Selezionare una tubazione",
"Select a pipeline url": "Selezionare l'URL di una pipeline",
"Select a tool": "",
"Select an Ollama instance": "Seleziona un'istanza Ollama",
"Select Documents": "",
"Select model": "Seleziona modello",
@ -496,6 +505,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Mostra",
"Show your support!": "",
"Showcased creativity": "Creatività messa in mostra",
"sidebar": "barra laterale",
"Sign in": "Accedi",
@ -584,6 +594,7 @@
"Users": "Utenti",
"Utilize": "Utilizza",
"Valid time units:": "Unità di tempo valide:",
"Valves": "",
"variable": "variabile",
"variable to have them replaced with clipboard content.": "variabile per farli sostituire con il contenuto degli appunti.",
"Version": "Versione",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "チャットの削除を許可",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "英数字とハイフン",
"Already have an account?": "すでにアカウントをお持ちですか?",
"an assistant": "アシスタント",
@ -165,9 +166,13 @@
"Deleted {{name}}": "{{name}}を削除しました",
"Description": "説明",
"Didn't fully follow instructions": "説明に沿って操作していませんでした",
"Discover a function": "",
"Discover a model": "モデルを検出する",
"Discover a prompt": "プロンプトを見つける",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "カスタムプロンプトを見つけて、ダウンロードして、探索",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "モデルプリセットを見つけて、ダウンロードして、探索",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "許可しない",
"Don't have an account?": "アカウントをお持ちではありませんか?",
"Don't like the style": "デザインが好きでない",
"Done": "",
"Download": "ダウンロードをキャンセルしました",
"Download canceled": "ダウンロードをキャンセルしました",
"Download Database": "データベースをダウンロード",
@ -312,6 +318,7 @@
"Manage Models": "モデルを管理",
"Manage Ollama Models": "Ollama モデルを管理",
"Manage Pipelines": "パイプラインの管理",
"Manage Valves": "",
"March": "3月",
"Max Tokens (num_predict)": "最大トークン数 (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "同時にダウンロードできるモデルは最大 3 つです。後でもう一度お試しください。",
@ -458,10 +465,12 @@
"Seed": "シード",
"Select a base model": "基本モデルの選択",
"Select a engine": "",
"Select a function": "",
"Select a mode": "モードを選択",
"Select a model": "モデルを選択",
"Select a pipeline": "パイプラインの選択",
"Select a pipeline url": "パイプラインの URL を選択する",
"Select a tool": "",
"Select an Ollama instance": "Ollama インスタンスを選択",
"Select Documents": "",
"Select model": "モデルを選択",
@ -494,6 +503,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "表示",
"Show your support!": "",
"Showcased creativity": "創造性を披露",
"sidebar": "サイドバー",
"Sign in": "サインイン",
@ -582,6 +592,7 @@
"Users": "ユーザー",
"Utilize": "活用",
"Valid time units:": "有効な時間単位:",
"Valves": "",
"variable": "変数",
"variable to have them replaced with clipboard content.": "クリップボードの内容に置き換える変数。",
"Version": "バージョン",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "მიმოწერის წაშლის დაშვება",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "ალფანუმერული სიმბოლოები და დეფისები",
"Already have an account?": "უკვე გაქვს ანგარიში?",
"an assistant": "ასისტენტი",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Deleted {{name}}",
"Description": "აღწერა",
"Didn't fully follow instructions": "ვერ ყველა ინფორმაციისთვის ვერ ხელახლა ჩაწერე",
"Discover a function": "",
"Discover a model": "გაიგეთ მოდელი",
"Discover a prompt": "აღმოაჩინეთ მოთხოვნა",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "აღმოაჩინეთ, ჩამოტვირთეთ და შეისწავლეთ მორგებული მოთხოვნები",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "აღმოაჩინეთ, ჩამოტვირთეთ და შეისწავლეთ მოდელის წინასწარ პარამეტრები",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "არ დაუშვა",
"Don't have an account?": "არ გაქვს ანგარიში?",
"Don't like the style": "არ ეთიკურია ფართოდ",
"Done": "",
"Download": "ჩამოტვირთვა გაუქმებულია",
"Download canceled": "ჩამოტვირთვა გაუქმებულია",
"Download Database": "გადმოწერე მონაცემთა ბაზა",
@ -312,6 +318,7 @@
"Manage Models": "მოდელების მართვა",
"Manage Ollama Models": "Ollama მოდელების მართვა",
"Manage Pipelines": "მილსადენების მართვა",
"Manage Valves": "",
"March": "მარტივი",
"Max Tokens (num_predict)": "მაქს ტოკენსი (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "მაქსიმუმ 3 მოდელის ჩამოტვირთვა შესაძლებელია ერთდროულად. Გთხოვთ სცადოთ მოგვიანებით.",
@ -459,10 +466,12 @@
"Seed": "სიდი",
"Select a base model": "აირჩიეთ ბაზის მოდელი",
"Select a engine": "",
"Select a function": "",
"Select a mode": "რეჟიმის არჩევა",
"Select a model": "მოდელის არჩევა",
"Select a pipeline": "აირჩიეთ მილსადენი",
"Select a pipeline url": "აირჩიეთ მილსადენის url",
"Select a tool": "",
"Select an Ollama instance": "Ollama ინსტანსის არჩევა",
"Select Documents": "",
"Select model": "მოდელის არჩევა",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "მალსახმობების ჩვენება",
"Show your support!": "",
"Showcased creativity": "ჩვენებული ქონება",
"sidebar": "საიდბარი",
"Sign in": "ავტორიზაცია",
@ -583,6 +593,7 @@
"Users": "მომხმარებლები",
"Utilize": "გამოყენება",
"Valid time units:": "მოქმედი დროის ერთეულები",
"Valves": "",
"variable": "ცვლადი",
"variable to have them replaced with clipboard content.": "ცვლადი, რომ შეცვალოს ისინი ბუფერში შიგთავსით.",
"Version": "ვერსია",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "채팅 삭제 허용",
"Allow non-local voices": "외부 음성 허용",
"Allow User Location": "사용자 위치 활용 허용",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "영문자, 숫자, 하이픈",
"Already have an account?": "이미 계정이 있으신가요?",
"an assistant": "어시스턴트",
@ -165,9 +166,13 @@
"Deleted {{name}}": "{{name}}을(를) 삭제했습니다.",
"Description": "설명",
"Didn't fully follow instructions": "완전히 지침을 따르지 않음",
"Discover a function": "",
"Discover a model": "모델 검색",
"Discover a prompt": "프롬프트 검색",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "사용자 정의 프롬프트 검색, 다운로드 및 탐색",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "모델 사전 설정 검색, 다운로드 및 탐색",
"Dismissible": "제외가능",
"Display Emoji in Call": "콜(call)에서 이모지 표시",
@ -180,6 +185,7 @@
"Don't Allow": "허용 안 함",
"Don't have an account?": "계정이 없으신가요?",
"Don't like the style": "스타일을 좋아하지 않으세요?",
"Done": "",
"Download": "다운로드",
"Download canceled": "다운로드 취소",
"Download Database": "데이터베이스 다운로드",
@ -312,6 +318,7 @@
"Manage Models": "모델 관리",
"Manage Ollama Models": "Ollama 모델 관리",
"Manage Pipelines": "파이프라인 관리",
"Manage Valves": "",
"March": "3월",
"Max Tokens (num_predict)": "최대 토큰(num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "최대 3개의 모델을 동시에 다운로드할 수 있습니다. 나중에 다시 시도하세요.",
@ -459,10 +466,12 @@
"Seed": "시드",
"Select a base model": "기본 모델 선택",
"Select a engine": "엔진 선택",
"Select a function": "",
"Select a mode": "모드 선택",
"Select a model": "모델 선택",
"Select a pipeline": "파이프라인 선택",
"Select a pipeline url": "파이프라인 URL 선택",
"Select a tool": "",
"Select an Ollama instance": "Ollama 인스턴스 선택",
"Select Documents": "문서 선택",
"Select model": "모델 선택",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "사용자용 계정 보류 설명창에, 관리자 상세 정보 노출",
"Show Model": "",
"Show shortcuts": "단축키 보기",
"Show your support!": "",
"Showcased creativity": "창의성 발휘",
"sidebar": "사이드바",
"Sign in": "로그인",
@ -583,6 +593,7 @@
"Users": "사용자",
"Utilize": "활용",
"Valid time units:": "유효 시간 단위:",
"Valves": "",
"variable": "변수",
"variable to have them replaced with clipboard content.": "변수를 사용하여 클립보드 내용으로 바꾸세요.",
"Version": "버전",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Leisti pokalbių ištrynimą",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "skaičiai, raidės ir brūkšneliai",
"Already have an account?": "Ar jau turite paskyrą?",
"an assistant": "assistentas",
@ -165,9 +166,13 @@
"Deleted {{name}}": "",
"Description": "Aprašymas",
"Didn't fully follow instructions": "Pilnai nesekė instrukcijų",
"Discover a function": "",
"Discover a model": "",
"Discover a prompt": "Atrasti užklausas",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Atrasti ir parsisiųsti užklausas",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Atrasti ir parsisiųsti modelių konfigūracija",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Neleisti",
"Don't have an account?": "Neturite paskyros?",
"Don't like the style": "Nepatinka stilius",
"Done": "",
"Download": "Parsisiųsti",
"Download canceled": "Parsisiuntimas atšauktas",
"Download Database": "Parsisiųsti duomenų bazę",
@ -312,6 +318,7 @@
"Manage Models": "Tvarkyti modelius",
"Manage Ollama Models": "Tvarkyti Ollama modelius",
"Manage Pipelines": "",
"Manage Valves": "",
"March": "Kovas",
"Max Tokens (num_predict)": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Daugiausiai trys modeliai gali būti parsisiunčiami vienu metu.",
@ -461,10 +468,12 @@
"Seed": "Sėkla",
"Select a base model": "",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Pasirinkti režimą",
"Select a model": "Pasirinkti modelį",
"Select a pipeline": "",
"Select a pipeline url": "",
"Select a tool": "",
"Select an Ollama instance": "Pasirinkti Ollama instanciją",
"Select Documents": "",
"Select model": "Pasirinkti modelį",
@ -497,6 +506,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Rodyti trumpinius",
"Show your support!": "",
"Showcased creativity": "Kūrybingų užklausų paroda",
"sidebar": "šoninis meniu",
"Sign in": "Prisijungti",
@ -585,6 +595,7 @@
"Users": "Naudotojai",
"Utilize": "Naudoti",
"Valid time units:": "Teisingūs laiko vienetai :",
"Valves": "",
"variable": "kintamasis",
"variable to have them replaced with clipboard content.": "kintamoji pakeičiama kopijuoklės turiniu.",
"Version": "Versija",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Tillat sletting av chatter",
"Allow non-local voices": "Tillat ikke-lokale stemmer",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "alfanumeriske tegn og bindestreker",
"Already have an account?": "Har du allerede en konto?",
"an assistant": "en assistent",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Slettet {{name}}",
"Description": "Beskrivelse",
"Didn't fully follow instructions": "Fulgte ikke instruksjonene fullt ut",
"Discover a function": "",
"Discover a model": "Oppdag en modell",
"Discover a prompt": "Oppdag en prompt",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Oppdag, last ned og utforsk egendefinerte prompts",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Oppdag, last ned og utforsk modellforhåndsinnstillinger",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Ikke tillat",
"Don't have an account?": "Har du ikke en konto?",
"Don't like the style": "Liker ikke stilen",
"Done": "",
"Download": "Last ned",
"Download canceled": "Nedlasting avbrutt",
"Download Database": "Last ned database",
@ -312,6 +318,7 @@
"Manage Models": "Administrer modeller",
"Manage Ollama Models": "Administrer Ollama-modeller",
"Manage Pipelines": "Administrer pipelines",
"Manage Valves": "",
"March": "Mars",
"Max Tokens (num_predict)": "Maks antall tokens (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maksimalt 3 modeller kan lastes ned samtidig. Vennligst prøv igjen senere.",
@ -459,10 +466,12 @@
"Seed": "Seed",
"Select a base model": "Velg en grunnmodell",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Velg en modus",
"Select a model": "Velg en modell",
"Select a pipeline": "Velg en pipeline",
"Select a pipeline url": "Velg en pipeline-URL",
"Select a tool": "",
"Select an Ollama instance": "Velg en Ollama-instans",
"Select Documents": "",
"Select model": "Velg modell",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "Vis administratordetaljer i ventende kontooverlay",
"Show Model": "",
"Show shortcuts": "Vis snarveier",
"Show your support!": "",
"Showcased creativity": "Vist frem kreativitet",
"sidebar": "sidefelt",
"Sign in": "Logg inn",
@ -583,6 +593,7 @@
"Users": "Brukere",
"Utilize": "Utnytt",
"Valid time units:": "Gyldige tidsenheter:",
"Valves": "",
"variable": "variabel",
"variable to have them replaced with clipboard content.": "variabel for å få dem erstattet med utklippstavleinnhold.",
"Version": "Versjon",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Sta Chat Verwijdering toe",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "alfanumerieke karakters en streepjes",
"Already have an account?": "Heb je al een account?",
"an assistant": "een assistent",
@ -165,9 +166,13 @@
"Deleted {{name}}": "{{name}} verwijderd",
"Description": "Beschrijving",
"Didn't fully follow instructions": "Ik heb niet alle instructies volgt",
"Discover a function": "",
"Discover a model": "Ontdek een model",
"Discover a prompt": "Ontdek een prompt",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Ontdek, download en verken aangepaste prompts",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Ontdek, download en verken model presets",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Niet Toestaan",
"Don't have an account?": "Heb je geen account?",
"Don't like the style": "Je vindt het stijl niet?",
"Done": "",
"Download": "Download",
"Download canceled": "Download geannuleerd",
"Download Database": "Download Database",
@ -312,6 +318,7 @@
"Manage Models": "Beheer Modellen",
"Manage Ollama Models": "Beheer Ollama Modellen",
"Manage Pipelines": "Pijplijnen beheren",
"Manage Valves": "",
"March": "Maart",
"Max Tokens (num_predict)": "Max Tokens (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maximaal 3 modellen kunnen tegelijkertijd worden gedownload. Probeer het later opnieuw.",
@ -459,10 +466,12 @@
"Seed": "Seed",
"Select a base model": "Selecteer een basismodel",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Selecteer een modus",
"Select a model": "Selecteer een model",
"Select a pipeline": "Selecteer een pijplijn",
"Select a pipeline url": "Selecteer een pijplijn-URL",
"Select a tool": "",
"Select an Ollama instance": "Selecteer een Ollama instantie",
"Select Documents": "",
"Select model": "Selecteer een model",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Toon snelkoppelingen",
"Show your support!": "",
"Showcased creativity": "Tooncase creativiteit",
"sidebar": "sidebar",
"Sign in": "Inloggen",
@ -583,6 +593,7 @@
"Users": "Gebruikers",
"Utilize": "Utilize",
"Valid time units:": "Geldige tijdseenheden:",
"Valves": "",
"variable": "variabele",
"variable to have them replaced with clipboard content.": "variabele om ze te laten vervangen door klembord inhoud.",
"Version": "Versie",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "ਗੱਲਬਾਤ ਮਿਟਾਉਣ ਦੀ ਆਗਿਆ ਦਿਓ",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "ਅਲਫ਼ਾਨਯੂਮੈਰਿਕ ਅੱਖਰ ਅਤੇ ਹਾਈਫਨ",
"Already have an account?": "ਪਹਿਲਾਂ ਹੀ ਖਾਤਾ ਹੈ?",
"an assistant": "ਇੱਕ ਸਹਾਇਕ",
@ -165,9 +166,13 @@
"Deleted {{name}}": "ਮਿਟਾ ਦਿੱਤਾ ਗਿਆ {{name}}",
"Description": "ਵਰਣਨਾ",
"Didn't fully follow instructions": "ਹਦਾਇਤਾਂ ਨੂੰ ਪੂਰੀ ਤਰ੍ਹਾਂ ਫਾਲੋ ਨਹੀਂ ਕੀਤਾ",
"Discover a function": "",
"Discover a model": "ਇੱਕ ਮਾਡਲ ਲੱਭੋ",
"Discover a prompt": "ਇੱਕ ਪ੍ਰੰਪਟ ਖੋਜੋ",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "ਕਸਟਮ ਪ੍ਰੰਪਟਾਂ ਨੂੰ ਖੋਜੋ, ਡਾਊਨਲੋਡ ਕਰੋ ਅਤੇ ਪੜਚੋਲ ਕਰੋ",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "ਮਾਡਲ ਪ੍ਰੀਸੈਟਾਂ ਨੂੰ ਖੋਜੋ, ਡਾਊਨਲੋਡ ਕਰੋ ਅਤੇ ਪੜਚੋਲ ਕਰੋ",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "ਆਗਿਆ ਨਾ ਦਿਓ",
"Don't have an account?": "ਖਾਤਾ ਨਹੀਂ ਹੈ?",
"Don't like the style": "ਸਟਾਈਲ ਪਸੰਦ ਨਹੀਂ ਹੈ",
"Done": "",
"Download": "ਡਾਊਨਲੋਡ",
"Download canceled": "ਡਾਊਨਲੋਡ ਰੱਦ ਕੀਤਾ ਗਿਆ",
"Download Database": "ਡਾਟਾਬੇਸ ਡਾਊਨਲੋਡ ਕਰੋ",
@ -312,6 +318,7 @@
"Manage Models": "ਮਾਡਲਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ",
"Manage Ollama Models": "ਓਲਾਮਾ ਮਾਡਲਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ",
"Manage Pipelines": "ਪਾਈਪਲਾਈਨਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ",
"Manage Valves": "",
"March": "ਮਾਰਚ",
"Max Tokens (num_predict)": "ਮੈਕਸ ਟੋਕਨ (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "ਇੱਕ ਸਮੇਂ ਵਿੱਚ ਵੱਧ ਤੋਂ ਵੱਧ 3 ਮਾਡਲ ਡਾਊਨਲੋਡ ਕੀਤੇ ਜਾ ਸਕਦੇ ਹਨ। ਕਿਰਪਾ ਕਰਕੇ ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।",
@ -459,10 +466,12 @@
"Seed": "ਬੀਜ",
"Select a base model": "ਆਧਾਰ ਮਾਡਲ ਚੁਣੋ",
"Select a engine": "",
"Select a function": "",
"Select a mode": "ਇੱਕ ਮੋਡ ਚੁਣੋ",
"Select a model": "ਇੱਕ ਮਾਡਲ ਚੁਣੋ",
"Select a pipeline": "ਪਾਈਪਲਾਈਨ ਚੁਣੋ",
"Select a pipeline url": "ਪਾਈਪਲਾਈਨ URL ਚੁਣੋ",
"Select a tool": "",
"Select an Ollama instance": "ਇੱਕ ਓਲਾਮਾ ਇੰਸਟੈਂਸ ਚੁਣੋ",
"Select Documents": "",
"Select model": "ਮਾਡਲ ਚੁਣੋ",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "ਸ਼ਾਰਟਕਟ ਦਿਖਾਓ",
"Show your support!": "",
"Showcased creativity": "ਸਿਰਜਣਾਤਮਕਤਾ ਦਿਖਾਈ",
"sidebar": "ਸਾਈਡਬਾਰ",
"Sign in": "ਸਾਈਨ ਇਨ ਕਰੋ",
@ -583,6 +593,7 @@
"Users": "ਉਪਭੋਗਤਾ",
"Utilize": "ਵਰਤੋਂ",
"Valid time units:": "ਵੈਧ ਸਮਾਂ ਇਕਾਈਆਂ:",
"Valves": "",
"variable": "ਵੈਰੀਏਬਲ",
"variable to have them replaced with clipboard content.": "ਕਲਿੱਪਬੋਰਡ ਸਮੱਗਰੀ ਨਾਲ ਬਦਲਣ ਲਈ ਵੈਰੀਏਬਲ।",
"Version": "ਵਰਜਨ",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Pozwól na usuwanie czatu",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "znaki alfanumeryczne i myślniki",
"Already have an account?": "Masz już konto?",
"an assistant": "asystent",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Usunięto {{name}}",
"Description": "Opis",
"Didn't fully follow instructions": "Nie postępował zgodnie z instrukcjami",
"Discover a function": "",
"Discover a model": "Odkryj model",
"Discover a prompt": "Odkryj prompt",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Odkryj, pobierz i eksploruj niestandardowe prompty",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Odkryj, pobierz i eksploruj ustawienia modeli",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Nie zezwalaj",
"Don't have an account?": "Nie masz konta?",
"Don't like the style": "Nie podobał mi się styl",
"Done": "",
"Download": "Pobieranie",
"Download canceled": "Pobieranie przerwane",
"Download Database": "Pobierz bazę danych",
@ -312,6 +318,7 @@
"Manage Models": "Zarządzaj modelami",
"Manage Ollama Models": "Zarządzaj modelami Ollama",
"Manage Pipelines": "Zarządzanie potokami",
"Manage Valves": "",
"March": "Marzec",
"Max Tokens (num_predict)": "Maksymalna liczba żetonów (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maksymalnie 3 modele można pobierać jednocześnie. Spróbuj ponownie później.",
@ -461,10 +468,12 @@
"Seed": "Seed",
"Select a base model": "Wybieranie modelu bazowego",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Wybierz tryb",
"Select a model": "Wybierz model",
"Select a pipeline": "Wybieranie potoku",
"Select a pipeline url": "Wybieranie adresu URL potoku",
"Select a tool": "",
"Select an Ollama instance": "Wybierz instancję Ollama",
"Select Documents": "",
"Select model": "Wybierz model",
@ -497,6 +506,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Pokaż skróty",
"Show your support!": "",
"Showcased creativity": "Pokaz kreatywności",
"sidebar": "Panel boczny",
"Sign in": "Zaloguj się",
@ -585,6 +595,7 @@
"Users": "Użytkownicy",
"Utilize": "Wykorzystaj",
"Valid time units:": "Poprawne jednostki czasu:",
"Valves": "",
"variable": "zmienna",
"variable to have them replaced with clipboard content.": "zmienna która zostanie zastąpiona zawartością schowka.",
"Version": "Wersja",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Permitir Exclusão de Bate-papo",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "caracteres alfanuméricos e hífens",
"Already have an account?": "Já tem uma conta?",
"an assistant": "um assistente",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Excluído {{nome}}",
"Description": "Descrição",
"Didn't fully follow instructions": "Não seguiu instruções com precisão",
"Discover a function": "",
"Discover a model": "Descubra um modelo",
"Discover a prompt": "Descobrir um prompt",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Descubra, baixe e explore prompts personalizados",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Descubra, baixe e explore predefinições de modelo",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Não Permitir",
"Don't have an account?": "Não tem uma conta?",
"Don't like the style": "Não gosta do estilo",
"Done": "",
"Download": "Baixar",
"Download canceled": "Download cancelado",
"Download Database": "Baixar Banco de Dados",
@ -312,6 +318,7 @@
"Manage Models": "Gerenciar Modelos",
"Manage Ollama Models": "Gerenciar Modelos Ollama",
"Manage Pipelines": "Gerenciar pipelines",
"Manage Valves": "",
"March": "Março",
"Max Tokens (num_predict)": "Fichas máximas (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Máximo de 3 modelos podem ser baixados simultaneamente. Tente novamente mais tarde.",
@ -460,10 +467,12 @@
"Seed": "Semente",
"Select a base model": "Selecione um modelo base",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Selecione um modo",
"Select a model": "Selecione um modelo",
"Select a pipeline": "Selecione um pipeline",
"Select a pipeline url": "Selecione uma URL de pipeline",
"Select a tool": "",
"Select an Ollama instance": "Selecione uma instância Ollama",
"Select Documents": "",
"Select model": "Selecione um modelo",
@ -496,6 +505,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Mostrar",
"Show your support!": "",
"Showcased creativity": "Criatividade Exibida",
"sidebar": "barra lateral",
"Sign in": "Entrar",
@ -584,6 +594,7 @@
"Users": "Usuários",
"Utilize": "Utilizar",
"Valid time units:": "Unidades de tempo válidas:",
"Valves": "",
"variable": "variável",
"variable to have them replaced with clipboard content.": "variável para que sejam substituídos pelo conteúdo da área de transferência.",
"Version": "Versão",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Permitir Exclusão de Conversa",
"Allow non-local voices": "Permitir vozes não locais",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "caracteres alfanuméricos e hífens",
"Already have an account?": "Já tem uma conta?",
"an assistant": "um assistente",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Apagado {{name}}",
"Description": "Descrição",
"Didn't fully follow instructions": "Não seguiu instruções com precisão",
"Discover a function": "",
"Discover a model": "Descubra um modelo",
"Discover a prompt": "Descobrir um prompt",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Descubra, descarregue e explore prompts personalizados",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Descubra, descarregue e explore predefinições de modelo",
"Dismissible": "Dispensável",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Não Permitir",
"Don't have an account?": "Não tem uma conta?",
"Don't like the style": "Não gosta do estilo",
"Done": "",
"Download": "Descarregar",
"Download canceled": "Download cancelado",
"Download Database": "Descarregar Base de Dados",
@ -312,6 +318,7 @@
"Manage Models": "Gerir Modelos",
"Manage Ollama Models": "Gerir Modelos Ollama",
"Manage Pipelines": "Gerir pipelines",
"Manage Valves": "",
"March": "Março",
"Max Tokens (num_predict)": "Máx Tokens (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "O máximo de 3 modelos podem ser descarregados simultaneamente. Tente novamente mais tarde.",
@ -460,10 +467,12 @@
"Seed": "Semente",
"Select a base model": "Selecione um modelo base",
"Select a engine": "Selecione um motor",
"Select a function": "",
"Select a mode": "Selecione um modo",
"Select a model": "Selecione um modelo",
"Select a pipeline": "Selecione um pipeline",
"Select a pipeline url": "Selecione um URL de pipeline",
"Select a tool": "",
"Select an Ollama instance": "Selecione uma instância Ollama",
"Select Documents": "",
"Select model": "Selecione o modelo",
@ -496,6 +505,7 @@
"Show Admin Details in Account Pending Overlay": "Mostrar Detalhes do Administrador na sobreposição de Conta Pendente",
"Show Model": "",
"Show shortcuts": "Mostrar atalhos",
"Show your support!": "",
"Showcased creativity": "Criatividade Exibida",
"sidebar": "barra lateral",
"Sign in": "Entrar",
@ -584,6 +594,7 @@
"Users": "Utilizadores",
"Utilize": "Utilizar",
"Valid time units:": "Unidades de tempo válidas:",
"Valves": "",
"variable": "variável",
"variable to have them replaced with clipboard content.": "variável para que sejam substituídos pelo conteúdo da área de transferência.",
"Version": "Versão",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Дозволять удаление чат",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "буквенно цифровые символы и дефисы",
"Already have an account?": "у вас уже есть аккаунт?",
"an assistant": "ассистент",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Удалено {{name}}",
"Description": "Описание",
"Didn't fully follow instructions": "Не полностью следул инструкциям",
"Discover a function": "",
"Discover a model": "Откройте для себя модель",
"Discover a prompt": "Найти промт",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Находите, загружайте и исследуйте настраиваемые промты",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Находите, загружайте и исследуйте предустановки модели",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Не разрешать",
"Don't have an account?": "у вас не есть аккаунт?",
"Don't like the style": "Не нравится стиль",
"Done": "",
"Download": "Загрузить",
"Download canceled": "Загрузка отменена",
"Download Database": "Загрузить базу данных",
@ -312,6 +318,7 @@
"Manage Models": "Управление моделями",
"Manage Ollama Models": "Управление моделями Ollama",
"Manage Pipelines": "Управление конвейерами",
"Manage Valves": "",
"March": "Март",
"Max Tokens (num_predict)": "Максимальное количество жетонов (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Максимальное количество моделей для загрузки одновременно - 3. Пожалуйста, попробуйте позже.",
@ -461,10 +468,12 @@
"Seed": "Сид",
"Select a base model": "Выбор базовой модели",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Выберите режим",
"Select a model": "Выберите модель",
"Select a pipeline": "Выбор конвейера",
"Select a pipeline url": "Выберите URL-адрес конвейера",
"Select a tool": "",
"Select an Ollama instance": "Выберите экземпляр Ollama",
"Select Documents": "",
"Select model": "Выберите модель",
@ -497,6 +506,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Показать клавиатурные сокращения",
"Show your support!": "",
"Showcased creativity": "Показать творчество",
"sidebar": "боковая панель",
"Sign in": "Войти",
@ -585,6 +595,7 @@
"Users": "Пользователи",
"Utilize": "Использовать",
"Valid time units:": "Допустимые единицы времени:",
"Valves": "",
"variable": "переменная",
"variable to have them replaced with clipboard content.": "переменная, чтобы их заменить содержимым буфера обмена.",
"Version": "Версия",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Дозволи брисање ћаскања",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "алфанумерички знакови и цртице",
"Already have an account?": "Већ имате налог?",
"an assistant": "помоћник",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Избрисано {{наме}}",
"Description": "Опис",
"Didn't fully follow instructions": "Упутства нису праћена у потпуности",
"Discover a function": "",
"Discover a model": "Откријте модел",
"Discover a prompt": "Откриј упит",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Откријте, преузмите и истражите прилагођене упите",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Откријте, преузмите и истражите образце модела",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "Не дозволи",
"Don't have an account?": "Немате налог?",
"Don't like the style": "Не свиђа ми се стил",
"Done": "",
"Download": "Преузми",
"Download canceled": "Преузимање отказано",
"Download Database": "Преузми базу података",
@ -312,6 +318,7 @@
"Manage Models": "Управљај моделима",
"Manage Ollama Models": "Управљај Ollama моделима",
"Manage Pipelines": "Управљање цевоводима",
"Manage Valves": "",
"March": "Март",
"Max Tokens (num_predict)": "Маx Токенс (нум_предицт)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Највише 3 модела могу бити преузета истовремено. Покушајте поново касније.",
@ -460,10 +467,12 @@
"Seed": "Семе",
"Select a base model": "Избор основног модела",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Изабери режим",
"Select a model": "Изабери модел",
"Select a pipeline": "Избор цевовода",
"Select a pipeline url": "Избор урл адресе цевовода",
"Select a tool": "",
"Select an Ollama instance": "Изабери Ollama инстанцу",
"Select Documents": "",
"Select model": "Изабери модел",
@ -496,6 +505,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Прикажи пречице",
"Show your support!": "",
"Showcased creativity": "Приказана креативност",
"sidebar": "бочна трака",
"Sign in": "Пријави се",
@ -584,6 +594,7 @@
"Users": "Корисници",
"Utilize": "Искористи",
"Valid time units:": "Важеће временске јединице:",
"Valves": "",
"variable": "променљива",
"variable to have them replaced with clipboard content.": "променљива за замену са садржајем оставе.",
"Version": "Издање",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Tillåt chattborttagning",
"Allow non-local voices": "Tillåt icke-lokala röster",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "alfanumeriska tecken och bindestreck",
"Already have an account?": "Har du redan ett konto?",
"an assistant": "en assistent",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Borttagen {{name}}",
"Description": "Beskrivning",
"Didn't fully follow instructions": "Följde inte instruktionerna",
"Discover a function": "",
"Discover a model": "Upptäck en modell",
"Discover a prompt": "Upptäck en instruktion",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Upptäck, ladda ner och utforska anpassade instruktioner",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Upptäck, ladda ner och utforska modellförinställningar",
"Dismissible": "Kan stängas",
"Display Emoji in Call": "Visa Emoji under samtal",
@ -180,6 +185,7 @@
"Don't Allow": "Tillåt inte",
"Don't have an account?": "Har du inget konto?",
"Don't like the style": "Tycker inte om utseendet",
"Done": "",
"Download": "Ladda ner",
"Download canceled": "Nedladdning avbruten",
"Download Database": "Ladda ner databas",
@ -312,6 +318,7 @@
"Manage Models": "Hantera modeller",
"Manage Ollama Models": "Hantera Ollama-modeller",
"Manage Pipelines": "Hantera rörledningar",
"Manage Valves": "",
"March": "mars",
"Max Tokens (num_predict)": "Maximalt antal tokens (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Högst 3 modeller kan laddas ner samtidigt. Vänligen försök igen senare.",
@ -459,10 +466,12 @@
"Seed": "Seed",
"Select a base model": "Välj en basmodell",
"Select a engine": "Välj en motor",
"Select a function": "",
"Select a mode": "Välj ett läge",
"Select a model": "Välj en modell",
"Select a pipeline": "Välj en rörledning",
"Select a pipeline url": "Välj en URL för rörledningen",
"Select a tool": "",
"Select an Ollama instance": "Välj en Ollama-instans",
"Select Documents": "Välj dokument",
"Select model": "Välj en modell",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "Visa administratörsinformation till väntande konton",
"Show Model": "",
"Show shortcuts": "Visa genvägar",
"Show your support!": "",
"Showcased creativity": "Visade kreativitet",
"sidebar": "sidofält",
"Sign in": "Logga in",
@ -583,6 +593,7 @@
"Users": "Användare",
"Utilize": "Använd",
"Valid time units:": "Giltiga tidsenheter:",
"Valves": "",
"variable": "variabel",
"variable to have them replaced with clipboard content.": "variabel för att få dem ersatta med urklippsinnehåll.",
"Version": "Version",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "",
"Already have an account?": "",
"an assistant": "",
@ -165,9 +166,13 @@
"Deleted {{name}}": "",
"Description": "",
"Didn't fully follow instructions": "",
"Discover a function": "",
"Discover a model": "",
"Discover a prompt": "",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "",
"Don't have an account?": "",
"Don't like the style": "",
"Done": "",
"Download": "",
"Download canceled": "",
"Download Database": "",
@ -312,6 +318,7 @@
"Manage Models": "",
"Manage Ollama Models": "",
"Manage Pipelines": "",
"Manage Valves": "",
"March": "",
"Max Tokens (num_predict)": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "",
@ -459,10 +466,12 @@
"Seed": "",
"Select a base model": "",
"Select a engine": "",
"Select a function": "",
"Select a mode": "",
"Select a model": "",
"Select a pipeline": "",
"Select a pipeline url": "",
"Select a tool": "",
"Select an Ollama instance": "",
"Select Documents": "",
"Select model": "",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "",
"Show your support!": "",
"Showcased creativity": "",
"sidebar": "",
"Sign in": "",
@ -583,6 +593,7 @@
"Users": "",
"Utilize": "",
"Valid time units:": "",
"Valves": "",
"variable": "",
"variable to have them replaced with clipboard content.": "",
"Version": "",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Sohbet Silmeye İzin Ver",
"Allow non-local voices": "Yerel olmayan seslere izin verin",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "alfanumerik karakterler ve tireler",
"Already have an account?": "Zaten bir hesabınız mı var?",
"an assistant": "bir asistan",
@ -165,9 +166,13 @@
"Deleted {{name}}": "{{name}} silindi",
"Description": "Açıklama",
"Didn't fully follow instructions": "Talimatları tam olarak takip etmedi",
"Discover a function": "",
"Discover a model": "Bir model keşfedin",
"Discover a prompt": "Bir prompt keşfedin",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Özel promptları keşfedin, indirin ve inceleyin",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Model ön ayarlarını keşfedin, indirin ve inceleyin",
"Dismissible": "",
"Display Emoji in Call": "",
@ -180,6 +185,7 @@
"Don't Allow": "İzin Verme",
"Don't have an account?": "Hesabınız yok mu?",
"Don't like the style": "Tarzını beğenmedim",
"Done": "",
"Download": "İndir",
"Download canceled": "İndirme iptal edildi",
"Download Database": "Veritabanını İndir",
@ -312,6 +318,7 @@
"Manage Models": "Modelleri Yönet",
"Manage Ollama Models": "Ollama Modellerini Yönet",
"Manage Pipelines": "Pipeline'ları Yönet",
"Manage Valves": "",
"March": "Mart",
"Max Tokens (num_predict)": "Maksimum Token (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Aynı anda en fazla 3 model indirilebilir. Lütfen daha sonra tekrar deneyin.",
@ -459,10 +466,12 @@
"Seed": "Seed",
"Select a base model": "Bir temel model seç",
"Select a engine": "",
"Select a function": "",
"Select a mode": "Bir mod seç",
"Select a model": "Bir model seç",
"Select a pipeline": "Bir pipeline seç",
"Select a pipeline url": "Bir pipeline URL'si seç",
"Select a tool": "",
"Select an Ollama instance": "Bir Ollama örneği seçin",
"Select Documents": "",
"Select model": "Model seç",
@ -495,6 +504,7 @@
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show shortcuts": "Kısayolları göster",
"Show your support!": "",
"Showcased creativity": "Sergilenen yaratıcılık",
"sidebar": "kenar çubuğu",
"Sign in": "Oturum aç",
@ -583,6 +593,7 @@
"Users": "Kullanıcılar",
"Utilize": "Kullan",
"Valid time units:": "Geçerli zaman birimleri:",
"Valves": "",
"variable": "değişken",
"variable to have them replaced with clipboard content.": "panodaki içerikle değiştirilmesi için değişken.",
"Version": "Sürüm",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Дозволити видалення чату",
"Allow non-local voices": "Дозволити не локальні голоси",
"Allow User Location": "Доступ до місцезнаходження",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "алфавітно-цифрові символи та дефіси",
"Already have an account?": "Вже є обліковий запис?",
"an assistant": "асистента",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Видалено {{name}}",
"Description": "Опис",
"Didn't fully follow instructions": "Не повністю дотримувалися інструкцій",
"Discover a function": "",
"Discover a model": "Знайдіть модель",
"Discover a prompt": "Знайти промт",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Знайдіть, завантажте та досліджуйте налаштовані промти",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Знайдіть, завантажте та досліджуйте налаштовані налаштування моделі",
"Dismissible": "Неприйнятно",
"Display Emoji in Call": "Відображати емодзі у викликах",
@ -180,6 +185,7 @@
"Don't Allow": "Не дозволяти",
"Don't have an account?": "Немає облікового запису?",
"Don't like the style": "Не подобається стиль",
"Done": "",
"Download": "Завантажити",
"Download canceled": "Завантаження скасовано",
"Download Database": "Завантажити базу даних",
@ -312,6 +318,7 @@
"Manage Models": "Керування моделями",
"Manage Ollama Models": "Керування моделями Ollama",
"Manage Pipelines": "Управління Pipelines",
"Manage Valves": "",
"March": "Березень",
"Max Tokens (num_predict)": "Макс токенів (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Максимум 3 моделі можна завантажити одночасно. Будь ласка, спробуйте пізніше.",
@ -461,10 +468,12 @@
"Seed": "Сід",
"Select a base model": "Вибрати базову модель",
"Select a engine": "Виберіть рушій",
"Select a function": "",
"Select a mode": "Оберіть режим",
"Select a model": "Виберіть модель",
"Select a pipeline": "Виберіть pipeline",
"Select a pipeline url": "Виберіть адресу pipeline",
"Select a tool": "",
"Select an Ollama instance": "Виберіть екземпляр Ollama",
"Select Documents": "Виберіть документи",
"Select model": "Вибрати модель",
@ -497,6 +506,7 @@
"Show Admin Details in Account Pending Overlay": "Відобразити дані адміна у вікні очікування облікового запису",
"Show Model": "Показати модель",
"Show shortcuts": "Показати клавіатурні скорочення",
"Show your support!": "",
"Showcased creativity": "Продемонстрований креатив",
"sidebar": "бокова панель",
"Sign in": "Увійти",
@ -585,6 +595,7 @@
"Users": "Користувачі",
"Utilize": "Використовувати",
"Valid time units:": "Дійсні одиниці часу:",
"Valves": "",
"variable": "змінна",
"variable to have them replaced with clipboard content.": "змінна, щоб замінити їх вмістом буфера обміну.",
"Version": "Версія",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "Cho phép Xóa nội dung chat",
"Allow non-local voices": "Cho phép giọng nói không bản xứ",
"Allow User Location": "Cho phép sử dụng vị trí người dùng",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "ký tự số và gạch nối",
"Already have an account?": "Bạn đã có tài khoản?",
"an assistant": "trợ lý",
@ -165,9 +166,13 @@
"Deleted {{name}}": "Đã xóa {{name}}",
"Description": "Mô tả",
"Didn't fully follow instructions": "Không tuân theo chỉ dẫn một cách đầy đủ",
"Discover a function": "",
"Discover a model": "Khám phá model",
"Discover a prompt": "Khám phá thêm prompt mới",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "Tìm kiếm, tải về và khám phá thêm các prompt tùy chỉnh",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "Tìm kiếm, tải về và khám phá thêm các thiết lập mô hình sẵn",
"Dismissible": "Có thể loại bỏ",
"Display Emoji in Call": "Hiển thị Emoji trong cuộc gọi",
@ -180,6 +185,7 @@
"Don't Allow": "Không Cho phép",
"Don't have an account?": "Không có tài khoản?",
"Don't like the style": "Không thích phong cách trả lời",
"Done": "",
"Download": "Tải về",
"Download canceled": "Đã hủy download",
"Download Database": "Tải xuống Cơ sở dữ liệu",
@ -312,6 +318,7 @@
"Manage Models": "Quản lý mô hình",
"Manage Ollama Models": "Quản lý mô hình với Ollama",
"Manage Pipelines": "Quản lý Pipelines",
"Manage Valves": "",
"March": "Tháng 3",
"Max Tokens (num_predict)": "Tokens tối đa (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Tối đa 3 mô hình có thể được tải xuống cùng lúc. Vui lòng thử lại sau.",
@ -458,10 +465,12 @@
"Seed": "Seed",
"Select a base model": "Chọn một base model",
"Select a engine": "Chọn dịch vụ",
"Select a function": "",
"Select a mode": "Chọn một chế độ",
"Select a model": "Chọn mô hình",
"Select a pipeline": "Chọn một quy trình",
"Select a pipeline url": "Chọn url quy trình",
"Select a tool": "",
"Select an Ollama instance": "Chọn một thực thể Ollama",
"Select Documents": "Chọn tài liệu",
"Select model": "Chọn model",
@ -494,6 +503,7 @@
"Show Admin Details in Account Pending Overlay": "Hiển thị thông tin của Quản trị viên trên màn hình hiển thị Tài khoản đang chờ xử lý",
"Show Model": "Hiện mô hình",
"Show shortcuts": "Hiển thị phím tắt",
"Show your support!": "",
"Showcased creativity": "Thể hiện sự sáng tạo",
"sidebar": "thanh bên",
"Sign in": "Đăng nhập",
@ -582,6 +592,7 @@
"Users": "Người sử dụng",
"Utilize": "Sử dụng",
"Valid time units:": "Đơn vị thời gian hợp lệ:",
"Valves": "",
"variable": "biến",
"variable to have them replaced with clipboard content.": "biến để có chúng được thay thế bằng nội dung clipboard.",
"Version": "Version",

View file

@ -43,6 +43,7 @@
"Allow Chat Deletion": "允许删除聊天记录",
"Allow non-local voices": "允许调用非本地音色",
"Allow User Location": "允许获取您的位置",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "字母数字字符和连字符",
"Already have an account?": "已经拥有账号了?",
"an assistant": "助手",
@ -99,7 +100,7 @@
"Clear memory": "清除记忆",
"Click here for help.": "点击这里获取帮助。",
"Click here to": "单击",
"Click here to download user import template file.": "",
"Click here to download user import template file.": "单击此处下载用户导入所需的模板文件。",
"Click here to select": "点击这里选择",
"Click here to select a csv file.": "单击此处选择 csv 文件。",
"Click here to select a py file.": "单击此处选择 py 文件。",
@ -135,8 +136,8 @@
"Create new secret key": "创建新安全密钥",
"Created at": "创建于",
"Created At": "创建于",
"Created by": "",
"CSV Import": "",
"Created by": "作者",
"CSV Import": "通过 CSV 文件导入",
"Current Model": "当前模型",
"Current Password": "当前密码",
"Custom": "自定义",
@ -165,9 +166,13 @@
"Deleted {{name}}": "已删除 {{name}}",
"Description": "描述",
"Didn't fully follow instructions": "没有完全遵照指示",
"Discover a function": "",
"Discover a model": "发现更多模型",
"Discover a prompt": "发现更多提示词",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "发现、下载并探索更多自定义提示词",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "发现、下载并探索更多模型预设",
"Dismissible": "是否可关闭",
"Display Emoji in Call": "在通话中显示 Emoji 表情符号",
@ -180,6 +185,7 @@
"Don't Allow": "不允许",
"Don't have an account?": "没有账号?",
"Don't like the style": "不喜欢这个文风",
"Done": "",
"Download": "下载",
"Download canceled": "下载已取消",
"Download Database": "下载数据库",
@ -250,7 +256,7 @@
"Fluidly stream large external response chunks": "流畅地传输外部大型响应块数据",
"Focus chat input": "聚焦对话输入",
"Followed instructions perfectly": "完全按照指示执行",
"Form": "",
"Form": "手动创建",
"Format your variables using square brackets like this:": "使用这样的方括号格式化你的变量:",
"Frequency Penalty": "频率惩罚",
"Functions": "功能",
@ -267,7 +273,7 @@
"Hello, {{name}}": "您好,{{name}}",
"Help": "帮助",
"Hide": "隐藏",
"Hide Model": "隐藏模型",
"Hide Model": "隐藏",
"How can I help you today?": "有什么我能帮您的吗?",
"Hybrid Search": "混合搜索",
"Image Generation (Experimental)": "图像生成(实验性)",
@ -312,6 +318,7 @@
"Manage Models": "管理模型",
"Manage Ollama Models": "管理 Ollama 模型",
"Manage Pipelines": "管理 Pipeline",
"Manage Valves": "",
"March": "三月",
"Max Tokens (num_predict)": "最多 Token (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "最多可以同时下载 3 个模型,请稍后重试。",
@ -458,10 +465,12 @@
"Seed": "种子 (Seed)",
"Select a base model": "选择一个基础模型",
"Select a engine": "选择一个搜索引擎",
"Select a function": "",
"Select a mode": "选择一个模式",
"Select a model": "选择一个模型",
"Select a pipeline": "选择一个管道",
"Select a pipeline url": "选择一个管道 URL",
"Select a tool": "",
"Select an Ollama instance": "选择一个 Ollama 实例",
"Select Documents": "选择文档",
"Select model": "选择模型",
@ -492,8 +501,9 @@
"short-summary": "简短总结",
"Show": "显示",
"Show Admin Details in Account Pending Overlay": "在用户待激活界面中显示管理员邮箱等详细信息",
"Show Model": "显示模型",
"Show Model": "显示",
"Show shortcuts": "显示快捷方式",
"Show your support!": "",
"Showcased creativity": "很有创意",
"sidebar": "侧边栏",
"Sign in": "登录",
@ -582,6 +592,7 @@
"Users": "用户",
"Utilize": "利用",
"Valid time units:": "有效时间单位:",
"Valves": "",
"variable": "变量",
"variable to have them replaced with clipboard content.": "变量将被剪贴板内容替换。",
"Version": "版本",

View file

@ -4,36 +4,36 @@
"(e.g. `sh webui.sh --api`)": "(例如 `sh webui.sh --api`)",
"(latest)": "(最新版)",
"{{ models }}": "{{ models }}",
"{{ owner }}: You cannot delete a base model": "{{ owner }}你無法刪除基本模型",
"{{ owner }}: You cannot delete a base model": "{{ owner }}您無法刪除基礎模型",
"{{modelName}} is thinking...": "{{modelName}} 正在思考...",
"{{user}}'s Chats": "{{user}} 的聊天",
"{{webUIName}} Backend Required": "需要 {{webUIName}} 後",
"A task model is used when performing tasks such as generating titles for chats and web search queries": "在執行任務時使用任務模型,例如為聊天和網絡搜索查詢生成標題",
"{{webUIName}} Backend Required": "需要 {{webUIName}} 後",
"A task model is used when performing tasks such as generating titles for chats and web search queries": "在執行任務時使用任務模型,例如為聊天和網頁搜尋查詢生成標題",
"a user": "使用者",
"About": "關於",
"Account": "帳號",
"Account Activation Pending": "",
"Accurate information": "準確信息",
"Active Users": "",
"Account Activation Pending": "帳號啟用中",
"Accurate information": "準確資訊",
"Active Users": "活躍使用者",
"Add": "新增",
"Add a model id": "新增模型 ID",
"Add a short description about what this model does": "為這個模型添加一個簡短描述",
"Add a short title for this prompt": "為這個提示詞添加一個簡短的標題",
"Add a short description about what this model does": "為這個模型新增一個簡短描述",
"Add a short title for this prompt": "為這個提示詞新增一個簡短的標題",
"Add a tag": "新增標籤",
"Add custom prompt": "新增自定義提示詞",
"Add custom prompt": "新增自提示詞",
"Add Docs": "新增文件",
"Add Files": "新增檔案",
"Add Memory": "新增記憶",
"Add message": "新增訊息",
"Add Model": "新增模型",
"Add Tags": "新增標籤",
"Add User": "新增用户",
"Add User": "新增使用者",
"Adjusting these settings will apply changes universally to all users.": "調整這些設定將對所有使用者進行更改。",
"admin": "管理員",
"Admin": "",
"Admin": "管理員",
"Admin Panel": "管理員控制台",
"Admin Settings": "管理設定",
"Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "",
"Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "管理員隨時可以使用所有工具;使用者需要在工作區中為每個模型分配工具。",
"Advanced Parameters": "進階參數",
"Advanced Params": "進階參數",
"all": "所有",
@ -41,43 +41,44 @@
"All Users": "所有使用者",
"Allow": "允許",
"Allow Chat Deletion": "允許刪除聊天紀錄",
"Allow non-local voices": "",
"Allow User Location": "",
"alphanumeric characters and hyphens": "英文字母、數字0~9和連字符-",
"Allow non-local voices": "允許非本機語音",
"Allow User Location": "允許使用者位置",
"Allow Voice Interruption in Call": "",
"alphanumeric characters and hyphens": "英文字母、數字0~9和連字元-",
"Already have an account?": "已經有帳號了嗎?",
"an assistant": "助手",
"and": "和",
"and create a new shared link.": "創建一個新的共享連結。",
"and create a new shared link.": "並建立一個新的共享連結。",
"API Base URL": "API 基本 URL",
"API Key": "API Key",
"API Key created.": "API Key",
"API keys": "API Keys",
"April": "4月",
"Archive": "",
"Archive All Chats": "所有聊天紀錄",
"Archived Chats": "聊天記錄存檔",
"API Key": "API 金鑰",
"API Key created.": "API 金鑰已建立。",
"API keys": "API 金鑰",
"April": "4 月",
"Archive": "存",
"Archive All Chats": "存所有聊天紀錄",
"Archived Chats": "已封存的聊天紀錄",
"are allowed - Activate this command by typing": "是允許的 - 透過輸入",
"Are you sure?": "確定嗎?",
"Are you sure?": "確定嗎?",
"Attach file": "附加檔案",
"Attention to detail": "細節精確",
"Audio": "音訊",
"August": "8月",
"August": "8 月",
"Auto-playback response": "自動播放回答",
"AUTOMATIC1111 Base URL": "AUTOMATIC1111 基本 URL",
"AUTOMATIC1111 Base URL is required.": "需要 AUTOMATIC1111 基本 URL",
"available!": "可以使用!",
"available!": "可用!",
"Back": "返回",
"Bad Response": "錯誤回應",
"Banners": "橫幅",
"Base Model (From)": "基模型(來自)",
"Batch Size (num_batch)": "",
"Base Model (From)": "基模型(來自)",
"Batch Size (num_batch)": "批次大小num_batch",
"before": "前",
"Being lazy": "懶人模式",
"Brave Search API Key": "搜尋 API Key",
"Bypass SSL verification for Websites": "跳過 SSL 驗證",
"Call": "",
"Call feature is not supported when using Web STT engine": "",
"Camera": "",
"Brave Search API Key": "Brave 搜尋 API 金鑰",
"Bypass SSL verification for Websites": "跳過網站的 SSL 驗證",
"Call": "呼叫",
"Call feature is not supported when using Web STT engine": "使用 Web STT 引擎時不支援呼叫功能",
"Camera": "相機",
"Cancel": "取消",
"Capabilities": "功能",
"Change Password": "修改密碼",
@ -85,27 +86,27 @@
"Chat Background Image": "",
"Chat Bubble UI": "聊天氣泡介面",
"Chat direction": "聊天方向",
"Chat History": "聊天紀錄功能",
"Chat History is off for this browser.": "此瀏覽器已關閉聊天紀錄功能。",
"Chat History": "聊天紀錄",
"Chat History is off for this browser.": "此瀏覽器已關閉聊天紀錄。",
"Chats": "聊天",
"Check Again": "重新檢查",
"Check for updates": "檢查更新",
"Checking for updates...": "正在檢查更新...",
"Choose a model before saving...": "儲存前選擇一個模型...",
"Chunk Overlap": "Chunk Overlap",
"Chunk Params": "Chunk 參數",
"Chunk Size": "Chunk 大小",
"Chunk Overlap": "區塊重疊",
"Chunk Params": "區塊參數",
"Chunk Size": "區塊大小",
"Citation": "引文",
"Clear memory": "",
"Click here for help.": "點擊這裡尋找幫助。",
"Click here to": "點這裡",
"Click here to download user import template file.": "",
"Click here to select": "點這裡選擇",
"Click here to select a csv file.": "點這裡選擇 csv 檔案。",
"Click here to select a py file.": "",
"Click here to select documents.": "點這裡選擇文件。",
"click here.": "點這裡。",
"Click on the user role button to change a user's role.": "點擊使用者 Role 按鈕以更改使用者的 Role。",
"Clear memory": "清除記憶",
"Click here for help.": "點選這裡尋求幫助。",
"Click here to": "點這裡",
"Click here to download user import template file.": "點選這裡下載使用者匯入的範本",
"Click here to select": "點這裡選擇",
"Click here to select a csv file.": "點這裡選擇 csv 檔案。",
"Click here to select a py file.": "點選這裡選擇 py 檔案。",
"Click here to select documents.": "點這裡選擇文件。",
"click here.": "點這裡。",
"Click on the user role button to change a user's role.": "點選使用者角色按鈕以更改使用者的角色。",
"Clone": "複製",
"Close": "關閉",
"Collection": "收藏",
@ -118,7 +119,7 @@
"Confirm Password": "確認密碼",
"Confirm your action": "",
"Connections": "連線",
"Contact Admin for WebUI Access": "",
"Contact Admin for WebUI Access": "聯絡管理員以取得 WebUI 存取權",
"Content": "內容",
"Context Length": "上下文長度",
"Continue Response": "繼續回答",
@ -131,8 +132,8 @@
"Copying to clipboard was successful!": "成功複製到剪貼簿!",
"Create a model": "建立模型",
"Create Account": "建立帳號",
"Create new key": "建立新鑰",
"Create new secret key": "建立新鑰",
"Create new key": "建立新鑰",
"Create new secret key": "建立新鑰",
"Created at": "建立於",
"Created At": "建立於",
"Created by": "",
@ -140,18 +141,18 @@
"Current Model": "目前模型",
"Current Password": "目前密碼",
"Custom": "自訂",
"Customize models for a specific purpose": "為特定目的自定義模型",
"Customize models for a specific purpose": "為特定目的自模型",
"Dark": "暗色",
"Dashboard": "",
"Dashboard": "儀表板",
"Database": "資料庫",
"December": "12月",
"December": "12 月",
"Default": "預設",
"Default (Automatic1111)": "預設Automatic1111",
"Default (SentenceTransformers)": "預設SentenceTransformers",
"Default Model": "預設模型",
"Default model updated": "預設模型已更新",
"Default Prompt Suggestions": "預設提示詞建議",
"Default User Role": "預設用戶 Role",
"Default User Role": "預設使用者角色",
"delete": "刪除",
"Delete": "刪除",
"Delete a model": "刪除一個模型",
@ -160,178 +161,184 @@
"Delete Chat": "刪除聊天紀錄",
"Delete chat?": "",
"delete this link": "刪除此連結",
"Delete User": "刪除用戶",
"Delete User": "刪除使用者",
"Deleted {{deleteModelTag}}": "已刪除 {{deleteModelTag}}",
"Deleted {{name}}": "已刪除 {{name}}",
"Description": "描述",
"Didn't fully follow instructions": "無法完全遵循指示",
"Didn't fully follow instructions": "未完全遵循指示",
"Discover a function": "",
"Discover a model": "發現新模型",
"Discover a prompt": "發現新提示詞",
"Discover, download, and explore custom prompts": "發現、下載並探索他人設置的提示詞",
"Discover, download, and explore model presets": "發現、下載並探索他人設置的模型",
"Dismissible": "",
"Display Emoji in Call": "",
"Display the username instead of You in the Chat": "在聊天中顯示使用者名稱而不是「你」",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover, download, and explore custom prompts": "發現、下載並探索自訂提示詞",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore model presets": "發現、下載並探索模型預設值",
"Dismissible": "可忽略",
"Display Emoji in Call": "在呼叫中顯示表情符號",
"Display the username instead of You in the Chat": "在聊天中顯示使用者名稱而不是「您」",
"Document": "文件",
"Document Settings": "文件設定",
"Documentation": "",
"Documentation": "文件",
"Documents": "文件",
"does not make any external connections, and your data stays securely on your locally hosted server.": "不會與外部溝通,你的數據會安全地留在你的本機伺服器上。",
"does not make any external connections, and your data stays securely on your locally hosted server.": "不會與外部連線,您的資料會安全地留在您的本機伺服器上。",
"Don't Allow": "不允許",
"Don't have an account?": "還沒有註冊帳號?",
"Don't like the style": "不喜歡這個樣式?",
"Done": "",
"Download": "下載",
"Download canceled": "下載已取消",
"Download Database": "下載資料庫",
"Drop any files here to add to the conversation": "拖拽文件到此處以新增至對話",
"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'。",
"Edit": "編輯",
"Edit Doc": "編輯文件",
"Edit Memory": "",
"Edit Memory": "編輯記憶",
"Edit User": "編輯使用者",
"Email": "電子郵件",
"Embedding Batch Size": "",
"Embedding Batch Size": "嵌入批次大小",
"Embedding Model": "嵌入模型",
"Embedding Model Engine": "嵌入模型引擎",
"Embedding model set to \"{{embedding_model}}\"": "嵌入模型已設定為 \"{{embedding_model}}\"",
"Enable Chat History": "啟用聊天歷史",
"Enable Community Sharing": "啟用社分享",
"Enable Chat History": "啟用聊天紀錄",
"Enable Community Sharing": "啟用社分享",
"Enable New Sign Ups": "允許註冊新帳號",
"Enable Web Search": "啟用網絡搜索",
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "請確保的 CSV 檔案包含這四個欄位,並按照此順序:名稱、電子郵件、密碼、角色。",
"Enable Web Search": "啟用網頁搜尋",
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "請確保的 CSV 檔案包含這四個欄位,並按照此順序:名稱、電子郵件、密碼、角色。",
"Enter {{role}} message here": "在這裡輸入 {{role}} 訊息",
"Enter a detail about yourself for your LLMs to recall": "輸入 LLM 記憶的詳細內容",
"Enter Brave Search API Key": "輸入 Brave Search API Key",
"Enter Chunk Overlap": "輸入 Chunk Overlap",
"Enter Chunk Size": "輸入 Chunk 大小",
"Enter Brave Search API Key": "輸入 Brave 搜尋 API 金鑰",
"Enter Chunk Overlap": "輸入區塊重疊",
"Enter Chunk Size": "輸入區塊大小",
"Enter Github Raw URL": "輸入 Github Raw URL",
"Enter Google PSE API Key": "輸入 Google PSE API Key",
"Enter Google PSE Engine Id": "輸入 Google PSE Engine Id",
"Enter Google PSE API Key": "輸入 Google PSE API 金鑰",
"Enter Google PSE Engine Id": "輸入 Google PSE 引擎 ID",
"Enter Image Size (e.g. 512x512)": "輸入圖片大小(例如 512x512",
"Enter language codes": "輸入語言代碼",
"Enter model tag (e.g. {{modelTag}})": "輸入模型標籤(例如 {{modelTag}}",
"Enter Number of Steps (e.g. 50)": "輸入步數(例如 50",
"Enter Score": "輸入分數",
"Enter Searxng Query URL": "輸入 Searxng 查詢 URL",
"Enter Serper API Key": "輸入 Serper API Key",
"Enter Serply API Key": "",
"Enter Serpstack API Key": "輸入 Serpstack API Key",
"Enter Serper API Key": "輸入 Serper API 金鑰",
"Enter Serply API Key": "輸入 Serply API 金鑰",
"Enter Serpstack API Key": "輸入 Serpstack API 金鑰",
"Enter stop sequence": "輸入停止序列",
"Enter Tavily API Key": "",
"Enter Tavily API Key": "輸入 Tavily API 金鑰",
"Enter Top K": "輸入 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 Email": "輸入的電子郵件",
"Enter Your Full Name": "輸入的全名",
"Enter Your Password": "輸入的密碼",
"Enter Your Role": "輸入的角色",
"Enter Your Email": "輸入的電子郵件",
"Enter Your Full Name": "輸入的全名",
"Enter Your Password": "輸入的密碼",
"Enter Your Role": "輸入的角色",
"Error": "錯誤",
"Experimental": "實驗功能",
"Export": "",
"Experimental": "實驗功能",
"Export": "出",
"Export All Chats (All Users)": "匯出所有聊天紀錄(所有使用者)",
"Export chat (.json)": "",
"Export chat (.json)": "匯出聊天紀錄(.json",
"Export Chats": "匯出聊天紀錄",
"Export Documents Mapping": "匯出文件",
"Export Functions": "",
"Export Documents Mapping": "匯出文件映",
"Export Functions": "匯出功能",
"Export Models": "匯出模型",
"Export Prompts": "匯出提示詞",
"Export Tools": "",
"External Models": "",
"Failed to create API Key.": "無法建 API 金鑰。",
"Export Tools": "匯出工具",
"External Models": "外部模型",
"Failed to create API Key.": "無法 API 金鑰。",
"Failed to read clipboard contents": "無法讀取剪貼簿內容",
"Failed to update settings": "",
"February": "2月",
"Feel free to add specific details": "請自由添加詳細內容。",
"File": "",
"Failed to update settings": "無法更新設定",
"February": "2 月",
"Feel free to add specific details": "請隨意新增詳細內容。",
"File": "檔案",
"File Mode": "檔案模式",
"File not found.": "找不到檔案。",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "偽裝偽裝檢測:無法使用頭像作為頭像。預設為預設頭像。",
"Fluidly stream large external response chunks": "流暢地傳輸大型外部應區塊",
"Filters": "篩選器",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "偽造偵測:無法使用初始頭像。預設為預設個人影象。",
"Fluidly stream large external response chunks": "流暢地傳輸大型外部應區塊",
"Focus chat input": "聚焦聊天輸入框",
"Followed instructions perfectly": "完全遵循指示",
"Form": "",
"Format your variables using square brackets like this:": "像這樣使用方括號來格式化的變數:",
"Form": "表單",
"Format your variables using square brackets like this:": "像這樣使用方括號來格式化的變數:",
"Frequency Penalty": "頻率懲罰",
"Functions": "",
"Functions": "功能",
"General": "常用",
"General Settings": "常用設定",
"Generate Image": "",
"Generating search query": "生成搜查詢",
"Generation Info": "生成信息",
"Generate Image": "生成圖片",
"Generating search query": "生成搜查詢",
"Generation Info": "生成資訊",
"Good Response": "優秀的回應",
"Google PSE API Key": "Google PSE API Key",
"Google PSE Engine Id": "Google PSE Engine Id",
"Google PSE API Key": "Google PSE API 金鑰",
"Google PSE Engine Id": "Google PSE 引擎 ID",
"h:mm a": "h:mm a",
"has no conversations.": "沒有對話",
"Hello, {{name}}": "好,{{name}}",
"Hello, {{name}}": "好,{{name}}",
"Help": "幫助",
"Hide": "隱藏",
"Hide Model": "",
"How can I help you today?": "今天能為你做什麼?",
"Hybrid Search": "混合搜",
"Image Generation (Experimental)": "圖像生成(實驗功能)",
"Image Generation Engine": "像生成引擎",
"Hide Model": "隱藏模型",
"How can I help you today?": "今天能為您做些什麼?",
"Hybrid Search": "混合搜",
"Image Generation (Experimental)": "影像生成(實驗性功能)",
"Image Generation Engine": "像生成引擎",
"Image Settings": "圖片設定",
"Images": "圖片",
"Import Chats": "匯入聊天紀錄",
"Import Documents Mapping": "匯入文件",
"Import Functions": "",
"Import Documents Mapping": "匯入文件映",
"Import Functions": "匯入功能",
"Import Models": "匯入模型",
"Import Prompts": "匯入提示詞",
"Import Tools": "",
"Include `--api` flag when running stable-diffusion-webui": "在行 stable-diffusion-webui 時加上 `--api` 標誌",
"Import Tools": "匯入工具",
"Include `--api` flag when running stable-diffusion-webui": "在行 stable-diffusion-webui 時加上 `--api` 標誌",
"Info": "資訊",
"Input commands": "輸入命令",
"Install from Github URL": "從 Github URL 安裝",
"Instant Auto-Send After Voice Transcription": "",
"Instant Auto-Send After Voice Transcription": "語音轉錄後立即自動傳送",
"Interface": "介面",
"Invalid Tag": "無效標籤",
"January": "1月",
"join our Discord for help.": "加入我們的 Discord 尋幫助。",
"January": "1 月",
"join our Discord for help.": "加入我們的 Discord 尋幫助。",
"JSON": "JSON",
"JSON Preview": "JSON 預覽",
"July": "7月",
"June": "6月",
"July": "7 月",
"June": "6 月",
"JWT Expiration": "JWT 過期時間",
"JWT Token": "JWT Token",
"Keep Alive": "保持活躍",
"Keyboard shortcuts": "鍵盤快速鍵",
"Knowledge": "",
"Knowledge": "知識",
"Language": "語言",
"Last Active": "最後活動",
"Last Modified": "",
"Last Modified": "最後修改",
"Light": "亮色",
"Listening...": "",
"Listening...": "正在聆聽...",
"LLMs can make mistakes. Verify important information.": "LLM 可能會產生錯誤。請驗證重要資訊。",
"Local Models": "",
"Local Models": "本機模型",
"LTR": "LTR",
"Made by OpenWebUI Community": "由 OpenWebUI 社製作",
"Made by OpenWebUI Community": "由 OpenWebUI 社製作",
"Make sure to enclose them with": "請確保變數有被以下符號框住:",
"Manage": "",
"Manage Models": "管理模",
"Manage": "管理",
"Manage Models": "管理模",
"Manage Ollama Models": "管理 Ollama 模型",
"Manage Pipelines": "管理管道",
"March": "3月",
"Manage Pipelines": "管理管線",
"Manage Valves": "",
"March": "3 月",
"Max Tokens (num_predict)": "最大 Tokennum_predict",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "最多可以同時下載 3 個模型。請稍後再試。",
"May": "5月",
"May": "5 月",
"Memories accessible by LLMs will be shown here.": "LLM 記憶將會顯示在此處。",
"Memory": "記憶",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "創建連結後發送的訊息將不會被共享。具有 URL 的用戶將會能夠檢視共享的聊天。",
"Minimum Score": "最分數",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "建立連結後傳送的訊息將不會被共享。具有 URL 的使用者將會能夠檢視共享的聊天。",
"Minimum Score": "最分數",
"Mirostat": "Mirostat",
"Mirostat Eta": "Mirostat Eta",
"Mirostat Tau": "Mirostat Tau",
"MMMM DD, YYYY": "MMMM DD, YYYY",
"MMMM DD, YYYY HH:mm": "MMMM DD, YYYY HH:mm",
"MMMM DD, YYYY hh:mm:ss A": "",
"MMMM DD, YYYY hh:mm:ss A": "MMMM DD, YYYY hh:mm:ss A",
"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 filesystem path detected. Model shortname is required for update, cannot continue.": "模型文件系統路徑已檢測。需要更新模型短名,無法繼續。",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "已偵測到模型檔案系統路徑。需要更新模型簡稱,無法繼續。",
"Model ID": "模型 ID",
"Model not selected": "未選擇模型",
"Model Params": "模型參數",
@ -345,33 +352,33 @@
"Name your model": "請輸入模型名稱",
"New Chat": "新增聊天",
"New Password": "新密碼",
"No documents found": "",
"No documents found": "找不到文件",
"No results found": "沒有找到結果",
"No search query generated": "沒有生成搜查詢",
"No search query generated": "沒有生成搜查詢",
"No source available": "沒有可用的來源",
"None": "無",
"Not factually correct": "與真實資訊不符",
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "註:如果設置最低分數,則搜索將只返回分數大於或等於最低分數的文檔。",
"Notifications": "桌面通知",
"November": "11月",
"num_thread (Ollama)": "num_thread奧拉馬",
"Not factually correct": "與真實資訊不符",
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "註:如果設定最低分數,則搜尋將只返回分數大於或等於最低分數的文件。",
"Notifications": "通知",
"November": "11 月",
"num_thread (Ollama)": "num_threadOllama",
"OAuth ID": "",
"October": "10 月",
"Off": "關閉",
"Okay, Let's Go!": "好的,啟動吧!",
"OLED Dark": "`",
"OLED Dark": "OLED 深色",
"Ollama": "Ollama",
"Ollama API": "Ollama API",
"Ollama API disabled": "Ollama API 已用",
"Ollama API is disabled": "",
"Ollama API disabled": "Ollama API 已用",
"Ollama API is disabled": "Ollama API 已停用",
"Ollama Version": "Ollama 版本",
"On": "開啟",
"Only": "僅有",
"Only alphanumeric characters and hyphens are allowed in the command string.": "命令字串中只能包含英文字母、數字0~9和連字-)。",
"Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "哎呀!請稍等!的文件還在處理中。我們正最佳化文件,請耐心等待,一旦準備好,我們會通知。",
"Only alphanumeric characters and hyphens are allowed in the command string.": "命令字串中只能包含英文字母、數字0~9和連字-)。",
"Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "哎呀!請稍等!的文件還在處理中。我們正最佳化文件,請耐心等待,一旦準備好,我們會通知。",
"Oops! Looks like the URL is invalid. Please double-check and try again.": "哎呀!看起來 URL 無效。請仔細檢查後再試一次。",
"Oops! There was an error in the previous response. Please try again or contact admin.": "",
"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "哎呀!你正在使用不支援的方法(僅有前台)。請從後台提供 WebUI。",
"Oops! There was an error in the previous response. Please try again or contact admin.": "哎呀!先前的回應發生錯誤。請重試或聯絡管理員",
"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "哎呀!您正在使用不支援的方法(僅有前端)。請從後端提供 WebUI。",
"Open": "開啟",
"Open AI": "Open AI",
"Open AI (Dall-E)": "Open AI (Dall-E)",
@ -385,22 +392,22 @@
"Other": "其他",
"Password": "密碼",
"PDF document (.pdf)": "PDF 文件 (.pdf)",
"PDF Extract Images (OCR)": "PDF 像擷取OCR 光學文字辨識)",
"PDF Extract Images (OCR)": "PDF 像擷取OCR 光學文字辨識)",
"pending": "待審查",
"Permission denied when accessing media devices": "",
"Permission denied when accessing microphone": "",
"Permission denied when accessing media devices": "存取媒體裝置時被拒絕權限",
"Permission denied when accessing microphone": "存取麥克風時被拒絕權限",
"Permission denied when accessing microphone: {{error}}": "存取麥克風時被拒絕權限:{{error}}",
"Personalization": "個人化",
"Pipelines": "管線",
"Pipelines Valves": "管線阀门",
"Pipelines Valves": "管線閥門",
"Plain text (.txt)": "純文字 (.txt)",
"Playground": "AI 對話遊樂場",
"Positive attitude": "積極態度",
"Previous 30 days": "前 30 天",
"Previous 7 days": "前 7 天",
"Profile Image": "個人像",
"Profile Image": "個人像",
"Prompt": "提示詞",
"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "提示詞(例如:告訴我關於羅馬帝國的事)",
"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "提示詞(例如:告訴我關於羅馬帝國的一些趣事)",
"Prompt Content": "提示詞內容",
"Prompt suggestions": "提示詞建議",
"Prompts": "提示詞",
@ -410,32 +417,32 @@
"RAG Template": "RAG 範例",
"Read Aloud": "讀出",
"Record voice": "錄音",
"Redirecting you to OpenWebUI Community": "將重新導向到 OpenWebUI 社群",
"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
"Refused when it shouldn't have": "拒絕時不該拒絕",
"Redirecting you to OpenWebUI Community": "將重新導向到 OpenWebUI 社群",
"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "將自己稱為「使用者」(例如,「使用者正在學習西班牙語」)",
"Refused when it shouldn't have": "不該拒絕時拒絕了",
"Regenerate": "重新生成",
"Release Notes": "發布說明",
"Remove": "移除",
"Remove Model": "移除模型",
"Rename": "重命名",
"Rename": "重命名",
"Repeat Last N": "重複最後 N 次",
"Request Mode": "請求模式",
"Reranking Model": "重新排序模型",
"Reranking model disabled": "重新排序模型已用",
"Reranking model disabled": "重新排序模型已用",
"Reranking model set to \"{{reranking_model}}\"": "重新排序模型設定為 \"{{reranking_model}}\"",
"Reset": "",
"Reset Upload Directory": "",
"Reset Vector Storage": "重向量儲存空間",
"Reset": "重設",
"Reset Upload Directory": "重設上傳目錄",
"Reset Vector Storage": "重向量儲存空間",
"Response AutoCopy to Clipboard": "自動複製回答到剪貼簿",
"Role": "Role",
"Role": "角色",
"Rosé Pine": "玫瑰松",
"Rosé Pine Dawn": "黎明玫瑰松",
"RTL": "RTL",
"Running": "",
"Running": "運作中",
"Save": "儲存",
"Save & Create": "儲存並建立",
"Save & Update": "儲存並更新",
"Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "現已不支援將聊天紀錄儲存到瀏覽器儲存空間中。請點擊下面的按鈕下載並刪除你的聊天記錄。別擔心,你可以通過以下方式輕鬆地重新匯入你的聊天記錄到後台",
"Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "現已不支援將聊天紀錄儲存到瀏覽器儲存空間中。請點選下面的按鈕下載並刪除您的聊天記錄。別擔心,您可以透過以下方式輕鬆地重新匯入您的聊天記錄到後端",
"Scan": "掃描",
"Scan complete!": "掃描完成!",
"Scan for documents from {{path}}": "從 {{path}} 掃描文件",
@ -443,37 +450,39 @@
"Search a model": "搜尋模型",
"Search Chats": "搜尋聊天",
"Search Documents": "搜尋文件",
"Search Functions": "",
"Search Functions": "搜尋功能",
"Search Models": "搜尋模型",
"Search Prompts": "搜尋提示詞",
"Search Query Generation Prompt": "",
"Search Query Generation Prompt Length Threshold": "",
"Search Query Generation Prompt": "搜尋查詢生成提示詞",
"Search Query Generation Prompt Length Threshold": "搜尋查詢生成提示詞長度閾值",
"Search Result Count": "搜尋結果數量",
"Search Tools": "",
"Searched {{count}} sites_other": "掃描 {{count}} 個網站_其他",
"Searching \"{{searchQuery}}\"": "",
"Search Tools": "搜尋工具",
"Searched {{count}} sites_other": "搜尋了 {{count}} 個網站",
"Searching \"{{searchQuery}}\"": "正在搜尋 \"{{searchQuery}}\"",
"Searxng Query URL": "Searxng 查詢 URL",
"See readme.md for instructions": "查看 readme.md 獲取指南",
"See what's new": "查看最新內容",
"See readme.md for instructions": "檢視 readme.md 取得指南",
"See what's new": "檢視最新內容",
"Seed": "種子",
"Select a base model": "選擇基礎模型",
"Select a engine": "",
"Select a engine": "選擇引擎",
"Select a function": "",
"Select a mode": "選擇模式",
"Select a model": "選擇一個模型",
"Select a pipeline": "選擇管道",
"Select a pipeline url": "選擇管道 URL",
"Select an Ollama instance": "選擇 Ollama 實例",
"Select Documents": "",
"Select a pipeline": "選擇管線",
"Select a pipeline url": "選擇管線 URL",
"Select a tool": "",
"Select an Ollama instance": "選擇 Ollama 執行個體",
"Select Documents": "選擇文件",
"Select model": "選擇模型",
"Select only one model to call": "",
"Selected model(s) do not support image inputs": "已選擇模型不支持圖像輸入",
"Select only one model to call": "僅選擇一個模型來呼叫",
"Selected model(s) do not support image inputs": "已選擇模型不支援影像輸入",
"Send": "傳送",
"Send a Message": "傳送訊息",
"Send message": "傳送訊息",
"September": "月",
"Serper API Key": "Serper API Key",
"Serply API Key": "",
"Serpstack API Key": "Serpstack API Key",
"September": "9 月",
"Serper API Key": "Serper API 金鑰",
"Serply API Key": "Serply API 金鑰",
"Serpstack API Key": "Serpstack API 金鑰",
"Server connection verified": "已驗證伺服器連線",
"Set as default": "設為預設",
"Set Default Model": "設定預設模型",
@ -485,15 +494,16 @@
"Set Voice": "設定語音",
"Settings": "設定",
"Settings saved successfully!": "成功儲存設定",
"Settings updated successfully": "",
"Settings updated successfully": "設定更新成功",
"Share": "分享",
"Share Chat": "分享聊天",
"Share to OpenWebUI Community": "分享到 OpenWebUI 社群",
"short-summary": "簡短摘要",
"Show": "顯示",
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show Admin Details in Account Pending Overlay": "在帳號待審覆蓋層中顯示管理員詳細資訊",
"Show Model": "顯示模型",
"Show shortcuts": "顯示快速鍵",
"Show your support!": "",
"Showcased creativity": "展示創造性",
"sidebar": "側邊欄",
"Sign in": "登入",
@ -504,115 +514,116 @@
"Speech recognition error: {{error}}": "語音識別錯誤:{{error}}",
"Speech-to-Text Engine": "語音轉文字引擎",
"Stop Sequence": "停止序列",
"STT Model": "",
"STT Model": "STT 模型",
"STT Settings": "語音轉文字設定",
"Submit": "提交",
"Subtitle (e.g. about the Roman Empire)": "標題(例如:關於羅馬帝國)",
"Subtitle (e.g. about the Roman Empire)": "標題(例如:關於羅馬帝國)",
"Success": "成功",
"Successfully updated.": "更新成功。",
"Suggested": "建議",
"System": "系統",
"System Prompt": "系統提示詞",
"Tags": "標籤",
"Tap to interrupt": "",
"Tavily API Key": "",
"Tap to interrupt": "點選以中斷",
"Tavily API Key": "Tavily API 金鑰",
"Tell us more:": "告訴我們更多:",
"Temperature": "溫度",
"Template": "模板",
"Text Completion": "文本補全Text Completion",
"Template": "範本",
"Text Completion": "文字補全",
"Text-to-Speech Engine": "文字轉語音引擎",
"Tfs Z": "Tfs Z",
"Thanks for your feedback!": "感謝的回饋!",
"Thanks for your feedback!": "感謝的回饋!",
"The score should be a value between 0.0 (0%) and 1.0 (100%).": "分數應該介於 0.00%)和 1.0100%)之間。",
"Theme": "主題",
"Thinking...": "",
"This action cannot be undone. Do you wish to continue?": "",
"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.": "",
"Thinking...": "正在思考...",
"This action cannot be undone. Do you wish to continue?": "此動作無法被復原。您想要繼續進行嗎?",
"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 setting does not sync across browsers or devices.": "此設定不會在瀏覽器或裝置間同步。",
"This will delete": "",
"Thorough explanation": "詳細說明",
"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "提示:透過在每次替換後在聊天輸入框中按 Tab 鍵連續更新多個變數。",
"Title": "標題",
"Title (e.g. Tell me a fun fact)": "標題(例如:告訴我一個有趣的事)",
"Title Auto-Generation": "自動標題",
"Title Auto-Generation": "自動生標題",
"Title cannot be an empty string.": "標題不能為空字串",
"Title Generation Prompt": "自動標題的提示詞",
"Title Generation Prompt": "自動生標題的提示詞",
"to": "到",
"To access the available model names for downloading,": "若想查看可供下載的模型名稱,",
"To access the GGUF models available for downloading,": "若想查看可供下載的 GGUF 模型名稱,",
"To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "",
"To add documents here, upload them to the \"Documents\" workspace first.": "",
"To access the available model names for downloading,": "若想檢視可供下載的模型名稱,",
"To access the GGUF models available for downloading,": "若想檢視可供下載的 GGUF 模型名稱,",
"To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "若要存取 WebUI請聯絡管理員。管理員可以從管理面板管理使用者狀態。",
"To add documents here, upload them to the \"Documents\" workspace first.": "若要在此新增文件,請先將它們上傳到「文件」工作區。",
"to chat input.": "到聊天輸入框來啟動此命令。",
"To select filters here, add them to the \"Functions\" workspace first.": "",
"To select toolkits here, add them to the \"Tools\" workspace first.": "",
"To select filters here, add them to the \"Functions\" workspace first.": "若要在此選擇篩選器,請先將它們新增到「功能」工作區。",
"To select toolkits here, add them to the \"Tools\" workspace first.": "若要在此選擇工具包,請先將它們新增到「工具」工作區。",
"Today": "今天",
"Toggle settings": "切換設定",
"Toggle sidebar": "切換側邊欄",
"Tokens To Keep On Context Refresh (num_keep)": "",
"Tools": "",
"Tokens To Keep On Context Refresh (num_keep)": "上下文重新整理時保留的 Token 數量num_keep",
"Tools": "工具",
"Top K": "Top K",
"Top P": "Top P",
"Trouble accessing Ollama?": "存取 Ollama 時遇到問題?",
"TTS Model": "",
"TTS Settings": "文字轉語音設定",
"TTS Voice": "",
"TTS Model": "文字轉語音TTS模型",
"TTS Settings": "文字轉語音TTS設定",
"TTS Voice": "文字轉語音TTS聲調",
"Type": "類型",
"Type Hugging Face Resolve (Download) URL": "輸入 Hugging Face 解析後的下載URL",
"Uh-oh! There was an issue connecting to {{provider}}.": "哎呀!連線到 {{provider}} 時出現問題。",
"UI": "",
"Unknown file type '{{file_type}}'. Proceeding with the file upload anyway.": "",
"Update": "",
"UI": "使用者界面",
"Unknown file type '{{file_type}}'. Proceeding with the file upload anyway.": "未知的檔案類型 '{{file_type}}'。但仍會繼續上傳。",
"Update": "更新",
"Update and Copy Link": "更新並複製連結",
"Update password": "更新密碼",
"Updated at": "",
"Upload": "",
"Updated at": "更新於",
"Upload": "上傳",
"Upload a GGUF model": "上傳一個 GGUF 模型",
"Upload Files": "上傳文件",
"Upload Pipeline": "",
"Upload Files": "上傳檔案",
"Upload Pipeline": "上傳管線",
"Upload Progress": "上傳進度",
"URL Mode": "URL 模式",
"Use '#' in the prompt input to load and select your documents.": "在輸入框中輸入 '#' 以載入並選擇的文件。",
"Use '#' in the prompt input to load and select your documents.": "在輸入框中輸入 '#' 以載入並選擇的文件。",
"Use Gravatar": "使用 Gravatar",
"Use Initials": "使用初始像",
"use_mlock (Ollama)": "use_mlock奧拉馬",
"use_mmap (Ollama)": "use_mmap Ollama",
"Use Initials": "使用初始像",
"use_mlock (Ollama)": "use_mlockOllama",
"use_mmap (Ollama)": "use_mmapOllama",
"user": "使用者",
"User Permissions": "使用者權限",
"Users": "使用者",
"Utilize": "使用",
"Valid time units:": "有效時間單位:",
"Valves": "",
"variable": "變數",
"variable to have them replaced with clipboard content.": "變數將替換為剪貼簿內容",
"Version": "版本",
"Voice": "",
"Warning": "警告",
"Warning: If you update or change your embedding model, you will need to re-import all documents.": "警告:如果更新或更改你的嵌入模型,則需要重新導入所有文件",
"Warning: If you update or change your embedding model, you will need to re-import all documents.": "警告:如果更新或更改您的嵌入模型,則需要重新匯入所有文件",
"Web": "網頁",
"Web API": "",
"Web Loader Settings": "Web 載入器設定",
"Web Params": "Web 參數",
"Web Search": "Web 搜尋",
"Web Search Engine": "Web 搜尋引擎",
"Web API": "網頁 API",
"Web Loader Settings": "網頁載入器設定",
"Web Params": "網頁參數",
"Web Search": "網頁搜尋",
"Web Search Engine": "網頁搜尋引擎",
"Webhook URL": "Webhook URL",
"WebUI Settings": "WebUI 設定",
"WebUI will make requests to": "WebUI 將會存取",
"Whats New in": "全新內容",
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "當歷史被關閉時,這個瀏覽器上的新聊天將不會出現在任何裝置的歷史記錄中",
"Whisper (Local)": "",
"Widescreen Mode": "",
"Whisper (Local)": "Whisper本地",
"Widescreen Mode": "寬螢幕模式",
"Workspace": "工作區",
"Write a prompt suggestion (e.g. Who are you?)": "寫一個提示詞建議(例如:是誰?)",
"Write a prompt suggestion (e.g. Who are you?)": "寫一個提示詞建議(例如:是誰?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "寫一個 50 字的摘要來概括 [主題或關鍵詞]。",
"Yesterday": "昨天",
"You": "",
"You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "",
"You cannot clone a base model": "不能複製基礎模型",
"You have no archived conversations.": "沒有任何已封存的對話",
"You have shared this chat": "已分享此聊天",
"You're a helpful assistant.": "是一位善於協助他人的助手。",
"You": "",
"You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "您可以透過下方的「管理」按鈕新增記憶,個人化您的 LLM 互動,使其更有幫助並更符合您的需求。",
"You cannot clone a base model": "不能複製基礎模型",
"You have no archived conversations.": "沒有任何已封存的對話",
"You have shared this chat": "已分享此聊天",
"You're a helpful assistant.": "是一位善於協助他人的助手。",
"You're now logged in.": "已登入。",
"Your account status is currently pending activation.": "",
"Your account status is currently pending activation.": "您的帳號狀態目前待啟用。",
"Youtube": "Youtube",
"Youtube Loader Settings": "Youtube 載入器設定"
}

View file

@ -506,13 +506,36 @@ export const removeEmojis = (str) => {
return str.replace(emojiRegex, '');
};
export const removeFormattings = (str) => {
return str.replace(/(\*)(.*?)\1/g, '').replace(/(```)(.*?)\1/gs, '');
};
export const extractSentences = (text) => {
// Split the paragraph into sentences based on common punctuation marks
const sentences = text.split(/(?<=[.!?])\s+/);
// This regular expression matches code blocks marked by triple backticks
const codeBlockRegex = /```[\s\S]*?```/g;
let codeBlocks = [];
let index = 0;
// Temporarily replace code blocks with placeholders and store the blocks separately
text = text.replace(codeBlockRegex, (match) => {
let placeholder = `\u0000${index}\u0000`; // Use a unique placeholder
codeBlocks[index++] = match;
return placeholder;
});
// Split the modified text into sentences based on common punctuation marks, avoiding these blocks
let sentences = text.split(/(?<=[.!?])\s+/);
// Restore code blocks and process sentences
sentences = sentences.map((sentence) => {
// Check if the sentence includes a placeholder for a code block
return sentence.replace(/\u0000(\d+)\u0000/g, (_, idx) => codeBlocks[idx]);
});
return sentences
.map((sentence) => removeEmojis(sentence.trim()))
.filter((sentence) => sentence !== '');
.map((sentence) => removeFormattings(removeEmojis(sentence.trim())))
.filter((sentence) => sentence);
};
export const extractSentencesForAudio = (text) => {

View file

@ -29,13 +29,15 @@
showChangelog,
config,
showCallOverlay,
tools
tools,
functions
} from '$lib/stores';
import SettingsModal from '$lib/components/chat/SettingsModal.svelte';
import Sidebar from '$lib/components/layout/Sidebar.svelte';
import ChangelogModal from '$lib/components/ChangelogModal.svelte';
import AccountPending from '$lib/components/layout/Overlay/AccountPending.svelte';
import { getFunctions } from '$lib/apis/functions';
const i18n = getContext('i18n');
@ -93,6 +95,9 @@
(async () => {
tools.set(await getTools(localStorage.token));
})(),
(async () => {
functions.set(await getFunctions(localStorage.token));
})(),
(async () => {
banners.set(await getBanners(localStorage.token));
})(),

View file

@ -1,7 +1,7 @@
<script>
import { showSidebar } from '$lib/stores';
import Playground from '$lib/components/workspace/Playground.svelte';
import Playground from '$lib/components/playground/Playground.svelte';
</script>
<div

View file

@ -9,7 +9,7 @@
const i18n = getContext('i18n');
onMount(async () => {
functions.set(await getFunctions(localStorage.token));
// functions.set(await getFunctions(localStorage.token));
});
</script>

View file

@ -37,6 +37,8 @@
let loaded = false;
const BREAKPOINT = 768;
let wakeLock = null;
onMount(async () => {
theme.set(localStorage.theme);
@ -51,6 +53,31 @@
window.addEventListener('resize', onResize);
const setWakeLock = async () => {
try {
wakeLock = await navigator.wakeLock.request('screen');
} catch (err) {
// The Wake Lock request has failed - usually system related, such as battery.
console.log(err);
}
wakeLock.addEventListener('release', () => {
// the wake lock has been released
console.log('Wake Lock released');
});
};
if ('wakeLock' in navigator) {
await setWakeLock();
document.addEventListener('visibilitychange', async () => {
// Re-request the wake lock if the document becomes visible
if (wakeLock !== null && document.visibilityState === 'visible') {
await setWakeLock();
}
});
}
let backendConfig = null;
try {
backendConfig = await getBackendConfig();