Merge branch 'refs/heads/dev' into feat/sqlalchemy-instead-of-peewee

# Conflicts:
#	backend/apps/webui/models/functions.py
#	backend/apps/webui/routers/chats.py
This commit is contained in:
Jonathan Rohde 2024-06-28 09:19:56 +02:00
commit df47c496d3
62 changed files with 693 additions and 317 deletions

View File

@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.3.6] - 2024-06-27
### Added
- **✨ "Functions" Feature**: You can now utilize "Functions" like filters (middleware) and pipe (model) functions directly within the WebUI. While largely compatible with Pipelines, these native functions can be executed easily within Open WebUI. Example use cases for filter functions include usage monitoring, real-time translation, moderation, and automemory. For pipe functions, the scope ranges from Cohere and Anthropic integration directly within Open WebUI, enabling "Valves" for per-user OpenAI API key usage, and much more. If you encounter issues, SAFE_MODE has been introduced.
- **📁 Files API**: Compatible with OpenAI, this feature allows for custom Retrieval-Augmented Generation (RAG) in conjunction with the Filter Function. More examples will be shared on our community platform and official documentation website.
- **🛠️ Tool Enhancements**: Tools now support citations and "Valves". Documentation will be available shortly.
- **🔗 Iframe Support via Files API**: Enables rendering HTML directly into your chat interface using functions and tools. Use cases include playing games like DOOM and Snake, displaying a weather applet, and implementing Anthropic "artifacts"-like features. Stay tuned for updates on our community platform and documentation.
- **🔒 Experimental OAuth Support**: New experimental OAuth support. Check our documentation for more details.
- **🖼️ Custom Background Support**: Set a custom background from Settings > Interface to personalize your experience.
- **🔑 AUTOMATIC1111_API_AUTH Support**: Enhanced security for the AUTOMATIC1111 API.
- **🎨 Code Highlight Optimization**: Improved code highlighting features.
- **🎙️ Voice Interruption Feature**: Reintroduced and now toggleable from Settings > Interface.
- **💤 Wakelock API**: Now in use to prevent screen dimming during important tasks.
- **🔐 API Key Privacy**: All API keys are now hidden by default for better security.
- **🔍 New Web Search Provider**: Added jina_search as a new option.
- **🌐 Enhanced Internationalization (i18n)**: Improved Korean translation and updated Chinese and Ukrainian translations.
### Fixed
- **🔧 Conversation Mode Issue**: Fixed the issue where Conversation Mode remained active after being removed from settings.
- **📏 Scroll Button Obstruction**: Resolved the issue where the scrollToBottom button container obstructed clicks on buttons beneath it.
### Changed
- **⏲️ AIOHTTP_CLIENT_TIMEOUT**: Now set to 'None' by default for improved configuration flexibility.
- **📞 Voice Call Enhancements**: Improved by skipping code blocks and expressions during calls.
- **🚫 Error Message Handling**: Disabled the continuation of operations with error messages.
- **🗂️ Playground Relocation**: Moved the Playground from the workspace to the user menu for better user experience.
## [0.3.5] - 2024-06-16
### Added

View File

@ -16,7 +16,7 @@ from faster_whisper import WhisperModel
from constants import ERROR_MESSAGES
from utils.utils import (
get_current_user,
get_verified_user,
get_admin_user,
)
@ -258,7 +258,7 @@ async def update_image_size(
@app.get("/models")
def get_models(user=Depends(get_current_user)):
def get_models(user=Depends(get_verified_user)):
try:
if app.state.config.ENGINE == "openai":
return [
@ -347,7 +347,7 @@ def set_model_handler(model: str):
@app.post("/models/default/update")
def update_default_model(
form_data: UpdateModelForm,
user=Depends(get_current_user),
user=Depends(get_verified_user),
):
return set_model_handler(form_data.model)
@ -424,7 +424,7 @@ def save_url_image(url):
@app.post("/generations")
def generate_image(
form_data: GenerateImageForm,
user=Depends(get_current_user),
user=Depends(get_verified_user),
):
width, height = tuple(map(int, app.state.config.IMAGE_SIZE.split("x")))

View File

@ -16,7 +16,7 @@ from apps.webui.models.users import Users
from constants import ERROR_MESSAGES
from utils.utils import (
decode_token,
get_current_user,
get_verified_user,
get_verified_user,
get_admin_user,
)
@ -296,7 +296,7 @@ async def get_all_models(raw: bool = False):
@app.get("/models")
@app.get("/models/{url_idx}")
async def get_models(url_idx: Optional[int] = None, user=Depends(get_current_user)):
async def get_models(url_idx: Optional[int] = None, user=Depends(get_verified_user)):
if url_idx == None:
models = await get_all_models()
if app.state.config.ENABLE_MODEL_FILTER:

View File

@ -85,7 +85,7 @@ from utils.misc import (
sanitize_filename,
extract_folders_after_data_docs,
)
from utils.utils import get_current_user, get_admin_user
from utils.utils import get_verified_user, get_admin_user
from config import (
AppConfig,
@ -529,7 +529,7 @@ async def update_rag_config(form_data: ConfigUpdateForm, user=Depends(get_admin_
@app.get("/template")
async def get_rag_template(user=Depends(get_current_user)):
async def get_rag_template(user=Depends(get_verified_user)):
return {
"status": True,
"template": app.state.config.RAG_TEMPLATE,
@ -586,7 +586,7 @@ class QueryDocForm(BaseModel):
@app.post("/query/doc")
def query_doc_handler(
form_data: QueryDocForm,
user=Depends(get_current_user),
user=Depends(get_verified_user),
):
try:
if app.state.config.ENABLE_RAG_HYBRID_SEARCH:
@ -626,7 +626,7 @@ class QueryCollectionsForm(BaseModel):
@app.post("/query/collection")
def query_collection_handler(
form_data: QueryCollectionsForm,
user=Depends(get_current_user),
user=Depends(get_verified_user),
):
try:
if app.state.config.ENABLE_RAG_HYBRID_SEARCH:
@ -657,7 +657,7 @@ def query_collection_handler(
@app.post("/youtube")
def store_youtube_video(form_data: UrlForm, user=Depends(get_current_user)):
def store_youtube_video(form_data: UrlForm, user=Depends(get_verified_user)):
try:
loader = YoutubeLoader.from_youtube_url(
form_data.url,
@ -686,7 +686,7 @@ def store_youtube_video(form_data: UrlForm, user=Depends(get_current_user)):
@app.post("/web")
def store_web(form_data: UrlForm, user=Depends(get_current_user)):
def store_web(form_data: UrlForm, user=Depends(get_verified_user)):
# "https://www.gutenberg.org/files/1727/1727-h/1727-h.htm"
try:
loader = get_web_loader(
@ -864,7 +864,7 @@ def search_web(engine: str, query: str) -> list[SearchResult]:
@app.post("/web/search")
def store_web_search(form_data: SearchForm, user=Depends(get_current_user)):
def store_web_search(form_data: SearchForm, user=Depends(get_verified_user)):
try:
logging.info(
f"trying to web search with {app.state.config.RAG_WEB_SEARCH_ENGINE, form_data.query}"
@ -1084,7 +1084,7 @@ def get_loader(filename: str, file_content_type: str, file_path: str):
def store_doc(
collection_name: Optional[str] = Form(None),
file: UploadFile = File(...),
user=Depends(get_current_user),
user=Depends(get_verified_user),
):
# "https://www.gutenberg.org/files/1727/1727-h/1727-h.htm"
@ -1145,7 +1145,7 @@ class ProcessDocForm(BaseModel):
@app.post("/process/doc")
def process_doc(
form_data: ProcessDocForm,
user=Depends(get_current_user),
user=Depends(get_verified_user),
):
try:
file = Files.get_file_by_id(form_data.file_id)
@ -1200,7 +1200,7 @@ class TextRAGForm(BaseModel):
@app.post("/text")
def store_text(
form_data: TextRAGForm,
user=Depends(get_current_user),
user=Depends(get_verified_user),
):
collection_name = form_data.collection_name

View File

@ -0,0 +1,49 @@
"""Peewee migrations -- 017_add_user_oauth_sub.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(
"function",
is_global=pw.BooleanField(default=False),
)
def rollback(migrator: Migrator, database: pw.Database, *, fake=False):
"""Write your rollback migrations here."""
migrator.remove_fields("function", "is_global")

View File

@ -33,6 +33,7 @@ class Function(Base):
meta = Column(JSONField)
valves = Column(JSONField)
is_active = Column(Boolean)
is_global = Column(Boolean)
updated_at = Column(BigInteger)
created_at = Column(BigInteger)
@ -50,6 +51,7 @@ class FunctionModel(BaseModel):
content: str
meta: FunctionMeta
is_active: bool = False
is_global: bool = False
updated_at: int # timestamp in epoch
created_at: int # timestamp in epoch
@ -68,6 +70,7 @@ class FunctionResponse(BaseModel):
name: str
meta: FunctionMeta
is_active: bool
is_global: bool
updated_at: int # timestamp in epoch
created_at: int # timestamp in epoch
@ -146,6 +149,16 @@ class FunctionsTable:
for function in Session.query(Function).filter_by(type=type).all()
]
def get_global_filter_functions(self) -> List[FunctionModel]:
return [
FunctionModel(**model_to_dict(function))
for function in Function.select().where(
Function.type == "filter",
Function.is_active == True,
Function.is_global == True,
)
]
def get_function_valves_by_id(self, id: str) -> Optional[dict]:
try:
function = Session.get(Function, id)

View File

@ -136,6 +136,7 @@ async def signin(request: Request, response: Response, form_data: SigninForm):
if not Users.get_user_by_email(trusted_email.lower()):
await signup(
request,
response,
SignupForm(
email=trusted_email, password=str(uuid.uuid4()), name=trusted_name
),
@ -153,6 +154,7 @@ async def signin(request: Request, response: Response, form_data: SigninForm):
await signup(
request,
response,
SignupForm(email=admin_email, password=admin_password, name="User"),
)

View File

@ -1,8 +1,7 @@
from fastapi import Depends, Request, HTTPException, status
from datetime import datetime, timedelta
from typing import List, Union, Optional
from utils.utils import get_current_user, get_admin_user
from utils.utils import get_verified_user, get_admin_user
from fastapi import APIRouter
from pydantic import BaseModel
import json
@ -44,7 +43,7 @@ router = APIRouter()
@router.get("/", response_model=List[ChatTitleIdResponse])
@router.get("/list", response_model=List[ChatTitleIdResponse])
async def get_session_user_chat_list(
user=Depends(get_current_user), skip: int = 0, limit: int = 50
user=Depends(get_verified_user), skip: int = 0, limit: int = 50
):
return Chats.get_chat_list_by_user_id(user.id, skip, limit)
@ -55,7 +54,7 @@ async def get_session_user_chat_list(
@router.delete("/", response_model=bool)
async def delete_all_user_chats(request: Request, user=Depends(get_current_user)):
async def delete_all_user_chats(request: Request, user=Depends(get_verified_user)):
if (
user.role == "user"
@ -93,7 +92,7 @@ async def get_user_chat_list_by_user_id(
@router.post("/new", response_model=Optional[ChatResponse])
async def create_new_chat(form_data: ChatForm, user=Depends(get_current_user)):
async def create_new_chat(form_data: ChatForm, user=Depends(get_verified_user)):
try:
chat = Chats.insert_new_chat(user.id, form_data)
return ChatResponse(**{**chat.model_dump(), "chat": json.loads(chat.chat)})
@ -110,7 +109,7 @@ async def create_new_chat(form_data: ChatForm, user=Depends(get_current_user)):
@router.get("/all", response_model=List[ChatResponse])
async def get_user_chats(user=Depends(get_current_user)):
async def get_user_chats(user=Depends(get_verified_user)):
return [
ChatResponse(**{**chat.model_dump(), "chat": json.loads(chat.chat)})
for chat in Chats.get_chats_by_user_id(user.id)
@ -123,7 +122,7 @@ async def get_user_chats(user=Depends(get_current_user)):
@router.get("/all/archived", response_model=List[ChatResponse])
async def get_user_archived_chats(user=Depends(get_current_user)):
async def get_user_archived_chats(user=Depends(get_verified_user)):
return [
ChatResponse(**{**chat.model_dump(), "chat": json.loads(chat.chat)})
for chat in Chats.get_archived_chats_by_user_id(user.id)
@ -155,7 +154,7 @@ async def get_all_user_chats_in_db(user=Depends(get_admin_user)):
@router.get("/archived", response_model=List[ChatTitleIdResponse])
async def get_archived_session_user_chat_list(
user=Depends(get_current_user), skip: int = 0, limit: int = 50
user=Depends(get_verified_user), skip: int = 0, limit: int = 50
):
return Chats.get_archived_chat_list_by_user_id(user.id, skip, limit)
@ -166,7 +165,7 @@ async def get_archived_session_user_chat_list(
@router.post("/archive/all", response_model=bool)
async def archive_all_chats(user=Depends(get_current_user)):
async def archive_all_chats(user=Depends(get_verified_user)):
return Chats.archive_all_chats_by_user_id(user.id)
@ -176,7 +175,7 @@ async def archive_all_chats(user=Depends(get_current_user)):
@router.get("/share/{share_id}", response_model=Optional[ChatResponse])
async def get_shared_chat_by_id(share_id: str, user=Depends(get_current_user)):
async def get_shared_chat_by_id(share_id: str, user=Depends(get_verified_user)):
if user.role == "pending":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND
@ -208,7 +207,7 @@ class TagNameForm(BaseModel):
@router.post("/tags", response_model=List[ChatTitleIdResponse])
async def get_user_chat_list_by_tag_name(
form_data: TagNameForm, user=Depends(get_current_user)
form_data: TagNameForm, user=Depends(get_verified_user)
):
print(form_data)
@ -233,7 +232,7 @@ async def get_user_chat_list_by_tag_name(
@router.get("/tags/all", response_model=List[TagModel])
async def get_all_tags(user=Depends(get_current_user)):
async def get_all_tags(user=Depends(get_verified_user)):
try:
tags = Tags.get_tags_by_user_id(user.id)
return tags
@ -250,7 +249,7 @@ async def get_all_tags(user=Depends(get_current_user)):
@router.get("/{id}", response_model=Optional[ChatResponse])
async def get_chat_by_id(id: str, user=Depends(get_current_user)):
async def get_chat_by_id(id: str, user=Depends(get_verified_user)):
chat = Chats.get_chat_by_id_and_user_id(id, user.id)
if chat:
@ -268,7 +267,7 @@ async def get_chat_by_id(id: str, user=Depends(get_current_user)):
@router.post("/{id}", response_model=Optional[ChatResponse])
async def update_chat_by_id(
id: str, form_data: ChatForm, user=Depends(get_current_user)
id: str, form_data: ChatForm, user=Depends(get_verified_user)
):
chat = Chats.get_chat_by_id_and_user_id(id, user.id)
if chat:
@ -289,7 +288,7 @@ async def update_chat_by_id(
@router.delete("/{id}", response_model=bool)
async def delete_chat_by_id(request: Request, id: str, user=Depends(get_current_user)):
async def delete_chat_by_id(request: Request, id: str, user=Depends(get_verified_user)):
if user.role == "admin":
result = Chats.delete_chat_by_id(id)
@ -311,7 +310,7 @@ async def delete_chat_by_id(request: Request, id: str, user=Depends(get_current_
@router.get("/{id}/clone", response_model=Optional[ChatResponse])
async def clone_chat_by_id(id: str, user=Depends(get_current_user)):
async def clone_chat_by_id(id: str, user=Depends(get_verified_user)):
chat = Chats.get_chat_by_id_and_user_id(id, user.id)
if chat:
@ -337,7 +336,7 @@ async def clone_chat_by_id(id: str, user=Depends(get_current_user)):
@router.get("/{id}/archive", response_model=Optional[ChatResponse])
async def archive_chat_by_id(id: str, user=Depends(get_current_user)):
async def archive_chat_by_id(id: str, user=Depends(get_verified_user)):
chat = Chats.get_chat_by_id_and_user_id(id, user.id)
if chat:
chat = Chats.toggle_chat_archive_by_id(id)
@ -354,7 +353,7 @@ async def archive_chat_by_id(id: str, user=Depends(get_current_user)):
@router.post("/{id}/share", response_model=Optional[ChatResponse])
async def share_chat_by_id(id: str, user=Depends(get_current_user)):
async def share_chat_by_id(id: str, user=Depends(get_verified_user)):
chat = Chats.get_chat_by_id_and_user_id(id, user.id)
if chat:
if chat.share_id:
@ -386,7 +385,7 @@ async def share_chat_by_id(id: str, user=Depends(get_current_user)):
@router.delete("/{id}/share", response_model=Optional[bool])
async def delete_shared_chat_by_id(id: str, user=Depends(get_current_user)):
async def delete_shared_chat_by_id(id: str, user=Depends(get_verified_user)):
chat = Chats.get_chat_by_id_and_user_id(id, user.id)
if chat:
if not chat.share_id:
@ -409,7 +408,7 @@ async def delete_shared_chat_by_id(id: str, user=Depends(get_current_user)):
@router.get("/{id}/tags", response_model=List[TagModel])
async def get_chat_tags_by_id(id: str, user=Depends(get_current_user)):
async def get_chat_tags_by_id(id: str, user=Depends(get_verified_user)):
tags = Tags.get_tags_by_chat_id_and_user_id(id, user.id)
if tags != None:
@ -427,7 +426,7 @@ async def get_chat_tags_by_id(id: str, user=Depends(get_current_user)):
@router.post("/{id}/tags", response_model=Optional[ChatIdTagModel])
async def add_chat_tag_by_id(
id: str, form_data: ChatIdTagForm, user=Depends(get_current_user)
id: str, form_data: ChatIdTagForm, user=Depends(get_verified_user)
):
tags = Tags.get_tags_by_chat_id_and_user_id(id, user.id)
@ -454,9 +453,7 @@ async def add_chat_tag_by_id(
@router.delete("/{id}/tags", response_model=Optional[bool])
async def delete_chat_tag_by_id(
id: str,
form_data: ChatIdTagForm,
user=Depends(get_current_user),
id: str, form_data: ChatIdTagForm, user=Depends(get_verified_user)
):
result = Tags.delete_tag_by_tag_name_and_chat_id_and_user_id(
form_data.tag_name, id, user.id
@ -476,7 +473,7 @@ async def delete_chat_tag_by_id(
@router.delete("/{id}/tags/all", response_model=Optional[bool])
async def delete_all_chat_tags_by_id(id: str, user=Depends(get_current_user)):
async def delete_all_chat_tags_by_id(id: str, user=Depends(get_verified_user)):
result = Tags.delete_tags_by_chat_id_and_user_id(id, user.id)
if result:

View File

@ -14,7 +14,7 @@ from apps.webui.models.users import Users
from utils.utils import (
get_password_hash,
get_current_user,
get_verified_user,
get_admin_user,
create_token,
)
@ -84,6 +84,6 @@ async def set_banners(
@router.get("/banners", response_model=List[BannerModel])
async def get_banners(
request: Request,
user=Depends(get_current_user),
user=Depends(get_verified_user),
):
return request.app.state.config.BANNERS

View File

@ -14,7 +14,7 @@ from apps.webui.models.documents import (
DocumentResponse,
)
from utils.utils import get_current_user, get_admin_user
from utils.utils import get_verified_user, get_admin_user
from constants import ERROR_MESSAGES
router = APIRouter()
@ -25,7 +25,7 @@ router = APIRouter()
@router.get("/", response_model=List[DocumentResponse])
async def get_documents(user=Depends(get_current_user)):
async def get_documents(user=Depends(get_verified_user)):
docs = [
DocumentResponse(
**{
@ -74,7 +74,7 @@ async def create_new_doc(form_data: DocumentForm, user=Depends(get_admin_user)):
@router.get("/doc", response_model=Optional[DocumentResponse])
async def get_doc_by_name(name: str, user=Depends(get_current_user)):
async def get_doc_by_name(name: str, user=Depends(get_verified_user)):
doc = Documents.get_doc_by_name(name)
if doc:
@ -106,7 +106,7 @@ class TagDocumentForm(BaseModel):
@router.post("/doc/tags", response_model=Optional[DocumentResponse])
async def tag_doc_by_name(form_data: TagDocumentForm, user=Depends(get_current_user)):
async def tag_doc_by_name(form_data: TagDocumentForm, user=Depends(get_verified_user)):
doc = Documents.update_doc_content_by_name(form_data.name, {"tags": form_data.tags})
if doc:

View File

@ -147,6 +147,33 @@ async def toggle_function_by_id(id: str, user=Depends(get_admin_user)):
)
############################
# ToggleGlobalById
############################
@router.post("/id/{id}/toggle/global", response_model=Optional[FunctionModel])
async def toggle_global_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_global": not function.is_global}
)
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
############################

View File

@ -8,7 +8,7 @@ import json
from apps.webui.models.prompts import Prompts, PromptForm, PromptModel
from utils.utils import get_current_user, get_admin_user
from utils.utils import get_verified_user, get_admin_user
from constants import ERROR_MESSAGES
router = APIRouter()
@ -19,7 +19,7 @@ router = APIRouter()
@router.get("/", response_model=List[PromptModel])
async def get_prompts(user=Depends(get_current_user)):
async def get_prompts(user=Depends(get_verified_user)):
return Prompts.get_prompts()
@ -52,7 +52,7 @@ async def create_new_prompt(form_data: PromptForm, user=Depends(get_admin_user))
@router.get("/command/{command}", response_model=Optional[PromptModel])
async def get_prompt_by_command(command: str, user=Depends(get_current_user)):
async def get_prompt_by_command(command: str, user=Depends(get_verified_user)):
prompt = Prompts.get_prompt_by_command(f"/{command}")
if prompt:

View File

@ -433,15 +433,21 @@ class ChatCompletionMiddleware(BaseHTTPMiddleware):
return 0
filter_ids = [
function.id for function in Functions.get_global_filter_functions()
]
if "info" in model and "meta" in model["info"]:
filter_ids.extend(model["info"]["meta"].get("filterIds", []))
filter_ids = list(set(filter_ids))
enabled_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"]:
filter_ids.extend(model["info"]["meta"].get("filterIds", []))
filter_ids = list(set(filter_ids))
filter_ids = [
filter_id for filter_id in filter_ids if filter_id in enabled_filter_ids
]
filter_ids.sort(key=get_priority)
for filter_id in filter_ids:
@ -939,7 +945,6 @@ async def generate_chat_completions(form_data: dict, user=Depends(get_verified_u
)
model = app.state.MODELS[model_id]
print(model)
pipe = model.get("pipe")
if pipe:
@ -1030,15 +1035,19 @@ async def chat_completed(form_data: dict, user=Depends(get_verified_user)):
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
filter_ids = [function.id for function in Functions.get_global_filter_functions()]
if "info" in model and "meta" in model["info"]:
filter_ids.extend(model["info"]["meta"].get("filterIds", []))
filter_ids = list(set(filter_ids))
enabled_filter_ids = [
function.id
for function in Functions.get_functions_by_type("filter", active_only=True)
]
filter_ids = [
filter_id for filter_id in filter_ids if filter_id in enabled_filter_ids
]
# Sort filter_ids by priority, using the get_priority function
filter_ids.sort(key=get_priority)

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "open-webui",
"version": "0.3.6.dev1",
"version": "0.3.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "open-webui",
"version": "0.3.6.dev1",
"version": "0.3.6",
"dependencies": {
"@codemirror/lang-javascript": "^6.2.2",
"@codemirror/lang-python": "^6.1.6",

View File

@ -1,6 +1,6 @@
{
"name": "open-webui",
"version": "0.3.6.dev1",
"version": "0.3.6",
"private": true,
"scripts": {
"dev": "npm run pyodide:fetch && vite dev --host",

View File

@ -224,6 +224,38 @@ export const toggleFunctionById = async (token: string, id: string) => {
return res;
};
export const toggleGlobalById = async (token: string, id: string) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/functions/id/${id}/toggle/global`, {
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;

View File

@ -230,7 +230,10 @@
{/if}
</div>
<SensitiveInput placeholder={$i18n.t('API Key')} value={OPENAI_API_KEYS[idx]} />
<SensitiveInput
placeholder={$i18n.t('API Key')}
bind:value={OPENAI_API_KEYS[idx]}
/>
<div class="self-center flex items-center">
{#if idx === 0}
<button

View File

@ -234,35 +234,40 @@
console.log(sentences);
sentencesAudio = sentences.reduce((a, e, i, arr) => {
a[i] = null;
return a;
}, {});
if (sentences.length > 0) {
sentencesAudio = sentences.reduce((a, e, i, arr) => {
a[i] = null;
return a;
}, {});
let lastPlayedAudioPromise = Promise.resolve(); // Initialize a promise that resolves immediately
let lastPlayedAudioPromise = Promise.resolve(); // Initialize a promise that resolves immediately
for (const [idx, sentence] of sentences.entries()) {
const res = await synthesizeOpenAISpeech(
localStorage.token,
$settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice,
sentence
).catch((error) => {
toast.error(error);
for (const [idx, sentence] of sentences.entries()) {
const res = await synthesizeOpenAISpeech(
localStorage.token,
$settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice,
sentence
).catch((error) => {
toast.error(error);
speaking = null;
loadingSpeech = false;
speaking = null;
loadingSpeech = false;
return null;
});
return null;
});
if (res) {
const blob = await res.blob();
const blobUrl = URL.createObjectURL(blob);
const audio = new Audio(blobUrl);
sentencesAudio[idx] = audio;
loadingSpeech = false;
lastPlayedAudioPromise = lastPlayedAudioPromise.then(() => playAudio(idx));
if (res) {
const blob = await res.blob();
const blobUrl = URL.createObjectURL(blob);
const audio = new Audio(blobUrl);
sentencesAudio[idx] = audio;
loadingSpeech = false;
lastPlayedAudioPromise = lastPlayedAudioPromise.then(() => playAudio(idx));
}
}
} else {
speaking = null;
loadingSpeech = false;
}
} else {
let voices = [];

View File

@ -1,5 +1,5 @@
<script lang="ts">
export let value: string;
export let value: string = '';
export let placeholder = '';
export let readOnly = false;
export let outerClassName = 'flex flex-1';

View File

@ -0,0 +1,19 @@
<script lang="ts">
export let className = 'w-4 h-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="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 0 1 3 12c0-1.605.42-3.113 1.157-4.418"
/>
</svg>

View File

@ -14,7 +14,8 @@
exportFunctions,
getFunctionById,
getFunctions,
toggleFunctionById
toggleFunctionById,
toggleGlobalById
} from '$lib/apis/functions';
import ArrowDownTray from '../icons/ArrowDownTray.svelte';
@ -113,6 +114,22 @@
models.set(await getModels(localStorage.token));
}
};
const toggleGlobalHandler = async (func) => {
const res = await toggleGlobalById(localStorage.token, func.id).catch((error) => {
toast.error(error);
});
if (res) {
if (func.is_global) {
toast.success($i18n.t('Filter is now globally enabled'));
} else {
toast.success($i18n.t('Filter is now globally disabled'));
}
functions.set(await getFunctions(localStorage.token));
}
};
</script>
<svelte:head>
@ -259,6 +276,7 @@
</Tooltip>
<FunctionMenu
{func}
editHandler={() => {
goto(`/workspace/functions/edit?id=${encodeURIComponent(func.id)}`);
}}
@ -275,6 +293,11 @@
selectedFunction = func;
showDeleteConfirm = true;
}}
toggleGlobalHandler={() => {
if (func.type === 'filter') {
toggleGlobalHandler(func);
}
}}
onClose={() => {}}
>
<button
@ -286,13 +309,15 @@
</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));
}}
/>
<Tooltip content={func.is_active ? 'Enabled' : 'Disabled'}>
<Switch
bind:state={func.is_active}
on:change={async (e) => {
toggleFunctionById(localStorage.token, func.id);
models.set(await getModels(localStorage.token));
}}
/>
</Tooltip>
</div>
</div>
</div>

View File

@ -5,21 +5,24 @@
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';
import Switch from '$lib/components/common/Switch.svelte';
import GlobeAlt from '$lib/components/icons/GlobeAlt.svelte';
const i18n = getContext('i18n');
export let func;
export let editHandler: Function;
export let shareHandler: Function;
export let cloneHandler: Function;
export let exportHandler: Function;
export let deleteHandler: Function;
export let toggleGlobalHandler: Function;
export let onClose: Function;
let show = false;
@ -45,6 +48,24 @@
align="start"
transition={flyAndScale}
>
{#if func.type === 'filter'}
<div
class="flex gap-2 justify-between items-center px-3 py-2 text-sm font-medium cursor-pointerrounded-md"
>
<div class="flex gap-2 items-center">
<GlobeAlt />
<div class="flex items-center">{$i18n.t('Global')}</div>
</div>
<div>
<Switch on:change={toggleGlobalHandler} bind:state={func.is_global} />
</div>
</div>
<hr class="border-gray-100 dark:border-gray-800 my-1" />
{/if}
<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={() => {

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "وضع الملف",
"File not found.": "لم يتم العثور على الملف.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "تم اكتشاف انتحال بصمة الإصبع: غير قادر على استخدام الأحرف الأولى كصورة رمزية. الافتراضي لصورة الملف الشخصي الافتراضية.",
"Fluidly stream large external response chunks": "دفق قطع الاستجابة الخارجية الكبيرة بسلاسة",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "إنشاء استعلام بحث",
"Generation Info": "معلومات الجيل",
"Global": "",
"Good Response": "استجابة جيدة",
"Google PSE API Key": "مفتاح واجهة برمجة تطبيقات PSE من Google",
"Google PSE Engine Id": "معرف محرك PSE من Google",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Файл Мод",
"File not found.": "Файл не е намерен.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Потвърждаване на отпечатък: Не може да се използва инициализационна буква като аватар. Потребителят се връща към стандартна аватарка.",
"Fluidly stream large external response chunks": "Плавно предаване на големи части от външен отговор",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "Генериране на заявка за търсене",
"Generation Info": "Информация за Генерация",
"Global": "",
"Good Response": "Добра отговор",
"Google PSE API Key": "Google PSE API ключ",
"Google PSE Engine Id": "Идентификатор на двигателя на Google PSE",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "ফাইল মোড",
"File not found.": "ফাইল পাওয়া যায়নি",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "ফিঙ্গারপ্রিন্ট স্পুফিং ধরা পড়েছে: অ্যাভাটার হিসেবে নামের আদ্যক্ষর ব্যবহার করা যাচ্ছে না। ডিফল্ট প্রোফাইল পিকচারে ফিরিয়ে নেয়া হচ্ছে।",
"Fluidly stream large external response chunks": "বড় এক্সটার্নাল রেসপন্স চাঙ্কগুলো মসৃণভাবে প্রবাহিত করুন",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "অনুসন্ধান ক্যোয়ারী তৈরি করা হচ্ছে",
"Generation Info": "জেনারেশন ইনফো",
"Global": "",
"Good Response": "ভালো সাড়া",
"Google PSE API Key": "গুগল পিএসই এপিআই কী",
"Google PSE Engine Id": "গুগল পিএসই ইঞ্জিন আইডি",

View File

@ -261,6 +261,8 @@
"File": "Arxiu",
"File Mode": "Mode d'arxiu",
"File not found.": "No s'ha trobat l'arxiu.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "Filtres",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "S'ha detectat la suplantació d'identitat de l'empremta digital: no es poden utilitzar les inicials com a avatar. S'estableix la imatge de perfil predeterminada.",
"Fluidly stream large external response chunks": "Transmetre amb fluïdesa grans trossos de resposta externa",
@ -279,6 +281,7 @@
"Generate Image": "Generar imatge",
"Generating search query": "Generant consulta",
"Generation Info": "Informació sobre la generació",
"Global": "",
"Good Response": "Bona resposta",
"Google PSE API Key": "Clau API PSE de Google",
"Google PSE Engine Id": "Identificador del motor PSE de Google",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "File mode",
"File not found.": "Wala makit-an ang file.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "",
"Fluidly stream large external response chunks": "Hapsay nga paghatud sa daghang mga tipik sa eksternal nga mga tubag",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "",
"Generation Info": "",
"Global": "",
"Good Response": "",
"Google PSE API Key": "",
"Google PSE Engine Id": "",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "File Modus",
"File not found.": "Datei nicht gefunden.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Fingerprint spoofing erkannt: Initialen können nicht als Avatar verwendet werden. Es wird auf das Standardprofilbild zurückgegriffen.",
"Fluidly stream large external response chunks": "Große externe Antwortblöcke flüssig streamen",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "Suchanfrage generieren",
"Generation Info": "Generierungsinformationen",
"Global": "",
"Good Response": "Gute Antwort",
"Google PSE API Key": "Google PSE-API-Schlüssel",
"Google PSE Engine Id": "Google PSE-Engine-ID",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Bark Mode",
"File not found.": "Bark not found.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Fingerprint dogeing: Unable to use initials as avatar. Defaulting to default doge image.",
"Fluidly stream large external response chunks": "Fluidly wow big chunks",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "",
"Generation Info": "",
"Global": "",
"Good Response": "",
"Google PSE API Key": "",
"Google PSE Engine Id": "",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "",
"File not found.": "",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "",
"Fluidly stream large external response chunks": "",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "",
"Generation Info": "",
"Global": "",
"Good Response": "",
"Google PSE API Key": "",
"Google PSE Engine Id": "",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "",
"File not found.": "",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "",
"Fluidly stream large external response chunks": "",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "",
"Generation Info": "",
"Global": "",
"Good Response": "",
"Google PSE API Key": "",
"Google PSE Engine Id": "",

View File

@ -4,7 +4,7 @@
"(e.g. `sh webui.sh --api --api-auth username_password`)": "",
"(e.g. `sh webui.sh --api`)": "(p.ej. `sh webui.sh --api`)",
"(latest)": "(latest)",
"{{ models }}": "{{ modelos }}",
"{{ models }}": "{{ models }}",
"{{ owner }}: You cannot delete a base model": "{{ owner }}: No se puede eliminar un modelo base",
"{{modelName}} is thinking...": "{{modelName}} está pensando...",
"{{user}}'s Chats": "{{user}}'s Chats",
@ -13,9 +13,9 @@
"a user": "un usuario",
"About": "Sobre nosotros",
"Account": "Cuenta",
"Account Activation Pending": "",
"Account Activation Pending": "Activación de cuenta pendiente",
"Accurate information": "Información precisa",
"Active Users": "",
"Active Users": "Usuarios activos",
"Add": "Agregar",
"Add a model id": "Adición de un identificador de modelo",
"Add a short description about what this model does": "Agregue una breve descripción sobre lo que hace este modelo",
@ -31,10 +31,10 @@
"Add User": "Agregar Usuario",
"Adjusting these settings will apply changes universally to all users.": "Ajustar estas opciones aplicará los cambios universalmente a todos los usuarios.",
"admin": "admin",
"Admin": "",
"Admin": "Admin",
"Admin Panel": "Panel de Administración",
"Admin Settings": "Configuración de Administrador",
"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.": "Admins tienen acceso a todas las herramientas en todo momento; los usuarios necesitan herramientas asignadas por modelo en el espacio de trabajo.",
"Advanced Parameters": "Parámetros Avanzados",
"Advanced Params": "Parámetros avanzados",
"all": "todo",
@ -42,9 +42,9 @@
"All Users": "Todos los Usuarios",
"Allow": "Permitir",
"Allow Chat Deletion": "Permitir Borrar Chats",
"Allow non-local voices": "",
"Allow User Location": "",
"Allow Voice Interruption in Call": "",
"Allow non-local voices": "Permitir voces no locales",
"Allow User Location": "Permitir Ubicación del Usuario",
"Allow Voice Interruption in Call": "Permitir interrupción de voz en llamada",
"alphanumeric characters and hyphens": "caracteres alfanuméricos y guiones",
"Already have an account?": "¿Ya tienes una cuenta?",
"an assistant": "un asistente",
@ -63,7 +63,7 @@
"Attach file": "Adjuntar archivo",
"Attention to detail": "Detalle preciso",
"Audio": "Audio",
"Audio settings updated successfully": "",
"Audio settings updated successfully": "Opciones de audio actualizadas correctamente",
"August": "Agosto",
"Auto-playback response": "Respuesta de reproducción automática",
"AUTOMATIC1111 Api Auth String": "",
@ -74,19 +74,19 @@
"Bad Response": "Respuesta incorrecta",
"Banners": "Banners",
"Base Model (From)": "Modelo base (desde)",
"Batch Size (num_batch)": "",
"Batch Size (num_batch)": "Tamaño del Batch (num_batch)",
"before": "antes",
"Being lazy": "Ser perezoso",
"Brave Search API Key": "Clave de API de Brave Search",
"Bypass SSL verification for Websites": "Desactivar la verificación SSL para sitios web",
"Call": "",
"Call feature is not supported when using Web STT engine": "",
"Camera": "",
"Call": "Llamada",
"Call feature is not supported when using Web STT engine": "La funcionalidad de llamada no puede usarse junto con el motor de STT Web",
"Camera": "Cámara",
"Cancel": "Cancelar",
"Capabilities": "Capacidades",
"Change Password": "Cambia la Contraseña",
"Chat": "Chat",
"Chat Background Image": "",
"Chat Background Image": "Imágen de fondo del Chat",
"Chat Bubble UI": "Burbuja de chat UI",
"Chat direction": "Dirección del Chat",
"Chat History": "Historial del Chat",
@ -100,35 +100,35 @@
"Chunk Params": "Parámetros de fragmentos",
"Chunk Size": "Tamaño de fragmentos",
"Citation": "Cita",
"Clear memory": "",
"Clear memory": "Liberar memoria",
"Click here for help.": "Presiona aquí para obtener ayuda.",
"Click here to": "Presiona aquí para",
"Click here to download user import template file.": "",
"Click here to download user import template file.": "Presiona aquí para descargar el archivo de plantilla de importación de usuario.",
"Click here to select": "Presiona aquí para seleccionar",
"Click here to select a csv file.": "Presiona aquí para seleccionar un archivo csv.",
"Click here to select a py file.": "",
"Click here to select a py file.": "Presiona aquí para seleccionar un archivo py.",
"Click here to select documents.": "Presiona aquí para seleccionar documentos",
"click here.": "Presiona aquí.",
"Click on the user role button to change a user's role.": "Presiona en el botón de roles del usuario para cambiar su rol.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "Clon",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Permisos de escritura del portapapeles denegados. Por favor, comprueba las configuraciones de tu navegador para otorgar el acceso necesario.",
"Clone": "Clonar",
"Close": "Cerrar",
"Code formatted successfully": "",
"Code formatted successfully": "Se ha formateado correctamente el código.",
"Collection": "Colección",
"ComfyUI": "ComfyUI",
"ComfyUI Base URL": "ComfyUI Base URL",
"ComfyUI Base URL is required.": "ComfyUI Base URL es requerido.",
"Command": "Comando",
"Concurrent Requests": "Solicitudes simultáneas",
"Confirm": "",
"Confirm": "Confirmar",
"Confirm Password": "Confirmar Contraseña",
"Confirm your action": "",
"Confirm your action": "Confirma tu acción",
"Connections": "Conexiones",
"Contact Admin for WebUI Access": "",
"Contact Admin for WebUI Access": "Contacta el administrador para obtener acceso al WebUI",
"Content": "Contenido",
"Context Length": "Longitud del contexto",
"Continue Response": "Continuar Respuesta",
"Continue with {{provider}}": "",
"Continue with {{provider}}": "Continuar con {{provider}}",
"Copied shared chat URL to clipboard!": "¡URL de chat compartido copiado al portapapeles!",
"Copy": "Copiar",
"Copy last code block": "Copia el último bloque de código",
@ -141,14 +141,14 @@
"Create new secret key": "Crear una nueva clave secreta",
"Created at": "Creado en",
"Created At": "Creado en",
"Created by": "",
"CSV Import": "",
"Created by": "Creado por",
"CSV Import": "Importa un CSV",
"Current Model": "Modelo Actual",
"Current Password": "Contraseña Actual",
"Custom": "Personalizado",
"Customize models for a specific purpose": "Personalizar modelos para un propósito específico",
"Dark": "Oscuro",
"Dashboard": "",
"Dashboard": "Panel de Control",
"Database": "Base de datos",
"December": "Diciembre",
"Default": "Por defecto",
@ -164,7 +164,7 @@
"Delete All Chats": "Eliminar todos los chats",
"Delete chat": "Borrar chat",
"Delete Chat": "Borrar Chat",
"Delete chat?": "",
"Delete chat?": "Borrar el chat?",
"Delete function?": "",
"Delete prompt?": "",
"delete this link": "Borrar este enlace",
@ -174,26 +174,26 @@
"Deleted {{name}}": "Eliminado {{nombre}}",
"Description": "Descripción",
"Didn't fully follow instructions": "No siguió las instrucciones",
"Discover a function": "",
"Discover a function": "Descubre una función",
"Discover a model": "Descubrir un modelo",
"Discover a prompt": "Descubre un Prompt",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"Discover a tool": "Descubre una herramienta",
"Discover, download, and explore custom functions": "Descubre, descarga y explora funciones personalizadas",
"Discover, download, and explore custom prompts": "Descubre, descarga, y explora Prompts personalizados",
"Discover, download, and explore custom tools": "",
"Discover, download, and explore custom tools": "Descubre, descarga y explora herramientas personalizadas",
"Discover, download, and explore model presets": "Descubre, descarga y explora ajustes preestablecidos de modelos",
"Dismissible": "",
"Display Emoji in Call": "",
"Dismissible": "Desestimable",
"Display Emoji in Call": "Muestra Emoji en llamada",
"Display the username instead of You in the Chat": "Mostrar el nombre de usuario en lugar de Usted en el chat",
"Document": "Documento",
"Document Settings": "Configuración del Documento",
"Documentation": "",
"Documentation": "Documentación",
"Documents": "Documentos",
"does not make any external connections, and your data stays securely on your locally hosted server.": "no realiza ninguna conexión externa y sus datos permanecen seguros en su servidor alojado localmente.",
"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": "",
"Done": "Hecho",
"Download": "Descargar",
"Download canceled": "Descarga cancelada",
"Download Database": "Descarga la Base de Datos",
@ -201,10 +201,10 @@
"e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "p.ej. '30s','10m'. Unidades válidas de tiempo son 's', 'm', 'h'.",
"Edit": "Editar",
"Edit Doc": "Editar Documento",
"Edit Memory": "",
"Edit Memory": "Editar Memoria",
"Edit User": "Editar Usuario",
"Email": "Email",
"Embedding Batch Size": "",
"Embedding Batch Size": "Tamaño de Embedding",
"Embedding Model": "Modelo de Embedding",
"Embedding Model Engine": "Motor de Modelo de Embedding",
"Embedding model set to \"{{embedding_model}}\"": "Modelo de Embedding configurado a \"{{embedding_model}}\"",
@ -229,10 +229,10 @@
"Enter Score": "Ingrese la puntuación",
"Enter Searxng Query URL": "Introduzca la URL de consulta de Searxng",
"Enter Serper API Key": "Ingrese la clave API de Serper",
"Enter Serply API Key": "",
"Enter Serply API Key": "Ingrese la clave API de Serply",
"Enter Serpstack API Key": "Ingrese la clave API de Serpstack",
"Enter stop sequence": "Ingrese la secuencia de parada",
"Enter Tavily API Key": "",
"Enter Tavily API Key": "Ingrese la clave API de Tavily",
"Enter Top K": "Ingrese el Top K",
"Enter URL (e.g. http://127.0.0.1:7860/)": "Ingrese la URL (p.ej., http://127.0.0.1:7860/)",
"Enter URL (e.g. http://localhost:11434)": "Ingrese la URL (p.ej., http://localhost:11434)",
@ -244,41 +244,44 @@
"Experimental": "Experimental",
"Export": "Exportar",
"Export All Chats (All Users)": "Exportar todos los chats (Todos los usuarios)",
"Export chat (.json)": "",
"Export chat (.json)": "Exportar chat (.json)",
"Export Chats": "Exportar Chats",
"Export Documents Mapping": "Exportar el mapeo de documentos",
"Export Functions": "",
"Export LiteLLM config.yaml": "",
"Export Models": "Modelos de exportación",
"Export Functions": "Exportar Funciones",
"Export LiteLLM config.yaml": "Exportar LiteLLM config.yaml",
"Export Models": "Exportar Modelos",
"Export Prompts": "Exportar Prompts",
"Export Tools": "",
"External Models": "",
"Export Tools": "Exportar Herramientas",
"External Models": "Modelos Externos",
"Failed to create API Key.": "No se pudo crear la clave API.",
"Failed to read clipboard contents": "No se pudo leer el contenido del portapapeles",
"Failed to update settings": "",
"Failed to update settings": "Falla al actualizar los ajustes",
"February": "Febrero",
"Feel free to add specific details": "Libre de agregar detalles específicos",
"File": "",
"File": "Archivo",
"File Mode": "Modo de archivo",
"File not found.": "Archivo no encontrado.",
"Filters": "",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "Filtros",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Se detectó suplantación de huellas: No se pueden usar las iniciales como avatar. Por defecto se utiliza la imagen de perfil predeterminada.",
"Fluidly stream large external response chunks": "Transmita con fluidez grandes fragmentos de respuesta externa",
"Focus chat input": "Enfoca la entrada del chat",
"Followed instructions perfectly": "Siguió las instrucciones perfectamente",
"Form": "",
"Form": "De",
"Format your variables using square brackets like this:": "Formatea tus variables usando corchetes de la siguiente manera:",
"Frequency Penalty": "Penalización de frecuencia",
"Function created successfully": "",
"Function deleted successfully": "",
"Function updated successfully": "",
"Functions": "",
"Functions imported successfully": "",
"Function created successfully": "Función creada exitosamente",
"Function deleted successfully": "Función borrada exitosamente",
"Function updated successfully": "Función actualizada exitosamente",
"Functions": "Funciones",
"Functions imported successfully": "Funciones importadas exitosamente",
"General": "General",
"General Settings": "Opciones Generales",
"Generate Image": "",
"Generate Image": "Generar imagen",
"Generating search query": "Generación de consultas de búsqueda",
"Generation Info": "Información de Generación",
"Global": "",
"Good Response": "Buena Respuesta",
"Google PSE API Key": "Clave API de Google PSE",
"Google PSE Engine Id": "ID del motor PSE de Google",
@ -287,7 +290,7 @@
"Hello, {{name}}": "Hola, {{name}}",
"Help": "Ayuda",
"Hide": "Esconder",
"Hide Model": "",
"Hide Model": "Esconder Modelo",
"How can I help you today?": "¿Cómo puedo ayudarte hoy?",
"Hybrid Search": "Búsqueda Híbrida",
"Image Generation (Experimental)": "Generación de imágenes (experimental)",
@ -296,16 +299,16 @@
"Images": "Imágenes",
"Import Chats": "Importar chats",
"Import Documents Mapping": "Importar Mapeo de Documentos",
"Import Functions": "",
"Import Functions": "Importar Funciones",
"Import Models": "Importar modelos",
"Import Prompts": "Importar Prompts",
"Import Tools": "",
"Import Tools": "Importar Herramientas",
"Include `--api-auth` flag when running stable-diffusion-webui": "",
"Include `--api` flag when running stable-diffusion-webui": "Incluir el indicador `--api` al ejecutar stable-diffusion-webui",
"Info": "Información",
"Input commands": "Ingresar comandos",
"Install from Github URL": "Instalar desde la URL de Github",
"Instant Auto-Send After Voice Transcription": "",
"Instant Auto-Send After Voice Transcription": "Auto-Enviar Después de la Transcripción de Voz",
"Interface": "Interfaz",
"Invalid Tag": "Etiqueta Inválida",
"January": "Enero",
@ -318,32 +321,32 @@
"JWT Token": "Token JWT",
"Keep Alive": "Mantener Vivo",
"Keyboard shortcuts": "Atajos de teclado",
"Knowledge": "",
"Knowledge": "Conocimiento",
"Language": "Lenguaje",
"Last Active": "Última Actividad",
"Last Modified": "",
"Last Modified": "Modificado por última vez",
"Light": "Claro",
"Listening...": "",
"Listening...": "Escuchando...",
"LLMs can make mistakes. Verify important information.": "Los LLM pueden cometer errores. Verifica la información importante.",
"Local Models": "",
"Local Models": "Modelos locales",
"LTR": "LTR",
"Made by OpenWebUI Community": "Hecho por la comunidad de OpenWebUI",
"Make sure to enclose them with": "Asegúrese de adjuntarlos con",
"Manage": "",
"Manage": "Gestionar",
"Manage Models": "Administrar Modelos",
"Manage Ollama Models": "Administrar Modelos Ollama",
"Manage Pipelines": "Administrar canalizaciones",
"Manage Valves": "",
"Manage Pipelines": "Administrar Pipelines",
"Manage Valves": "Gestionar 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.",
"May": "Mayo",
"Memories accessible by LLMs will be shown here.": "Las memorias accesibles por los LLMs se mostrarán aquí.",
"Memory": "Memoria",
"Memory added successfully": "",
"Memory cleared successfully": "",
"Memory deleted successfully": "",
"Memory updated successfully": "",
"Memory added successfully": "Memoria añadida correctamente",
"Memory cleared successfully": "Memoria liberada correctamente",
"Memory deleted successfully": "Memoria borrada correctamente",
"Memory updated successfully": "Memoria actualizada correctamente",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Los mensajes que envíe después de crear su enlace no se compartirán. Los usuarios con el enlace podrán ver el chat compartido.",
"Minimum Score": "Puntuación mínima",
"Mirostat": "Mirostat",
@ -351,18 +354,18 @@
"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.": "El modelo '{{modelName}}' se ha descargado correctamente.",
"Model '{{modelTag}}' is already in queue for downloading.": "El modelo '{{modelTag}}' ya está en cola para descargar.",
"Model {{modelId}} not found": "El modelo {{modelId}} no fue encontrado",
"Model {{modelName}} is not vision capable": "El modelo {{modelName}} no es capaz de ver",
"Model {{name}} is now {{status}}": "El modelo {{name}} ahora es {{status}}",
"Model created successfully!": "",
"Model created successfully!": "Modelo creado correctamente!",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "Se detectó la ruta del sistema de archivos del modelo. Se requiere el nombre corto del modelo para la actualización, no se puede continuar.",
"Model ID": "ID del modelo",
"Model not selected": "Modelo no seleccionado",
"Model Params": "Parámetros del modelo",
"Model updated successfully": "",
"Model updated successfully": "Modelo actualizado correctamente",
"Model Whitelisting": "Listado de Modelos habilitados",
"Model(s) Whitelisted": "Modelo(s) habilitados",
"Modelfile Content": "Contenido del Modelfile",
@ -373,20 +376,20 @@
"Name your model": "Asigne un nombre a su modelo",
"New Chat": "Nuevo Chat",
"New Password": "Nueva Contraseña",
"No content to speak": "",
"No documents found": "",
"No file selected": "",
"No content to speak": "No hay contenido para hablar",
"No documents found": "No se han encontrado documentos",
"No file selected": "Ningún archivo fué seleccionado",
"No results found": "No se han encontrado resultados",
"No search query generated": "No se ha generado ninguna consulta de búsqueda",
"No source available": "No hay fuente disponible",
"No valves to update": "",
"No valves to update": "No valves para actualizar",
"None": "Ninguno",
"Not factually correct": "No es correcto en todos los aspectos",
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Nota: Si estableces una puntuación mínima, la búsqueda sólo devolverá documentos con una puntuación mayor o igual a la puntuación mínima.",
"Notifications": "Notificaciones",
"November": "Noviembre",
"num_thread (Ollama)": "num_thread (Ollama)",
"OAuth ID": "",
"OAuth ID": "OAuth ID",
"October": "Octubre",
"Off": "Desactivado",
"Okay, Let's Go!": "Bien, ¡Vamos!",
@ -394,14 +397,14 @@
"Ollama": "Ollama",
"Ollama API": "Ollama API",
"Ollama API disabled": "API de Ollama deshabilitada",
"Ollama API is disabled": "",
"Ollama API is disabled": "API de Ollama desactivada",
"Ollama Version": "Versión de Ollama",
"On": "Activado",
"Only": "Solamente",
"Only alphanumeric characters and hyphens are allowed in the command string.": "Sólo se permiten caracteres alfanuméricos y guiones en la cadena de comando.",
"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.": "¡Ups! ¡Agárrate fuerte! Tus archivos todavía están en el horno de procesamiento. Los estamos cocinando a la perfección. Tenga paciencia y le avisaremos una vez que estén listos.",
"Oops! Looks like the URL is invalid. Please double-check and try again.": "¡Ups! Parece que la URL no es válida. Vuelva a verificar e inténtelo nuevamente.",
"Oops! There was an error in the previous response. Please try again or contact admin.": "",
"Oops! There was an error in the previous response. Please try again or contact admin.": "¡Oops! Hubo un error en la respuesta anterior. Intente de nuevo o póngase en contacto con el administrador.",
"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "¡Ups! Estás utilizando un método no compatible (solo frontend). Por favor ejecute la WebUI desde el backend.",
"Open": "Abrir",
"Open AI (Dall-E)": "Abrir AI (Dall-E)",
@ -417,14 +420,14 @@
"PDF document (.pdf)": "PDF document (.pdf)",
"PDF Extract Images (OCR)": "Extraer imágenes de PDF (OCR)",
"pending": "pendiente",
"Permission denied when accessing media devices": "",
"Permission denied when accessing microphone": "",
"Permission denied when accessing media devices": "Permiso denegado al acceder a los dispositivos",
"Permission denied when accessing microphone": "Permiso denegado al acceder a la micrófono",
"Permission denied when accessing microphone: {{error}}": "Permiso denegado al acceder al micrófono: {{error}}",
"Personalization": "Personalización",
"Pipeline deleted successfully": "",
"Pipeline downloaded successfully": "",
"Pipelines": "Tuberías",
"Pipelines Not Detected": "",
"Pipeline deleted successfully": "Pipeline borrada exitosamente",
"Pipeline downloaded successfully": "Pipeline descargada exitosamente",
"Pipelines": "Pipelines",
"Pipelines Not Detected": "Pipeline No Detectada",
"Pipelines Valves": "Tuberías Válvulas",
"Plain text (.txt)": "Texto plano (.txt)",
"Playground": "Patio de juegos",
@ -444,7 +447,7 @@
"Read Aloud": "Leer al oído",
"Record voice": "Grabar voz",
"Redirecting you to OpenWebUI Community": "Redireccionándote a la comunidad OpenWebUI",
"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Referirse a usted mismo como \"Usuario\" (por ejemplo, \"El usuario está aprendiendo Español\")",
"Refused when it shouldn't have": "Rechazado cuando no debería",
"Regenerate": "Regenerar",
"Release Notes": "Notas de la versión",
@ -456,16 +459,16 @@
"Reranking Model": "Modelo de reranking",
"Reranking model disabled": "Modelo de reranking deshabilitado",
"Reranking model set to \"{{reranking_model}}\"": "Modelo de reranking establecido en \"{{reranking_model}}\"",
"Reset": "",
"Reset Upload Directory": "",
"Reset": "Reiniciar",
"Reset Upload Directory": "Reiniciar Directorio de carga",
"Reset Vector Storage": "Restablecer almacenamiento vectorial",
"Response AutoCopy to Clipboard": "Copiar respuesta automáticamente al portapapeles",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Las notificaciones de respuesta no pueden activarse debido a que los permisos del sitio web han sido denegados. Por favor, visite las configuraciones de su navegador para otorgar el acceso necesario.",
"Role": "Rol",
"Rosé Pine": "Rosé Pine",
"Rosé Pine Dawn": "Rosé Pine Dawn",
"RTL": "RTL",
"Running": "",
"Running": "Ejecutando",
"Save": "Guardar",
"Save & Create": "Guardar y Crear",
"Save & Update": "Guardar y Actualizar",
@ -477,40 +480,40 @@
"Search a model": "Buscar un modelo",
"Search Chats": "Chats de búsqueda",
"Search Documents": "Buscar Documentos",
"Search Functions": "",
"Search Functions": "Funciones de Búsqueda",
"Search Models": "Modelos de búsqueda",
"Search Prompts": "Buscar Prompts",
"Search Query Generation Prompt": "",
"Search Query Generation Prompt Length Threshold": "",
"Search Query Generation Prompt": "Búsqueda de consulta de generación de prompts",
"Search Query Generation Prompt Length Threshold": "Nivel de longitud de Búsqueda de consulta de generación de prompts",
"Search Result Count": "Recuento de resultados de búsqueda",
"Search Tools": "",
"Search Tools": "Búsqueda de herramientas",
"Searched {{count}} sites_one": "Buscado {{count}} sites_one",
"Searched {{count}} sites_many": "Buscado {{count}} sites_many",
"Searched {{count}} sites_other": "Buscó {{count}} sites_other",
"Searching \"{{searchQuery}}\"": "",
"Searching \"{{searchQuery}}\"": "Buscando \"{{searchQuery}}\"",
"Searxng Query URL": "Searxng URL de consulta",
"See readme.md for instructions": "Vea el readme.md para instrucciones",
"See what's new": "Ver las novedades",
"Seed": "Seed",
"Select a base model": "Seleccionar un modelo base",
"Select a engine": "",
"Select a function": "",
"Select a engine": "Busca un motor",
"Select a function": "Busca una función",
"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 a pipeline": "Selección de una Pipeline",
"Select a pipeline url": "Selección de una dirección URL de Pipeline",
"Select a tool": "Busca una herramienta",
"Select an Ollama instance": "Seleccione una instancia de Ollama",
"Select Documents": "",
"Select Documents": "Seleccionar Documentos",
"Select model": "Selecciona un modelo",
"Select only one model to call": "",
"Select only one model to call": "Selecciona sólo un modelo para llamar",
"Selected model(s) do not support image inputs": "Los modelos seleccionados no admiten entradas de imagen",
"Send": "Enviar",
"Send a Message": "Enviar un Mensaje",
"Send message": "Enviar Mensaje",
"September": "Septiembre",
"Serper API Key": "Clave API de Serper",
"Serply API Key": "",
"Serply API Key": "Clave API de Serply",
"Serpstack API Key": "Clave API de Serpstack",
"Server connection verified": "Conexión del servidor verificada",
"Set as default": "Establecer por defecto",
@ -522,18 +525,18 @@
"Set Task Model": "Establecer modelo de tarea",
"Set Voice": "Establecer la voz",
"Settings": "Configuración",
"Settings saved successfully!": "¡Configuración guardada exitosamente!",
"Settings updated successfully": "",
"Settings saved successfully!": "¡Configuración guardada con éxito!",
"Settings updated successfully": "¡Configuración actualizada con éxito!",
"Share": "Compartir",
"Share Chat": "Compartir Chat",
"Share to OpenWebUI Community": "Compartir con la comunidad OpenWebUI",
"short-summary": "resumen-corto",
"Show": "Mostrar",
"Show Admin Details in Account Pending Overlay": "",
"Show Model": "",
"Show Admin Details in Account Pending Overlay": "Mostrar detalles de administración en la capa de espera de la cuenta",
"Show Model": "Mostrar Modelo",
"Show shortcuts": "Mostrar atajos",
"Show your support!": "",
"Showcased creativity": "Mostrar creatividad",
"Show your support!": "¡Muestra tu apoyo!",
"Showcased creativity": "Creatividad mostrada",
"sidebar": "barra lateral",
"Sign in": "Iniciar sesión",
"Sign Out": "Cerrar sesión",
@ -543,7 +546,7 @@
"Speech recognition error: {{error}}": "Error de reconocimiento de voz: {{error}}",
"Speech-to-Text Engine": "Motor de voz a texto",
"Stop Sequence": "Detener secuencia",
"STT Model": "",
"STT Model": "Modelo STT",
"STT Settings": "Configuraciones de STT",
"Submit": "Enviar",
"Subtitle (e.g. about the Roman Empire)": "Subtítulo (por ejemplo, sobre el Imperio Romano)",
@ -553,8 +556,8 @@
"System": "Sistema",
"System Prompt": "Prompt del sistema",
"Tags": "Etiquetas",
"Tap to interrupt": "",
"Tavily API Key": "",
"Tap to interrupt": "Toca para interrumpir",
"Tavily API Key": "Clave API de Tavily",
"Tell us more:": "Dinos más:",
"Temperature": "Temperatura",
"Template": "Plantilla",
@ -564,12 +567,12 @@
"Thanks for your feedback!": "¡Gracias por tu retroalimentación!",
"The score should be a value between 0.0 (0%) and 1.0 (100%).": "El puntaje debe ser un valor entre 0.0 (0%) y 1.0 (100%).",
"Theme": "Tema",
"Thinking...": "",
"This action cannot be undone. Do you wish to continue?": "",
"Thinking...": "Pensando...",
"This action cannot be undone. Do you wish to continue?": "Esta acción no se puede deshacer. ¿Desea continuar?",
"This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "Esto garantiza que sus valiosas conversaciones se guarden de forma segura en su base de datos en el backend. ¡Gracias!",
"This is an experimental feature, it may not function as expected and is subject to change at any time.": "",
"This is an experimental feature, it may not function as expected and is subject to change at any time.": "Esta es una característica experimental que puede no funcionar como se esperaba y está sujeto a cambios en cualquier momento.",
"This setting does not sync across browsers or devices.": "Esta configuración no se sincroniza entre navegadores o dispositivos.",
"This will delete": "",
"This will delete": "Esto eliminará",
"Thorough explanation": "Explicación exhaustiva",
"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "Consejo: Actualice múltiples variables consecutivamente presionando la tecla tab en la entrada del chat después de cada reemplazo.",
"Title": "Título",
@ -580,39 +583,39 @@
"to": "para",
"To access the available model names for downloading,": "Para acceder a los nombres de modelos disponibles para descargar,",
"To access the GGUF models available for downloading,": "Para acceder a los modelos GGUF disponibles para descargar,",
"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 WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "Para acceder al interfaz de usuario web, por favor contacte al administrador. Los administradores pueden administrar los estados de los usuarios desde el panel de administración.",
"To add documents here, upload them to the \"Documents\" workspace first.": "Para agregar documentos aquí, subalos al área de trabajo \"Documentos\" primero.",
"to chat input.": "a la entrada del chat.",
"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.": "Para seleccionar filtros aquí, agreguelos al área de trabajo \"Funciones\" primero.",
"To select toolkits here, add them to the \"Tools\" workspace first.": "Para seleccionar herramientas aquí, agreguelas al área de trabajo \"Herramientas\" primero.",
"Today": "Hoy",
"Toggle settings": "Alternar configuración",
"Toggle sidebar": "Alternar barra lateral",
"Tokens To Keep On Context Refresh (num_keep)": "",
"Tool created successfully": "",
"Tool deleted successfully": "",
"Tool imported successfully": "",
"Tool updated successfully": "",
"Tools": "",
"Tokens To Keep On Context Refresh (num_keep)": "Tokens a mantener en el contexto de actualización (num_keep)",
"Tool created successfully": "Herramienta creada con éxito",
"Tool deleted successfully": "Herramienta eliminada con éxito",
"Tool imported successfully": "Herramienta importada con éxito",
"Tool updated successfully": "Herramienta actualizada con éxito",
"Tools": "Herramientas",
"Top K": "Top K",
"Top P": "Top P",
"Trouble accessing Ollama?": "¿Problemas para acceder a Ollama?",
"TTS Model": "",
"TTS Model": "Modelo TTS",
"TTS Settings": "Configuración de TTS",
"TTS Voice": "",
"TTS Voice": "Voz del TTS",
"Type": "Tipo",
"Type Hugging Face Resolve (Download) URL": "Escriba la URL (Descarga) de Hugging Face Resolve",
"Uh-oh! There was an issue connecting to {{provider}}.": "¡Uh oh! Hubo un problema al conectarse a {{provider}}.",
"UI": "",
"Unknown file type '{{file_type}}'. Proceeding with the file upload anyway.": "",
"Update": "",
"UI": "UI",
"Unknown file type '{{file_type}}'. Proceeding with the file upload anyway.": "Tipo de archivo desconocido '{{file_type}}'. Procediendo con la carga del archivo de todos modos.",
"Update": "Actualizar",
"Update and Copy Link": "Actualizar y copiar enlace",
"Update password": "Actualizar contraseña",
"Updated at": "",
"Upload": "",
"Updated at": "Actualizado en",
"Upload": "Subir",
"Upload a GGUF model": "Subir un modelo GGUF",
"Upload Files": "Subir archivos",
"Upload Pipeline": "",
"Upload Pipeline": "Subir Pipeline",
"Upload Progress": "Progreso de carga",
"URL Mode": "Modo de URL",
"Use '#' in the prompt input to load and select your documents.": "Utilice '#' en el prompt para cargar y seleccionar sus documentos.",
@ -621,22 +624,22 @@
"use_mlock (Ollama)": "use_mlock (Ollama)",
"use_mmap (Ollama)": "use_mmap (Ollama)",
"user": "usuario",
"User location successfully retrieved.": "",
"User location successfully retrieved.": "Localización del usuario recuperada con éxito.",
"User Permissions": "Permisos de usuario",
"Users": "Usuarios",
"Utilize": "Utilizar",
"Valid time units:": "Unidades válidas de tiempo:",
"Valves": "",
"Valves updated": "",
"Valves updated successfully": "",
"Valves": "Valves",
"Valves updated": "Valves actualizados",
"Valves updated successfully": "Valves actualizados con éxito",
"variable": "variable",
"variable to have them replaced with clipboard content.": "variable para reemplazarlos con el contenido del portapapeles.",
"Version": "Versión",
"Voice": "",
"Voice": "Voz",
"Warning": "Advertencia",
"Warning: If you update or change your embedding model, you will need to re-import all documents.": "Advertencia: Si actualiza o cambia su modelo de inserción, necesitará volver a importar todos los documentos.",
"Web": "Web",
"Web API": "",
"Web API": "API Web",
"Web Loader Settings": "Web Loader Settings",
"Web Params": "Web Params",
"Web Search": "Búsqueda en la Web",
@ -646,20 +649,20 @@
"WebUI will make requests to": "WebUI realizará solicitudes a",
"Whats New in": "Novedades en",
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "Cuando el historial está desactivado, los nuevos chats en este navegador no aparecerán en el historial de ninguno de sus dispositivos..",
"Whisper (Local)": "",
"Widescreen Mode": "",
"Whisper (Local)": "Whisper (Local)",
"Widescreen Mode": "Modo de pantalla ancha",
"Workspace": "Espacio de trabajo",
"Write a prompt suggestion (e.g. Who are you?)": "Escribe una sugerencia para un prompt (por ejemplo, ¿quién eres?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "Escribe un resumen en 50 palabras que resuma [tema o palabra clave].",
"Yesterday": "Ayer",
"You": "Usted",
"You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "",
"You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Puede personalizar sus interacciones con LLMs añadiendo memorias a través del botón 'Gestionar' debajo, haciendo que sean más útiles y personalizados para usted.",
"You cannot clone a base model": "No se puede clonar un modelo base",
"You have no archived conversations.": "No tiene conversaciones archivadas.",
"You have shared this chat": "Usted ha compartido esta conversación",
"You're a helpful assistant.": "Usted es un asistente útil.",
"You're now logged in.": "Usted ahora está conectado.",
"Your account status is currently pending activation.": "",
"Your account status is currently pending activation.": "El estado de su cuenta actualmente se encuentra pendiente de activación.",
"Youtube": "Youtube",
"Youtube Loader Settings": "Configuración del cargador de Youtube"
}

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "حالت فایل",
"File not found.": "فایل یافت نشد.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "فانگ سرفیس شناسایی شد: نمی توان از نمایه شما به عنوان آواتار استفاده کرد. پیش فرض به عکس پروفایل پیش فرض برگشت داده شد.",
"Fluidly stream large external response chunks": "تکه های پاسخ خارجی بزرگ را به صورت سیال پخش کنید",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "در حال تولید پرسوجوی جستجو",
"Generation Info": "اطلاعات تولید",
"Global": "",
"Good Response": "پاسخ خوب",
"Google PSE API Key": "گوگل PSE API کلید",
"Google PSE Engine Id": "شناسه موتور PSE گوگل",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Tiedostotila",
"File not found.": "Tiedostoa ei löytynyt.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Sormenjäljen väärentäminen havaittu: Ei voi käyttää alkukirjaimia avatarina. Käytetään oletusprofiilikuvaa.",
"Fluidly stream large external response chunks": "Virtaa suuria ulkoisia vastausosia joustavasti",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "Hakukyselyn luominen",
"Generation Info": "Generointitiedot",
"Global": "",
"Good Response": "Hyvä vastaus",
"Google PSE API Key": "Google PSE API -avain",
"Google PSE Engine Id": "Google PSE -moduulin tunnus",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Mode fichier",
"File not found.": "Fichier introuvable.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Détection de falsification de empreinte digitale\u00a0: impossible d'utiliser les initiales comme avatar. Par défaut, l'image de profil par défaut est utilisée.",
"Fluidly stream large external response chunks": "Diffusez de manière fluide de gros morceaux de réponses externes",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "Génération dune requête de recherche",
"Generation Info": "Informations de génération",
"Global": "",
"Good Response": "Bonne réponse",
"Google PSE API Key": "Clé dAPI Google PSE",
"Google PSE Engine Id": "Id du moteur Google PSE",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Mode Fichier",
"File not found.": "Fichier non trouvé.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Usurpation d'empreinte digitale détectée : Impossible d'utiliser les initiales comme avatar. L'image de profil par défaut sera utilisée.",
"Fluidly stream large external response chunks": "Diffusez de manière fluide de gros morceaux de réponses externes",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "Génération dune requête de recherche",
"Generation Info": "Informations de la Génération",
"Global": "",
"Good Response": "Bonne Réponse",
"Google PSE API Key": "Clé API Google PSE",
"Google PSE Engine Id": "ID du moteur Google PSE",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "מצב קובץ",
"File not found.": "הקובץ לא נמצא.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "התגלתה הזיית טביעת אצבע: לא ניתן להשתמש בראשי תיבות כאווטאר. משתמש בתמונת פרופיל ברירת מחדל.",
"Fluidly stream large external response chunks": "שידור נתונים חיצוניים בקצב רציף",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "יצירת שאילתת חיפוש",
"Generation Info": "מידע על היצירה",
"Global": "",
"Good Response": "תגובה טובה",
"Google PSE API Key": "מפתח API של Google PSE",
"Google PSE Engine Id": "מזהה מנוע PSE של Google",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "फ़ाइल मोड",
"File not found.": "फ़ाइल प्राप्त नहीं हुई।",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "फ़िंगरप्रिंट स्पूफ़िंग का पता चला: प्रारंभिक अक्षरों को अवतार के रूप में उपयोग करने में असमर्थ। प्रोफ़ाइल छवि को डिफ़ॉल्ट पर डिफ़ॉल्ट किया जा रहा है.",
"Fluidly stream large external response chunks": "बड़े बाह्य प्रतिक्रिया खंडों को तरल रूप से प्रवाहित करें",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "खोज क्वेरी जनरेट करना",
"Generation Info": "जनरेशन की जानकारी",
"Global": "",
"Good Response": "अच्छी प्रतिक्रिया",
"Google PSE API Key": "Google PSE API कुंजी",
"Google PSE Engine Id": "Google PSE इंजन आईडी",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Način datoteke",
"File not found.": "Datoteka nije pronađena.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Otkriveno krivotvorenje otisaka prstiju: Nemoguće je koristiti inicijale kao avatar. Postavljanje na zadanu profilnu sliku.",
"Fluidly stream large external response chunks": "Glavno strujanje velikih vanjskih dijelova odgovora",
@ -279,6 +281,7 @@
"Generate Image": "Gneriraj sliku",
"Generating search query": "Generiranje upita za pretraživanje",
"Generation Info": "Informacije o generaciji",
"Global": "",
"Good Response": "Dobar odgovor",
"Google PSE API Key": "Google PSE API ključ",
"Google PSE Engine Id": "ID Google PSE modula",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Modalità file",
"File not found.": "File non trovato.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Rilevato spoofing delle impronte digitali: impossibile utilizzare le iniziali come avatar. Ripristino all'immagine del profilo predefinita.",
"Fluidly stream large external response chunks": "Trasmetti in modo fluido blocchi di risposta esterni di grandi dimensioni",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "Generazione di query di ricerca",
"Generation Info": "Informazioni generazione",
"Global": "",
"Good Response": "Buona risposta",
"Google PSE API Key": "Chiave API PSE di Google",
"Google PSE Engine Id": "ID motore PSE di Google",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "ファイルモード",
"File not found.": "ファイルが見つかりません。",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "指紋のなりすましが検出されました: イニシャルをアバターとして使用できません。デフォルトのプロファイル画像にデフォルト設定されています。",
"Fluidly stream large external response chunks": "大規模な外部応答チャンクを流動的にストリーミングする",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "検索クエリの生成",
"Generation Info": "生成情報",
"Global": "",
"Good Response": "良い応答",
"Google PSE API Key": "Google PSE APIキー",
"Google PSE Engine Id": "Google PSE エンジン ID",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "ფაილური რეჟიმი",
"File not found.": "ფაილი ვერ მოიძებნა",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "აღმოჩენილია თითის ანაბეჭდის გაყალბება: ინიციალების გამოყენება ავატარად შეუძლებელია. დეფოლტ პროფილის დეფოლტ სურათი.",
"Fluidly stream large external response chunks": "თხევადი ნაკადი დიდი გარე საპასუხო ნაწილაკების",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "საძიებო მოთხოვნის გენერირება",
"Generation Info": "გენერაციის ინფორმაცია",
"Global": "",
"Good Response": "დიდი პასუხი",
"Google PSE API Key": "Google PSE API გასაღები",
"Google PSE Engine Id": "Google PSE ძრავის Id",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "파일 모드",
"File not found.": "파일을 찾을 수 없습니다.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Fingerprint spoofing 감지: 이니셜을 아바타로 사용할 수 없습니다. 기본 프로필 이미지로 설정합니다.",
"Fluidly stream large external response chunks": "대규모 외부 응답 청크를 유연하게 스트리밍",
@ -279,6 +281,7 @@
"Generate Image": "이미지 생성",
"Generating search query": "검색 쿼리 생성",
"Generation Info": "생성 정보",
"Global": "",
"Good Response": "좋은 응답",
"Google PSE API Key": "Google PSE API 키",
"Google PSE Engine Id": "Google PSE 엔진 ID",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Dokumentų rėžimas",
"File not found.": "Failas nerastas.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Nepavyko nsutatyti profilio nuotraukos",
"Fluidly stream large external response chunks": "Sklandžiai transliuoti ilgus atsakymus",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "",
"Generation Info": "Generavimo informacija",
"Global": "",
"Good Response": "Geras atsakymas",
"Google PSE API Key": "",
"Google PSE Engine Id": "",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Filmodus",
"File not found.": "Fil ikke funnet.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Fingeravtrykk-spoofing oppdaget: Kan ikke bruke initialer som avatar. Bruker standard profilbilde.",
"Fluidly stream large external response chunks": "Strøm store eksterne svarchunks flytende",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "Genererer søkeforespørsel",
"Generation Info": "Generasjonsinfo",
"Global": "",
"Good Response": "Godt svar",
"Google PSE API Key": "Google PSE API-nøkkel",
"Google PSE Engine Id": "Google PSE Motor-ID",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Bestandsmodus",
"File not found.": "Bestand niet gevonden.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Vingerafdruk spoofing gedetecteerd: kan initialen niet gebruiken als avatar. Standaardprofielafbeelding wordt gebruikt.",
"Fluidly stream large external response chunks": "Stream vloeiend grote externe responsbrokken",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "Zoekopdracht genereren",
"Generation Info": "Generatie Info",
"Global": "",
"Good Response": "Goede Antwoord",
"Google PSE API Key": "Google PSE API-sleutel",
"Google PSE Engine Id": "Google PSE-engine-ID",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "ਫਾਈਲ ਮੋਡ",
"File not found.": "ਫਾਈਲ ਨਹੀਂ ਮਿਲੀ।",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "ਫਿੰਗਰਪ੍ਰਿੰਟ ਸਪੂਫਿੰਗ ਪਾਈ ਗਈ: ਅਵਤਾਰ ਵਜੋਂ ਸ਼ੁਰੂਆਤੀ ਅੱਖਰ ਵਰਤਣ ਵਿੱਚ ਅਸਮਰੱਥ। ਮੂਲ ਪ੍ਰੋਫਾਈਲ ਚਿੱਤਰ 'ਤੇ ਡਿਫਾਲਟ।",
"Fluidly stream large external response chunks": "ਵੱਡੇ ਬਾਹਰੀ ਜਵਾਬ ਚੰਕਾਂ ਨੂੰ ਸਹੀ ਢੰਗ ਨਾਲ ਸਟ੍ਰੀਮ ਕਰੋ",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "ਖੋਜ ਪੁੱਛਗਿੱਛ ਤਿਆਰ ਕਰਨਾ",
"Generation Info": "ਜਨਰੇਸ਼ਨ ਜਾਣਕਾਰੀ",
"Global": "",
"Good Response": "ਵਧੀਆ ਜਵਾਬ",
"Google PSE API Key": "Google PSE API ਕੁੰਜੀ",
"Google PSE Engine Id": "ਗੂਗਲ PSE ਇੰਜਣ ID",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Tryb pliku",
"File not found.": "Plik nie został znaleziony.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Wykryto podszywanie się pod odcisk palca: Nie można używać inicjałów jako awatara. Przechodzenie do domyślnego obrazu profilowego.",
"Fluidly stream large external response chunks": "Płynnie przesyłaj strumieniowo duże fragmenty odpowiedzi zewnętrznych",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "Generowanie zapytania",
"Generation Info": "Informacja o generacji",
"Global": "",
"Good Response": "Dobra odpowiedź",
"Google PSE API Key": "Klucz API Google PSE",
"Google PSE Engine Id": "Identyfikator silnika Google PSE",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Modo de Arquivo",
"File not found.": "Arquivo não encontrado.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Impostação de impressão digital detectada: Não é possível usar iniciais como avatar. Padronizando para imagem de perfil padrão.",
"Fluidly stream large external response chunks": "Transmita com fluidez grandes blocos de resposta externa",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "Gerando consulta de pesquisa",
"Generation Info": "Informações de Geração",
"Global": "",
"Good Response": "Boa Resposta",
"Google PSE API Key": "Chave de API PSE do Google",
"Google PSE Engine Id": "ID do mecanismo PSE do Google",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Modo de Ficheiro",
"File not found.": "Ficheiro não encontrado.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Detectada falsificação da impressão digital: Não é possível usar iniciais como avatar. A usar a imagem de perfil padrão.",
"Fluidly stream large external response chunks": "Transmita com fluidez grandes blocos de resposta externa",
@ -279,6 +281,7 @@
"Generate Image": "Gerar imagem",
"Generating search query": "A gerar a consulta da pesquisa",
"Generation Info": "Informações de Geração",
"Global": "",
"Good Response": "Boa Resposta",
"Google PSE API Key": "Chave da API PSE do Google",
"Google PSE Engine Id": "ID do mecanismo PSE do Google",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Режим файла",
"File not found.": "Файл не найден.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Определение подделки отпечатка: Невозможно использовать инициалы в качестве аватара. По умолчанию используется изображение профиля по умолчанию.",
"Fluidly stream large external response chunks": "Плавная потоковая передача больших фрагментов внешних ответов",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "Генерация поискового запроса",
"Generation Info": "Информация о генерации",
"Global": "",
"Good Response": "Хороший ответ",
"Google PSE API Key": "Ключ API Google PSE",
"Google PSE Engine Id": "Идентификатор движка Google PSE",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Режим датотеке",
"File not found.": "Датотека није пронађена.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Откривено лажно представљање отиска прста: Немогуће је користити иницијале као аватар. Прелазак на подразумевану профилну слику.",
"Fluidly stream large external response chunks": "Течно стримујте велике спољне делове одговора",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "Генерисање упита претраге",
"Generation Info": "Информације о стварању",
"Global": "",
"Good Response": "Добар одговор",
"Google PSE API Key": "Гоогле ПСЕ АПИ кључ",
"Google PSE Engine Id": "Гоогле ПСЕ ИД мотора",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Fil-läge",
"File not found.": "Fil hittades inte.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Fingeravtrycksmanipulering upptäckt: Kan inte använda initialer som avatar. Återställning till standardprofilbild.",
"Fluidly stream large external response chunks": "Strömma flytande stora externa svarschunks",
@ -279,6 +281,7 @@
"Generate Image": "Generera bild",
"Generating search query": "Genererar sökfråga",
"Generation Info": "Info om generation",
"Global": "",
"Good Response": "Bra svar",
"Google PSE API Key": "Google PSE API-nyckel",
"Google PSE Engine Id": "Google PSE Engine Id",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "",
"File not found.": "",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "",
"Fluidly stream large external response chunks": "",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "",
"Generation Info": "",
"Global": "",
"Good Response": "",
"Google PSE API Key": "",
"Google PSE Engine Id": "",

View File

@ -261,6 +261,8 @@
"File": "",
"File Mode": "Dosya Modu",
"File not found.": "Dosya bulunamadı.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Parmak izi sahteciliği tespit edildi: Avatar olarak baş harfler kullanılamıyor. Varsayılan profil resmine dönülüyor.",
"Fluidly stream large external response chunks": "Büyük harici yanıt chunklarını akıcı bir şekilde yayınlayın",
@ -279,6 +281,7 @@
"Generate Image": "",
"Generating search query": "Arama sorgusu oluşturma",
"Generation Info": "Üretim Bilgisi",
"Global": "",
"Good Response": "İyi Yanıt",
"Google PSE API Key": "Google PSE API Anahtarı",
"Google PSE Engine Id": "Google PSE Engine Id",

View File

@ -261,6 +261,8 @@
"File": "Файл",
"File Mode": "Файловий режим",
"File not found.": "Файл не знайдено.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "Фільтри",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Виявлено підробку відбитків: Неможливо використовувати ініціали як аватар. Повернення до зображення профілю за замовчуванням.",
"Fluidly stream large external response chunks": "Плавно передавати великі фрагменти зовнішніх відповідей",
@ -279,6 +281,7 @@
"Generate Image": "Створити зображення",
"Generating search query": "Сформувати пошуковий запит",
"Generation Info": "Інформація про генерацію",
"Global": "",
"Good Response": "Гарна відповідь",
"Google PSE API Key": "Ключ API Google PSE",
"Google PSE Engine Id": "Id рушія Google PSE",

View File

@ -261,6 +261,8 @@
"File": "Tệp",
"File Mode": "Chế độ Tệp văn bản",
"File not found.": "Không tìm thấy tệp.",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Phát hiện giả mạo vân tay: Không thể sử dụng tên viết tắt làm hình đại diện. Mặc định là hình ảnh hồ sơ mặc định.",
"Fluidly stream large external response chunks": "Truyền tải các khối phản hồi bên ngoài lớn một cách trôi chảy",
@ -279,6 +281,7 @@
"Generate Image": "Sinh ảnh",
"Generating search query": "Tạo truy vấn tìm kiếm",
"Generation Info": "Thông tin chung",
"Global": "",
"Good Response": "Trả lời tốt",
"Google PSE API Key": "Khóa API Google PSE",
"Google PSE Engine Id": "ID công cụ Google PSE",

View File

@ -18,7 +18,7 @@
"Active Users": "当前在线用户",
"Add": "添加",
"Add a model id": "添加一个模型 ID",
"Add a short description about what this model does": "添加有关该模型能的简短描述",
"Add a short description about what this model does": "添加有关该模型的简短描述",
"Add a short title for this prompt": "为此提示词添加一个简短的标题",
"Add a tag": "添加标签",
"Add custom prompt": "添加自定义提示词",
@ -44,7 +44,7 @@
"Allow Chat Deletion": "允许删除聊天记录",
"Allow non-local voices": "允许调用非本地音色",
"Allow User Location": "允许获取您的位置",
"Allow Voice Interruption in Call": "",
"Allow Voice Interruption in Call": "允许通话中的打断语音",
"alphanumeric characters and hyphens": "字母数字字符和连字符",
"Already have an account?": "已经拥有账号了?",
"an assistant": "助手",
@ -63,7 +63,7 @@
"Attach file": "添加文件",
"Attention to detail": "注重细节",
"Audio": "语音",
"Audio settings updated successfully": "",
"Audio settings updated successfully": "语音设置更新成功",
"August": "八月",
"Auto-playback response": "自动念出回复内容",
"AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api鉴权字符串",
@ -110,10 +110,10 @@
"Click here to select documents.": "单击选择文档",
"click here.": "点击这里。",
"Click on the user role button to change a user's role.": "点击角色前方的组别按钮以更改用户所属权限组。",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "写入剪贴板时被拒绝。请检查浏览器设置,授予必要权限。",
"Clone": "复制",
"Close": "关闭",
"Code formatted successfully": "",
"Code formatted successfully": "代码格式化成功",
"Collection": "集合",
"ComfyUI": "ComfyUI",
"ComfyUI Base URL": "ComfyUI 基础地址",
@ -128,7 +128,7 @@
"Content": "内容",
"Context Length": "上下文长度",
"Continue Response": "继续生成",
"Continue with {{provider}}": "",
"Continue with {{provider}}": "使用 {{provider}} 继续",
"Copied shared chat URL to clipboard!": "已复制此对话分享链接至剪贴板!",
"Copy": "复制",
"Copy last code block": "复制最后一个代码块中的代码",
@ -165,22 +165,22 @@
"Delete chat": "删除对话记录",
"Delete Chat": "删除对话记录",
"Delete chat?": "删除对话记录?",
"Delete function?": "",
"Delete prompt?": "",
"Delete function?": "删除函数?",
"Delete prompt?": "删除提示词?",
"delete this link": "此处删除这个链接",
"Delete tool?": "",
"Delete tool?": "删除工具?",
"Delete User": "删除用户",
"Deleted {{deleteModelTag}}": "已删除 {{deleteModelTag}}",
"Deleted {{name}}": "已删除 {{name}}",
"Description": "描述",
"Didn't fully follow instructions": "没有完全遵照指示",
"Discover a function": "",
"Discover a function": "发现更多函数",
"Discover a model": "发现更多模型",
"Discover a prompt": "发现更多提示词",
"Discover a tool": "",
"Discover, download, and explore custom functions": "",
"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 custom tools": "发现、下载并探索更多工具",
"Discover, download, and explore model presets": "发现、下载并探索更多模型预设",
"Dismissible": "是否可关闭",
"Display Emoji in Call": "在通话中显示 Emoji 表情符号",
@ -193,7 +193,7 @@
"Don't Allow": "不允许",
"Don't have an account?": "没有账号?",
"Don't like the style": "不喜欢这个文风",
"Done": "",
"Done": "完成",
"Download": "下载",
"Download canceled": "下载已取消",
"Download Database": "下载数据库",
@ -247,8 +247,8 @@
"Export chat (.json)": "JSON 文件 (.json)",
"Export Chats": "导出对话",
"Export Documents Mapping": "导出文档映射",
"Export Functions": "导出功能",
"Export LiteLLM config.yaml": "",
"Export Functions": "导出函数",
"Export LiteLLM config.yaml": "导出 LteLLM config.yaml 文件",
"Export Models": "导出模型",
"Export Prompts": "导出提示词",
"Export Tools": "导出工具",
@ -261,6 +261,8 @@
"File": "文件",
"File Mode": "文件模式",
"File not found.": "文件未找到。",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "过滤器",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "检测到指纹伪造:无法使用姓名缩写作为头像。默认使用默认个人形象。",
"Fluidly stream large external response chunks": "流畅地传输外部大型响应块数据",
@ -269,16 +271,17 @@
"Form": "手动创建",
"Format your variables using square brackets like this:": "使用这样的方括号格式化你的变量:",
"Frequency Penalty": "频率惩罚",
"Function created successfully": "",
"Function deleted successfully": "",
"Function updated successfully": "",
"Functions": "功能",
"Functions imported successfully": "",
"Function created successfully": "函数创建成功",
"Function deleted successfully": "函数删除成功",
"Function updated successfully": "函数更新成功",
"Functions": "函数",
"Functions imported successfully": "函数导入成功",
"General": "通用",
"General Settings": "通用设置",
"Generate Image": "生成图像",
"Generating search query": "生成搜索查询",
"Generation Info": "生成信息",
"Global": "",
"Good Response": "点赞此回答",
"Google PSE API Key": "Google PSE API 密钥",
"Google PSE Engine Id": "Google PSE 引擎 ID",
@ -296,7 +299,7 @@
"Images": "图像",
"Import Chats": "导入对话记录",
"Import Documents Mapping": "导入文档映射",
"Import Functions": "导入功能",
"Import Functions": "导入函数",
"Import Models": "导入模型",
"Import Prompts": "导入提示词",
"Import Tools": "导入工具",
@ -333,17 +336,17 @@
"Manage Models": "管理模型",
"Manage Ollama Models": "管理 Ollama 模型",
"Manage Pipelines": "管理 Pipeline",
"Manage Valves": "",
"Manage Valves": "管理值",
"March": "三月",
"Max Tokens (num_predict)": "最多 Token (num_predict)",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "最多可以同时下载 3 个模型,请稍后重试。",
"May": "五月",
"Memories accessible by LLMs will be shown here.": "大语言模型可访问的记忆将在此显示。",
"Memory": "记忆",
"Memory added successfully": "",
"Memory cleared successfully": "",
"Memory deleted successfully": "",
"Memory updated successfully": "",
"Memory added successfully": "记忆添加成功",
"Memory cleared successfully": "记忆清除成功",
"Memory deleted successfully": "记忆删除成功",
"Memory updated successfully": "记忆更新成功",
"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",
@ -355,14 +358,14 @@
"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 {{modelName}} is not vision capable": "模型 {{modelName}} 不支持视觉",
"Model {{name}} is now {{status}}": "模型 {{name}} 现在是 {{status}}",
"Model created successfully!": "",
"Model created successfully!": "模型创建成功!",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "检测到模型文件系统路径,无法继续进行。更新操作需要提供模型简称。",
"Model ID": "模型 ID",
"Model not selected": "未选择模型",
"Model Params": "模型参数",
"Model updated successfully": "",
"Model updated successfully": "模型更新成功",
"Model Whitelisting": "白名单模型",
"Model(s) Whitelisted": "模型已加入白名单",
"Modelfile Content": "模型文件内容",
@ -373,20 +376,20 @@
"Name your model": "为您的模型命名",
"New Chat": "新对话",
"New Password": "新密码",
"No content to speak": "",
"No content to speak": "没有内容可朗读",
"No documents found": "未找到文档",
"No file selected": "",
"No file selected": "未选中文件",
"No results found": "未找到结果",
"No search query generated": "未生成搜索查询",
"No source available": "没有可用来源",
"No valves to update": "",
"No valves to update": "没有需要更新的值",
"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": "十一月",
"num_thread (Ollama)": "num_threadOllama",
"OAuth ID": "",
"OAuth ID": "OAuth ID",
"October": "十月",
"Off": "关闭",
"Okay, Let's Go!": "确认,开始使用!",
@ -421,10 +424,10 @@
"Permission denied when accessing microphone": "申请麦克风权限被拒绝",
"Permission denied when accessing microphone: {{error}}": "申请麦克风权限被拒绝:{{error}}",
"Personalization": "个性化",
"Pipeline deleted successfully": "",
"Pipeline downloaded successfully": "",
"Pipeline deleted successfully": "Pipeline 删除成功",
"Pipeline downloaded successfully": "Pipeline 下载成功",
"Pipelines": "Pipeline",
"Pipelines Not Detected": "",
"Pipelines Not Detected": "未检测到 Pipeline",
"Pipelines Valves": "Pipeline 值",
"Plain text (.txt)": "TXT 文档 (.txt)",
"Playground": "AI 对话游乐场",
@ -460,7 +463,7 @@
"Reset Upload Directory": "重置上传目录",
"Reset Vector Storage": "重置向量存储",
"Response AutoCopy to Clipboard": "自动复制回复到剪贴板",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "无法激活回复时发送通知。请检查浏览器设置,并授予必要的访问权限。",
"Role": "权限组",
"Rosé Pine": "Rosé Pine",
"Rosé Pine Dawn": "Rosé Pine Dawn",
@ -477,7 +480,7 @@
"Search a model": "搜索模型",
"Search Chats": "搜索对话",
"Search Documents": "搜索文档",
"Search Functions": "搜索功能",
"Search Functions": "搜索函数",
"Search Models": "搜索模型",
"Search Prompts": "搜索提示词",
"Search Query Generation Prompt": "搜索查询生成提示",
@ -492,12 +495,12 @@
"Seed": "种子 (Seed)",
"Select a base model": "选择一个基础模型",
"Select a engine": "选择一个搜索引擎",
"Select a function": "",
"Select a function": "选择一个函数",
"Select a mode": "选择一个模式",
"Select a model": "选择一个模型",
"Select a pipeline": "选择一个管道",
"Select a pipeline url": "选择一个管道 URL",
"Select a tool": "",
"Select a tool": "选择一个工具",
"Select an Ollama instance": "选择一个 Ollama 实例",
"Select Documents": "选择文档",
"Select model": "选择模型",
@ -530,7 +533,7 @@
"Show Admin Details in Account Pending Overlay": "在用户待激活界面中显示管理员邮箱等详细信息",
"Show Model": "显示",
"Show shortcuts": "显示快捷方式",
"Show your support!": "",
"Show your support!": "表达你的支持!",
"Showcased creativity": "很有创意",
"sidebar": "侧边栏",
"Sign in": "登录",
@ -581,16 +584,16 @@
"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 chat input.": "到对话输入。",
"To select filters here, add them to the \"Functions\" 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)": "在语境刷新时需保留的 Tokens",
"Tool created successfully": "",
"Tool deleted successfully": "",
"Tool imported successfully": "",
"Tool updated successfully": "",
"Tool created successfully": "工具创建成功",
"Tool deleted successfully": "工具删除成功",
"Tool imported successfully": "工具导入成功",
"Tool updated successfully": "工具更新成功",
"Tools": "工具",
"Top K": "Top K",
"Top P": "Top P",
@ -619,14 +622,14 @@
"use_mlock (Ollama)": "use_mlockOllama",
"use_mmap (Ollama)": "use_mmap Ollama",
"user": "用户",
"User location successfully retrieved.": "",
"User location successfully retrieved.": "成功检索到用户位置。",
"User Permissions": "用户权限",
"Users": "用户",
"Utilize": "利用",
"Valid time units:": "有效时间单位:",
"Valves": "",
"Valves updated": "",
"Valves updated successfully": "",
"Valves": "",
"Valves updated": "已更新值",
"Valves updated successfully": "值更新成功",
"variable": "变量",
"variable to have them replaced with clipboard content.": "变量将被剪贴板内容替换。",
"Version": "版本",

View File

@ -261,6 +261,8 @@
"File": "檔案",
"File Mode": "檔案模式",
"File not found.": "找不到檔案。",
"Filter is now globally disabled": "",
"Filter is now globally enabled": "",
"Filters": "篩選器",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "偽造偵測:無法使用初始頭像。預設為預設個人影象。",
"Fluidly stream large external response chunks": "流暢地傳輸大型外部回應區塊",
@ -279,6 +281,7 @@
"Generate Image": "生成圖片",
"Generating search query": "生成搜尋查詢",
"Generation Info": "生成資訊",
"Global": "",
"Good Response": "優秀的回應",
"Google PSE API Key": "Google PSE API 金鑰",
"Google PSE Engine Id": "Google PSE 引擎 ID",

View File

@ -48,6 +48,10 @@
console.log(func);
});
if (window.opener ?? false) {
window.opener.postMessage('loaded', '*');
}
if (sessionStorage.function) {
func = JSON.parse(sessionStorage.function);
sessionStorage.removeItem('function');
@ -61,14 +65,16 @@
</script>
{#if mounted}
<FunctionEditor
id={func?.id ?? ''}
name={func?.name ?? ''}
meta={func?.meta ?? { description: '' }}
content={func?.content ?? ''}
{clone}
on:save={(e) => {
saveHandler(e.detail);
}}
/>
{#key func?.content}
<FunctionEditor
id={func?.id ?? ''}
name={func?.name ?? ''}
meta={func?.meta ?? { description: '' }}
content={func?.content ?? ''}
{clone}
on:save={(e) => {
saveHandler(e.detail);
}}
/>
{/key}
{/if}

View File

@ -2,7 +2,7 @@
import { v4 as uuidv4 } from 'uuid';
import { toast } from 'svelte-sonner';
import { goto } from '$app/navigation';
import { settings, user, config, models, tools } from '$lib/stores';
import { settings, user, config, models, tools, functions } from '$lib/stores';
import TurndownService from 'turndown';
@ -17,6 +17,7 @@
import ToolsSelector from '$lib/components/workspace/Models/ToolsSelector.svelte';
import { stringify } from 'postcss';
import { parseFile } from '$lib/utils/characters';
import FiltersSelector from '$lib/components/workspace/Models/FiltersSelector.svelte';
const i18n = getContext('i18n');
@ -61,6 +62,7 @@
let toolIds = [];
let knowledge = [];
let filterIds = [];
$: if (name) {
id = name
@ -105,6 +107,14 @@
}
}
if (filterIds.length > 0) {
info.meta.filterIds = filterIds;
} else {
if (info.meta.filterIds) {
delete info.meta.filterIds;
}
}
info.params.stop = params.stop ? params.stop.split(',').filter((s) => s.trim()) : null;
Object.keys(info.params).forEach((key) => {
if (info.params[key] === '' || info.params[key] === null) {
@ -173,6 +183,10 @@
capabilities = { ...capabilities, ...(model?.info?.meta?.capabilities ?? {}) };
toolIds = model?.info?.meta?.toolIds ?? [];
if (model?.info?.meta?.filterIds) {
filterIds = [...model?.info?.meta?.filterIds];
}
info = {
...info,
...model.info
@ -604,6 +618,13 @@
<ToolsSelector bind:selectedToolIds={toolIds} tools={$tools} />
</div>
<div class="my-2">
<FiltersSelector
bind:selectedFilterIds={filterIds}
filters={$functions.filter((func) => func.type === 'filter')}
/>
</div>
<div class="my-1">
<div class="flex w-full justify-between mb-1">
<div class=" self-center text-sm font-semibold">{$i18n.t('Capabilities')}</div>

View File

@ -45,6 +45,10 @@
console.log(tool);
});
if (window.opener ?? false) {
window.opener.postMessage('loaded', '*');
}
if (sessionStorage.tool) {
tool = JSON.parse(sessionStorage.tool);
sessionStorage.removeItem('tool');
@ -58,14 +62,16 @@
</script>
{#if mounted}
<ToolkitEditor
id={tool?.id ?? ''}
name={tool?.name ?? ''}
meta={tool?.meta ?? { description: '' }}
content={tool?.content ?? ''}
{clone}
on:save={(e) => {
saveHandler(e.detail);
}}
/>
{#key tool?.content}
<ToolkitEditor
id={tool?.id ?? ''}
name={tool?.name ?? ''}
meta={tool?.meta ?? { description: '' }}
content={tool?.content ?? ''}
{clone}
on:save={(e) => {
saveHandler(e.detail);
}}
/>
{/key}
{/if}