mirror of
https://git.mirrors.martin98.com/https://github.com/open-webui/open-webui
synced 2025-08-16 14:05:58 +08:00
Merge remote-tracking branch 'upstream/dev' into update-IT-translation
This commit is contained in:
commit
ebf2e4141e
@ -26,6 +26,9 @@ ARG BUILD_HASH
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# to store git revision in build
|
||||||
|
RUN apk add --no-cache git
|
||||||
|
|
||||||
COPY package.json package-lock.json ./
|
COPY package.json package-lock.json ./
|
||||||
RUN npm ci
|
RUN npm ci
|
||||||
|
|
||||||
|
@ -989,6 +989,26 @@ DEFAULT_USER_ROLE = PersistentConfig(
|
|||||||
os.getenv("DEFAULT_USER_ROLE", "pending"),
|
os.getenv("DEFAULT_USER_ROLE", "pending"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
PENDING_USER_OVERLAY_TITLE = PersistentConfig(
|
||||||
|
"PENDING_USER_OVERLAY_TITLE",
|
||||||
|
"ui.pending_user_overlay_title",
|
||||||
|
os.environ.get("PENDING_USER_OVERLAY_TITLE", ""),
|
||||||
|
)
|
||||||
|
|
||||||
|
PENDING_USER_OVERLAY_CONTENT = PersistentConfig(
|
||||||
|
"PENDING_USER_OVERLAY_CONTENT",
|
||||||
|
"ui.pending_user_overlay_content",
|
||||||
|
os.environ.get("PENDING_USER_OVERLAY_CONTENT", ""),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
RESPONSE_WATERMARK = PersistentConfig(
|
||||||
|
"RESPONSE_WATERMARK",
|
||||||
|
"ui.watermark",
|
||||||
|
os.environ.get("RESPONSE_WATERMARK", ""),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
USER_PERMISSIONS_WORKSPACE_MODELS_ACCESS = (
|
USER_PERMISSIONS_WORKSPACE_MODELS_ACCESS = (
|
||||||
os.environ.get("USER_PERMISSIONS_WORKSPACE_MODELS_ACCESS", "False").lower()
|
os.environ.get("USER_PERMISSIONS_WORKSPACE_MODELS_ACCESS", "False").lower()
|
||||||
== "true"
|
== "true"
|
||||||
@ -1731,6 +1751,9 @@ QDRANT_API_KEY = os.environ.get("QDRANT_API_KEY", None)
|
|||||||
QDRANT_ON_DISK = os.environ.get("QDRANT_ON_DISK", "false").lower() == "true"
|
QDRANT_ON_DISK = os.environ.get("QDRANT_ON_DISK", "false").lower() == "true"
|
||||||
QDRANT_PREFER_GRPC = os.environ.get("QDRANT_PREFER_GRPC", "False").lower() == "true"
|
QDRANT_PREFER_GRPC = os.environ.get("QDRANT_PREFER_GRPC", "False").lower() == "true"
|
||||||
QDRANT_GRPC_PORT = int(os.environ.get("QDRANT_GRPC_PORT", "6334"))
|
QDRANT_GRPC_PORT = int(os.environ.get("QDRANT_GRPC_PORT", "6334"))
|
||||||
|
ENABLE_QDRANT_MULTITENANCY_MODE = (
|
||||||
|
os.environ.get("ENABLE_QDRANT_MULTITENANCY_MODE", "false").lower() == "true"
|
||||||
|
)
|
||||||
|
|
||||||
# OpenSearch
|
# OpenSearch
|
||||||
OPENSEARCH_URI = os.environ.get("OPENSEARCH_URI", "https://localhost:9200")
|
OPENSEARCH_URI = os.environ.get("OPENSEARCH_URI", "https://localhost:9200")
|
||||||
@ -1825,6 +1848,18 @@ CONTENT_EXTRACTION_ENGINE = PersistentConfig(
|
|||||||
os.environ.get("CONTENT_EXTRACTION_ENGINE", "").lower(),
|
os.environ.get("CONTENT_EXTRACTION_ENGINE", "").lower(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
EXTERNAL_DOCUMENT_LOADER_URL = PersistentConfig(
|
||||||
|
"EXTERNAL_DOCUMENT_LOADER_URL",
|
||||||
|
"rag.external_document_loader_url",
|
||||||
|
os.environ.get("EXTERNAL_DOCUMENT_LOADER_URL", ""),
|
||||||
|
)
|
||||||
|
|
||||||
|
EXTERNAL_DOCUMENT_LOADER_API_KEY = PersistentConfig(
|
||||||
|
"EXTERNAL_DOCUMENT_LOADER_API_KEY",
|
||||||
|
"rag.external_document_loader_api_key",
|
||||||
|
os.environ.get("EXTERNAL_DOCUMENT_LOADER_API_KEY", ""),
|
||||||
|
)
|
||||||
|
|
||||||
TIKA_SERVER_URL = PersistentConfig(
|
TIKA_SERVER_URL = PersistentConfig(
|
||||||
"TIKA_SERVER_URL",
|
"TIKA_SERVER_URL",
|
||||||
"rag.tika_server_url",
|
"rag.tika_server_url",
|
||||||
@ -1849,6 +1884,12 @@ DOCLING_OCR_LANG = PersistentConfig(
|
|||||||
os.getenv("DOCLING_OCR_LANG", "eng,fra,deu,spa"),
|
os.getenv("DOCLING_OCR_LANG", "eng,fra,deu,spa"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
DOCLING_DO_PICTURE_DESCRIPTION = PersistentConfig(
|
||||||
|
"DOCLING_DO_PICTURE_DESCRIPTION",
|
||||||
|
"rag.docling_do_picture_description",
|
||||||
|
os.getenv("DOCLING_DO_PICTURE_DESCRIPTION", "False").lower() == "true",
|
||||||
|
)
|
||||||
|
|
||||||
DOCUMENT_INTELLIGENCE_ENDPOINT = PersistentConfig(
|
DOCUMENT_INTELLIGENCE_ENDPOINT = PersistentConfig(
|
||||||
"DOCUMENT_INTELLIGENCE_ENDPOINT",
|
"DOCUMENT_INTELLIGENCE_ENDPOINT",
|
||||||
"rag.document_intelligence_endpoint",
|
"rag.document_intelligence_endpoint",
|
||||||
@ -1920,6 +1961,16 @@ RAG_FILE_MAX_SIZE = PersistentConfig(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
RAG_ALLOWED_FILE_EXTENSIONS = PersistentConfig(
|
||||||
|
"RAG_ALLOWED_FILE_EXTENSIONS",
|
||||||
|
"rag.file.allowed_extensions",
|
||||||
|
[
|
||||||
|
ext.strip()
|
||||||
|
for ext in os.environ.get("RAG_ALLOWED_FILE_EXTENSIONS", "").split(",")
|
||||||
|
if ext.strip()
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
RAG_EMBEDDING_ENGINE = PersistentConfig(
|
RAG_EMBEDDING_ENGINE = PersistentConfig(
|
||||||
"RAG_EMBEDDING_ENGINE",
|
"RAG_EMBEDDING_ENGINE",
|
||||||
"rag.embedding_engine",
|
"rag.embedding_engine",
|
||||||
@ -2839,6 +2890,12 @@ LDAP_CA_CERT_FILE = PersistentConfig(
|
|||||||
os.environ.get("LDAP_CA_CERT_FILE", ""),
|
os.environ.get("LDAP_CA_CERT_FILE", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
LDAP_VALIDATE_CERT = PersistentConfig(
|
||||||
|
"LDAP_VALIDATE_CERT",
|
||||||
|
"ldap.server.validate_cert",
|
||||||
|
os.environ.get("LDAP_VALIDATE_CERT", "True").lower() == "true",
|
||||||
|
)
|
||||||
|
|
||||||
LDAP_CIPHERS = PersistentConfig(
|
LDAP_CIPHERS = PersistentConfig(
|
||||||
"LDAP_CIPHERS", "ldap.server.ciphers", os.environ.get("LDAP_CIPHERS", "ALL")
|
"LDAP_CIPHERS", "ldap.server.ciphers", os.environ.get("LDAP_CIPHERS", "ALL")
|
||||||
)
|
)
|
||||||
|
@ -197,6 +197,7 @@ from open_webui.config import (
|
|||||||
RAG_EMBEDDING_ENGINE,
|
RAG_EMBEDDING_ENGINE,
|
||||||
RAG_EMBEDDING_BATCH_SIZE,
|
RAG_EMBEDDING_BATCH_SIZE,
|
||||||
RAG_RELEVANCE_THRESHOLD,
|
RAG_RELEVANCE_THRESHOLD,
|
||||||
|
RAG_ALLOWED_FILE_EXTENSIONS,
|
||||||
RAG_FILE_MAX_COUNT,
|
RAG_FILE_MAX_COUNT,
|
||||||
RAG_FILE_MAX_SIZE,
|
RAG_FILE_MAX_SIZE,
|
||||||
RAG_OPENAI_API_BASE_URL,
|
RAG_OPENAI_API_BASE_URL,
|
||||||
@ -206,10 +207,13 @@ from open_webui.config import (
|
|||||||
CHUNK_OVERLAP,
|
CHUNK_OVERLAP,
|
||||||
CHUNK_SIZE,
|
CHUNK_SIZE,
|
||||||
CONTENT_EXTRACTION_ENGINE,
|
CONTENT_EXTRACTION_ENGINE,
|
||||||
|
EXTERNAL_DOCUMENT_LOADER_URL,
|
||||||
|
EXTERNAL_DOCUMENT_LOADER_API_KEY,
|
||||||
TIKA_SERVER_URL,
|
TIKA_SERVER_URL,
|
||||||
DOCLING_SERVER_URL,
|
DOCLING_SERVER_URL,
|
||||||
DOCLING_OCR_ENGINE,
|
DOCLING_OCR_ENGINE,
|
||||||
DOCLING_OCR_LANG,
|
DOCLING_OCR_LANG,
|
||||||
|
DOCLING_DO_PICTURE_DESCRIPTION,
|
||||||
DOCUMENT_INTELLIGENCE_ENDPOINT,
|
DOCUMENT_INTELLIGENCE_ENDPOINT,
|
||||||
DOCUMENT_INTELLIGENCE_KEY,
|
DOCUMENT_INTELLIGENCE_KEY,
|
||||||
MISTRAL_OCR_API_KEY,
|
MISTRAL_OCR_API_KEY,
|
||||||
@ -291,6 +295,8 @@ from open_webui.config import (
|
|||||||
ENABLE_EVALUATION_ARENA_MODELS,
|
ENABLE_EVALUATION_ARENA_MODELS,
|
||||||
USER_PERMISSIONS,
|
USER_PERMISSIONS,
|
||||||
DEFAULT_USER_ROLE,
|
DEFAULT_USER_ROLE,
|
||||||
|
PENDING_USER_OVERLAY_CONTENT,
|
||||||
|
PENDING_USER_OVERLAY_TITLE,
|
||||||
DEFAULT_PROMPT_SUGGESTIONS,
|
DEFAULT_PROMPT_SUGGESTIONS,
|
||||||
DEFAULT_MODELS,
|
DEFAULT_MODELS,
|
||||||
DEFAULT_ARENA_MODEL,
|
DEFAULT_ARENA_MODEL,
|
||||||
@ -317,6 +323,7 @@ from open_webui.config import (
|
|||||||
LDAP_APP_PASSWORD,
|
LDAP_APP_PASSWORD,
|
||||||
LDAP_USE_TLS,
|
LDAP_USE_TLS,
|
||||||
LDAP_CA_CERT_FILE,
|
LDAP_CA_CERT_FILE,
|
||||||
|
LDAP_VALIDATE_CERT,
|
||||||
LDAP_CIPHERS,
|
LDAP_CIPHERS,
|
||||||
# Misc
|
# Misc
|
||||||
ENV,
|
ENV,
|
||||||
@ -327,6 +334,7 @@ from open_webui.config import (
|
|||||||
DEFAULT_LOCALE,
|
DEFAULT_LOCALE,
|
||||||
OAUTH_PROVIDERS,
|
OAUTH_PROVIDERS,
|
||||||
WEBUI_URL,
|
WEBUI_URL,
|
||||||
|
RESPONSE_WATERMARK,
|
||||||
# Admin
|
# Admin
|
||||||
ENABLE_ADMIN_CHAT_ACCESS,
|
ENABLE_ADMIN_CHAT_ACCESS,
|
||||||
ENABLE_ADMIN_EXPORT,
|
ENABLE_ADMIN_EXPORT,
|
||||||
@ -373,6 +381,7 @@ from open_webui.env import (
|
|||||||
OFFLINE_MODE,
|
OFFLINE_MODE,
|
||||||
ENABLE_OTEL,
|
ENABLE_OTEL,
|
||||||
EXTERNAL_PWA_MANIFEST_URL,
|
EXTERNAL_PWA_MANIFEST_URL,
|
||||||
|
AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -573,6 +582,11 @@ app.state.config.DEFAULT_MODELS = DEFAULT_MODELS
|
|||||||
app.state.config.DEFAULT_PROMPT_SUGGESTIONS = DEFAULT_PROMPT_SUGGESTIONS
|
app.state.config.DEFAULT_PROMPT_SUGGESTIONS = DEFAULT_PROMPT_SUGGESTIONS
|
||||||
app.state.config.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE
|
app.state.config.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE
|
||||||
|
|
||||||
|
app.state.config.PENDING_USER_OVERLAY_CONTENT = PENDING_USER_OVERLAY_CONTENT
|
||||||
|
app.state.config.PENDING_USER_OVERLAY_TITLE = PENDING_USER_OVERLAY_TITLE
|
||||||
|
|
||||||
|
app.state.config.RESPONSE_WATERMARK = RESPONSE_WATERMARK
|
||||||
|
|
||||||
app.state.config.USER_PERMISSIONS = USER_PERMISSIONS
|
app.state.config.USER_PERMISSIONS = USER_PERMISSIONS
|
||||||
app.state.config.WEBHOOK_URL = WEBHOOK_URL
|
app.state.config.WEBHOOK_URL = WEBHOOK_URL
|
||||||
app.state.config.BANNERS = WEBUI_BANNERS
|
app.state.config.BANNERS = WEBUI_BANNERS
|
||||||
@ -609,6 +623,7 @@ app.state.config.LDAP_SEARCH_BASE = LDAP_SEARCH_BASE
|
|||||||
app.state.config.LDAP_SEARCH_FILTERS = LDAP_SEARCH_FILTERS
|
app.state.config.LDAP_SEARCH_FILTERS = LDAP_SEARCH_FILTERS
|
||||||
app.state.config.LDAP_USE_TLS = LDAP_USE_TLS
|
app.state.config.LDAP_USE_TLS = LDAP_USE_TLS
|
||||||
app.state.config.LDAP_CA_CERT_FILE = LDAP_CA_CERT_FILE
|
app.state.config.LDAP_CA_CERT_FILE = LDAP_CA_CERT_FILE
|
||||||
|
app.state.config.LDAP_VALIDATE_CERT = LDAP_VALIDATE_CERT
|
||||||
app.state.config.LDAP_CIPHERS = LDAP_CIPHERS
|
app.state.config.LDAP_CIPHERS = LDAP_CIPHERS
|
||||||
|
|
||||||
|
|
||||||
@ -631,6 +646,7 @@ app.state.FUNCTIONS = {}
|
|||||||
app.state.config.TOP_K = RAG_TOP_K
|
app.state.config.TOP_K = RAG_TOP_K
|
||||||
app.state.config.TOP_K_RERANKER = RAG_TOP_K_RERANKER
|
app.state.config.TOP_K_RERANKER = RAG_TOP_K_RERANKER
|
||||||
app.state.config.RELEVANCE_THRESHOLD = RAG_RELEVANCE_THRESHOLD
|
app.state.config.RELEVANCE_THRESHOLD = RAG_RELEVANCE_THRESHOLD
|
||||||
|
app.state.config.ALLOWED_FILE_EXTENSIONS = RAG_ALLOWED_FILE_EXTENSIONS
|
||||||
app.state.config.FILE_MAX_SIZE = RAG_FILE_MAX_SIZE
|
app.state.config.FILE_MAX_SIZE = RAG_FILE_MAX_SIZE
|
||||||
app.state.config.FILE_MAX_COUNT = RAG_FILE_MAX_COUNT
|
app.state.config.FILE_MAX_COUNT = RAG_FILE_MAX_COUNT
|
||||||
|
|
||||||
@ -641,10 +657,13 @@ app.state.config.ENABLE_RAG_HYBRID_SEARCH = ENABLE_RAG_HYBRID_SEARCH
|
|||||||
app.state.config.ENABLE_WEB_LOADER_SSL_VERIFICATION = ENABLE_WEB_LOADER_SSL_VERIFICATION
|
app.state.config.ENABLE_WEB_LOADER_SSL_VERIFICATION = ENABLE_WEB_LOADER_SSL_VERIFICATION
|
||||||
|
|
||||||
app.state.config.CONTENT_EXTRACTION_ENGINE = CONTENT_EXTRACTION_ENGINE
|
app.state.config.CONTENT_EXTRACTION_ENGINE = CONTENT_EXTRACTION_ENGINE
|
||||||
|
app.state.config.EXTERNAL_DOCUMENT_LOADER_URL = EXTERNAL_DOCUMENT_LOADER_URL
|
||||||
|
app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY = EXTERNAL_DOCUMENT_LOADER_API_KEY
|
||||||
app.state.config.TIKA_SERVER_URL = TIKA_SERVER_URL
|
app.state.config.TIKA_SERVER_URL = TIKA_SERVER_URL
|
||||||
app.state.config.DOCLING_SERVER_URL = DOCLING_SERVER_URL
|
app.state.config.DOCLING_SERVER_URL = DOCLING_SERVER_URL
|
||||||
app.state.config.DOCLING_OCR_ENGINE = DOCLING_OCR_ENGINE
|
app.state.config.DOCLING_OCR_ENGINE = DOCLING_OCR_ENGINE
|
||||||
app.state.config.DOCLING_OCR_LANG = DOCLING_OCR_LANG
|
app.state.config.DOCLING_OCR_LANG = DOCLING_OCR_LANG
|
||||||
|
app.state.config.DOCLING_DO_PICTURE_DESCRIPTION = DOCLING_DO_PICTURE_DESCRIPTION
|
||||||
app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT = DOCUMENT_INTELLIGENCE_ENDPOINT
|
app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT = DOCUMENT_INTELLIGENCE_ENDPOINT
|
||||||
app.state.config.DOCUMENT_INTELLIGENCE_KEY = DOCUMENT_INTELLIGENCE_KEY
|
app.state.config.DOCUMENT_INTELLIGENCE_KEY = DOCUMENT_INTELLIGENCE_KEY
|
||||||
app.state.config.MISTRAL_OCR_API_KEY = MISTRAL_OCR_API_KEY
|
app.state.config.MISTRAL_OCR_API_KEY = MISTRAL_OCR_API_KEY
|
||||||
@ -1167,11 +1186,12 @@ async def chat_completion(
|
|||||||
"chat_id": form_data.pop("chat_id", None),
|
"chat_id": form_data.pop("chat_id", None),
|
||||||
"message_id": form_data.pop("id", None),
|
"message_id": form_data.pop("id", None),
|
||||||
"session_id": form_data.pop("session_id", None),
|
"session_id": form_data.pop("session_id", None),
|
||||||
|
"filter_ids": form_data.pop("filter_ids", []),
|
||||||
"tool_ids": form_data.get("tool_ids", None),
|
"tool_ids": form_data.get("tool_ids", None),
|
||||||
"tool_servers": form_data.pop("tool_servers", None),
|
"tool_servers": form_data.pop("tool_servers", None),
|
||||||
"files": form_data.get("files", None),
|
"files": form_data.get("files", None),
|
||||||
"features": form_data.get("features", None),
|
"features": form_data.get("features", {}),
|
||||||
"variables": form_data.get("variables", None),
|
"variables": form_data.get("variables", {}),
|
||||||
"model": model,
|
"model": model,
|
||||||
"direct": model_item.get("direct", False),
|
"direct": model_item.get("direct", False),
|
||||||
**(
|
**(
|
||||||
@ -1395,6 +1415,11 @@ async def get_app_config(request: Request):
|
|||||||
"sharepoint_url": ONEDRIVE_SHAREPOINT_URL.value,
|
"sharepoint_url": ONEDRIVE_SHAREPOINT_URL.value,
|
||||||
"sharepoint_tenant_id": ONEDRIVE_SHAREPOINT_TENANT_ID.value,
|
"sharepoint_tenant_id": ONEDRIVE_SHAREPOINT_TENANT_ID.value,
|
||||||
},
|
},
|
||||||
|
"ui": {
|
||||||
|
"pending_user_overlay_title": app.state.config.PENDING_USER_OVERLAY_TITLE,
|
||||||
|
"pending_user_overlay_content": app.state.config.PENDING_USER_OVERLAY_CONTENT,
|
||||||
|
"response_watermark": app.state.config.RESPONSE_WATERMARK,
|
||||||
|
},
|
||||||
"license_metadata": app.state.LICENSE_METADATA,
|
"license_metadata": app.state.LICENSE_METADATA,
|
||||||
**(
|
**(
|
||||||
{
|
{
|
||||||
@ -1446,7 +1471,8 @@ async def get_app_latest_release_version(user=Depends(get_verified_user)):
|
|||||||
timeout = aiohttp.ClientTimeout(total=1)
|
timeout = aiohttp.ClientTimeout(total=1)
|
||||||
async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session:
|
async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session:
|
||||||
async with session.get(
|
async with session.get(
|
||||||
"https://api.github.com/repos/open-webui/open-webui/releases/latest"
|
"https://api.github.com/repos/open-webui/open-webui/releases/latest",
|
||||||
|
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
) as response:
|
) as response:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = await response.json()
|
data = await response.json()
|
||||||
|
58
backend/open_webui/retrieval/loaders/external_document.py
Normal file
58
backend/open_webui/retrieval/loaders/external_document.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import requests
|
||||||
|
import logging
|
||||||
|
from typing import Iterator, List, Union
|
||||||
|
|
||||||
|
from langchain_core.document_loaders import BaseLoader
|
||||||
|
from langchain_core.documents import Document
|
||||||
|
from open_webui.env import SRC_LOG_LEVELS
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.setLevel(SRC_LOG_LEVELS["RAG"])
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalDocumentLoader(BaseLoader):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
file_path,
|
||||||
|
url: str,
|
||||||
|
api_key: str,
|
||||||
|
mime_type=None,
|
||||||
|
**kwargs,
|
||||||
|
) -> None:
|
||||||
|
self.url = url
|
||||||
|
self.api_key = api_key
|
||||||
|
|
||||||
|
self.file_path = file_path
|
||||||
|
self.mime_type = mime_type
|
||||||
|
|
||||||
|
def load(self) -> list[Document]:
|
||||||
|
with open(self.file_path, "rb") as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
headers = {}
|
||||||
|
if self.mime_type is not None:
|
||||||
|
headers["Content-Type"] = self.mime_type
|
||||||
|
|
||||||
|
if self.api_key is not None:
|
||||||
|
headers["Authorization"] = f"Bearer {self.api_key}"
|
||||||
|
|
||||||
|
url = self.url
|
||||||
|
if url.endswith("/"):
|
||||||
|
url = url[:-1]
|
||||||
|
|
||||||
|
r = requests.put(f"{url}/process", data=data, headers=headers)
|
||||||
|
|
||||||
|
if r.ok:
|
||||||
|
res = r.json()
|
||||||
|
|
||||||
|
if res:
|
||||||
|
return [
|
||||||
|
Document(
|
||||||
|
page_content=res.get("page_content"),
|
||||||
|
metadata=res.get("metadata"),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
raise Exception("Error loading document: No content returned")
|
||||||
|
else:
|
||||||
|
raise Exception(f"Error loading document: {r.status_code} {r.text}")
|
@ -10,7 +10,7 @@ log = logging.getLogger(__name__)
|
|||||||
log.setLevel(SRC_LOG_LEVELS["RAG"])
|
log.setLevel(SRC_LOG_LEVELS["RAG"])
|
||||||
|
|
||||||
|
|
||||||
class ExternalLoader(BaseLoader):
|
class ExternalWebLoader(BaseLoader):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
web_paths: Union[str, List[str]],
|
web_paths: Union[str, List[str]],
|
||||||
@ -32,7 +32,7 @@ class ExternalLoader(BaseLoader):
|
|||||||
response = requests.post(
|
response = requests.post(
|
||||||
self.external_url,
|
self.external_url,
|
||||||
headers={
|
headers={
|
||||||
"User-Agent": "Open WebUI (https://github.com/open-webui/open-webui) RAG Bot",
|
"User-Agent": "Open WebUI (https://github.com/open-webui/open-webui) External Web Loader",
|
||||||
"Authorization": f"Bearer {self.external_api_key}",
|
"Authorization": f"Bearer {self.external_api_key}",
|
||||||
},
|
},
|
||||||
json={
|
json={
|
@ -21,6 +21,8 @@ from langchain_community.document_loaders import (
|
|||||||
)
|
)
|
||||||
from langchain_core.documents import Document
|
from langchain_core.documents import Document
|
||||||
|
|
||||||
|
|
||||||
|
from open_webui.retrieval.loaders.external_document import ExternalDocumentLoader
|
||||||
from open_webui.retrieval.loaders.mistral import MistralLoader
|
from open_webui.retrieval.loaders.mistral import MistralLoader
|
||||||
|
|
||||||
from open_webui.env import SRC_LOG_LEVELS, GLOBAL_LOG_LEVEL
|
from open_webui.env import SRC_LOG_LEVELS, GLOBAL_LOG_LEVEL
|
||||||
@ -126,14 +128,12 @@ class TikaLoader:
|
|||||||
|
|
||||||
|
|
||||||
class DoclingLoader:
|
class DoclingLoader:
|
||||||
def __init__(
|
def __init__(self, url, file_path=None, mime_type=None, params=None):
|
||||||
self, url, file_path=None, mime_type=None, ocr_engine=None, ocr_lang=None
|
|
||||||
):
|
|
||||||
self.url = url.rstrip("/")
|
self.url = url.rstrip("/")
|
||||||
self.file_path = file_path
|
self.file_path = file_path
|
||||||
self.mime_type = mime_type
|
self.mime_type = mime_type
|
||||||
self.ocr_engine = ocr_engine
|
|
||||||
self.ocr_lang = ocr_lang
|
self.params = params or {}
|
||||||
|
|
||||||
def load(self) -> list[Document]:
|
def load(self) -> list[Document]:
|
||||||
with open(self.file_path, "rb") as f:
|
with open(self.file_path, "rb") as f:
|
||||||
@ -150,10 +150,18 @@ class DoclingLoader:
|
|||||||
"table_mode": "accurate",
|
"table_mode": "accurate",
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ocr_engine and self.ocr_lang:
|
if self.params:
|
||||||
params["ocr_engine"] = self.ocr_engine
|
if self.params.get("do_picture_classification"):
|
||||||
|
params["do_picture_classification"] = self.params.get(
|
||||||
|
"do_picture_classification"
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.params.get("ocr_engine") and self.params.get("ocr_lang"):
|
||||||
|
params["ocr_engine"] = self.params.get("ocr_engine")
|
||||||
params["ocr_lang"] = [
|
params["ocr_lang"] = [
|
||||||
lang.strip() for lang in self.ocr_lang.split(",") if lang.strip()
|
lang.strip()
|
||||||
|
for lang in self.params.get("ocr_lang").split(",")
|
||||||
|
if lang.strip()
|
||||||
]
|
]
|
||||||
|
|
||||||
endpoint = f"{self.url}/v1alpha/convert/file"
|
endpoint = f"{self.url}/v1alpha/convert/file"
|
||||||
@ -207,6 +215,17 @@ class Loader:
|
|||||||
def _get_loader(self, filename: str, file_content_type: str, file_path: str):
|
def _get_loader(self, filename: str, file_content_type: str, file_path: str):
|
||||||
file_ext = filename.split(".")[-1].lower()
|
file_ext = filename.split(".")[-1].lower()
|
||||||
|
|
||||||
|
if (
|
||||||
|
self.engine == "external"
|
||||||
|
and self.kwargs.get("EXTERNAL_DOCUMENT_LOADER_URL")
|
||||||
|
and self.kwargs.get("EXTERNAL_DOCUMENT_LOADER_API_KEY")
|
||||||
|
):
|
||||||
|
loader = ExternalDocumentLoader(
|
||||||
|
file_path=file_path,
|
||||||
|
url=self.kwargs.get("EXTERNAL_DOCUMENT_LOADER_URL"),
|
||||||
|
api_key=self.kwargs.get("EXTERNAL_DOCUMENT_LOADER_API_KEY"),
|
||||||
|
mime_type=file_content_type,
|
||||||
|
)
|
||||||
if self.engine == "tika" and self.kwargs.get("TIKA_SERVER_URL"):
|
if self.engine == "tika" and self.kwargs.get("TIKA_SERVER_URL"):
|
||||||
if self._is_text_file(file_ext, file_content_type):
|
if self._is_text_file(file_ext, file_content_type):
|
||||||
loader = TextLoader(file_path, autodetect_encoding=True)
|
loader = TextLoader(file_path, autodetect_encoding=True)
|
||||||
@ -225,8 +244,13 @@ class Loader:
|
|||||||
url=self.kwargs.get("DOCLING_SERVER_URL"),
|
url=self.kwargs.get("DOCLING_SERVER_URL"),
|
||||||
file_path=file_path,
|
file_path=file_path,
|
||||||
mime_type=file_content_type,
|
mime_type=file_content_type,
|
||||||
ocr_engine=self.kwargs.get("DOCLING_OCR_ENGINE"),
|
params={
|
||||||
ocr_lang=self.kwargs.get("DOCLING_OCR_LANG"),
|
"ocr_engine": self.kwargs.get("DOCLING_OCR_ENGINE"),
|
||||||
|
"ocr_lang": self.kwargs.get("DOCLING_OCR_LANG"),
|
||||||
|
"do_picture_classification": self.kwargs.get(
|
||||||
|
"DOCLING_DO_PICTURE_DESCRIPTION"
|
||||||
|
),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
elif (
|
elif (
|
||||||
self.engine == "document_intelligence"
|
self.engine == "document_intelligence"
|
||||||
@ -258,6 +282,15 @@ class Loader:
|
|||||||
loader = MistralLoader(
|
loader = MistralLoader(
|
||||||
api_key=self.kwargs.get("MISTRAL_OCR_API_KEY"), file_path=file_path
|
api_key=self.kwargs.get("MISTRAL_OCR_API_KEY"), file_path=file_path
|
||||||
)
|
)
|
||||||
|
elif (
|
||||||
|
self.engine == "external"
|
||||||
|
and self.kwargs.get("MISTRAL_OCR_API_KEY") != ""
|
||||||
|
and file_ext
|
||||||
|
in ["pdf"] # Mistral OCR currently only supports PDF and images
|
||||||
|
):
|
||||||
|
loader = MistralLoader(
|
||||||
|
api_key=self.kwargs.get("MISTRAL_OCR_API_KEY"), file_path=file_path
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if file_ext == "pdf":
|
if file_ext == "pdf":
|
||||||
loader = PyPDFLoader(
|
loader = PyPDFLoader(
|
||||||
|
@ -12,7 +12,7 @@ from langchain_community.retrievers import BM25Retriever
|
|||||||
from langchain_core.documents import Document
|
from langchain_core.documents import Document
|
||||||
|
|
||||||
from open_webui.config import VECTOR_DB
|
from open_webui.config import VECTOR_DB
|
||||||
from open_webui.retrieval.vector.connector import VECTOR_DB_CLIENT
|
from open_webui.retrieval.vector.factory import VECTOR_DB_CLIENT
|
||||||
|
|
||||||
from open_webui.models.users import UserModel
|
from open_webui.models.users import UserModel
|
||||||
from open_webui.models.files import Files
|
from open_webui.models.files import Files
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
from open_webui.config import VECTOR_DB
|
|
||||||
|
|
||||||
if VECTOR_DB == "milvus":
|
|
||||||
from open_webui.retrieval.vector.dbs.milvus import MilvusClient
|
|
||||||
|
|
||||||
VECTOR_DB_CLIENT = MilvusClient()
|
|
||||||
elif VECTOR_DB == "qdrant":
|
|
||||||
from open_webui.retrieval.vector.dbs.qdrant import QdrantClient
|
|
||||||
|
|
||||||
VECTOR_DB_CLIENT = QdrantClient()
|
|
||||||
elif VECTOR_DB == "opensearch":
|
|
||||||
from open_webui.retrieval.vector.dbs.opensearch import OpenSearchClient
|
|
||||||
|
|
||||||
VECTOR_DB_CLIENT = OpenSearchClient()
|
|
||||||
elif VECTOR_DB == "pgvector":
|
|
||||||
from open_webui.retrieval.vector.dbs.pgvector import PgvectorClient
|
|
||||||
|
|
||||||
VECTOR_DB_CLIENT = PgvectorClient()
|
|
||||||
elif VECTOR_DB == "elasticsearch":
|
|
||||||
from open_webui.retrieval.vector.dbs.elasticsearch import ElasticsearchClient
|
|
||||||
|
|
||||||
VECTOR_DB_CLIENT = ElasticsearchClient()
|
|
||||||
elif VECTOR_DB == "pinecone":
|
|
||||||
from open_webui.retrieval.vector.dbs.pinecone import PineconeClient
|
|
||||||
|
|
||||||
VECTOR_DB_CLIENT = PineconeClient()
|
|
||||||
else:
|
|
||||||
from open_webui.retrieval.vector.dbs.chroma import ChromaClient
|
|
||||||
|
|
||||||
VECTOR_DB_CLIENT = ChromaClient()
|
|
712
backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py
Normal file
712
backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py
Normal file
@ -0,0 +1,712 @@
|
|||||||
|
import logging
|
||||||
|
from typing import Optional, Tuple
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
import grpc
|
||||||
|
from open_webui.config import (
|
||||||
|
QDRANT_API_KEY,
|
||||||
|
QDRANT_GRPC_PORT,
|
||||||
|
QDRANT_ON_DISK,
|
||||||
|
QDRANT_PREFER_GRPC,
|
||||||
|
QDRANT_URI,
|
||||||
|
)
|
||||||
|
from open_webui.env import SRC_LOG_LEVELS
|
||||||
|
from open_webui.retrieval.vector.main import (
|
||||||
|
GetResult,
|
||||||
|
SearchResult,
|
||||||
|
VectorDBBase,
|
||||||
|
VectorItem,
|
||||||
|
)
|
||||||
|
from qdrant_client import QdrantClient as Qclient
|
||||||
|
from qdrant_client.http.exceptions import UnexpectedResponse
|
||||||
|
from qdrant_client.http.models import PointStruct
|
||||||
|
from qdrant_client.models import models
|
||||||
|
|
||||||
|
NO_LIMIT = 999999999
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.setLevel(SRC_LOG_LEVELS["RAG"])
|
||||||
|
|
||||||
|
|
||||||
|
class QdrantClient(VectorDBBase):
|
||||||
|
def __init__(self):
|
||||||
|
self.collection_prefix = "open-webui"
|
||||||
|
self.QDRANT_URI = QDRANT_URI
|
||||||
|
self.QDRANT_API_KEY = QDRANT_API_KEY
|
||||||
|
self.QDRANT_ON_DISK = QDRANT_ON_DISK
|
||||||
|
self.PREFER_GRPC = QDRANT_PREFER_GRPC
|
||||||
|
self.GRPC_PORT = QDRANT_GRPC_PORT
|
||||||
|
|
||||||
|
if not self.QDRANT_URI:
|
||||||
|
self.client = None
|
||||||
|
return
|
||||||
|
|
||||||
|
# Unified handling for either scheme
|
||||||
|
parsed = urlparse(self.QDRANT_URI)
|
||||||
|
host = parsed.hostname or self.QDRANT_URI
|
||||||
|
http_port = parsed.port or 6333 # default REST port
|
||||||
|
|
||||||
|
if self.PREFER_GRPC:
|
||||||
|
self.client = Qclient(
|
||||||
|
host=host,
|
||||||
|
port=http_port,
|
||||||
|
grpc_port=self.GRPC_PORT,
|
||||||
|
prefer_grpc=self.PREFER_GRPC,
|
||||||
|
api_key=self.QDRANT_API_KEY,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.client = Qclient(url=self.QDRANT_URI, api_key=self.QDRANT_API_KEY)
|
||||||
|
|
||||||
|
# Main collection types for multi-tenancy
|
||||||
|
self.MEMORY_COLLECTION = f"{self.collection_prefix}_memories"
|
||||||
|
self.KNOWLEDGE_COLLECTION = f"{self.collection_prefix}_knowledge"
|
||||||
|
self.FILE_COLLECTION = f"{self.collection_prefix}_files"
|
||||||
|
self.WEB_SEARCH_COLLECTION = f"{self.collection_prefix}_web-search"
|
||||||
|
self.HASH_BASED_COLLECTION = f"{self.collection_prefix}_hash-based"
|
||||||
|
|
||||||
|
def _result_to_get_result(self, points) -> GetResult:
|
||||||
|
ids = []
|
||||||
|
documents = []
|
||||||
|
metadatas = []
|
||||||
|
|
||||||
|
for point in points:
|
||||||
|
payload = point.payload
|
||||||
|
ids.append(point.id)
|
||||||
|
documents.append(payload["text"])
|
||||||
|
metadatas.append(payload["metadata"])
|
||||||
|
|
||||||
|
return GetResult(
|
||||||
|
**{
|
||||||
|
"ids": [ids],
|
||||||
|
"documents": [documents],
|
||||||
|
"metadatas": [metadatas],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_collection_and_tenant_id(self, collection_name: str) -> Tuple[str, str]:
|
||||||
|
"""
|
||||||
|
Maps the traditional collection name to multi-tenant collection and tenant ID.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (collection_name, tenant_id)
|
||||||
|
"""
|
||||||
|
# Check for user memory collections
|
||||||
|
tenant_id = collection_name
|
||||||
|
|
||||||
|
if collection_name.startswith("user-memory-"):
|
||||||
|
return self.MEMORY_COLLECTION, tenant_id
|
||||||
|
|
||||||
|
# Check for file collections
|
||||||
|
elif collection_name.startswith("file-"):
|
||||||
|
return self.FILE_COLLECTION, tenant_id
|
||||||
|
|
||||||
|
# Check for web search collections
|
||||||
|
elif collection_name.startswith("web-search-"):
|
||||||
|
return self.WEB_SEARCH_COLLECTION, tenant_id
|
||||||
|
|
||||||
|
# Handle hash-based collections (YouTube and web URLs)
|
||||||
|
elif len(collection_name) == 63 and all(
|
||||||
|
c in "0123456789abcdef" for c in collection_name
|
||||||
|
):
|
||||||
|
return self.HASH_BASED_COLLECTION, tenant_id
|
||||||
|
|
||||||
|
else:
|
||||||
|
return self.KNOWLEDGE_COLLECTION, tenant_id
|
||||||
|
|
||||||
|
def _extract_error_message(self, exception):
|
||||||
|
"""
|
||||||
|
Extract error message from either HTTP or gRPC exceptions
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (status_code, error_message)
|
||||||
|
"""
|
||||||
|
# Check if it's an HTTP exception
|
||||||
|
if isinstance(exception, UnexpectedResponse):
|
||||||
|
try:
|
||||||
|
error_data = exception.structured()
|
||||||
|
error_msg = error_data.get("status", {}).get("error", "")
|
||||||
|
return exception.status_code, error_msg
|
||||||
|
except Exception as inner_e:
|
||||||
|
log.error(f"Failed to parse HTTP error: {inner_e}")
|
||||||
|
return exception.status_code, str(exception)
|
||||||
|
|
||||||
|
# Check if it's a gRPC exception
|
||||||
|
elif isinstance(exception, grpc.RpcError):
|
||||||
|
# Extract status code from gRPC error
|
||||||
|
status_code = None
|
||||||
|
if hasattr(exception, "code") and callable(exception.code):
|
||||||
|
status_code = exception.code().value[0]
|
||||||
|
|
||||||
|
# Extract error message
|
||||||
|
error_msg = str(exception)
|
||||||
|
if "details =" in error_msg:
|
||||||
|
# Parse the details line which contains the actual error message
|
||||||
|
try:
|
||||||
|
details_line = [
|
||||||
|
line.strip()
|
||||||
|
for line in error_msg.split("\n")
|
||||||
|
if "details =" in line
|
||||||
|
][0]
|
||||||
|
error_msg = details_line.split("details =")[1].strip(' "')
|
||||||
|
except (IndexError, AttributeError):
|
||||||
|
# Fall back to full message if parsing fails
|
||||||
|
pass
|
||||||
|
|
||||||
|
return status_code, error_msg
|
||||||
|
|
||||||
|
# For any other type of exception
|
||||||
|
return None, str(exception)
|
||||||
|
|
||||||
|
def _is_collection_not_found_error(self, exception):
|
||||||
|
"""
|
||||||
|
Check if the exception is due to collection not found, supporting both HTTP and gRPC
|
||||||
|
"""
|
||||||
|
status_code, error_msg = self._extract_error_message(exception)
|
||||||
|
|
||||||
|
# HTTP error (404)
|
||||||
|
if (
|
||||||
|
status_code == 404
|
||||||
|
and "Collection" in error_msg
|
||||||
|
and "doesn't exist" in error_msg
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
|
||||||
|
# gRPC error (NOT_FOUND status)
|
||||||
|
if (
|
||||||
|
isinstance(exception, grpc.RpcError)
|
||||||
|
and exception.code() == grpc.StatusCode.NOT_FOUND
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _is_dimension_mismatch_error(self, exception):
|
||||||
|
"""
|
||||||
|
Check if the exception is due to dimension mismatch, supporting both HTTP and gRPC
|
||||||
|
"""
|
||||||
|
status_code, error_msg = self._extract_error_message(exception)
|
||||||
|
|
||||||
|
# Common patterns in both HTTP and gRPC
|
||||||
|
return (
|
||||||
|
"Vector dimension error" in error_msg
|
||||||
|
or "dimensions mismatch" in error_msg
|
||||||
|
or "invalid vector size" in error_msg
|
||||||
|
)
|
||||||
|
|
||||||
|
def _create_multi_tenant_collection_if_not_exists(
|
||||||
|
self, mt_collection_name: str, dimension: int = 384
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Creates a collection with multi-tenancy configuration if it doesn't exist.
|
||||||
|
Default dimension is set to 384 which corresponds to 'sentence-transformers/all-MiniLM-L6-v2'.
|
||||||
|
When creating collections dynamically (insert/upsert), the actual vector dimensions will be used.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Try to create the collection directly - will fail if it already exists
|
||||||
|
self.client.create_collection(
|
||||||
|
collection_name=mt_collection_name,
|
||||||
|
vectors_config=models.VectorParams(
|
||||||
|
size=dimension,
|
||||||
|
distance=models.Distance.COSINE,
|
||||||
|
on_disk=self.QDRANT_ON_DISK,
|
||||||
|
),
|
||||||
|
hnsw_config=models.HnswConfigDiff(
|
||||||
|
payload_m=16, # Enable per-tenant indexing
|
||||||
|
m=0,
|
||||||
|
on_disk=self.QDRANT_ON_DISK,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create tenant ID payload index
|
||||||
|
self.client.create_payload_index(
|
||||||
|
collection_name=mt_collection_name,
|
||||||
|
field_name="tenant_id",
|
||||||
|
field_schema=models.KeywordIndexParams(
|
||||||
|
type=models.KeywordIndexType.KEYWORD,
|
||||||
|
is_tenant=True,
|
||||||
|
on_disk=self.QDRANT_ON_DISK,
|
||||||
|
),
|
||||||
|
wait=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
f"Multi-tenant collection {mt_collection_name} created with dimension {dimension}!"
|
||||||
|
)
|
||||||
|
except (UnexpectedResponse, grpc.RpcError) as e:
|
||||||
|
# Check for the specific error indicating collection already exists
|
||||||
|
status_code, error_msg = self._extract_error_message(e)
|
||||||
|
|
||||||
|
# HTTP status code 409 or gRPC ALREADY_EXISTS
|
||||||
|
if (isinstance(e, UnexpectedResponse) and status_code == 409) or (
|
||||||
|
isinstance(e, grpc.RpcError)
|
||||||
|
and e.code() == grpc.StatusCode.ALREADY_EXISTS
|
||||||
|
):
|
||||||
|
if "already exists" in error_msg:
|
||||||
|
log.debug(f"Collection {mt_collection_name} already exists")
|
||||||
|
return
|
||||||
|
# If it's not an already exists error, re-raise
|
||||||
|
raise e
|
||||||
|
except Exception as e:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def _create_points(self, items: list[VectorItem], tenant_id: str):
|
||||||
|
"""
|
||||||
|
Create point structs from vector items with tenant ID.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
PointStruct(
|
||||||
|
id=item["id"],
|
||||||
|
vector=item["vector"],
|
||||||
|
payload={
|
||||||
|
"text": item["text"],
|
||||||
|
"metadata": item["metadata"],
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
for item in items
|
||||||
|
]
|
||||||
|
|
||||||
|
def has_collection(self, collection_name: str) -> bool:
|
||||||
|
"""
|
||||||
|
Check if a logical collection exists by checking for any points with the tenant ID.
|
||||||
|
"""
|
||||||
|
if not self.client:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Map to multi-tenant collection and tenant ID
|
||||||
|
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
|
||||||
|
|
||||||
|
# Create tenant filter
|
||||||
|
tenant_filter = models.FieldCondition(
|
||||||
|
key="tenant_id", match=models.MatchValue(value=tenant_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Try directly querying - most of the time collection should exist
|
||||||
|
response = self.client.query_points(
|
||||||
|
collection_name=mt_collection,
|
||||||
|
query_filter=models.Filter(must=[tenant_filter]),
|
||||||
|
limit=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Collection exists with this tenant ID if there are points
|
||||||
|
return len(response.points) > 0
|
||||||
|
except (UnexpectedResponse, grpc.RpcError) as e:
|
||||||
|
if self._is_collection_not_found_error(e):
|
||||||
|
log.debug(f"Collection {mt_collection} doesn't exist")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
# For other API errors, log and return False
|
||||||
|
_, error_msg = self._extract_error_message(e)
|
||||||
|
log.warning(f"Unexpected Qdrant error: {error_msg}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
# For any other errors, log and return False
|
||||||
|
log.debug(f"Error checking collection {mt_collection}: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def delete(
|
||||||
|
self,
|
||||||
|
collection_name: str,
|
||||||
|
ids: Optional[list[str]] = None,
|
||||||
|
filter: Optional[dict] = None,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Delete vectors by ID or filter from a collection with tenant isolation.
|
||||||
|
"""
|
||||||
|
if not self.client:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Map to multi-tenant collection and tenant ID
|
||||||
|
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
|
||||||
|
|
||||||
|
# Create tenant filter
|
||||||
|
tenant_filter = models.FieldCondition(
|
||||||
|
key="tenant_id", match=models.MatchValue(value=tenant_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
must_conditions = [tenant_filter]
|
||||||
|
should_conditions = []
|
||||||
|
|
||||||
|
if ids:
|
||||||
|
for id_value in ids:
|
||||||
|
should_conditions.append(
|
||||||
|
models.FieldCondition(
|
||||||
|
key="metadata.id",
|
||||||
|
match=models.MatchValue(value=id_value),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
elif filter:
|
||||||
|
for key, value in filter.items():
|
||||||
|
must_conditions.append(
|
||||||
|
models.FieldCondition(
|
||||||
|
key=f"metadata.{key}",
|
||||||
|
match=models.MatchValue(value=value),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Try to delete directly - most of the time collection should exist
|
||||||
|
update_result = self.client.delete(
|
||||||
|
collection_name=mt_collection,
|
||||||
|
points_selector=models.FilterSelector(
|
||||||
|
filter=models.Filter(must=must_conditions, should=should_conditions)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return update_result
|
||||||
|
except (UnexpectedResponse, grpc.RpcError) as e:
|
||||||
|
if self._is_collection_not_found_error(e):
|
||||||
|
log.debug(
|
||||||
|
f"Collection {mt_collection} doesn't exist, nothing to delete"
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
# For other API errors, log and re-raise
|
||||||
|
_, error_msg = self._extract_error_message(e)
|
||||||
|
log.warning(f"Unexpected Qdrant error: {error_msg}")
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
# For non-Qdrant exceptions, re-raise
|
||||||
|
raise
|
||||||
|
|
||||||
|
def search(
|
||||||
|
self, collection_name: str, vectors: list[list[float | int]], limit: int
|
||||||
|
) -> Optional[SearchResult]:
|
||||||
|
"""
|
||||||
|
Search for the nearest neighbor items based on the vectors with tenant isolation.
|
||||||
|
"""
|
||||||
|
if not self.client:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Map to multi-tenant collection and tenant ID
|
||||||
|
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
|
||||||
|
|
||||||
|
# Get the vector dimension from the query vector
|
||||||
|
dimension = len(vectors[0]) if vectors and len(vectors) > 0 else None
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Try the search operation directly - most of the time collection should exist
|
||||||
|
|
||||||
|
# Create tenant filter
|
||||||
|
tenant_filter = models.FieldCondition(
|
||||||
|
key="tenant_id", match=models.MatchValue(value=tenant_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure vector dimensions match the collection
|
||||||
|
collection_dim = self.client.get_collection(
|
||||||
|
mt_collection
|
||||||
|
).config.params.vectors.size
|
||||||
|
|
||||||
|
if collection_dim != dimension:
|
||||||
|
if collection_dim < dimension:
|
||||||
|
vectors = [vector[:collection_dim] for vector in vectors]
|
||||||
|
else:
|
||||||
|
vectors = [
|
||||||
|
vector + [0] * (collection_dim - dimension)
|
||||||
|
for vector in vectors
|
||||||
|
]
|
||||||
|
|
||||||
|
# Search with tenant filter
|
||||||
|
prefetch_query = models.Prefetch(
|
||||||
|
filter=models.Filter(must=[tenant_filter]),
|
||||||
|
limit=NO_LIMIT,
|
||||||
|
)
|
||||||
|
query_response = self.client.query_points(
|
||||||
|
collection_name=mt_collection,
|
||||||
|
query=vectors[0],
|
||||||
|
prefetch=prefetch_query,
|
||||||
|
limit=limit,
|
||||||
|
)
|
||||||
|
|
||||||
|
get_result = self._result_to_get_result(query_response.points)
|
||||||
|
return SearchResult(
|
||||||
|
ids=get_result.ids,
|
||||||
|
documents=get_result.documents,
|
||||||
|
metadatas=get_result.metadatas,
|
||||||
|
# qdrant distance is [-1, 1], normalize to [0, 1]
|
||||||
|
distances=[
|
||||||
|
[(point.score + 1.0) / 2.0 for point in query_response.points]
|
||||||
|
],
|
||||||
|
)
|
||||||
|
except (UnexpectedResponse, grpc.RpcError) as e:
|
||||||
|
if self._is_collection_not_found_error(e):
|
||||||
|
log.debug(
|
||||||
|
f"Collection {mt_collection} doesn't exist, search returns None"
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
# For other API errors, log and re-raise
|
||||||
|
_, error_msg = self._extract_error_message(e)
|
||||||
|
log.warning(f"Unexpected Qdrant error during search: {error_msg}")
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
# For non-Qdrant exceptions, log and return None
|
||||||
|
log.exception(f"Error searching collection '{collection_name}': {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def query(self, collection_name: str, filter: dict, limit: Optional[int] = None):
|
||||||
|
"""
|
||||||
|
Query points with filters and tenant isolation.
|
||||||
|
"""
|
||||||
|
if not self.client:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Map to multi-tenant collection and tenant ID
|
||||||
|
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
|
||||||
|
|
||||||
|
# Set default limit if not provided
|
||||||
|
if limit is None:
|
||||||
|
limit = NO_LIMIT
|
||||||
|
|
||||||
|
# Create tenant filter
|
||||||
|
tenant_filter = models.FieldCondition(
|
||||||
|
key="tenant_id", match=models.MatchValue(value=tenant_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create metadata filters
|
||||||
|
field_conditions = []
|
||||||
|
for key, value in filter.items():
|
||||||
|
field_conditions.append(
|
||||||
|
models.FieldCondition(
|
||||||
|
key=f"metadata.{key}", match=models.MatchValue(value=value)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Combine tenant filter with metadata filters
|
||||||
|
combined_filter = models.Filter(must=[tenant_filter, *field_conditions])
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Try the query directly - most of the time collection should exist
|
||||||
|
points = self.client.query_points(
|
||||||
|
collection_name=mt_collection,
|
||||||
|
query_filter=combined_filter,
|
||||||
|
limit=limit,
|
||||||
|
)
|
||||||
|
|
||||||
|
return self._result_to_get_result(points.points)
|
||||||
|
except (UnexpectedResponse, grpc.RpcError) as e:
|
||||||
|
if self._is_collection_not_found_error(e):
|
||||||
|
log.debug(
|
||||||
|
f"Collection {mt_collection} doesn't exist, query returns None"
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
# For other API errors, log and re-raise
|
||||||
|
_, error_msg = self._extract_error_message(e)
|
||||||
|
log.warning(f"Unexpected Qdrant error during query: {error_msg}")
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
# For non-Qdrant exceptions, log and re-raise
|
||||||
|
log.exception(f"Error querying collection '{collection_name}': {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get(self, collection_name: str) -> Optional[GetResult]:
|
||||||
|
"""
|
||||||
|
Get all items in a collection with tenant isolation.
|
||||||
|
"""
|
||||||
|
if not self.client:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Map to multi-tenant collection and tenant ID
|
||||||
|
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
|
||||||
|
|
||||||
|
# Create tenant filter
|
||||||
|
tenant_filter = models.FieldCondition(
|
||||||
|
key="tenant_id", match=models.MatchValue(value=tenant_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Try to get points directly - most of the time collection should exist
|
||||||
|
points = self.client.query_points(
|
||||||
|
collection_name=mt_collection,
|
||||||
|
query_filter=models.Filter(must=[tenant_filter]),
|
||||||
|
limit=NO_LIMIT,
|
||||||
|
)
|
||||||
|
|
||||||
|
return self._result_to_get_result(points.points)
|
||||||
|
except (UnexpectedResponse, grpc.RpcError) as e:
|
||||||
|
if self._is_collection_not_found_error(e):
|
||||||
|
log.debug(f"Collection {mt_collection} doesn't exist, get returns None")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
# For other API errors, log and re-raise
|
||||||
|
_, error_msg = self._extract_error_message(e)
|
||||||
|
log.warning(f"Unexpected Qdrant error during get: {error_msg}")
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
# For non-Qdrant exceptions, log and return None
|
||||||
|
log.exception(f"Error getting collection '{collection_name}': {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _handle_operation_with_error_retry(
|
||||||
|
self, operation_name, mt_collection, points, dimension
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Private helper to handle common error cases for insert and upsert operations.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
operation_name: 'insert' or 'upsert'
|
||||||
|
mt_collection: The multi-tenant collection name
|
||||||
|
points: The vector points to insert/upsert
|
||||||
|
dimension: The dimension of the vectors
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The operation result (for upsert) or None (for insert)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if operation_name == "insert":
|
||||||
|
self.client.upload_points(mt_collection, points)
|
||||||
|
return None
|
||||||
|
else: # upsert
|
||||||
|
return self.client.upsert(mt_collection, points)
|
||||||
|
except (UnexpectedResponse, grpc.RpcError) as e:
|
||||||
|
# Handle collection not found
|
||||||
|
if self._is_collection_not_found_error(e):
|
||||||
|
log.info(
|
||||||
|
f"Collection {mt_collection} doesn't exist. Creating it with dimension {dimension}."
|
||||||
|
)
|
||||||
|
# Create collection with correct dimensions from our vectors
|
||||||
|
self._create_multi_tenant_collection_if_not_exists(
|
||||||
|
mt_collection_name=mt_collection, dimension=dimension
|
||||||
|
)
|
||||||
|
# Try operation again - no need for dimension adjustment since we just created with correct dimensions
|
||||||
|
if operation_name == "insert":
|
||||||
|
self.client.upload_points(mt_collection, points)
|
||||||
|
return None
|
||||||
|
else: # upsert
|
||||||
|
return self.client.upsert(mt_collection, points)
|
||||||
|
|
||||||
|
# Handle dimension mismatch
|
||||||
|
elif self._is_dimension_mismatch_error(e):
|
||||||
|
# For dimension errors, the collection must exist, so get its configuration
|
||||||
|
mt_collection_info = self.client.get_collection(mt_collection)
|
||||||
|
existing_size = mt_collection_info.config.params.vectors.size
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
f"Dimension mismatch: Collection {mt_collection} expects {existing_size}, got {dimension}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if existing_size < dimension:
|
||||||
|
# Truncate vectors to fit
|
||||||
|
log.info(
|
||||||
|
f"Truncating vectors from {dimension} to {existing_size} dimensions"
|
||||||
|
)
|
||||||
|
points = [
|
||||||
|
PointStruct(
|
||||||
|
id=point.id,
|
||||||
|
vector=point.vector[:existing_size],
|
||||||
|
payload=point.payload,
|
||||||
|
)
|
||||||
|
for point in points
|
||||||
|
]
|
||||||
|
elif existing_size > dimension:
|
||||||
|
# Pad vectors with zeros
|
||||||
|
log.info(
|
||||||
|
f"Padding vectors from {dimension} to {existing_size} dimensions with zeros"
|
||||||
|
)
|
||||||
|
points = [
|
||||||
|
PointStruct(
|
||||||
|
id=point.id,
|
||||||
|
vector=point.vector
|
||||||
|
+ [0] * (existing_size - len(point.vector)),
|
||||||
|
payload=point.payload,
|
||||||
|
)
|
||||||
|
for point in points
|
||||||
|
]
|
||||||
|
# Try operation again with adjusted dimensions
|
||||||
|
if operation_name == "insert":
|
||||||
|
self.client.upload_points(mt_collection, points)
|
||||||
|
return None
|
||||||
|
else: # upsert
|
||||||
|
return self.client.upsert(mt_collection, points)
|
||||||
|
else:
|
||||||
|
# Not a known error we can handle, log and re-raise
|
||||||
|
_, error_msg = self._extract_error_message(e)
|
||||||
|
log.warning(f"Unhandled Qdrant error: {error_msg}")
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
# For non-Qdrant exceptions, re-raise
|
||||||
|
raise
|
||||||
|
|
||||||
|
def insert(self, collection_name: str, items: list[VectorItem]):
|
||||||
|
"""
|
||||||
|
Insert items with tenant ID.
|
||||||
|
"""
|
||||||
|
if not self.client or not items:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Map to multi-tenant collection and tenant ID
|
||||||
|
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
|
||||||
|
|
||||||
|
# Get dimensions from the actual vectors
|
||||||
|
dimension = len(items[0]["vector"]) if items else None
|
||||||
|
|
||||||
|
# Create points with tenant ID
|
||||||
|
points = self._create_points(items, tenant_id)
|
||||||
|
|
||||||
|
# Handle the operation with error retry
|
||||||
|
return self._handle_operation_with_error_retry(
|
||||||
|
"insert", mt_collection, points, dimension
|
||||||
|
)
|
||||||
|
|
||||||
|
def upsert(self, collection_name: str, items: list[VectorItem]):
|
||||||
|
"""
|
||||||
|
Upsert items with tenant ID.
|
||||||
|
"""
|
||||||
|
if not self.client or not items:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Map to multi-tenant collection and tenant ID
|
||||||
|
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
|
||||||
|
|
||||||
|
# Get dimensions from the actual vectors
|
||||||
|
dimension = len(items[0]["vector"]) if items else None
|
||||||
|
|
||||||
|
# Create points with tenant ID
|
||||||
|
points = self._create_points(items, tenant_id)
|
||||||
|
|
||||||
|
# Handle the operation with error retry
|
||||||
|
return self._handle_operation_with_error_retry(
|
||||||
|
"upsert", mt_collection, points, dimension
|
||||||
|
)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""
|
||||||
|
Reset the database by deleting all collections.
|
||||||
|
"""
|
||||||
|
if not self.client:
|
||||||
|
return None
|
||||||
|
|
||||||
|
collection_names = self.client.get_collections().collections
|
||||||
|
for collection_name in collection_names:
|
||||||
|
if collection_name.name.startswith(self.collection_prefix):
|
||||||
|
self.client.delete_collection(collection_name=collection_name.name)
|
||||||
|
|
||||||
|
def delete_collection(self, collection_name: str):
|
||||||
|
"""
|
||||||
|
Delete a collection.
|
||||||
|
"""
|
||||||
|
if not self.client:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Map to multi-tenant collection and tenant ID
|
||||||
|
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
|
||||||
|
|
||||||
|
tenant_filter = models.FieldCondition(
|
||||||
|
key="tenant_id", match=models.MatchValue(value=tenant_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
field_conditions = [tenant_filter]
|
||||||
|
|
||||||
|
update_result = self.client.delete(
|
||||||
|
collection_name=mt_collection,
|
||||||
|
points_selector=models.FilterSelector(
|
||||||
|
filter=models.Filter(must=field_conditions)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.client.get_collection(mt_collection).points_count == 0:
|
||||||
|
self.client.delete_collection(mt_collection)
|
||||||
|
|
||||||
|
return update_result
|
55
backend/open_webui/retrieval/vector/factory.py
Normal file
55
backend/open_webui/retrieval/vector/factory.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
from open_webui.retrieval.vector.main import VectorDBBase
|
||||||
|
from open_webui.retrieval.vector.type import VectorType
|
||||||
|
from open_webui.config import VECTOR_DB, ENABLE_QDRANT_MULTITENANCY_MODE
|
||||||
|
|
||||||
|
|
||||||
|
class Vector:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_vector(vector_type: str) -> VectorDBBase:
|
||||||
|
"""
|
||||||
|
get vector db instance by vector type
|
||||||
|
"""
|
||||||
|
match vector_type:
|
||||||
|
case VectorType.MILVUS:
|
||||||
|
from open_webui.retrieval.vector.dbs.milvus import MilvusClient
|
||||||
|
|
||||||
|
return MilvusClient()
|
||||||
|
case VectorType.QDRANT:
|
||||||
|
if ENABLE_QDRANT_MULTITENANCY_MODE:
|
||||||
|
from open_webui.retrieval.vector.dbs.qdrant_multitenancy import (
|
||||||
|
QdrantClient,
|
||||||
|
)
|
||||||
|
|
||||||
|
return QdrantClient()
|
||||||
|
else:
|
||||||
|
from open_webui.retrieval.vector.dbs.qdrant import QdrantClient
|
||||||
|
|
||||||
|
return QdrantClient()
|
||||||
|
case VectorType.PINECONE:
|
||||||
|
from open_webui.retrieval.vector.dbs.pinecone import PineconeClient
|
||||||
|
|
||||||
|
return PineconeClient()
|
||||||
|
case VectorType.OPENSEARCH:
|
||||||
|
from open_webui.retrieval.vector.dbs.opensearch import OpenSearchClient
|
||||||
|
|
||||||
|
return OpenSearchClient()
|
||||||
|
case VectorType.PGVECTOR:
|
||||||
|
from open_webui.retrieval.vector.dbs.pgvector import PgvectorClient
|
||||||
|
|
||||||
|
return PgvectorClient()
|
||||||
|
case VectorType.ELASTICSEARCH:
|
||||||
|
from open_webui.retrieval.vector.dbs.elasticsearch import (
|
||||||
|
ElasticsearchClient,
|
||||||
|
)
|
||||||
|
|
||||||
|
return ElasticsearchClient()
|
||||||
|
case VectorType.CHROMA:
|
||||||
|
from open_webui.retrieval.vector.dbs.chroma import ChromaClient
|
||||||
|
|
||||||
|
return ChromaClient()
|
||||||
|
case _:
|
||||||
|
raise ValueError(f"Unsupported vector type: {vector_type}")
|
||||||
|
|
||||||
|
|
||||||
|
VECTOR_DB_CLIENT = Vector.get_vector(VECTOR_DB)
|
11
backend/open_webui/retrieval/vector/type.py
Normal file
11
backend/open_webui/retrieval/vector/type.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from enum import StrEnum
|
||||||
|
|
||||||
|
|
||||||
|
class VectorType(StrEnum):
|
||||||
|
MILVUS = "milvus"
|
||||||
|
QDRANT = "qdrant"
|
||||||
|
CHROMA = "chroma"
|
||||||
|
PINECONE = "pinecone"
|
||||||
|
ELASTICSEARCH = "elasticsearch"
|
||||||
|
OPENSEARCH = "opensearch"
|
||||||
|
PGVECTOR = "pgvector"
|
@ -25,7 +25,7 @@ from langchain_community.document_loaders.firecrawl import FireCrawlLoader
|
|||||||
from langchain_community.document_loaders.base import BaseLoader
|
from langchain_community.document_loaders.base import BaseLoader
|
||||||
from langchain_core.documents import Document
|
from langchain_core.documents import Document
|
||||||
from open_webui.retrieval.loaders.tavily import TavilyLoader
|
from open_webui.retrieval.loaders.tavily import TavilyLoader
|
||||||
from open_webui.retrieval.loaders.external import ExternalLoader
|
from open_webui.retrieval.loaders.external_web import ExternalWebLoader
|
||||||
from open_webui.constants import ERROR_MESSAGES
|
from open_webui.constants import ERROR_MESSAGES
|
||||||
from open_webui.config import (
|
from open_webui.config import (
|
||||||
ENABLE_RAG_LOCAL_WEB_FETCH,
|
ENABLE_RAG_LOCAL_WEB_FETCH,
|
||||||
@ -39,7 +39,7 @@ from open_webui.config import (
|
|||||||
EXTERNAL_WEB_LOADER_URL,
|
EXTERNAL_WEB_LOADER_URL,
|
||||||
EXTERNAL_WEB_LOADER_API_KEY,
|
EXTERNAL_WEB_LOADER_API_KEY,
|
||||||
)
|
)
|
||||||
from open_webui.env import SRC_LOG_LEVELS
|
from open_webui.env import SRC_LOG_LEVELS, AIOHTTP_CLIENT_SESSION_SSL
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
log.setLevel(SRC_LOG_LEVELS["RAG"])
|
log.setLevel(SRC_LOG_LEVELS["RAG"])
|
||||||
@ -515,7 +515,9 @@ class SafeWebBaseLoader(WebBaseLoader):
|
|||||||
kwargs["ssl"] = False
|
kwargs["ssl"] = False
|
||||||
|
|
||||||
async with session.get(
|
async with session.get(
|
||||||
url, **(self.requests_kwargs | kwargs)
|
url,
|
||||||
|
**(self.requests_kwargs | kwargs),
|
||||||
|
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
) as response:
|
) as response:
|
||||||
if self.raise_for_status:
|
if self.raise_for_status:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
@ -628,7 +630,7 @@ def get_web_loader(
|
|||||||
web_loader_args["extract_depth"] = TAVILY_EXTRACT_DEPTH.value
|
web_loader_args["extract_depth"] = TAVILY_EXTRACT_DEPTH.value
|
||||||
|
|
||||||
if WEB_LOADER_ENGINE.value == "external":
|
if WEB_LOADER_ENGINE.value == "external":
|
||||||
WebLoaderClass = ExternalLoader
|
WebLoaderClass = ExternalWebLoader
|
||||||
web_loader_args["external_url"] = EXTERNAL_WEB_LOADER_URL.value
|
web_loader_args["external_url"] = EXTERNAL_WEB_LOADER_URL.value
|
||||||
web_loader_args["external_api_key"] = EXTERNAL_WEB_LOADER_API_KEY.value
|
web_loader_args["external_api_key"] = EXTERNAL_WEB_LOADER_API_KEY.value
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ from functools import lru_cache
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from pydub import AudioSegment
|
from pydub import AudioSegment
|
||||||
from pydub.silence import split_on_silence
|
from pydub.silence import split_on_silence
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import aiofiles
|
import aiofiles
|
||||||
@ -38,6 +39,7 @@ from open_webui.config import (
|
|||||||
|
|
||||||
from open_webui.constants import ERROR_MESSAGES
|
from open_webui.constants import ERROR_MESSAGES
|
||||||
from open_webui.env import (
|
from open_webui.env import (
|
||||||
|
AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
AIOHTTP_CLIENT_TIMEOUT,
|
AIOHTTP_CLIENT_TIMEOUT,
|
||||||
ENV,
|
ENV,
|
||||||
SRC_LOG_LEVELS,
|
SRC_LOG_LEVELS,
|
||||||
@ -49,7 +51,7 @@ from open_webui.env import (
|
|||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
# Constants
|
# Constants
|
||||||
MAX_FILE_SIZE_MB = 25
|
MAX_FILE_SIZE_MB = 20
|
||||||
MAX_FILE_SIZE = MAX_FILE_SIZE_MB * 1024 * 1024 # Convert MB to bytes
|
MAX_FILE_SIZE = MAX_FILE_SIZE_MB * 1024 * 1024 # Convert MB to bytes
|
||||||
AZURE_MAX_FILE_SIZE_MB = 200
|
AZURE_MAX_FILE_SIZE_MB = 200
|
||||||
AZURE_MAX_FILE_SIZE = AZURE_MAX_FILE_SIZE_MB * 1024 * 1024 # Convert MB to bytes
|
AZURE_MAX_FILE_SIZE = AZURE_MAX_FILE_SIZE_MB * 1024 * 1024 # Convert MB to bytes
|
||||||
@ -86,8 +88,6 @@ def get_audio_convert_format(file_path):
|
|||||||
and info.get("codec_tag_string") == "mp4a"
|
and info.get("codec_tag_string") == "mp4a"
|
||||||
):
|
):
|
||||||
return "mp4"
|
return "mp4"
|
||||||
elif info.get("format_name") == "ogg":
|
|
||||||
return "ogg"
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Error getting audio format: {e}")
|
log.error(f"Error getting audio format: {e}")
|
||||||
return False
|
return False
|
||||||
@ -326,6 +326,7 @@ async def speech(request: Request, user=Depends(get_verified_user)):
|
|||||||
else {}
|
else {}
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
) as r:
|
) as r:
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
|
||||||
@ -381,6 +382,7 @@ async def speech(request: Request, user=Depends(get_verified_user)):
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"xi-api-key": request.app.state.config.TTS_API_KEY,
|
"xi-api-key": request.app.state.config.TTS_API_KEY,
|
||||||
},
|
},
|
||||||
|
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
) as r:
|
) as r:
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
|
||||||
@ -439,6 +441,7 @@ async def speech(request: Request, user=Depends(get_verified_user)):
|
|||||||
"X-Microsoft-OutputFormat": output_format,
|
"X-Microsoft-OutputFormat": output_format,
|
||||||
},
|
},
|
||||||
data=data,
|
data=data,
|
||||||
|
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
) as r:
|
) as r:
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
|
||||||
@ -507,8 +510,7 @@ async def speech(request: Request, user=Depends(get_verified_user)):
|
|||||||
return FileResponse(file_path)
|
return FileResponse(file_path)
|
||||||
|
|
||||||
|
|
||||||
def transcribe(request: Request, file_path):
|
def transcription_handler(request, file_path):
|
||||||
log.info(f"transcribe: {file_path}")
|
|
||||||
filename = os.path.basename(file_path)
|
filename = os.path.basename(file_path)
|
||||||
file_dir = os.path.dirname(file_path)
|
file_dir = os.path.dirname(file_path)
|
||||||
id = filename.split(".")[0]
|
id = filename.split(".")[0]
|
||||||
@ -771,24 +773,119 @@ def transcribe(request: Request, file_path):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def transcribe(request: Request, file_path):
|
||||||
|
log.info(f"transcribe: {file_path}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
file_path = compress_audio(file_path)
|
||||||
|
except Exception as e:
|
||||||
|
log.exception(e)
|
||||||
|
|
||||||
|
# Always produce a list of chunk paths (could be one entry if small)
|
||||||
|
try:
|
||||||
|
chunk_paths = split_audio(file_path, MAX_FILE_SIZE)
|
||||||
|
print(f"Chunk paths: {chunk_paths}")
|
||||||
|
except Exception as e:
|
||||||
|
log.exception(e)
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail=ERROR_MESSAGES.DEFAULT(e),
|
||||||
|
)
|
||||||
|
|
||||||
|
results = []
|
||||||
|
try:
|
||||||
|
with ThreadPoolExecutor() as executor:
|
||||||
|
# Submit tasks for each chunk_path
|
||||||
|
futures = [
|
||||||
|
executor.submit(transcription_handler, request, chunk_path)
|
||||||
|
for chunk_path in chunk_paths
|
||||||
|
]
|
||||||
|
# Gather results as they complete
|
||||||
|
for future in futures:
|
||||||
|
try:
|
||||||
|
results.append(future.result())
|
||||||
|
except Exception as transcribe_exc:
|
||||||
|
log.exception(f"Error transcribing chunk: {transcribe_exc}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="Error during transcription.",
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
# Clean up only the temporary chunks, never the original file
|
||||||
|
for chunk_path in chunk_paths:
|
||||||
|
if chunk_path != file_path and os.path.isfile(chunk_path):
|
||||||
|
try:
|
||||||
|
os.remove(chunk_path)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return {
|
||||||
|
"text": " ".join([result["text"] for result in results]),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def compress_audio(file_path):
|
def compress_audio(file_path):
|
||||||
if os.path.getsize(file_path) > MAX_FILE_SIZE:
|
if os.path.getsize(file_path) > MAX_FILE_SIZE:
|
||||||
|
id = os.path.splitext(os.path.basename(file_path))[
|
||||||
|
0
|
||||||
|
] # Handles names with multiple dots
|
||||||
file_dir = os.path.dirname(file_path)
|
file_dir = os.path.dirname(file_path)
|
||||||
|
|
||||||
audio = AudioSegment.from_file(file_path)
|
audio = AudioSegment.from_file(file_path)
|
||||||
audio = audio.set_frame_rate(16000).set_channels(1) # Compress audio
|
audio = audio.set_frame_rate(16000).set_channels(1) # Compress audio
|
||||||
compressed_path = f"{file_dir}/{id}_compressed.opus"
|
|
||||||
audio.export(compressed_path, format="opus", bitrate="32k")
|
|
||||||
log.debug(f"Compressed audio to {compressed_path}")
|
|
||||||
|
|
||||||
if (
|
compressed_path = os.path.join(file_dir, f"{id}_compressed.mp3")
|
||||||
os.path.getsize(compressed_path) > MAX_FILE_SIZE
|
audio.export(compressed_path, format="mp3", bitrate="32k")
|
||||||
): # Still larger than MAX_FILE_SIZE after compression
|
# log.debug(f"Compressed audio to {compressed_path}") # Uncomment if log is defined
|
||||||
raise Exception(ERROR_MESSAGES.FILE_TOO_LARGE(size=f"{MAX_FILE_SIZE_MB}MB"))
|
|
||||||
return compressed_path
|
return compressed_path
|
||||||
else:
|
else:
|
||||||
return file_path
|
return file_path
|
||||||
|
|
||||||
|
|
||||||
|
def split_audio(file_path, max_bytes, format="mp3", bitrate="32k"):
|
||||||
|
"""
|
||||||
|
Splits audio into chunks not exceeding max_bytes.
|
||||||
|
Returns a list of chunk file paths. If audio fits, returns list with original path.
|
||||||
|
"""
|
||||||
|
file_size = os.path.getsize(file_path)
|
||||||
|
if file_size <= max_bytes:
|
||||||
|
return [file_path] # Nothing to split
|
||||||
|
|
||||||
|
audio = AudioSegment.from_file(file_path)
|
||||||
|
duration_ms = len(audio)
|
||||||
|
orig_size = file_size
|
||||||
|
|
||||||
|
approx_chunk_ms = max(int(duration_ms * (max_bytes / orig_size)) - 1000, 1000)
|
||||||
|
chunks = []
|
||||||
|
start = 0
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
base, _ = os.path.splitext(file_path)
|
||||||
|
|
||||||
|
while start < duration_ms:
|
||||||
|
end = min(start + approx_chunk_ms, duration_ms)
|
||||||
|
chunk = audio[start:end]
|
||||||
|
chunk_path = f"{base}_chunk_{i}.{format}"
|
||||||
|
chunk.export(chunk_path, format=format, bitrate=bitrate)
|
||||||
|
|
||||||
|
# Reduce chunk duration if still too large
|
||||||
|
while os.path.getsize(chunk_path) > max_bytes and (end - start) > 5000:
|
||||||
|
end = start + ((end - start) // 2)
|
||||||
|
chunk = audio[start:end]
|
||||||
|
chunk.export(chunk_path, format=format, bitrate=bitrate)
|
||||||
|
|
||||||
|
if os.path.getsize(chunk_path) > max_bytes:
|
||||||
|
os.remove(chunk_path)
|
||||||
|
raise Exception("Audio chunk cannot be reduced below max file size.")
|
||||||
|
|
||||||
|
chunks.append(chunk_path)
|
||||||
|
start = end
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return chunks
|
||||||
|
|
||||||
|
|
||||||
@router.post("/transcriptions")
|
@router.post("/transcriptions")
|
||||||
def transcription(
|
def transcription(
|
||||||
request: Request,
|
request: Request,
|
||||||
@ -803,6 +900,7 @@ def transcription(
|
|||||||
"audio/ogg",
|
"audio/ogg",
|
||||||
"audio/x-m4a",
|
"audio/x-m4a",
|
||||||
"audio/webm",
|
"audio/webm",
|
||||||
|
"video/webm",
|
||||||
)
|
)
|
||||||
|
|
||||||
if not file.content_type.startswith(supported_filetypes):
|
if not file.content_type.startswith(supported_filetypes):
|
||||||
@ -826,19 +924,13 @@ def transcription(
|
|||||||
f.write(contents)
|
f.write(contents)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
try:
|
result = transcribe(request, file_path)
|
||||||
file_path = compress_audio(file_path)
|
|
||||||
except Exception as e:
|
|
||||||
log.exception(e)
|
|
||||||
|
|
||||||
raise HTTPException(
|
return {
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
**result,
|
||||||
detail=ERROR_MESSAGES.DEFAULT(e),
|
"filename": os.path.basename(file_path),
|
||||||
)
|
}
|
||||||
|
|
||||||
data = transcribe(request, file_path)
|
|
||||||
file_path = file_path.split("/")[-1]
|
|
||||||
return {**data, "filename": file_path}
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ from open_webui.env import (
|
|||||||
SRC_LOG_LEVELS,
|
SRC_LOG_LEVELS,
|
||||||
)
|
)
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
||||||
from fastapi.responses import RedirectResponse, Response
|
from fastapi.responses import RedirectResponse, Response, JSONResponse
|
||||||
from open_webui.config import OPENID_PROVIDER_URL, ENABLE_OAUTH_SIGNUP, ENABLE_LDAP
|
from open_webui.config import OPENID_PROVIDER_URL, ENABLE_OAUTH_SIGNUP, ENABLE_LDAP
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ from open_webui.utils.access_control import get_permissions
|
|||||||
|
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
|
|
||||||
from ssl import CERT_REQUIRED, PROTOCOL_TLS
|
from ssl import CERT_NONE, CERT_REQUIRED, PROTOCOL_TLS
|
||||||
|
|
||||||
if ENABLE_LDAP.value:
|
if ENABLE_LDAP.value:
|
||||||
from ldap3 import Server, Connection, NONE, Tls
|
from ldap3 import Server, Connection, NONE, Tls
|
||||||
@ -186,6 +186,9 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm):
|
|||||||
LDAP_APP_PASSWORD = request.app.state.config.LDAP_APP_PASSWORD
|
LDAP_APP_PASSWORD = request.app.state.config.LDAP_APP_PASSWORD
|
||||||
LDAP_USE_TLS = request.app.state.config.LDAP_USE_TLS
|
LDAP_USE_TLS = request.app.state.config.LDAP_USE_TLS
|
||||||
LDAP_CA_CERT_FILE = request.app.state.config.LDAP_CA_CERT_FILE
|
LDAP_CA_CERT_FILE = request.app.state.config.LDAP_CA_CERT_FILE
|
||||||
|
LDAP_VALIDATE_CERT = (
|
||||||
|
CERT_REQUIRED if request.app.state.config.LDAP_VALIDATE_CERT else CERT_NONE
|
||||||
|
)
|
||||||
LDAP_CIPHERS = (
|
LDAP_CIPHERS = (
|
||||||
request.app.state.config.LDAP_CIPHERS
|
request.app.state.config.LDAP_CIPHERS
|
||||||
if request.app.state.config.LDAP_CIPHERS
|
if request.app.state.config.LDAP_CIPHERS
|
||||||
@ -197,7 +200,7 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
tls = Tls(
|
tls = Tls(
|
||||||
validate=CERT_REQUIRED,
|
validate=LDAP_VALIDATE_CERT,
|
||||||
version=PROTOCOL_TLS,
|
version=PROTOCOL_TLS,
|
||||||
ca_certs_file=LDAP_CA_CERT_FILE,
|
ca_certs_file=LDAP_CA_CERT_FILE,
|
||||||
ciphers=LDAP_CIPHERS,
|
ciphers=LDAP_CIPHERS,
|
||||||
@ -478,10 +481,6 @@ async def signup(request: Request, response: Response, form_data: SignupForm):
|
|||||||
"admin" if user_count == 0 else request.app.state.config.DEFAULT_USER_ROLE
|
"admin" if user_count == 0 else request.app.state.config.DEFAULT_USER_ROLE
|
||||||
)
|
)
|
||||||
|
|
||||||
if user_count == 0:
|
|
||||||
# Disable signup after the first user is created
|
|
||||||
request.app.state.config.ENABLE_SIGNUP = False
|
|
||||||
|
|
||||||
# The password passed to bcrypt must be 72 bytes or fewer. If it is longer, it will be truncated before hashing.
|
# The password passed to bcrypt must be 72 bytes or fewer. If it is longer, it will be truncated before hashing.
|
||||||
if len(form_data.password.encode("utf-8")) > 72:
|
if len(form_data.password.encode("utf-8")) > 72:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
@ -541,6 +540,10 @@ async def signup(request: Request, response: Response, form_data: SignupForm):
|
|||||||
user.id, request.app.state.config.USER_PERMISSIONS
|
user.id, request.app.state.config.USER_PERMISSIONS
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if user_count == 0:
|
||||||
|
# Disable signup after the first user is created
|
||||||
|
request.app.state.config.ENABLE_SIGNUP = False
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"token": token,
|
"token": token,
|
||||||
"token_type": "Bearer",
|
"token_type": "Bearer",
|
||||||
@ -574,9 +577,14 @@ async def signout(request: Request, response: Response):
|
|||||||
logout_url = openid_data.get("end_session_endpoint")
|
logout_url = openid_data.get("end_session_endpoint")
|
||||||
if logout_url:
|
if logout_url:
|
||||||
response.delete_cookie("oauth_id_token")
|
response.delete_cookie("oauth_id_token")
|
||||||
return RedirectResponse(
|
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=200,
|
||||||
|
content={
|
||||||
|
"status": True,
|
||||||
|
"redirect_url": f"{logout_url}?id_token_hint={oauth_id_token}",
|
||||||
|
},
|
||||||
headers=response.headers,
|
headers=response.headers,
|
||||||
url=f"{logout_url}?id_token_hint={oauth_id_token}",
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
@ -591,12 +599,18 @@ async def signout(request: Request, response: Response):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if WEBUI_AUTH_SIGNOUT_REDIRECT_URL:
|
if WEBUI_AUTH_SIGNOUT_REDIRECT_URL:
|
||||||
return RedirectResponse(
|
return JSONResponse(
|
||||||
|
status_code=200,
|
||||||
|
content={
|
||||||
|
"status": True,
|
||||||
|
"redirect_url": WEBUI_AUTH_SIGNOUT_REDIRECT_URL,
|
||||||
|
},
|
||||||
headers=response.headers,
|
headers=response.headers,
|
||||||
url=WEBUI_AUTH_SIGNOUT_REDIRECT_URL,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return {"status": True}
|
return JSONResponse(
|
||||||
|
status_code=200, content={"status": True}, headers=response.headers
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
############################
|
############################
|
||||||
@ -696,6 +710,9 @@ async def get_admin_config(request: Request, user=Depends(get_admin_user)):
|
|||||||
"ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS,
|
"ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS,
|
||||||
"ENABLE_NOTES": request.app.state.config.ENABLE_NOTES,
|
"ENABLE_NOTES": request.app.state.config.ENABLE_NOTES,
|
||||||
"ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS,
|
"ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS,
|
||||||
|
"PENDING_USER_OVERLAY_TITLE": request.app.state.config.PENDING_USER_OVERLAY_TITLE,
|
||||||
|
"PENDING_USER_OVERLAY_CONTENT": request.app.state.config.PENDING_USER_OVERLAY_CONTENT,
|
||||||
|
"RESPONSE_WATERMARK": request.app.state.config.RESPONSE_WATERMARK,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -713,6 +730,9 @@ class AdminConfig(BaseModel):
|
|||||||
ENABLE_CHANNELS: bool
|
ENABLE_CHANNELS: bool
|
||||||
ENABLE_NOTES: bool
|
ENABLE_NOTES: bool
|
||||||
ENABLE_USER_WEBHOOKS: bool
|
ENABLE_USER_WEBHOOKS: bool
|
||||||
|
PENDING_USER_OVERLAY_TITLE: Optional[str] = None
|
||||||
|
PENDING_USER_OVERLAY_CONTENT: Optional[str] = None
|
||||||
|
RESPONSE_WATERMARK: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
@router.post("/admin/config")
|
@router.post("/admin/config")
|
||||||
@ -750,6 +770,15 @@ async def update_admin_config(
|
|||||||
|
|
||||||
request.app.state.config.ENABLE_USER_WEBHOOKS = form_data.ENABLE_USER_WEBHOOKS
|
request.app.state.config.ENABLE_USER_WEBHOOKS = form_data.ENABLE_USER_WEBHOOKS
|
||||||
|
|
||||||
|
request.app.state.config.PENDING_USER_OVERLAY_TITLE = (
|
||||||
|
form_data.PENDING_USER_OVERLAY_TITLE
|
||||||
|
)
|
||||||
|
request.app.state.config.PENDING_USER_OVERLAY_CONTENT = (
|
||||||
|
form_data.PENDING_USER_OVERLAY_CONTENT
|
||||||
|
)
|
||||||
|
|
||||||
|
request.app.state.config.RESPONSE_WATERMARK = form_data.RESPONSE_WATERMARK
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"SHOW_ADMIN_DETAILS": request.app.state.config.SHOW_ADMIN_DETAILS,
|
"SHOW_ADMIN_DETAILS": request.app.state.config.SHOW_ADMIN_DETAILS,
|
||||||
"WEBUI_URL": request.app.state.config.WEBUI_URL,
|
"WEBUI_URL": request.app.state.config.WEBUI_URL,
|
||||||
@ -764,6 +793,9 @@ async def update_admin_config(
|
|||||||
"ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS,
|
"ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS,
|
||||||
"ENABLE_NOTES": request.app.state.config.ENABLE_NOTES,
|
"ENABLE_NOTES": request.app.state.config.ENABLE_NOTES,
|
||||||
"ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS,
|
"ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS,
|
||||||
|
"PENDING_USER_OVERLAY_TITLE": request.app.state.config.PENDING_USER_OVERLAY_TITLE,
|
||||||
|
"PENDING_USER_OVERLAY_CONTENT": request.app.state.config.PENDING_USER_OVERLAY_CONTENT,
|
||||||
|
"RESPONSE_WATERMARK": request.app.state.config.RESPONSE_WATERMARK,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -779,6 +811,7 @@ class LdapServerConfig(BaseModel):
|
|||||||
search_filters: str = ""
|
search_filters: str = ""
|
||||||
use_tls: bool = True
|
use_tls: bool = True
|
||||||
certificate_path: Optional[str] = None
|
certificate_path: Optional[str] = None
|
||||||
|
validate_cert: bool = True
|
||||||
ciphers: Optional[str] = "ALL"
|
ciphers: Optional[str] = "ALL"
|
||||||
|
|
||||||
|
|
||||||
@ -796,6 +829,7 @@ async def get_ldap_server(request: Request, user=Depends(get_admin_user)):
|
|||||||
"search_filters": request.app.state.config.LDAP_SEARCH_FILTERS,
|
"search_filters": request.app.state.config.LDAP_SEARCH_FILTERS,
|
||||||
"use_tls": request.app.state.config.LDAP_USE_TLS,
|
"use_tls": request.app.state.config.LDAP_USE_TLS,
|
||||||
"certificate_path": request.app.state.config.LDAP_CA_CERT_FILE,
|
"certificate_path": request.app.state.config.LDAP_CA_CERT_FILE,
|
||||||
|
"validate_cert": request.app.state.config.LDAP_VALIDATE_CERT,
|
||||||
"ciphers": request.app.state.config.LDAP_CIPHERS,
|
"ciphers": request.app.state.config.LDAP_CIPHERS,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -831,6 +865,7 @@ async def update_ldap_server(
|
|||||||
request.app.state.config.LDAP_SEARCH_FILTERS = form_data.search_filters
|
request.app.state.config.LDAP_SEARCH_FILTERS = form_data.search_filters
|
||||||
request.app.state.config.LDAP_USE_TLS = form_data.use_tls
|
request.app.state.config.LDAP_USE_TLS = form_data.use_tls
|
||||||
request.app.state.config.LDAP_CA_CERT_FILE = form_data.certificate_path
|
request.app.state.config.LDAP_CA_CERT_FILE = form_data.certificate_path
|
||||||
|
request.app.state.config.LDAP_VALIDATE_CERT = form_data.validate_cert
|
||||||
request.app.state.config.LDAP_CIPHERS = form_data.ciphers
|
request.app.state.config.LDAP_CIPHERS = form_data.ciphers
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -845,6 +880,7 @@ async def update_ldap_server(
|
|||||||
"search_filters": request.app.state.config.LDAP_SEARCH_FILTERS,
|
"search_filters": request.app.state.config.LDAP_SEARCH_FILTERS,
|
||||||
"use_tls": request.app.state.config.LDAP_USE_TLS,
|
"use_tls": request.app.state.config.LDAP_USE_TLS,
|
||||||
"certificate_path": request.app.state.config.LDAP_CA_CERT_FILE,
|
"certificate_path": request.app.state.config.LDAP_CA_CERT_FILE,
|
||||||
|
"validate_cert": request.app.state.config.LDAP_VALIDATE_CERT,
|
||||||
"ciphers": request.app.state.config.LDAP_CIPHERS,
|
"ciphers": request.app.state.config.LDAP_CIPHERS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,13 +74,17 @@ class FeedbackUserResponse(FeedbackResponse):
|
|||||||
@router.get("/feedbacks/all", response_model=list[FeedbackUserResponse])
|
@router.get("/feedbacks/all", response_model=list[FeedbackUserResponse])
|
||||||
async def get_all_feedbacks(user=Depends(get_admin_user)):
|
async def get_all_feedbacks(user=Depends(get_admin_user)):
|
||||||
feedbacks = Feedbacks.get_all_feedbacks()
|
feedbacks = Feedbacks.get_all_feedbacks()
|
||||||
return [
|
|
||||||
|
feedback_list = []
|
||||||
|
for feedback in feedbacks:
|
||||||
|
user = Users.get_user_by_id(feedback.user_id)
|
||||||
|
feedback_list.append(
|
||||||
FeedbackUserResponse(
|
FeedbackUserResponse(
|
||||||
**feedback.model_dump(),
|
**feedback.model_dump(),
|
||||||
user=UserResponse(**Users.get_user_by_id(feedback.user_id).model_dump()),
|
user=UserResponse(**user.model_dump()) if user else None,
|
||||||
)
|
)
|
||||||
for feedback in feedbacks
|
)
|
||||||
]
|
return feedback_list
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/feedbacks/all")
|
@router.delete("/feedbacks/all")
|
||||||
@ -92,12 +96,7 @@ async def delete_all_feedbacks(user=Depends(get_admin_user)):
|
|||||||
@router.get("/feedbacks/all/export", response_model=list[FeedbackModel])
|
@router.get("/feedbacks/all/export", response_model=list[FeedbackModel])
|
||||||
async def get_all_feedbacks(user=Depends(get_admin_user)):
|
async def get_all_feedbacks(user=Depends(get_admin_user)):
|
||||||
feedbacks = Feedbacks.get_all_feedbacks()
|
feedbacks = Feedbacks.get_all_feedbacks()
|
||||||
return [
|
return feedbacks
|
||||||
FeedbackModel(
|
|
||||||
**feedback.model_dump(), user=Users.get_user_by_id(feedback.user_id)
|
|
||||||
)
|
|
||||||
for feedback in feedbacks
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/feedbacks/user", response_model=list[FeedbackUserResponse])
|
@router.get("/feedbacks/user", response_model=list[FeedbackUserResponse])
|
||||||
|
@ -95,6 +95,20 @@ def upload_file(
|
|||||||
unsanitized_filename = file.filename
|
unsanitized_filename = file.filename
|
||||||
filename = os.path.basename(unsanitized_filename)
|
filename = os.path.basename(unsanitized_filename)
|
||||||
|
|
||||||
|
file_extension = os.path.splitext(filename)[1]
|
||||||
|
if request.app.state.config.ALLOWED_FILE_EXTENSIONS:
|
||||||
|
request.app.state.config.ALLOWED_FILE_EXTENSIONS = [
|
||||||
|
ext for ext in request.app.state.config.ALLOWED_FILE_EXTENSIONS if ext
|
||||||
|
]
|
||||||
|
|
||||||
|
if file_extension not in request.app.state.config.ALLOWED_FILE_EXTENSIONS:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail=ERROR_MESSAGES.DEFAULT(
|
||||||
|
f"File type {file_extension} is not allowed"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
# replace filename with uuid
|
# replace filename with uuid
|
||||||
id = str(uuid.uuid4())
|
id = str(uuid.uuid4())
|
||||||
name = filename
|
name = filename
|
||||||
@ -125,7 +139,7 @@ def upload_file(
|
|||||||
)
|
)
|
||||||
if process:
|
if process:
|
||||||
try:
|
try:
|
||||||
|
if file.content_type:
|
||||||
if file.content_type.startswith(
|
if file.content_type.startswith(
|
||||||
(
|
(
|
||||||
"audio/mpeg",
|
"audio/mpeg",
|
||||||
@ -153,6 +167,11 @@ def upload_file(
|
|||||||
"video/quicktime",
|
"video/quicktime",
|
||||||
]:
|
]:
|
||||||
process_file(request, ProcessFileForm(file_id=id), user=user)
|
process_file(request, ProcessFileForm(file_id=id), user=user)
|
||||||
|
else:
|
||||||
|
log.info(
|
||||||
|
f"File type {file.content_type} is not provided, but trying to process anyway"
|
||||||
|
)
|
||||||
|
process_file(request, ProcessFileForm(file_id=id), user=user)
|
||||||
|
|
||||||
file_item = Files.get_file_by_id(id=id)
|
file_item = Files.get_file_by_id(id=id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -10,7 +10,7 @@ from open_webui.models.knowledge import (
|
|||||||
KnowledgeUserResponse,
|
KnowledgeUserResponse,
|
||||||
)
|
)
|
||||||
from open_webui.models.files import Files, FileModel, FileMetadataResponse
|
from open_webui.models.files import Files, FileModel, FileMetadataResponse
|
||||||
from open_webui.retrieval.vector.connector import VECTOR_DB_CLIENT
|
from open_webui.retrieval.vector.factory import VECTOR_DB_CLIENT
|
||||||
from open_webui.routers.retrieval import (
|
from open_webui.routers.retrieval import (
|
||||||
process_file,
|
process_file,
|
||||||
ProcessFileForm,
|
ProcessFileForm,
|
||||||
|
@ -4,7 +4,7 @@ import logging
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from open_webui.models.memories import Memories, MemoryModel
|
from open_webui.models.memories import Memories, MemoryModel
|
||||||
from open_webui.retrieval.vector.connector import VECTOR_DB_CLIENT
|
from open_webui.retrieval.vector.factory import VECTOR_DB_CLIENT
|
||||||
from open_webui.utils.auth import get_verified_user
|
from open_webui.utils.auth import get_verified_user
|
||||||
from open_webui.env import SRC_LOG_LEVELS
|
from open_webui.env import SRC_LOG_LEVELS
|
||||||
|
|
||||||
|
@ -340,6 +340,8 @@ async def get_all_models(request: Request, user: UserModel = None):
|
|||||||
), # Legacy support
|
), # Legacy support
|
||||||
)
|
)
|
||||||
|
|
||||||
|
connection_type = api_config.get("connection_type", "local")
|
||||||
|
|
||||||
prefix_id = api_config.get("prefix_id", None)
|
prefix_id = api_config.get("prefix_id", None)
|
||||||
tags = api_config.get("tags", [])
|
tags = api_config.get("tags", [])
|
||||||
model_ids = api_config.get("model_ids", [])
|
model_ids = api_config.get("model_ids", [])
|
||||||
@ -352,14 +354,16 @@ async def get_all_models(request: Request, user: UserModel = None):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if prefix_id:
|
|
||||||
for model in response.get("models", []):
|
for model in response.get("models", []):
|
||||||
|
if prefix_id:
|
||||||
model["model"] = f"{prefix_id}.{model['model']}"
|
model["model"] = f"{prefix_id}.{model['model']}"
|
||||||
|
|
||||||
if tags:
|
if tags:
|
||||||
for model in response.get("models", []):
|
|
||||||
model["tags"] = tags
|
model["tags"] = tags
|
||||||
|
|
||||||
|
if connection_type:
|
||||||
|
model["connection_type"] = connection_type
|
||||||
|
|
||||||
def merge_models_lists(model_lists):
|
def merge_models_lists(model_lists):
|
||||||
merged_models = {}
|
merged_models = {}
|
||||||
|
|
||||||
@ -1585,7 +1589,9 @@ async def upload_model(
|
|||||||
if url_idx is None:
|
if url_idx is None:
|
||||||
url_idx = 0
|
url_idx = 0
|
||||||
ollama_url = request.app.state.config.OLLAMA_BASE_URLS[url_idx]
|
ollama_url = request.app.state.config.OLLAMA_BASE_URLS[url_idx]
|
||||||
file_path = os.path.join(UPLOAD_DIR, file.filename)
|
|
||||||
|
filename = os.path.basename(file.filename)
|
||||||
|
file_path = os.path.join(UPLOAD_DIR, filename)
|
||||||
os.makedirs(UPLOAD_DIR, exist_ok=True)
|
os.makedirs(UPLOAD_DIR, exist_ok=True)
|
||||||
|
|
||||||
# --- P1: save file locally ---
|
# --- P1: save file locally ---
|
||||||
@ -1630,13 +1636,13 @@ async def upload_model(
|
|||||||
os.remove(file_path)
|
os.remove(file_path)
|
||||||
|
|
||||||
# Create model in ollama
|
# Create model in ollama
|
||||||
model_name, ext = os.path.splitext(file.filename)
|
model_name, ext = os.path.splitext(filename)
|
||||||
log.info(f"Created Model: {model_name}") # DEBUG
|
log.info(f"Created Model: {model_name}") # DEBUG
|
||||||
|
|
||||||
create_payload = {
|
create_payload = {
|
||||||
"model": model_name,
|
"model": model_name,
|
||||||
# Reference the file by its original name => the uploaded blob's digest
|
# Reference the file by its original name => the uploaded blob's digest
|
||||||
"files": {file.filename: f"sha256:{file_hash}"},
|
"files": {filename: f"sha256:{file_hash}"},
|
||||||
}
|
}
|
||||||
log.info(f"Model Payload: {create_payload}") # DEBUG
|
log.info(f"Model Payload: {create_payload}") # DEBUG
|
||||||
|
|
||||||
@ -1653,7 +1659,7 @@ async def upload_model(
|
|||||||
done_msg = {
|
done_msg = {
|
||||||
"done": True,
|
"done": True,
|
||||||
"blob": f"sha256:{file_hash}",
|
"blob": f"sha256:{file_hash}",
|
||||||
"name": file.filename,
|
"name": filename,
|
||||||
"model_created": model_name,
|
"model_created": model_name,
|
||||||
}
|
}
|
||||||
yield f"data: {json.dumps(done_msg)}\n\n"
|
yield f"data: {json.dumps(done_msg)}\n\n"
|
||||||
|
@ -353,21 +353,22 @@ async def get_all_models_responses(request: Request, user: UserModel) -> list:
|
|||||||
), # Legacy support
|
), # Legacy support
|
||||||
)
|
)
|
||||||
|
|
||||||
|
connection_type = api_config.get("connection_type", "external")
|
||||||
prefix_id = api_config.get("prefix_id", None)
|
prefix_id = api_config.get("prefix_id", None)
|
||||||
tags = api_config.get("tags", [])
|
tags = api_config.get("tags", [])
|
||||||
|
|
||||||
if prefix_id:
|
|
||||||
for model in (
|
for model in (
|
||||||
response if isinstance(response, list) else response.get("data", [])
|
response if isinstance(response, list) else response.get("data", [])
|
||||||
):
|
):
|
||||||
|
if prefix_id:
|
||||||
model["id"] = f"{prefix_id}.{model['id']}"
|
model["id"] = f"{prefix_id}.{model['id']}"
|
||||||
|
|
||||||
if tags:
|
if tags:
|
||||||
for model in (
|
|
||||||
response if isinstance(response, list) else response.get("data", [])
|
|
||||||
):
|
|
||||||
model["tags"] = tags
|
model["tags"] = tags
|
||||||
|
|
||||||
|
if connection_type:
|
||||||
|
model["connection_type"] = connection_type
|
||||||
|
|
||||||
log.debug(f"get_all_models:responses() {responses}")
|
log.debug(f"get_all_models:responses() {responses}")
|
||||||
return responses
|
return responses
|
||||||
|
|
||||||
@ -415,6 +416,7 @@ async def get_all_models(request: Request, user: UserModel) -> dict[str, list]:
|
|||||||
"name": model.get("name", model["id"]),
|
"name": model.get("name", model["id"]),
|
||||||
"owned_by": "openai",
|
"owned_by": "openai",
|
||||||
"openai": model,
|
"openai": model,
|
||||||
|
"connection_type": model.get("connection_type", "external"),
|
||||||
"urlIdx": idx,
|
"urlIdx": idx,
|
||||||
}
|
}
|
||||||
for model in models
|
for model in models
|
||||||
|
@ -18,7 +18,7 @@ from pydantic import BaseModel
|
|||||||
from starlette.responses import FileResponse
|
from starlette.responses import FileResponse
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from open_webui.env import SRC_LOG_LEVELS
|
from open_webui.env import SRC_LOG_LEVELS, AIOHTTP_CLIENT_SESSION_SSL
|
||||||
from open_webui.config import CACHE_DIR
|
from open_webui.config import CACHE_DIR
|
||||||
from open_webui.constants import ERROR_MESSAGES
|
from open_webui.constants import ERROR_MESSAGES
|
||||||
|
|
||||||
@ -69,7 +69,10 @@ async def process_pipeline_inlet_filter(request, payload, user, models):
|
|||||||
async with aiohttp.ClientSession(trust_env=True) as session:
|
async with aiohttp.ClientSession(trust_env=True) as session:
|
||||||
for filter in sorted_filters:
|
for filter in sorted_filters:
|
||||||
urlIdx = filter.get("urlIdx")
|
urlIdx = filter.get("urlIdx")
|
||||||
if urlIdx is None:
|
|
||||||
|
try:
|
||||||
|
urlIdx = int(urlIdx)
|
||||||
|
except:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
url = request.app.state.config.OPENAI_API_BASE_URLS[urlIdx]
|
url = request.app.state.config.OPENAI_API_BASE_URLS[urlIdx]
|
||||||
@ -89,6 +92,7 @@ async def process_pipeline_inlet_filter(request, payload, user, models):
|
|||||||
f"{url}/{filter['id']}/filter/inlet",
|
f"{url}/{filter['id']}/filter/inlet",
|
||||||
headers=headers,
|
headers=headers,
|
||||||
json=request_data,
|
json=request_data,
|
||||||
|
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
) as response:
|
) as response:
|
||||||
payload = await response.json()
|
payload = await response.json()
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
@ -118,7 +122,10 @@ async def process_pipeline_outlet_filter(request, payload, user, models):
|
|||||||
async with aiohttp.ClientSession(trust_env=True) as session:
|
async with aiohttp.ClientSession(trust_env=True) as session:
|
||||||
for filter in sorted_filters:
|
for filter in sorted_filters:
|
||||||
urlIdx = filter.get("urlIdx")
|
urlIdx = filter.get("urlIdx")
|
||||||
if urlIdx is None:
|
|
||||||
|
try:
|
||||||
|
urlIdx = int(urlIdx)
|
||||||
|
except:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
url = request.app.state.config.OPENAI_API_BASE_URLS[urlIdx]
|
url = request.app.state.config.OPENAI_API_BASE_URLS[urlIdx]
|
||||||
@ -138,6 +145,7 @@ async def process_pipeline_outlet_filter(request, payload, user, models):
|
|||||||
f"{url}/{filter['id']}/filter/outlet",
|
f"{url}/{filter['id']}/filter/outlet",
|
||||||
headers=headers,
|
headers=headers,
|
||||||
json=request_data,
|
json=request_data,
|
||||||
|
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
) as response:
|
) as response:
|
||||||
payload = await response.json()
|
payload = await response.json()
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
@ -197,8 +205,10 @@ async def upload_pipeline(
|
|||||||
user=Depends(get_admin_user),
|
user=Depends(get_admin_user),
|
||||||
):
|
):
|
||||||
log.info(f"upload_pipeline: urlIdx={urlIdx}, filename={file.filename}")
|
log.info(f"upload_pipeline: urlIdx={urlIdx}, filename={file.filename}")
|
||||||
|
filename = os.path.basename(file.filename)
|
||||||
|
|
||||||
# Check if the uploaded file is a python file
|
# Check if the uploaded file is a python file
|
||||||
if not (file.filename and file.filename.endswith(".py")):
|
if not (filename and filename.endswith(".py")):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
detail="Only Python (.py) files are allowed.",
|
detail="Only Python (.py) files are allowed.",
|
||||||
@ -206,7 +216,7 @@ async def upload_pipeline(
|
|||||||
|
|
||||||
upload_folder = f"{CACHE_DIR}/pipelines"
|
upload_folder = f"{CACHE_DIR}/pipelines"
|
||||||
os.makedirs(upload_folder, exist_ok=True)
|
os.makedirs(upload_folder, exist_ok=True)
|
||||||
file_path = os.path.join(upload_folder, file.filename)
|
file_path = os.path.join(upload_folder, filename)
|
||||||
|
|
||||||
r = None
|
r = None
|
||||||
try:
|
try:
|
||||||
|
@ -36,7 +36,7 @@ from open_webui.models.knowledge import Knowledges
|
|||||||
from open_webui.storage.provider import Storage
|
from open_webui.storage.provider import Storage
|
||||||
|
|
||||||
|
|
||||||
from open_webui.retrieval.vector.connector import VECTOR_DB_CLIENT
|
from open_webui.retrieval.vector.factory import VECTOR_DB_CLIENT
|
||||||
|
|
||||||
# Document loaders
|
# Document loaders
|
||||||
from open_webui.retrieval.loaders.main import Loader
|
from open_webui.retrieval.loaders.main import Loader
|
||||||
@ -352,10 +352,13 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)):
|
|||||||
# Content extraction settings
|
# Content extraction settings
|
||||||
"CONTENT_EXTRACTION_ENGINE": request.app.state.config.CONTENT_EXTRACTION_ENGINE,
|
"CONTENT_EXTRACTION_ENGINE": request.app.state.config.CONTENT_EXTRACTION_ENGINE,
|
||||||
"PDF_EXTRACT_IMAGES": request.app.state.config.PDF_EXTRACT_IMAGES,
|
"PDF_EXTRACT_IMAGES": request.app.state.config.PDF_EXTRACT_IMAGES,
|
||||||
|
"EXTERNAL_DOCUMENT_LOADER_URL": request.app.state.config.EXTERNAL_DOCUMENT_LOADER_URL,
|
||||||
|
"EXTERNAL_DOCUMENT_LOADER_API_KEY": request.app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY,
|
||||||
"TIKA_SERVER_URL": request.app.state.config.TIKA_SERVER_URL,
|
"TIKA_SERVER_URL": request.app.state.config.TIKA_SERVER_URL,
|
||||||
"DOCLING_SERVER_URL": request.app.state.config.DOCLING_SERVER_URL,
|
"DOCLING_SERVER_URL": request.app.state.config.DOCLING_SERVER_URL,
|
||||||
"DOCLING_OCR_ENGINE": request.app.state.config.DOCLING_OCR_ENGINE,
|
"DOCLING_OCR_ENGINE": request.app.state.config.DOCLING_OCR_ENGINE,
|
||||||
"DOCLING_OCR_LANG": request.app.state.config.DOCLING_OCR_LANG,
|
"DOCLING_OCR_LANG": request.app.state.config.DOCLING_OCR_LANG,
|
||||||
|
"DOCLING_DO_PICTURE_DESCRIPTION": request.app.state.config.DOCLING_DO_PICTURE_DESCRIPTION,
|
||||||
"DOCUMENT_INTELLIGENCE_ENDPOINT": request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT,
|
"DOCUMENT_INTELLIGENCE_ENDPOINT": request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT,
|
||||||
"DOCUMENT_INTELLIGENCE_KEY": request.app.state.config.DOCUMENT_INTELLIGENCE_KEY,
|
"DOCUMENT_INTELLIGENCE_KEY": request.app.state.config.DOCUMENT_INTELLIGENCE_KEY,
|
||||||
"MISTRAL_OCR_API_KEY": request.app.state.config.MISTRAL_OCR_API_KEY,
|
"MISTRAL_OCR_API_KEY": request.app.state.config.MISTRAL_OCR_API_KEY,
|
||||||
@ -371,6 +374,7 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)):
|
|||||||
# File upload settings
|
# File upload settings
|
||||||
"FILE_MAX_SIZE": request.app.state.config.FILE_MAX_SIZE,
|
"FILE_MAX_SIZE": request.app.state.config.FILE_MAX_SIZE,
|
||||||
"FILE_MAX_COUNT": request.app.state.config.FILE_MAX_COUNT,
|
"FILE_MAX_COUNT": request.app.state.config.FILE_MAX_COUNT,
|
||||||
|
"ALLOWED_FILE_EXTENSIONS": request.app.state.config.ALLOWED_FILE_EXTENSIONS,
|
||||||
# Integration settings
|
# Integration settings
|
||||||
"ENABLE_GOOGLE_DRIVE_INTEGRATION": request.app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION,
|
"ENABLE_GOOGLE_DRIVE_INTEGRATION": request.app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION,
|
||||||
"ENABLE_ONEDRIVE_INTEGRATION": request.app.state.config.ENABLE_ONEDRIVE_INTEGRATION,
|
"ENABLE_ONEDRIVE_INTEGRATION": request.app.state.config.ENABLE_ONEDRIVE_INTEGRATION,
|
||||||
@ -492,10 +496,14 @@ class ConfigForm(BaseModel):
|
|||||||
# Content extraction settings
|
# Content extraction settings
|
||||||
CONTENT_EXTRACTION_ENGINE: Optional[str] = None
|
CONTENT_EXTRACTION_ENGINE: Optional[str] = None
|
||||||
PDF_EXTRACT_IMAGES: Optional[bool] = None
|
PDF_EXTRACT_IMAGES: Optional[bool] = None
|
||||||
|
EXTERNAL_DOCUMENT_LOADER_URL: Optional[str] = None
|
||||||
|
EXTERNAL_DOCUMENT_LOADER_API_KEY: Optional[str] = None
|
||||||
|
|
||||||
TIKA_SERVER_URL: Optional[str] = None
|
TIKA_SERVER_URL: Optional[str] = None
|
||||||
DOCLING_SERVER_URL: Optional[str] = None
|
DOCLING_SERVER_URL: Optional[str] = None
|
||||||
DOCLING_OCR_ENGINE: Optional[str] = None
|
DOCLING_OCR_ENGINE: Optional[str] = None
|
||||||
DOCLING_OCR_LANG: Optional[str] = None
|
DOCLING_OCR_LANG: Optional[str] = None
|
||||||
|
DOCLING_DO_PICTURE_DESCRIPTION: Optional[bool] = None
|
||||||
DOCUMENT_INTELLIGENCE_ENDPOINT: Optional[str] = None
|
DOCUMENT_INTELLIGENCE_ENDPOINT: Optional[str] = None
|
||||||
DOCUMENT_INTELLIGENCE_KEY: Optional[str] = None
|
DOCUMENT_INTELLIGENCE_KEY: Optional[str] = None
|
||||||
MISTRAL_OCR_API_KEY: Optional[str] = None
|
MISTRAL_OCR_API_KEY: Optional[str] = None
|
||||||
@ -514,6 +522,7 @@ class ConfigForm(BaseModel):
|
|||||||
# File upload settings
|
# File upload settings
|
||||||
FILE_MAX_SIZE: Optional[int] = None
|
FILE_MAX_SIZE: Optional[int] = None
|
||||||
FILE_MAX_COUNT: Optional[int] = None
|
FILE_MAX_COUNT: Optional[int] = None
|
||||||
|
ALLOWED_FILE_EXTENSIONS: Optional[List[str]] = None
|
||||||
|
|
||||||
# Integration settings
|
# Integration settings
|
||||||
ENABLE_GOOGLE_DRIVE_INTEGRATION: Optional[bool] = None
|
ENABLE_GOOGLE_DRIVE_INTEGRATION: Optional[bool] = None
|
||||||
@ -581,6 +590,16 @@ async def update_rag_config(
|
|||||||
if form_data.PDF_EXTRACT_IMAGES is not None
|
if form_data.PDF_EXTRACT_IMAGES is not None
|
||||||
else request.app.state.config.PDF_EXTRACT_IMAGES
|
else request.app.state.config.PDF_EXTRACT_IMAGES
|
||||||
)
|
)
|
||||||
|
request.app.state.config.EXTERNAL_DOCUMENT_LOADER_URL = (
|
||||||
|
form_data.EXTERNAL_DOCUMENT_LOADER_URL
|
||||||
|
if form_data.EXTERNAL_DOCUMENT_LOADER_URL is not None
|
||||||
|
else request.app.state.config.EXTERNAL_DOCUMENT_LOADER_URL
|
||||||
|
)
|
||||||
|
request.app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY = (
|
||||||
|
form_data.EXTERNAL_DOCUMENT_LOADER_API_KEY
|
||||||
|
if form_data.EXTERNAL_DOCUMENT_LOADER_API_KEY is not None
|
||||||
|
else request.app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY
|
||||||
|
)
|
||||||
request.app.state.config.TIKA_SERVER_URL = (
|
request.app.state.config.TIKA_SERVER_URL = (
|
||||||
form_data.TIKA_SERVER_URL
|
form_data.TIKA_SERVER_URL
|
||||||
if form_data.TIKA_SERVER_URL is not None
|
if form_data.TIKA_SERVER_URL is not None
|
||||||
@ -601,6 +620,13 @@ async def update_rag_config(
|
|||||||
if form_data.DOCLING_OCR_LANG is not None
|
if form_data.DOCLING_OCR_LANG is not None
|
||||||
else request.app.state.config.DOCLING_OCR_LANG
|
else request.app.state.config.DOCLING_OCR_LANG
|
||||||
)
|
)
|
||||||
|
|
||||||
|
request.app.state.config.DOCLING_DO_PICTURE_DESCRIPTION = (
|
||||||
|
form_data.DOCLING_DO_PICTURE_DESCRIPTION
|
||||||
|
if form_data.DOCLING_DO_PICTURE_DESCRIPTION is not None
|
||||||
|
else request.app.state.config.DOCLING_DO_PICTURE_DESCRIPTION
|
||||||
|
)
|
||||||
|
|
||||||
request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT = (
|
request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT = (
|
||||||
form_data.DOCUMENT_INTELLIGENCE_ENDPOINT
|
form_data.DOCUMENT_INTELLIGENCE_ENDPOINT
|
||||||
if form_data.DOCUMENT_INTELLIGENCE_ENDPOINT is not None
|
if form_data.DOCUMENT_INTELLIGENCE_ENDPOINT is not None
|
||||||
@ -688,6 +714,11 @@ async def update_rag_config(
|
|||||||
if form_data.FILE_MAX_COUNT is not None
|
if form_data.FILE_MAX_COUNT is not None
|
||||||
else request.app.state.config.FILE_MAX_COUNT
|
else request.app.state.config.FILE_MAX_COUNT
|
||||||
)
|
)
|
||||||
|
request.app.state.config.ALLOWED_FILE_EXTENSIONS = (
|
||||||
|
form_data.ALLOWED_FILE_EXTENSIONS
|
||||||
|
if form_data.ALLOWED_FILE_EXTENSIONS is not None
|
||||||
|
else request.app.state.config.ALLOWED_FILE_EXTENSIONS
|
||||||
|
)
|
||||||
|
|
||||||
# Integration settings
|
# Integration settings
|
||||||
request.app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION = (
|
request.app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION = (
|
||||||
@ -809,10 +840,13 @@ async def update_rag_config(
|
|||||||
# Content extraction settings
|
# Content extraction settings
|
||||||
"CONTENT_EXTRACTION_ENGINE": request.app.state.config.CONTENT_EXTRACTION_ENGINE,
|
"CONTENT_EXTRACTION_ENGINE": request.app.state.config.CONTENT_EXTRACTION_ENGINE,
|
||||||
"PDF_EXTRACT_IMAGES": request.app.state.config.PDF_EXTRACT_IMAGES,
|
"PDF_EXTRACT_IMAGES": request.app.state.config.PDF_EXTRACT_IMAGES,
|
||||||
|
"EXTERNAL_DOCUMENT_LOADER_URL": request.app.state.config.EXTERNAL_DOCUMENT_LOADER_URL,
|
||||||
|
"EXTERNAL_DOCUMENT_LOADER_API_KEY": request.app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY,
|
||||||
"TIKA_SERVER_URL": request.app.state.config.TIKA_SERVER_URL,
|
"TIKA_SERVER_URL": request.app.state.config.TIKA_SERVER_URL,
|
||||||
"DOCLING_SERVER_URL": request.app.state.config.DOCLING_SERVER_URL,
|
"DOCLING_SERVER_URL": request.app.state.config.DOCLING_SERVER_URL,
|
||||||
"DOCLING_OCR_ENGINE": request.app.state.config.DOCLING_OCR_ENGINE,
|
"DOCLING_OCR_ENGINE": request.app.state.config.DOCLING_OCR_ENGINE,
|
||||||
"DOCLING_OCR_LANG": request.app.state.config.DOCLING_OCR_LANG,
|
"DOCLING_OCR_LANG": request.app.state.config.DOCLING_OCR_LANG,
|
||||||
|
"DOCLING_DO_PICTURE_DESCRIPTION": request.app.state.config.DOCLING_DO_PICTURE_DESCRIPTION,
|
||||||
"DOCUMENT_INTELLIGENCE_ENDPOINT": request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT,
|
"DOCUMENT_INTELLIGENCE_ENDPOINT": request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT,
|
||||||
"DOCUMENT_INTELLIGENCE_KEY": request.app.state.config.DOCUMENT_INTELLIGENCE_KEY,
|
"DOCUMENT_INTELLIGENCE_KEY": request.app.state.config.DOCUMENT_INTELLIGENCE_KEY,
|
||||||
"MISTRAL_OCR_API_KEY": request.app.state.config.MISTRAL_OCR_API_KEY,
|
"MISTRAL_OCR_API_KEY": request.app.state.config.MISTRAL_OCR_API_KEY,
|
||||||
@ -828,6 +862,7 @@ async def update_rag_config(
|
|||||||
# File upload settings
|
# File upload settings
|
||||||
"FILE_MAX_SIZE": request.app.state.config.FILE_MAX_SIZE,
|
"FILE_MAX_SIZE": request.app.state.config.FILE_MAX_SIZE,
|
||||||
"FILE_MAX_COUNT": request.app.state.config.FILE_MAX_COUNT,
|
"FILE_MAX_COUNT": request.app.state.config.FILE_MAX_COUNT,
|
||||||
|
"ALLOWED_FILE_EXTENSIONS": request.app.state.config.ALLOWED_FILE_EXTENSIONS,
|
||||||
# Integration settings
|
# Integration settings
|
||||||
"ENABLE_GOOGLE_DRIVE_INTEGRATION": request.app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION,
|
"ENABLE_GOOGLE_DRIVE_INTEGRATION": request.app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION,
|
||||||
"ENABLE_ONEDRIVE_INTEGRATION": request.app.state.config.ENABLE_ONEDRIVE_INTEGRATION,
|
"ENABLE_ONEDRIVE_INTEGRATION": request.app.state.config.ENABLE_ONEDRIVE_INTEGRATION,
|
||||||
@ -1129,10 +1164,13 @@ def process_file(
|
|||||||
file_path = Storage.get_file(file_path)
|
file_path = Storage.get_file(file_path)
|
||||||
loader = Loader(
|
loader = Loader(
|
||||||
engine=request.app.state.config.CONTENT_EXTRACTION_ENGINE,
|
engine=request.app.state.config.CONTENT_EXTRACTION_ENGINE,
|
||||||
|
EXTERNAL_DOCUMENT_LOADER_URL=request.app.state.config.EXTERNAL_DOCUMENT_LOADER_URL,
|
||||||
|
EXTERNAL_DOCUMENT_LOADER_API_KEY=request.app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY,
|
||||||
TIKA_SERVER_URL=request.app.state.config.TIKA_SERVER_URL,
|
TIKA_SERVER_URL=request.app.state.config.TIKA_SERVER_URL,
|
||||||
DOCLING_SERVER_URL=request.app.state.config.DOCLING_SERVER_URL,
|
DOCLING_SERVER_URL=request.app.state.config.DOCLING_SERVER_URL,
|
||||||
DOCLING_OCR_ENGINE=request.app.state.config.DOCLING_OCR_ENGINE,
|
DOCLING_OCR_ENGINE=request.app.state.config.DOCLING_OCR_ENGINE,
|
||||||
DOCLING_OCR_LANG=request.app.state.config.DOCLING_OCR_LANG,
|
DOCLING_OCR_LANG=request.app.state.config.DOCLING_OCR_LANG,
|
||||||
|
DOCLING_DO_PICTURE_DESCRIPTION=request.app.state.config.DOCLING_DO_PICTURE_DESCRIPTION,
|
||||||
PDF_EXTRACT_IMAGES=request.app.state.config.PDF_EXTRACT_IMAGES,
|
PDF_EXTRACT_IMAGES=request.app.state.config.PDF_EXTRACT_IMAGES,
|
||||||
DOCUMENT_INTELLIGENCE_ENDPOINT=request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT,
|
DOCUMENT_INTELLIGENCE_ENDPOINT=request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT,
|
||||||
DOCUMENT_INTELLIGENCE_KEY=request.app.state.config.DOCUMENT_INTELLIGENCE_KEY,
|
DOCUMENT_INTELLIGENCE_KEY=request.app.state.config.DOCUMENT_INTELLIGENCE_KEY,
|
||||||
|
@ -20,10 +20,7 @@ from open_webui.utils.auth import get_admin_user, get_verified_user
|
|||||||
from open_webui.constants import TASKS
|
from open_webui.constants import TASKS
|
||||||
|
|
||||||
from open_webui.routers.pipelines import process_pipeline_inlet_filter
|
from open_webui.routers.pipelines import process_pipeline_inlet_filter
|
||||||
from open_webui.utils.filter import (
|
|
||||||
get_sorted_filter_ids,
|
|
||||||
process_filter_functions,
|
|
||||||
)
|
|
||||||
from open_webui.utils.task import get_task_model_id
|
from open_webui.utils.task import get_task_model_id
|
||||||
|
|
||||||
from open_webui.config import (
|
from open_webui.config import (
|
||||||
|
@ -13,6 +13,8 @@ import pytz
|
|||||||
from pytz import UTC
|
from pytz import UTC
|
||||||
from typing import Optional, Union, List, Dict
|
from typing import Optional, Union, List, Dict
|
||||||
|
|
||||||
|
from opentelemetry import trace
|
||||||
|
|
||||||
from open_webui.models.users import Users
|
from open_webui.models.users import Users
|
||||||
|
|
||||||
from open_webui.constants import ERROR_MESSAGES
|
from open_webui.constants import ERROR_MESSAGES
|
||||||
@ -194,7 +196,17 @@ def get_current_user(
|
|||||||
status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.API_KEY_NOT_ALLOWED
|
status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.API_KEY_NOT_ALLOWED
|
||||||
)
|
)
|
||||||
|
|
||||||
return get_current_user_by_api_key(token)
|
user = get_current_user_by_api_key(token)
|
||||||
|
|
||||||
|
# Add user info to current span
|
||||||
|
current_span = trace.get_current_span()
|
||||||
|
if current_span:
|
||||||
|
current_span.set_attribute("client.user.id", user.id)
|
||||||
|
current_span.set_attribute("client.user.email", user.email)
|
||||||
|
current_span.set_attribute("client.user.role", user.role)
|
||||||
|
current_span.set_attribute("client.auth.type", "api_key")
|
||||||
|
|
||||||
|
return user
|
||||||
|
|
||||||
# auth by jwt token
|
# auth by jwt token
|
||||||
try:
|
try:
|
||||||
@ -213,6 +225,14 @@ def get_current_user(
|
|||||||
detail=ERROR_MESSAGES.INVALID_TOKEN,
|
detail=ERROR_MESSAGES.INVALID_TOKEN,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
# Add user info to current span
|
||||||
|
current_span = trace.get_current_span()
|
||||||
|
if current_span:
|
||||||
|
current_span.set_attribute("client.user.id", user.id)
|
||||||
|
current_span.set_attribute("client.user.email", user.email)
|
||||||
|
current_span.set_attribute("client.user.role", user.role)
|
||||||
|
current_span.set_attribute("client.auth.type", "jwt")
|
||||||
|
|
||||||
# Refresh the user's last active timestamp asynchronously
|
# Refresh the user's last active timestamp asynchronously
|
||||||
# to prevent blocking the request
|
# to prevent blocking the request
|
||||||
if background_tasks:
|
if background_tasks:
|
||||||
@ -234,6 +254,14 @@ def get_current_user_by_api_key(api_key: str):
|
|||||||
detail=ERROR_MESSAGES.INVALID_TOKEN,
|
detail=ERROR_MESSAGES.INVALID_TOKEN,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
# Add user info to current span
|
||||||
|
current_span = trace.get_current_span()
|
||||||
|
if current_span:
|
||||||
|
current_span.set_attribute("client.user.id", user.id)
|
||||||
|
current_span.set_attribute("client.user.email", user.email)
|
||||||
|
current_span.set_attribute("client.user.role", user.role)
|
||||||
|
current_span.set_attribute("client.auth.type", "api_key")
|
||||||
|
|
||||||
Users.update_user_last_active_by_id(user.id)
|
Users.update_user_last_active_by_id(user.id)
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
@ -309,6 +309,7 @@ async def chat_completed(request: Request, form_data: dict, user: Any):
|
|||||||
metadata = {
|
metadata = {
|
||||||
"chat_id": data["chat_id"],
|
"chat_id": data["chat_id"],
|
||||||
"message_id": data["id"],
|
"message_id": data["id"],
|
||||||
|
"filter_ids": data.get("filter_ids", []),
|
||||||
"session_id": data["session_id"],
|
"session_id": data["session_id"],
|
||||||
"user_id": user.id,
|
"user_id": user.id,
|
||||||
}
|
}
|
||||||
@ -330,7 +331,9 @@ async def chat_completed(request: Request, form_data: dict, user: Any):
|
|||||||
try:
|
try:
|
||||||
filter_functions = [
|
filter_functions = [
|
||||||
Functions.get_function_by_id(filter_id)
|
Functions.get_function_by_id(filter_id)
|
||||||
for filter_id in get_sorted_filter_ids(model)
|
for filter_id in get_sorted_filter_ids(
|
||||||
|
request, model, metadata.get("filter_ids", [])
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
result, _ = await process_filter_functions(
|
result, _ = await process_filter_functions(
|
||||||
|
@ -9,7 +9,20 @@ log = logging.getLogger(__name__)
|
|||||||
log.setLevel(SRC_LOG_LEVELS["MAIN"])
|
log.setLevel(SRC_LOG_LEVELS["MAIN"])
|
||||||
|
|
||||||
|
|
||||||
def get_sorted_filter_ids(model: dict):
|
def get_function_module(request, function_id):
|
||||||
|
"""
|
||||||
|
Get the function module by its ID.
|
||||||
|
"""
|
||||||
|
if function_id in request.app.state.FUNCTIONS:
|
||||||
|
function_module = request.app.state.FUNCTIONS[function_id]
|
||||||
|
else:
|
||||||
|
function_module, _, _ = load_function_module_by_id(function_id)
|
||||||
|
request.app.state.FUNCTIONS[function_id] = function_module
|
||||||
|
|
||||||
|
return function_module
|
||||||
|
|
||||||
|
|
||||||
|
def get_sorted_filter_ids(request, model: dict, enabled_filter_ids: list = None):
|
||||||
def get_priority(function_id):
|
def get_priority(function_id):
|
||||||
function = Functions.get_function_by_id(function_id)
|
function = Functions.get_function_by_id(function_id)
|
||||||
if function is not None:
|
if function is not None:
|
||||||
@ -21,14 +34,23 @@ def get_sorted_filter_ids(model: dict):
|
|||||||
if "info" in model and "meta" in model["info"]:
|
if "info" in model and "meta" in model["info"]:
|
||||||
filter_ids.extend(model["info"]["meta"].get("filterIds", []))
|
filter_ids.extend(model["info"]["meta"].get("filterIds", []))
|
||||||
filter_ids = list(set(filter_ids))
|
filter_ids = list(set(filter_ids))
|
||||||
|
active_filter_ids = [
|
||||||
enabled_filter_ids = [
|
|
||||||
function.id
|
function.id
|
||||||
for function in Functions.get_functions_by_type("filter", active_only=True)
|
for function in Functions.get_functions_by_type("filter", active_only=True)
|
||||||
]
|
]
|
||||||
|
|
||||||
filter_ids = [fid for fid in filter_ids if fid in enabled_filter_ids]
|
for filter_id in active_filter_ids:
|
||||||
|
function_module = get_function_module(request, filter_id)
|
||||||
|
|
||||||
|
if getattr(function_module, "toggle", None) and (
|
||||||
|
filter_id not in enabled_filter_ids
|
||||||
|
):
|
||||||
|
active_filter_ids.remove(filter_id)
|
||||||
|
continue
|
||||||
|
|
||||||
|
filter_ids = [fid for fid in filter_ids if fid in active_filter_ids]
|
||||||
filter_ids.sort(key=get_priority)
|
filter_ids.sort(key=get_priority)
|
||||||
|
|
||||||
return filter_ids
|
return filter_ids
|
||||||
|
|
||||||
|
|
||||||
@ -43,12 +65,7 @@ async def process_filter_functions(
|
|||||||
if not filter:
|
if not filter:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if filter_id in request.app.state.FUNCTIONS:
|
function_module = get_function_module(request, filter_id)
|
||||||
function_module = request.app.state.FUNCTIONS[filter_id]
|
|
||||||
else:
|
|
||||||
function_module, _, _ = load_function_module_by_id(filter_id)
|
|
||||||
request.app.state.FUNCTIONS[filter_id] = function_module
|
|
||||||
|
|
||||||
# Prepare handler function
|
# Prepare handler function
|
||||||
handler = getattr(function_module, filter_type, None)
|
handler = getattr(function_module, filter_type, None)
|
||||||
if not handler:
|
if not handler:
|
||||||
|
@ -340,6 +340,11 @@ async def chat_web_search_handler(
|
|||||||
log.exception(e)
|
log.exception(e)
|
||||||
queries = [user_message]
|
queries = [user_message]
|
||||||
|
|
||||||
|
# Check if generated queries are empty
|
||||||
|
if len(queries) == 1 and queries[0].strip() == "":
|
||||||
|
queries = [user_message]
|
||||||
|
|
||||||
|
# Check if queries are not found
|
||||||
if len(queries) == 0:
|
if len(queries) == 0:
|
||||||
await event_emitter(
|
await event_emitter(
|
||||||
{
|
{
|
||||||
@ -651,7 +656,7 @@ def apply_params_to_form_data(form_data, model):
|
|||||||
convert_logit_bias_input_to_json(params["logit_bias"])
|
convert_logit_bias_input_to_json(params["logit_bias"])
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error parsing logit_bias: {e}")
|
log.exception(f"Error parsing logit_bias: {e}")
|
||||||
|
|
||||||
return form_data
|
return form_data
|
||||||
|
|
||||||
@ -749,9 +754,12 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
filter_functions = [
|
filter_functions = [
|
||||||
Functions.get_function_by_id(filter_id)
|
Functions.get_function_by_id(filter_id)
|
||||||
for filter_id in get_sorted_filter_ids(model)
|
for filter_id in get_sorted_filter_ids(
|
||||||
|
request, model, metadata.get("filter_ids", [])
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
form_data, flags = await process_filter_functions(
|
form_data, flags = await process_filter_functions(
|
||||||
@ -942,21 +950,35 @@ async def process_chat_response(
|
|||||||
message = message_map.get(metadata["message_id"]) if message_map else None
|
message = message_map.get(metadata["message_id"]) if message_map else None
|
||||||
|
|
||||||
if message:
|
if message:
|
||||||
messages = get_message_list(message_map, message.get("id"))
|
message_list = get_message_list(message_map, message.get("id"))
|
||||||
|
|
||||||
# Remove reasoning details and files from the messages.
|
# Remove details tags and files from the messages.
|
||||||
# as get_message_list creates a new list, it does not affect
|
# as get_message_list creates a new list, it does not affect
|
||||||
# the original messages outside of this handler
|
# the original messages outside of this handler
|
||||||
for message in messages:
|
|
||||||
message["content"] = re.sub(
|
messages = []
|
||||||
r"<details\s+type=\"reasoning\"[^>]*>.*?<\/details>",
|
for message in message_list:
|
||||||
|
content = message.get("content", "")
|
||||||
|
if isinstance(content, list):
|
||||||
|
for item in content:
|
||||||
|
if item.get("type") == "text":
|
||||||
|
content = item["text"]
|
||||||
|
break
|
||||||
|
|
||||||
|
if isinstance(content, str):
|
||||||
|
content = re.sub(
|
||||||
|
r"<details\b[^>]*>.*?<\/details>",
|
||||||
"",
|
"",
|
||||||
message["content"],
|
content,
|
||||||
flags=re.S,
|
flags=re.S | re.I,
|
||||||
).strip()
|
).strip()
|
||||||
|
|
||||||
if message.get("files"):
|
messages.append(
|
||||||
message["files"] = []
|
{
|
||||||
|
"role": message["role"],
|
||||||
|
"content": content,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
if tasks and messages:
|
if tasks and messages:
|
||||||
if TASKS.TITLE_GENERATION in tasks:
|
if TASKS.TITLE_GENERATION in tasks:
|
||||||
@ -1169,7 +1191,9 @@ async def process_chat_response(
|
|||||||
}
|
}
|
||||||
filter_functions = [
|
filter_functions = [
|
||||||
Functions.get_function_by_id(filter_id)
|
Functions.get_function_by_id(filter_id)
|
||||||
for filter_id in get_sorted_filter_ids(model)
|
for filter_id in get_sorted_filter_ids(
|
||||||
|
request, model, metadata.get("filter_ids", [])
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
# Streaming response
|
# Streaming response
|
||||||
|
@ -49,6 +49,7 @@ async def get_all_base_models(request: Request, user: UserModel = None):
|
|||||||
"created": int(time.time()),
|
"created": int(time.time()),
|
||||||
"owned_by": "ollama",
|
"owned_by": "ollama",
|
||||||
"ollama": model,
|
"ollama": model,
|
||||||
|
"connection_type": model.get("connection_type", "local"),
|
||||||
"tags": model.get("tags", []),
|
"tags": model.get("tags", []),
|
||||||
}
|
}
|
||||||
for model in ollama_models["models"]
|
for model in ollama_models["models"]
|
||||||
@ -110,6 +111,14 @@ async def get_all_models(request, user: UserModel = None):
|
|||||||
for function in Functions.get_functions_by_type("action", active_only=True)
|
for function in Functions.get_functions_by_type("action", active_only=True)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
global_filter_ids = [
|
||||||
|
function.id for function in Functions.get_global_filter_functions()
|
||||||
|
]
|
||||||
|
enabled_filter_ids = [
|
||||||
|
function.id
|
||||||
|
for function in Functions.get_functions_by_type("filter", active_only=True)
|
||||||
|
]
|
||||||
|
|
||||||
custom_models = Models.get_all_models()
|
custom_models = Models.get_all_models()
|
||||||
for custom_model in custom_models:
|
for custom_model in custom_models:
|
||||||
if custom_model.base_model_id is None:
|
if custom_model.base_model_id is None:
|
||||||
@ -125,13 +134,20 @@ async def get_all_models(request, user: UserModel = None):
|
|||||||
model["name"] = custom_model.name
|
model["name"] = custom_model.name
|
||||||
model["info"] = custom_model.model_dump()
|
model["info"] = custom_model.model_dump()
|
||||||
|
|
||||||
|
# Set action_ids and filter_ids
|
||||||
action_ids = []
|
action_ids = []
|
||||||
|
filter_ids = []
|
||||||
|
|
||||||
if "info" in model and "meta" in model["info"]:
|
if "info" in model and "meta" in model["info"]:
|
||||||
action_ids.extend(
|
action_ids.extend(
|
||||||
model["info"]["meta"].get("actionIds", [])
|
model["info"]["meta"].get("actionIds", [])
|
||||||
)
|
)
|
||||||
|
filter_ids.extend(
|
||||||
|
model["info"]["meta"].get("filterIds", [])
|
||||||
|
)
|
||||||
|
|
||||||
model["action_ids"] = action_ids
|
model["action_ids"] = action_ids
|
||||||
|
model["filter_ids"] = filter_ids
|
||||||
else:
|
else:
|
||||||
models.remove(model)
|
models.remove(model)
|
||||||
|
|
||||||
@ -140,7 +156,9 @@ async def get_all_models(request, user: UserModel = None):
|
|||||||
):
|
):
|
||||||
owned_by = "openai"
|
owned_by = "openai"
|
||||||
pipe = None
|
pipe = None
|
||||||
|
|
||||||
action_ids = []
|
action_ids = []
|
||||||
|
filter_ids = []
|
||||||
|
|
||||||
for model in models:
|
for model in models:
|
||||||
if (
|
if (
|
||||||
@ -154,9 +172,13 @@ async def get_all_models(request, user: UserModel = None):
|
|||||||
|
|
||||||
if custom_model.meta:
|
if custom_model.meta:
|
||||||
meta = custom_model.meta.model_dump()
|
meta = custom_model.meta.model_dump()
|
||||||
|
|
||||||
if "actionIds" in meta:
|
if "actionIds" in meta:
|
||||||
action_ids.extend(meta["actionIds"])
|
action_ids.extend(meta["actionIds"])
|
||||||
|
|
||||||
|
if "filterIds" in meta:
|
||||||
|
filter_ids.extend(meta["filterIds"])
|
||||||
|
|
||||||
models.append(
|
models.append(
|
||||||
{
|
{
|
||||||
"id": f"{custom_model.id}",
|
"id": f"{custom_model.id}",
|
||||||
@ -168,6 +190,7 @@ async def get_all_models(request, user: UserModel = None):
|
|||||||
"preset": True,
|
"preset": True,
|
||||||
**({"pipe": pipe} if pipe is not None else {}),
|
**({"pipe": pipe} if pipe is not None else {}),
|
||||||
"action_ids": action_ids,
|
"action_ids": action_ids,
|
||||||
|
"filter_ids": filter_ids,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -181,8 +204,11 @@ async def get_all_models(request, user: UserModel = None):
|
|||||||
"id": f"{function.id}.{action['id']}",
|
"id": f"{function.id}.{action['id']}",
|
||||||
"name": action.get("name", f"{function.name} ({action['id']})"),
|
"name": action.get("name", f"{function.name} ({action['id']})"),
|
||||||
"description": function.meta.description,
|
"description": function.meta.description,
|
||||||
"icon_url": action.get(
|
"icon": action.get(
|
||||||
"icon_url", function.meta.manifest.get("icon_url", None)
|
"icon_url",
|
||||||
|
function.meta.manifest.get("icon_url", None)
|
||||||
|
or getattr(module, "icon_url", None)
|
||||||
|
or getattr(module, "icon", None),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
for action in actions
|
for action in actions
|
||||||
@ -193,7 +219,22 @@ async def get_all_models(request, user: UserModel = None):
|
|||||||
"id": function.id,
|
"id": function.id,
|
||||||
"name": function.name,
|
"name": function.name,
|
||||||
"description": function.meta.description,
|
"description": function.meta.description,
|
||||||
"icon_url": function.meta.manifest.get("icon_url", None),
|
"icon": function.meta.manifest.get("icon_url", None)
|
||||||
|
or getattr(module, "icon_url", None)
|
||||||
|
or getattr(module, "icon", None),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
# Process filter_ids to get the filters
|
||||||
|
def get_filter_items_from_module(function, module):
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id": function.id,
|
||||||
|
"name": function.name,
|
||||||
|
"description": function.meta.description,
|
||||||
|
"icon": function.meta.manifest.get("icon_url", None)
|
||||||
|
or getattr(module, "icon_url", None)
|
||||||
|
or getattr(module, "icon", None),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -211,6 +252,11 @@ async def get_all_models(request, user: UserModel = None):
|
|||||||
for action_id in list(set(model.pop("action_ids", []) + global_action_ids))
|
for action_id in list(set(model.pop("action_ids", []) + global_action_ids))
|
||||||
if action_id in enabled_action_ids
|
if action_id in enabled_action_ids
|
||||||
]
|
]
|
||||||
|
filter_ids = [
|
||||||
|
filter_id
|
||||||
|
for filter_id in list(set(model.pop("filter_ids", []) + global_filter_ids))
|
||||||
|
if filter_id in enabled_filter_ids
|
||||||
|
]
|
||||||
|
|
||||||
model["actions"] = []
|
model["actions"] = []
|
||||||
for action_id in action_ids:
|
for action_id in action_ids:
|
||||||
@ -222,6 +268,20 @@ async def get_all_models(request, user: UserModel = None):
|
|||||||
model["actions"].extend(
|
model["actions"].extend(
|
||||||
get_action_items_from_module(action_function, function_module)
|
get_action_items_from_module(action_function, function_module)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
model["filters"] = []
|
||||||
|
for filter_id in filter_ids:
|
||||||
|
filter_function = Functions.get_function_by_id(filter_id)
|
||||||
|
if filter_function is None:
|
||||||
|
raise Exception(f"Filter not found: {filter_id}")
|
||||||
|
|
||||||
|
function_module = get_function_module_by_id(filter_id)
|
||||||
|
|
||||||
|
if getattr(function_module, "toggle", None):
|
||||||
|
model["filters"].extend(
|
||||||
|
get_filter_items_from_module(filter_function, function_module)
|
||||||
|
)
|
||||||
|
|
||||||
log.debug(f"get_all_models() returned {len(models)} models")
|
log.debug(f"get_all_models() returned {len(models)} models")
|
||||||
|
|
||||||
request.app.state.MODELS = {model["id"]: model for model in models}
|
request.app.state.MODELS = {model["id"]: model for model in models}
|
||||||
|
@ -41,6 +41,7 @@ from open_webui.config import (
|
|||||||
)
|
)
|
||||||
from open_webui.constants import ERROR_MESSAGES, WEBHOOK_MESSAGES
|
from open_webui.constants import ERROR_MESSAGES, WEBHOOK_MESSAGES
|
||||||
from open_webui.env import (
|
from open_webui.env import (
|
||||||
|
AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
WEBUI_NAME,
|
WEBUI_NAME,
|
||||||
WEBUI_AUTH_COOKIE_SAME_SITE,
|
WEBUI_AUTH_COOKIE_SAME_SITE,
|
||||||
WEBUI_AUTH_COOKIE_SECURE,
|
WEBUI_AUTH_COOKIE_SECURE,
|
||||||
@ -305,8 +306,10 @@ class OAuthManager:
|
|||||||
get_kwargs["headers"] = {
|
get_kwargs["headers"] = {
|
||||||
"Authorization": f"Bearer {access_token}",
|
"Authorization": f"Bearer {access_token}",
|
||||||
}
|
}
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession(trust_env=True) as session:
|
||||||
async with session.get(picture_url, **get_kwargs) as resp:
|
async with session.get(
|
||||||
|
picture_url, **get_kwargs, ssl=AIOHTTP_CLIENT_SESSION_SSL
|
||||||
|
) as resp:
|
||||||
if resp.ok:
|
if resp.ok:
|
||||||
picture = await resp.read()
|
picture = await resp.read()
|
||||||
base64_encoded_picture = base64.b64encode(picture).decode(
|
base64_encoded_picture = base64.b64encode(picture).decode(
|
||||||
@ -371,7 +374,9 @@ class OAuthManager:
|
|||||||
headers = {"Authorization": f"Bearer {access_token}"}
|
headers = {"Authorization": f"Bearer {access_token}"}
|
||||||
async with aiohttp.ClientSession(trust_env=True) as session:
|
async with aiohttp.ClientSession(trust_env=True) as session:
|
||||||
async with session.get(
|
async with session.get(
|
||||||
"https://api.github.com/user/emails", headers=headers
|
"https://api.github.com/user/emails",
|
||||||
|
headers=headers,
|
||||||
|
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
) as resp:
|
) as resp:
|
||||||
if resp.ok:
|
if resp.ok:
|
||||||
emails = await resp.json()
|
emails = await resp.json()
|
||||||
|
@ -37,6 +37,7 @@ from open_webui.models.tools import Tools
|
|||||||
from open_webui.models.users import UserModel
|
from open_webui.models.users import UserModel
|
||||||
from open_webui.utils.plugin import load_tool_module_by_id
|
from open_webui.utils.plugin import load_tool_module_by_id
|
||||||
from open_webui.env import (
|
from open_webui.env import (
|
||||||
|
SRC_LOG_LEVELS,
|
||||||
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA,
|
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA,
|
||||||
AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL,
|
AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL,
|
||||||
)
|
)
|
||||||
@ -44,6 +45,7 @@ from open_webui.env import (
|
|||||||
import copy
|
import copy
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
log.setLevel(SRC_LOG_LEVELS["MODELS"])
|
||||||
|
|
||||||
|
|
||||||
def get_async_tool_function_and_apply_extra_params(
|
def get_async_tool_function_and_apply_extra_params(
|
||||||
@ -477,7 +479,7 @@ async def get_tool_server_data(token: str, url: str) -> Dict[str, Any]:
|
|||||||
"specs": convert_openapi_to_tool_payload(res),
|
"specs": convert_openapi_to_tool_payload(res),
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Fetched data:", data)
|
log.info("Fetched data:", data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
@ -510,7 +512,7 @@ async def get_tool_servers_data(
|
|||||||
results = []
|
results = []
|
||||||
for (idx, server, url, _), response in zip(server_entries, responses):
|
for (idx, server, url, _), response in zip(server_entries, responses):
|
||||||
if isinstance(response, Exception):
|
if isinstance(response, Exception):
|
||||||
print(f"Failed to connect to {url} OpenAPI tool server")
|
log.error(f"Failed to connect to {url} OpenAPI tool server")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
results.append(
|
results.append(
|
||||||
@ -620,5 +622,5 @@ async def execute_tool_server(
|
|||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
error = str(err)
|
error = str(err)
|
||||||
print("API Request Error:", error)
|
log.exception("API Request Error:", error)
|
||||||
return {"error": error}
|
return {"error": error}
|
||||||
|
@ -37,7 +37,8 @@ asgiref==3.8.1
|
|||||||
# AI libraries
|
# AI libraries
|
||||||
openai
|
openai
|
||||||
anthropic
|
anthropic
|
||||||
google-generativeai==0.8.4
|
google-genai==1.15.0
|
||||||
|
google-generativeai==0.8.5
|
||||||
tiktoken
|
tiktoken
|
||||||
|
|
||||||
langchain==0.3.24
|
langchain==0.3.24
|
||||||
@ -98,7 +99,7 @@ pytube==15.0.0
|
|||||||
|
|
||||||
extract_msg
|
extract_msg
|
||||||
pydub
|
pydub
|
||||||
duckduckgo-search~=8.0.0
|
duckduckgo-search==8.0.2
|
||||||
|
|
||||||
## Google Drive
|
## Google Drive
|
||||||
google-api-python-client
|
google-api-python-client
|
||||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "open-webui",
|
"name": "open-webui",
|
||||||
"version": "0.6.9",
|
"version": "0.6.10",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "open-webui",
|
"name": "open-webui",
|
||||||
"version": "0.6.9",
|
"version": "0.6.10",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/msal-browser": "^4.5.0",
|
"@azure/msal-browser": "^4.5.0",
|
||||||
"@codemirror/lang-javascript": "^6.2.2",
|
"@codemirror/lang-javascript": "^6.2.2",
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "open-webui",
|
"name": "open-webui",
|
||||||
"version": "0.6.9",
|
"version": "0.6.10",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "npm run pyodide:fetch && vite dev --host",
|
"dev": "npm run pyodide:fetch && vite dev --host",
|
||||||
"dev:5050": "npm run pyodide:fetch && vite dev --port 5050",
|
"dev:5050": "npm run pyodide:fetch && vite dev --port 5050",
|
||||||
"build": "npm run pyodide:fetch && vite build",
|
"build": "npm run pyodide:fetch && vite build",
|
||||||
|
"build:watch": "npm run pyodide:fetch && vite build --watch",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||||
|
@ -45,7 +45,8 @@ dependencies = [
|
|||||||
|
|
||||||
"openai",
|
"openai",
|
||||||
"anthropic",
|
"anthropic",
|
||||||
"google-generativeai==0.8.4",
|
"google-genai==1.15.0",
|
||||||
|
"google-generativeai==0.8.5",
|
||||||
"tiktoken",
|
"tiktoken",
|
||||||
|
|
||||||
"langchain==0.3.24",
|
"langchain==0.3.24",
|
||||||
@ -105,7 +106,7 @@ dependencies = [
|
|||||||
|
|
||||||
"extract_msg",
|
"extract_msg",
|
||||||
"pydub",
|
"pydub",
|
||||||
"duckduckgo-search~=8.0.0",
|
"duckduckgo-search==8.0.2",
|
||||||
|
|
||||||
"google-api-python-client",
|
"google-api-python-client",
|
||||||
"google-auth-httplib2",
|
"google-auth-httplib2",
|
||||||
|
10
src/app.css
10
src/app.css
@ -314,12 +314,20 @@ input[type='number'] {
|
|||||||
.ProseMirror p.is-editor-empty:first-child::before {
|
.ProseMirror p.is-editor-empty:first-child::before {
|
||||||
content: attr(data-placeholder);
|
content: attr(data-placeholder);
|
||||||
float: left;
|
float: left;
|
||||||
color: #adb5bd;
|
/* Below color is from tailwind, and has the proper contrast
|
||||||
|
text-gray-600 from: https://tailwindcss.com/docs/color */
|
||||||
|
color: #676767;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
@apply line-clamp-1 absolute;
|
@apply line-clamp-1 absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
.ProseMirror p.is-editor-empty:first-child::before {
|
||||||
|
color: #757575;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.ai-autocompletion::after {
|
.ai-autocompletion::after {
|
||||||
color: #a0a0a0;
|
color: #a0a0a0;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ export const getAudioConfig = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -52,7 +52,7 @@ export const updateAudioConfig = async (token: string, payload: OpenAIConfigForm
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -83,7 +83,7 @@ export const transcribeAudio = async (token: string, file: File) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ export const synthesizeOpenAISpeech = async (
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -152,7 +152,7 @@ export const getModels = async (token: string = ''): Promise<AvailableModelsResp
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -180,7 +180,7 @@ export const getVoices = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -15,7 +15,7 @@ export const getAdminDetails = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -42,7 +42,7 @@ export const getAdminConfig = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -70,7 +70,7 @@ export const updateAdminConfig = async (token: string, body: object) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -98,7 +98,7 @@ export const getSessionUser = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -129,7 +129,7 @@ export const ldapUserSignIn = async (user: string, password: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
|
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
@ -157,7 +157,7 @@ export const getLdapConfig = async (token: string = '') => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -187,7 +187,7 @@ export const updateLdapConfig = async (token: string = '', enable_ldap: boolean)
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -214,7 +214,7 @@ export const getLdapServer = async (token: string = '') => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -242,7 +242,7 @@ export const updateLdapServer = async (token: string = '', body: object) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -273,7 +273,7 @@ export const userSignIn = async (email: string, password: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
|
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
@ -312,7 +312,7 @@ export const userSignUp = async (
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -339,7 +339,7 @@ export const userSignOut = async () => {
|
|||||||
return res;
|
return res;
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -347,6 +347,7 @@ export const userSignOut = async () => {
|
|||||||
if (error) {
|
if (error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addUser = async (
|
export const addUser = async (
|
||||||
@ -378,7 +379,7 @@ export const addUser = async (
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -409,7 +410,7 @@ export const updateUserProfile = async (token: string, name: string, profileImag
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -440,7 +441,7 @@ export const updateUserPassword = async (token: string, password: string, newPas
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -467,7 +468,7 @@ export const getSignUpEnabledStatus = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -494,7 +495,7 @@ export const getDefaultUserRole = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -524,7 +525,7 @@ export const updateDefaultUserRole = async (token: string, role: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -551,7 +552,7 @@ export const toggleSignUpEnabledStatus = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -578,7 +579,7 @@ export const getJWTExpiresDuration = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -608,7 +609,7 @@ export const updateJWTExpiresDuration = async (token: string, duration: string)
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -635,7 +636,7 @@ export const createAPIKey = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -660,7 +661,7 @@ export const getAPIKey = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -685,7 +686,7 @@ export const deleteAPIKey = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -28,7 +28,7 @@ export const createNewChannel = async (token: string = '', channel: ChannelForm)
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ export const getChannels = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ export const getChannelById = async (token: string = '', channel_id: string) =>
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ export const updateChannelById = async (
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ export const deleteChannelById = async (token: string = '', channel_id: string)
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ export const getChannelMessages = async (
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -236,7 +236,7 @@ export const getChannelThreadMessages = async (
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -275,7 +275,7 @@ export const sendMessage = async (token: string = '', channel_id: string, messag
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -315,7 +315,7 @@ export const updateMessage = async (
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -355,7 +355,7 @@ export const addReaction = async (
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -395,7 +395,7 @@ export const removeReaction = async (
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -429,7 +429,7 @@ export const deleteMessage = async (token: string = '', channel_id: string, mess
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export const createNewChat = async (token: string, chat: object) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ export const importChat = async (
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ export const getChatList = async (token: string = '', page: number | null = null
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ export const getChatListByUserId = async (token: string = '', userId: string) =>
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ export const getArchivedChatList = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ export const getAllChats = async (token: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ export const getChatListBySearchText = async (token: string, text: string, page:
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -265,7 +265,7 @@ export const getChatsByFolderId = async (token: string, folderId: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -296,7 +296,7 @@ export const getAllArchivedChats = async (token: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -327,7 +327,7 @@ export const getAllUserChats = async (token: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -358,7 +358,7 @@ export const getAllTags = async (token: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -389,7 +389,7 @@ export const getPinnedChatList = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -426,7 +426,7 @@ export const getChatListByTagName = async (token: string = '', tagName: string)
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -461,7 +461,7 @@ export const getChatById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -493,7 +493,7 @@ export const getChatByShareId = async (token: string, share_id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -531,7 +531,7 @@ export const getChatPinnedStatusById = async (token: string, id: string) => {
|
|||||||
error = err;
|
error = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -569,7 +569,7 @@ export const toggleChatPinnedStatusById = async (token: string, id: string) => {
|
|||||||
error = err;
|
error = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -610,7 +610,7 @@ export const cloneChatById = async (token: string, id: string, title?: string) =
|
|||||||
error = err;
|
error = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -648,7 +648,7 @@ export const cloneSharedChatById = async (token: string, id: string) => {
|
|||||||
error = err;
|
error = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -680,7 +680,7 @@ export const shareChatById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -715,7 +715,7 @@ export const updateChatFolderIdById = async (token: string, id: string, folderId
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -747,7 +747,7 @@ export const archiveChatById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -779,7 +779,7 @@ export const deleteSharedChatById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -814,7 +814,7 @@ export const updateChatById = async (token: string, id: string, chat: object) =>
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -846,7 +846,7 @@ export const deleteChatById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -878,7 +878,7 @@ export const getTagsById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -912,7 +912,7 @@ export const addTagById = async (token: string, id: string, tagName: string) =>
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -947,7 +947,7 @@ export const deleteTagById = async (token: string, id: string, tagName: string)
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -978,7 +978,7 @@ export const deleteTagsById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1010,7 +1010,7 @@ export const deleteAllChats = async (token: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1042,7 +1042,7 @@ export const archiveAllChats = async (token: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ export const importConfig = async (token: string, config) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -46,7 +46,7 @@ export const exportConfig = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -73,7 +73,7 @@ export const getDirectConnectionsConfig = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -103,7 +103,7 @@ export const setDirectConnectionsConfig = async (token: string, config: object)
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -130,7 +130,7 @@ export const getToolServerConnections = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -160,7 +160,7 @@ export const setToolServerConnections = async (token: string, connections: objec
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -190,7 +190,7 @@ export const verifyToolServerConnection = async (token: string, connection: obje
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -217,7 +217,7 @@ export const getCodeExecutionConfig = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -247,7 +247,7 @@ export const setCodeExecutionConfig = async (token: string, config: object) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -274,7 +274,7 @@ export const getModelsConfig = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -304,7 +304,7 @@ export const setModelsConfig = async (token: string, config: object) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -334,7 +334,7 @@ export const setDefaultPromptSuggestions = async (token: string, promptSuggestio
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -361,7 +361,7 @@ export const getBanners = async (token: string): Promise<Banner[]> => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -391,7 +391,7 @@ export const setBanners = async (token: string, banners: Banner[]) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -20,7 +20,7 @@ export const getConfig = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ export const updateConfig = async (token: string, config: object) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ export const getAllFeedbacks = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ export const exportAllFeedbacks = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ export const createNewFeedback = async (token: string, feedback: object) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -175,7 +175,7 @@ export const getFeedbackById = async (token: string, feedbackId: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -206,7 +206,7 @@ export const updateFeedbackById = async (token: string, feedbackId: string, feed
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -234,7 +234,7 @@ export const deleteFeedbackById = async (token: string, feedbackId: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ export const uploadFile = async (token: string, file: File) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ export const getFiles = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ export const getFileById = async (token: string, id: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ export const updateFileDataContentById = async (token: string, id: string, conte
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ export const getFileContentById = async (id: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -200,7 +200,7 @@ export const deleteFileById = async (token: string, id: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ export const deleteAllFiles = async (token: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ export const getFolders = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ export const getFolderById = async (token: string, id: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ export const updateFolderNameById = async (token: string, id: string, name: stri
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ export const updateFolderIsExpandedById = async (
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ export const updateFolderParentIdById = async (token: string, id: string, parent
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -226,7 +226,7 @@ export const updateFolderItemsById = async (token: string, id: string, items: Fo
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -257,7 +257,7 @@ export const deleteFolderById = async (token: string, id: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export const createNewFunction = async (token: string, func: object) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ export const getFunctions = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ export const exportFunctions = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ export const getFunctionById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ export const updateFunctionById = async (token: string, id: string, func: object
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ export const deleteFunctionById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -213,7 +213,7 @@ export const toggleFunctionById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -245,7 +245,7 @@ export const toggleGlobalById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ export const getFunctionValvesById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -309,7 +309,7 @@ export const getFunctionValvesSpecById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -344,7 +344,7 @@ export const updateFunctionValvesById = async (token: string, id: string, valves
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -376,7 +376,7 @@ export const getUserValvesById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -408,7 +408,7 @@ export const getUserValvesSpecById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -443,7 +443,7 @@ export const updateUserValvesById = async (token: string, id: string, valves: ob
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export const createNewGroup = async (token: string, group: object) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ export const getGroups = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ export const getGroupById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ export const updateGroupById = async (token: string, id: string, group: object)
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ export const deleteGroupById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ export const getConfig = async (token: string = '') => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -51,7 +51,7 @@ export const updateConfig = async (token: string = '', config: object) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -83,7 +83,7 @@ export const verifyConfigUrl = async (token: string = '') => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -115,7 +115,7 @@ export const getImageGenerationConfig = async (token: string = '') => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -148,7 +148,7 @@ export const updateImageGenerationConfig = async (token: string = '', config: ob
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -180,7 +180,7 @@ export const getImageGenerationModels = async (token: string = '') => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -215,7 +215,7 @@ export const imageGenerations = async (token: string = '', prompt: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
|
@ -25,7 +25,7 @@ export const getModels = async (
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -173,7 +173,7 @@ export const chatCompleted = async (token: string, body: ChatCompletedForm) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -212,7 +212,7 @@ export const chatAction = async (token: string, action_id: string, body: ChatAct
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -244,7 +244,7 @@ export const stopTask = async (token: string, id: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -276,7 +276,7 @@ export const getTaskIdsByChatId = async (token: string, chat_id: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -315,7 +315,7 @@ export const getToolServerData = async (token: string, url: string) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -491,7 +491,7 @@ export const getTaskConfig = async (token: string = '') => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -520,7 +520,7 @@ export const updateTaskConfig = async (token: string, config: object) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -562,7 +562,7 @@ export const generateTitle = async (
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
}
|
}
|
||||||
@ -634,7 +634,7 @@ export const generateTags = async (
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
}
|
}
|
||||||
@ -706,7 +706,7 @@ export const generateEmoji = async (
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
}
|
}
|
||||||
@ -756,7 +756,7 @@ export const generateQueries = async (
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
}
|
}
|
||||||
@ -828,7 +828,7 @@ export const generateAutoCompletion = async (
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
}
|
}
|
||||||
@ -892,7 +892,7 @@ export const generateMoACompletion = async (
|
|||||||
stream: true
|
stream: true
|
||||||
})
|
})
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -920,7 +920,7 @@ export const getPipelinesList = async (token: string = '') => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -954,7 +954,7 @@ export const uploadPipeline = async (token: string, file: File, urlIdx: string)
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -990,7 +990,7 @@ export const downloadPipeline = async (token: string, url: string, urlIdx: strin
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -1026,7 +1026,7 @@ export const deletePipeline = async (token: string, id: string, urlIdx: string)
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -1063,7 +1063,7 @@ export const getPipelines = async (token: string, urlIdx?: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1100,7 +1100,7 @@ export const getPipelineValves = async (token: string, pipeline_id: string, urlI
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1136,7 +1136,7 @@ export const getPipelineValvesSpec = async (token: string, pipeline_id: string,
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1178,7 +1178,7 @@ export const updatePipelineValves = async (
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
|
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
@ -1210,7 +1210,7 @@ export const getBackendConfig = async () => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1236,7 +1236,7 @@ export const getChangelog = async () => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1263,7 +1263,7 @@ export const getVersionUpdates = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1290,7 +1290,7 @@ export const getModelFilterConfig = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1325,7 +1325,7 @@ export const updateModelFilterConfig = async (
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1352,7 +1352,7 @@ export const getWebhookUrl = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1382,7 +1382,7 @@ export const updateWebhookUrl = async (token: string, url: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1409,7 +1409,7 @@ export const getCommunitySharingEnabledStatus = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1436,7 +1436,7 @@ export const toggleCommunitySharingEnabledStatus = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1463,7 +1463,7 @@ export const getModelConfig = async (token: string): Promise<GlobalModelConfig>
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1511,7 +1511,7 @@ export const updateModelConfig = async (token: string, config: GlobalModelConfig
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -27,7 +27,7 @@ export const createNewKnowledge = async (
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ export const getKnowledgeBases = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ export const getKnowledgeBaseList = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ export const getKnowledgeById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -166,7 +166,7 @@ export const updateKnowledgeById = async (token: string, id: string, form: Knowl
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -201,7 +201,7 @@ export const addFileToKnowledgeById = async (token: string, id: string, fileId:
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -236,7 +236,7 @@ export const updateFileFromKnowledgeById = async (token: string, id: string, fil
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -271,7 +271,7 @@ export const removeFileFromKnowledgeById = async (token: string, id: string, fil
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -303,7 +303,7 @@ export const resetKnowledgeById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -335,7 +335,7 @@ export const deleteKnowledgeById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -363,7 +363,7 @@ export const reindexKnowledgeFiles = async (token: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ export const getMemories = async (token: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ export const addNewMemory = async (token: string, content: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ export const updateMemoryById = async (token: string, id: string, content: strin
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ export const queryMemory = async (token: string, content: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ export const deleteMemoryById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -174,7 +174,7 @@ export const deleteMemoriesByUserId = async (token: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export const getModels = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ export const getBaseModels = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ export const createNewModel = async (token: string, model: object) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ export const getModelById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ export const toggleModelById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -186,7 +186,7 @@ export const updateModelById = async (token: string, id: string, model: object)
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -221,7 +221,7 @@ export const deleteModelById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -253,7 +253,7 @@ export const deleteAllModels = async (token: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ export const createNewNote = async (token: string, note: NoteItem) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ export const getNotes = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ export const getNoteById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ export const updateNoteById = async (token: string, id: string, note: NoteItem)
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -175,7 +175,7 @@ export const deleteNoteById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ export const getOllamaConfig = async (token: string = '') => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -92,7 +92,7 @@ export const updateOllamaConfig = async (token: string = '', config: OllamaConfi
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -124,7 +124,7 @@ export const getOllamaUrls = async (token: string = '') => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -159,7 +159,7 @@ export const updateOllamaUrls = async (token: string = '', urls: string[]) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -191,7 +191,7 @@ export const getOllamaVersion = async (token: string, urlIdx?: number) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -223,7 +223,7 @@ export const getOllamaModels = async (token: string = '', urlIdx: null | number
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -268,7 +268,7 @@ export const generatePrompt = async (token: string = '', model: string, conversa
|
|||||||
`
|
`
|
||||||
})
|
})
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
}
|
}
|
||||||
@ -408,11 +408,11 @@ export const deleteModel = async (token: string, tagName: string, urlIdx: string
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
console.log(json);
|
console.debug(json);
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
@ -445,7 +445,7 @@ export const pullModel = async (token: string, tagName: string, urlIdx: number |
|
|||||||
name: tagName
|
name: tagName
|
||||||
})
|
})
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
@ -481,7 +481,7 @@ export const downloadModel = async (
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
).catch((err) => {
|
).catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
@ -512,7 +512,7 @@ export const uploadModel = async (token: string, file: File, urlIdx: string | nu
|
|||||||
body: formData
|
body: formData
|
||||||
}
|
}
|
||||||
).catch((err) => {
|
).catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
|
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
|
@ -16,7 +16,7 @@ export const getOpenAIConfig = async (token: string = '') => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -58,7 +58,7 @@ export const updateOpenAIConfig = async (token: string = '', config: OpenAIConfi
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -90,7 +90,7 @@ export const getOpenAIUrls = async (token: string = '') => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -125,7 +125,7 @@ export const updateOpenAIUrls = async (token: string = '', urls: string[]) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -157,7 +157,7 @@ export const getOpenAIKeys = async (token: string = '') => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -192,7 +192,7 @@ export const updateOpenAIKeys = async (token: string = '', keys: string[]) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
if ('detail' in err) {
|
if ('detail' in err) {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
} else {
|
} else {
|
||||||
@ -346,7 +346,7 @@ export const chatCompletion = async (
|
|||||||
},
|
},
|
||||||
body: JSON.stringify(body)
|
body: JSON.stringify(body)
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -409,7 +409,7 @@ export const synthesizeOpenAISpeech = async (
|
|||||||
voice: speaker
|
voice: speaker
|
||||||
})
|
})
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -28,7 +28,7 @@ export const createNewPrompt = async (token: string, prompt: PromptItem) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ export const getPrompts = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ export const getPromptList = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ export const getPromptByCommand = async (token: string, command: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -158,7 +158,7 @@ export const updatePromptByCommand = async (token: string, prompt: PromptItem) =
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ export const deletePromptByCommand = async (token: string, command: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ export const getRAGConfig = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -77,7 +77,7 @@ export const updateRAGConfig = async (token: string, payload: RAGConfigForm) =>
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -104,7 +104,7 @@ export const getQuerySettings = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -140,7 +140,7 @@ export const updateQuerySettings = async (token: string, settings: QuerySettings
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -167,7 +167,7 @@ export const getEmbeddingConfig = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -209,7 +209,7 @@ export const updateEmbeddingConfig = async (token: string, payload: EmbeddingMod
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -236,7 +236,7 @@ export const getRerankingConfig = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -270,7 +270,7 @@ export const updateRerankingConfig = async (token: string, payload: RerankingMod
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -313,7 +313,7 @@ export const processFile = async (
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -344,7 +344,7 @@ export const processYoutubeVideo = async (token: string, url: string) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -376,7 +376,7 @@ export const processWeb = async (token: string, collection_name: string, url: st
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -410,7 +410,7 @@ export const processWebSearch = async (
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -20,7 +20,7 @@ export const createNewTool = async (token: string, tool: object) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ export const getTools = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ export const getToolList = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ export const exportTools = async (token: string = '') => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ export const getToolById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ export const updateToolById = async (token: string, id: string, tool: object) =>
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -212,7 +212,7 @@ export const deleteToolById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ export const getToolValvesById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -276,7 +276,7 @@ export const getToolValvesSpecById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -311,7 +311,7 @@ export const updateToolValvesById = async (token: string, id: string, valves: ob
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -343,7 +343,7 @@ export const getUserValvesById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -375,7 +375,7 @@ export const getUserValvesSpecById = async (token: string, id: string) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -410,7 +410,7 @@ export const updateUserValvesById = async (token: string, id: string, valves: ob
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
|
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ export const getUserGroups = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -43,7 +43,7 @@ export const getUserDefaultPermissions = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -73,7 +73,7 @@ export const updateUserDefaultPermissions = async (token: string, permissions: o
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -104,7 +104,7 @@ export const updateUserRole = async (token: string, id: string, role: string) =>
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -154,7 +154,7 @@ export const getUsers = async (
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -182,7 +182,7 @@ export const getAllUsers = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -208,7 +208,7 @@ export const getUserSettings = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -238,7 +238,7 @@ export const updateUserSettings = async (token: string, settings: object) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -265,7 +265,7 @@ export const getUserById = async (token: string, userId: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -291,7 +291,7 @@ export const getUserInfo = async (token: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -321,7 +321,7 @@ export const updateUserInfo = async (token: string, info: object) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -335,7 +335,7 @@ export const updateUserInfo = async (token: string, info: object) => {
|
|||||||
|
|
||||||
export const getAndUpdateUserLocation = async (token: string) => {
|
export const getAndUpdateUserLocation = async (token: string) => {
|
||||||
const location = await getUserPosition().catch((err) => {
|
const location = await getUserPosition().catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -343,7 +343,7 @@ export const getAndUpdateUserLocation = async (token: string) => {
|
|||||||
await updateUserInfo(token, { location: location });
|
await updateUserInfo(token, { location: location });
|
||||||
return location;
|
return location;
|
||||||
} else {
|
} else {
|
||||||
console.log('Failed to get user location');
|
console.info('Failed to get user location');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -363,7 +363,7 @@ export const deleteUserById = async (token: string, userId: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -403,7 +403,7 @@ export const updateUserById = async (token: string, userId: string, user: UserUp
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -15,7 +15,7 @@ export const getGravatarUrl = async (token: string, email: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -41,7 +41,7 @@ export const executeCode = async (token: string, code: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
|
|
||||||
error = err;
|
error = err;
|
||||||
if (err.detail) {
|
if (err.detail) {
|
||||||
@ -75,7 +75,7 @@ export const formatPythonCode = async (token: string, code: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
|
|
||||||
error = err;
|
error = err;
|
||||||
if (err.detail) {
|
if (err.detail) {
|
||||||
@ -110,7 +110,7 @@ export const downloadChatAsPDF = async (token: string, title: string, messages:
|
|||||||
return res.blob();
|
return res.blob();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -136,7 +136,7 @@ export const getHTMLFromMarkdown = async (token: string, md: string) => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err;
|
error = err;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -170,7 +170,7 @@ export const downloadDatabase = async (token: string) => {
|
|||||||
window.URL.revokeObjectURL(url);
|
window.URL.revokeObjectURL(url);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -206,7 +206,7 @@ export const downloadLiteLLMConfig = async (token: string) => {
|
|||||||
window.URL.revokeObjectURL(url);
|
window.URL.revokeObjectURL(url);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
error = err.detail;
|
error = err.detail;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
let url = '';
|
let url = '';
|
||||||
let key = '';
|
let key = '';
|
||||||
|
|
||||||
|
let connectionType = 'external';
|
||||||
|
let azure = false;
|
||||||
|
|
||||||
let prefixId = '';
|
let prefixId = '';
|
||||||
let enable = true;
|
let enable = true;
|
||||||
let tags = [];
|
let tags = [];
|
||||||
@ -95,7 +98,9 @@
|
|||||||
enable: enable,
|
enable: enable,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
prefix_id: prefixId,
|
prefix_id: prefixId,
|
||||||
model_ids: modelIds
|
model_ids: modelIds,
|
||||||
|
connection_type: connectionType,
|
||||||
|
...(!ollama && azure ? { azure: true } : {})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -120,6 +125,13 @@
|
|||||||
tags = connection.config?.tags ?? [];
|
tags = connection.config?.tags ?? [];
|
||||||
prefixId = connection.config?.prefix_id ?? '';
|
prefixId = connection.config?.prefix_id ?? '';
|
||||||
modelIds = connection.config?.model_ids ?? [];
|
modelIds = connection.config?.model_ids ?? [];
|
||||||
|
|
||||||
|
if (ollama) {
|
||||||
|
connectionType = connection.config?.connection_type ?? 'local';
|
||||||
|
} else {
|
||||||
|
connectionType = connection.config?.connection_type ?? 'external';
|
||||||
|
azure = connection.config?.azure ?? false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -134,7 +146,7 @@
|
|||||||
|
|
||||||
<Modal size="sm" bind:show>
|
<Modal size="sm" bind:show>
|
||||||
<div>
|
<div>
|
||||||
<div class=" flex justify-between dark:text-gray-100 px-5 pt-4 pb-2">
|
<div class=" flex justify-between dark:text-gray-100 px-5 pt-4 pb-1.5">
|
||||||
<div class=" text-lg font-medium self-center font-primary">
|
<div class=" text-lg font-medium self-center font-primary">
|
||||||
{#if edit}
|
{#if edit}
|
||||||
{$i18n.t('Edit Connection')}
|
{$i18n.t('Edit Connection')}
|
||||||
@ -172,6 +184,28 @@
|
|||||||
>
|
>
|
||||||
<div class="px-1">
|
<div class="px-1">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
|
<div class="flex w-full justify-between items-center">
|
||||||
|
<div class=" text-xs text-gray-500">{$i18n.t('Connection Type')}</div>
|
||||||
|
|
||||||
|
<div class="">
|
||||||
|
<button
|
||||||
|
on:click={() => {
|
||||||
|
connectionType = connectionType === 'local' ? 'external' : 'local';
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
class=" text-xs text-gray-700 dark:text-gray-300"
|
||||||
|
>
|
||||||
|
{#if connectionType === 'local'}
|
||||||
|
{$i18n.t('Local')}
|
||||||
|
{:else}
|
||||||
|
{$i18n.t('External')}
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-2 mt-1.5">
|
||||||
<div class="flex flex-col w-full">
|
<div class="flex flex-col w-full">
|
||||||
<div class=" mb-0.5 text-xs text-gray-500">{$i18n.t('URL')}</div>
|
<div class=" mb-0.5 text-xs text-gray-500">{$i18n.t('URL')}</div>
|
||||||
|
|
||||||
|
@ -277,7 +277,7 @@ class Pipe:
|
|||||||
await tick();
|
await tick();
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
console.log('Code formatted successfully');
|
console.info('Code formatted successfully');
|
||||||
|
|
||||||
saveHandler();
|
saveHandler();
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Update embedding model attempt:', embeddingModel);
|
console.debug('Update embedding model attempt:', embeddingModel);
|
||||||
|
|
||||||
updateEmbeddingModelLoading = true;
|
updateEmbeddingModelLoading = true;
|
||||||
const res = await updateEmbeddingConfig(localStorage.token, {
|
const res = await updateEmbeddingConfig(localStorage.token, {
|
||||||
@ -114,7 +114,7 @@
|
|||||||
updateEmbeddingModelLoading = false;
|
updateEmbeddingModelLoading = false;
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
console.log('embeddingModelUpdateHandler:', res);
|
console.debug('embeddingModelUpdateHandler:', res);
|
||||||
if (res.status === true) {
|
if (res.status === true) {
|
||||||
toast.success($i18n.t('Embedding model set to "{{embedding_model}}"', res), {
|
toast.success($i18n.t('Embedding model set to "{{embedding_model}}"', res), {
|
||||||
duration: 1000 * 10
|
duration: 1000 * 10
|
||||||
@ -124,6 +124,13 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const submitHandler = async () => {
|
const submitHandler = async () => {
|
||||||
|
if (
|
||||||
|
RAGConfig.CONTENT_EXTRACTION_ENGINE === 'external' &&
|
||||||
|
RAGConfig.EXTERNAL_DOCUMENT_LOADER_URL === ''
|
||||||
|
) {
|
||||||
|
toast.error($i18n.t('External Document Loader URL required.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (RAGConfig.CONTENT_EXTRACTION_ENGINE === 'tika' && RAGConfig.TIKA_SERVER_URL === '') {
|
if (RAGConfig.CONTENT_EXTRACTION_ENGINE === 'tika' && RAGConfig.TIKA_SERVER_URL === '') {
|
||||||
toast.error($i18n.t('Tika Server URL required.'));
|
toast.error($i18n.t('Tika Server URL required.'));
|
||||||
return;
|
return;
|
||||||
@ -163,6 +170,10 @@
|
|||||||
await embeddingModelUpdateHandler();
|
await embeddingModelUpdateHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RAGConfig.ALLOWED_FILE_EXTENSIONS = RAGConfig.ALLOWED_FILE_EXTENSIONS.split(',')
|
||||||
|
.map((ext) => ext.trim())
|
||||||
|
.filter((ext) => ext !== '');
|
||||||
|
|
||||||
const res = await updateRAGConfig(localStorage.token, RAGConfig);
|
const res = await updateRAGConfig(localStorage.token, RAGConfig);
|
||||||
dispatch('save');
|
dispatch('save');
|
||||||
};
|
};
|
||||||
@ -185,7 +196,10 @@
|
|||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await setEmbeddingConfig();
|
await setEmbeddingConfig();
|
||||||
|
|
||||||
RAGConfig = await getRAGConfig(localStorage.token);
|
const config = await getRAGConfig(localStorage.token);
|
||||||
|
config.ALLOWED_FILE_EXTENSIONS = config.ALLOWED_FILE_EXTENSIONS.join(', ');
|
||||||
|
|
||||||
|
RAGConfig = config;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -246,7 +260,7 @@
|
|||||||
<hr class=" border-gray-100 dark:border-gray-850 my-2" />
|
<hr class=" border-gray-100 dark:border-gray-850 my-2" />
|
||||||
|
|
||||||
<div class="mb-2.5 flex flex-col w-full justify-between">
|
<div class="mb-2.5 flex flex-col w-full justify-between">
|
||||||
<div class="flex w-full justify-between">
|
<div class="flex w-full justify-between mb-1">
|
||||||
<div class="self-center text-xs font-medium">
|
<div class="self-center text-xs font-medium">
|
||||||
{$i18n.t('Content Extraction Engine')}
|
{$i18n.t('Content Extraction Engine')}
|
||||||
</div>
|
</div>
|
||||||
@ -256,6 +270,7 @@
|
|||||||
bind:value={RAGConfig.CONTENT_EXTRACTION_ENGINE}
|
bind:value={RAGConfig.CONTENT_EXTRACTION_ENGINE}
|
||||||
>
|
>
|
||||||
<option value="">{$i18n.t('Default')}</option>
|
<option value="">{$i18n.t('Default')}</option>
|
||||||
|
<option value="external">{$i18n.t('External')}</option>
|
||||||
<option value="tika">{$i18n.t('Tika')}</option>
|
<option value="tika">{$i18n.t('Tika')}</option>
|
||||||
<option value="docling">{$i18n.t('Docling')}</option>
|
<option value="docling">{$i18n.t('Docling')}</option>
|
||||||
<option value="document_intelligence">{$i18n.t('Document Intelligence')}</option>
|
<option value="document_intelligence">{$i18n.t('Document Intelligence')}</option>
|
||||||
@ -275,11 +290,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{:else if RAGConfig.CONTENT_EXTRACTION_ENGINE === 'external'}
|
||||||
|
<div class="my-0.5 flex gap-2 pr-2">
|
||||||
|
<input
|
||||||
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
|
placeholder={$i18n.t('Enter External Document Loader URL')}
|
||||||
|
bind:value={RAGConfig.EXTERNAL_DOCUMENT_LOADER_URL}
|
||||||
|
/>
|
||||||
|
<SensitiveInput
|
||||||
|
placeholder={$i18n.t('Enter External Document Loader API Key')}
|
||||||
|
required={false}
|
||||||
|
bind:value={RAGConfig.EXTERNAL_DOCUMENT_LOADER_API_KEY}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
{:else if RAGConfig.CONTENT_EXTRACTION_ENGINE === 'tika'}
|
{:else if RAGConfig.CONTENT_EXTRACTION_ENGINE === 'tika'}
|
||||||
<div class="flex w-full mt-1">
|
<div class="flex w-full mt-1">
|
||||||
<div class="flex-1 mr-2">
|
<div class="flex-1 mr-2">
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
placeholder={$i18n.t('Enter Tika Server URL')}
|
placeholder={$i18n.t('Enter Tika Server URL')}
|
||||||
bind:value={RAGConfig.TIKA_SERVER_URL}
|
bind:value={RAGConfig.TIKA_SERVER_URL}
|
||||||
/>
|
/>
|
||||||
@ -288,27 +316,38 @@
|
|||||||
{:else if RAGConfig.CONTENT_EXTRACTION_ENGINE === 'docling'}
|
{:else if RAGConfig.CONTENT_EXTRACTION_ENGINE === 'docling'}
|
||||||
<div class="flex w-full mt-1">
|
<div class="flex w-full mt-1">
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
placeholder={$i18n.t('Enter Docling Server URL')}
|
placeholder={$i18n.t('Enter Docling Server URL')}
|
||||||
bind:value={RAGConfig.DOCLING_SERVER_URL}
|
bind:value={RAGConfig.DOCLING_SERVER_URL}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex w-full mt-2">
|
<div class="flex w-full mt-2">
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
placeholder={$i18n.t('Enter Docling OCR Engine')}
|
placeholder={$i18n.t('Enter Docling OCR Engine')}
|
||||||
bind:value={RAGConfig.DOCLING_OCR_ENGINE}
|
bind:value={RAGConfig.DOCLING_OCR_ENGINE}
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
placeholder={$i18n.t('Enter Docling OCR Language(s)')}
|
placeholder={$i18n.t('Enter Docling OCR Language(s)')}
|
||||||
bind:value={RAGConfig.DOCLING_OCR_LANG}
|
bind:value={RAGConfig.DOCLING_OCR_LANG}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex w-full mt-2">
|
||||||
|
<div class="flex-1 flex justify-between">
|
||||||
|
<div class=" self-center text-xs font-medium">
|
||||||
|
{$i18n.t('Describe Pictures in Documents')}
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center relative">
|
||||||
|
<Switch bind:state={RAGConfig.DOCLING_DO_PICTURE_DESCRIPTION} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{:else if RAGConfig.CONTENT_EXTRACTION_ENGINE === 'document_intelligence'}
|
{:else if RAGConfig.CONTENT_EXTRACTION_ENGINE === 'document_intelligence'}
|
||||||
<div class="my-0.5 flex gap-2 pr-2">
|
<div class="my-0.5 flex gap-2 pr-2">
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
placeholder={$i18n.t('Enter Document Intelligence Endpoint')}
|
placeholder={$i18n.t('Enter Document Intelligence Endpoint')}
|
||||||
bind:value={RAGConfig.DOCUMENT_INTELLIGENCE_ENDPOINT}
|
bind:value={RAGConfig.DOCUMENT_INTELLIGENCE_ENDPOINT}
|
||||||
/>
|
/>
|
||||||
@ -437,7 +476,7 @@
|
|||||||
{#if embeddingEngine === 'openai'}
|
{#if embeddingEngine === 'openai'}
|
||||||
<div class="my-0.5 flex gap-2 pr-2">
|
<div class="my-0.5 flex gap-2 pr-2">
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
placeholder={$i18n.t('API Base URL')}
|
placeholder={$i18n.t('API Base URL')}
|
||||||
bind:value={OpenAIUrl}
|
bind:value={OpenAIUrl}
|
||||||
required
|
required
|
||||||
@ -448,7 +487,7 @@
|
|||||||
{:else if embeddingEngine === 'ollama'}
|
{:else if embeddingEngine === 'ollama'}
|
||||||
<div class="my-0.5 flex gap-2 pr-2">
|
<div class="my-0.5 flex gap-2 pr-2">
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
placeholder={$i18n.t('API Base URL')}
|
placeholder={$i18n.t('API Base URL')}
|
||||||
bind:value={OllamaUrl}
|
bind:value={OllamaUrl}
|
||||||
required
|
required
|
||||||
@ -471,7 +510,7 @@
|
|||||||
<div class="flex w-full">
|
<div class="flex w-full">
|
||||||
<div class="flex-1 mr-2">
|
<div class="flex-1 mr-2">
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
bind:value={embeddingModel}
|
bind:value={embeddingModel}
|
||||||
placeholder={$i18n.t('Set embedding model')}
|
placeholder={$i18n.t('Set embedding model')}
|
||||||
required
|
required
|
||||||
@ -482,7 +521,7 @@
|
|||||||
<div class="flex w-full">
|
<div class="flex w-full">
|
||||||
<div class="flex-1 mr-2">
|
<div class="flex-1 mr-2">
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
placeholder={$i18n.t('Set embedding model (e.g. {{model}})', {
|
placeholder={$i18n.t('Set embedding model (e.g. {{model}})', {
|
||||||
model: embeddingModel.slice(-40)
|
model: embeddingModel.slice(-40)
|
||||||
})}
|
})}
|
||||||
@ -639,7 +678,7 @@
|
|||||||
{#if RAGConfig.RAG_RERANKING_ENGINE === 'external'}
|
{#if RAGConfig.RAG_RERANKING_ENGINE === 'external'}
|
||||||
<div class="my-0.5 flex gap-2 pr-2">
|
<div class="my-0.5 flex gap-2 pr-2">
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
placeholder={$i18n.t('API Base URL')}
|
placeholder={$i18n.t('API Base URL')}
|
||||||
bind:value={RAGConfig.RAG_EXTERNAL_RERANKER_URL}
|
bind:value={RAGConfig.RAG_EXTERNAL_RERANKER_URL}
|
||||||
required
|
required
|
||||||
@ -661,7 +700,7 @@
|
|||||||
<div class="flex w-full">
|
<div class="flex w-full">
|
||||||
<div class="flex-1 mr-2">
|
<div class="flex-1 mr-2">
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
placeholder={$i18n.t('Set reranking model (e.g. {{model}})', {
|
placeholder={$i18n.t('Set reranking model (e.g. {{model}})', {
|
||||||
model: 'BAAI/bge-reranker-v2-m3'
|
model: 'BAAI/bge-reranker-v2-m3'
|
||||||
})}
|
})}
|
||||||
@ -677,7 +716,7 @@
|
|||||||
<div class=" self-center text-xs font-medium">{$i18n.t('Top K')}</div>
|
<div class=" self-center text-xs font-medium">{$i18n.t('Top K')}</div>
|
||||||
<div class="flex items-center relative">
|
<div class="flex items-center relative">
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
type="number"
|
type="number"
|
||||||
placeholder={$i18n.t('Enter Top K')}
|
placeholder={$i18n.t('Enter Top K')}
|
||||||
bind:value={RAGConfig.TOP_K}
|
bind:value={RAGConfig.TOP_K}
|
||||||
@ -692,7 +731,7 @@
|
|||||||
<div class="self-center text-xs font-medium">{$i18n.t('Top K Reranker')}</div>
|
<div class="self-center text-xs font-medium">{$i18n.t('Top K Reranker')}</div>
|
||||||
<div class="flex items-center relative">
|
<div class="flex items-center relative">
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
type="number"
|
type="number"
|
||||||
placeholder={$i18n.t('Enter Top K Reranker')}
|
placeholder={$i18n.t('Enter Top K Reranker')}
|
||||||
bind:value={RAGConfig.TOP_K_RERANKER}
|
bind:value={RAGConfig.TOP_K_RERANKER}
|
||||||
@ -711,7 +750,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center relative">
|
<div class="flex items-center relative">
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
type="number"
|
type="number"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
placeholder={$i18n.t('Enter Score')}
|
placeholder={$i18n.t('Enter Score')}
|
||||||
@ -760,6 +799,26 @@
|
|||||||
|
|
||||||
<hr class=" border-gray-100 dark:border-gray-850 my-2" />
|
<hr class=" border-gray-100 dark:border-gray-850 my-2" />
|
||||||
|
|
||||||
|
<div class=" mb-2.5 flex w-full justify-between">
|
||||||
|
<div class=" self-center text-xs font-medium">{$i18n.t('Allowed File Extensions')}</div>
|
||||||
|
<div class="flex items-center relative">
|
||||||
|
<Tooltip
|
||||||
|
content={$i18n.t(
|
||||||
|
'Allowed file extensions for upload. Separate multiple extensions with commas. Leave empty for all file types.'
|
||||||
|
)}
|
||||||
|
placement="top-start"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
|
type="text"
|
||||||
|
placeholder={$i18n.t('e.g. pdf, docx, txt')}
|
||||||
|
bind:value={RAGConfig.ALLOWED_FILE_EXTENSIONS}
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class=" mb-2.5 flex w-full justify-between">
|
<div class=" mb-2.5 flex w-full justify-between">
|
||||||
<div class=" self-center text-xs font-medium">{$i18n.t('Max Upload Size')}</div>
|
<div class=" self-center text-xs font-medium">{$i18n.t('Max Upload Size')}</div>
|
||||||
<div class="flex items-center relative">
|
<div class="flex items-center relative">
|
||||||
@ -770,7 +829,7 @@
|
|||||||
placement="top-start"
|
placement="top-start"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
type="number"
|
type="number"
|
||||||
placeholder={$i18n.t('Leave empty for unlimited')}
|
placeholder={$i18n.t('Leave empty for unlimited')}
|
||||||
bind:value={RAGConfig.FILE_MAX_SIZE}
|
bind:value={RAGConfig.FILE_MAX_SIZE}
|
||||||
@ -791,7 +850,7 @@
|
|||||||
placement="top-start"
|
placement="top-start"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
class="flex-1 w-full rounded-lg text-sm bg-transparent outline-hidden"
|
class="flex-1 w-full text-sm bg-transparent outline-hidden"
|
||||||
type="number"
|
type="number"
|
||||||
placeholder={$i18n.t('Leave empty for unlimited')}
|
placeholder={$i18n.t('Leave empty for unlimited')}
|
||||||
bind:value={RAGConfig.FILE_MAX_COUNT}
|
bind:value={RAGConfig.FILE_MAX_COUNT}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
import { compareVersion } from '$lib/utils';
|
import { compareVersion } from '$lib/utils';
|
||||||
import { onMount, getContext } from 'svelte';
|
import { onMount, getContext } from 'svelte';
|
||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
|
import Textarea from '$lib/components/common/Textarea.svelte';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@ -58,10 +59,10 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(version);
|
console.info(version);
|
||||||
|
|
||||||
updateAvailable = compareVersion(version.latest, version.current);
|
updateAvailable = compareVersion(version.latest, version.current);
|
||||||
console.log(updateAvailable);
|
console.info(updateAvailable);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateLdapServerHandler = async () => {
|
const updateLdapServerHandler = async () => {
|
||||||
@ -305,6 +306,31 @@
|
|||||||
<Switch bind:state={adminConfig.SHOW_ADMIN_DETAILS} />
|
<Switch bind:state={adminConfig.SHOW_ADMIN_DETAILS} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2.5">
|
||||||
|
<div class=" self-center text-xs font-medium mb-2">
|
||||||
|
{$i18n.t('Pending User Overlay Title')}
|
||||||
|
</div>
|
||||||
|
<Textarea
|
||||||
|
rows={2}
|
||||||
|
placeholder={$i18n.t(
|
||||||
|
'Enter a title for the pending user info overlay. Leave empty for default.'
|
||||||
|
)}
|
||||||
|
bind:value={adminConfig.PENDING_USER_OVERLAY_TITLE}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2.5">
|
||||||
|
<div class=" self-center text-xs font-medium mb-2">
|
||||||
|
{$i18n.t('Pending User Overlay Content')}
|
||||||
|
</div>
|
||||||
|
<Textarea
|
||||||
|
placeholder={$i18n.t(
|
||||||
|
'Enter content for the pending user info overlay. Leave empty for default.'
|
||||||
|
)}
|
||||||
|
bind:value={adminConfig.PENDING_USER_OVERLAY_CONTENT}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mb-2.5 flex w-full justify-between pr-2">
|
<div class="mb-2.5 flex w-full justify-between pr-2">
|
||||||
<div class=" self-center text-xs font-medium">{$i18n.t('Enable API Key')}</div>
|
<div class=" self-center text-xs font-medium">{$i18n.t('Enable API Key')}</div>
|
||||||
|
|
||||||
@ -559,6 +585,13 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex justify-between items-center text-xs">
|
||||||
|
<div class=" font-medium">Validate certificate</div>
|
||||||
|
|
||||||
|
<div class="mt-1">
|
||||||
|
<Switch bind:state={LDAP_SERVER.validate_cert} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="flex w-full gap-2">
|
<div class="flex w-full gap-2">
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<div class=" self-center text-xs font-medium min-w-fit mb-1">
|
<div class=" self-center text-xs font-medium min-w-fit mb-1">
|
||||||
@ -625,6 +658,16 @@
|
|||||||
<Switch bind:state={adminConfig.ENABLE_USER_WEBHOOKS} />
|
<Switch bind:state={adminConfig.ENABLE_USER_WEBHOOKS} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2.5">
|
||||||
|
<div class=" self-center text-xs font-medium mb-2">
|
||||||
|
{$i18n.t('Response Watermark')}
|
||||||
|
</div>
|
||||||
|
<Textarea
|
||||||
|
placeholder={$i18n.t('Enter a watermark for the response. Leave empty for none.')}
|
||||||
|
bind:value={adminConfig.RESPONSE_WATERMARK}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mb-2.5 w-full justify-between">
|
<div class="mb-2.5 w-full justify-between">
|
||||||
<div class="flex w-full justify-between">
|
<div class="flex w-full justify-between">
|
||||||
<div class=" self-center text-xs font-medium">{$i18n.t('WebUI URL')}</div>
|
<div class=" self-center text-xs font-medium">{$i18n.t('WebUI URL')}</div>
|
||||||
|
@ -198,14 +198,14 @@
|
|||||||
2
|
2
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
requiredWorkflowNodes = requiredWorkflowNodes.map((node) => {
|
requiredWorkflowNodes = requiredWorkflowNodes.map((node) => {
|
||||||
const n = config.comfyui.COMFYUI_WORKFLOW_NODES.find((n) => n.type === node.type) ?? node;
|
const n = config.comfyui.COMFYUI_WORKFLOW_NODES.find((n) => n.type === node.type) ?? node;
|
||||||
|
|
||||||
console.log(n);
|
console.debug(n);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: n.type,
|
type: n.type,
|
||||||
|
@ -90,7 +90,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('models', models);
|
console.debug('models', models);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -108,8 +108,8 @@
|
|||||||
|
|
||||||
<hr class=" border-gray-100 dark:border-gray-850 my-2" />
|
<hr class=" border-gray-100 dark:border-gray-850 my-2" />
|
||||||
|
|
||||||
<div class=" mb-1 font-medium flex items-center">
|
<div class=" mb-2 font-medium flex items-center">
|
||||||
<div class=" text-xs mr-1">{$i18n.t('Set Task Model')}</div>
|
<div class=" text-xs mr-1">{$i18n.t('Task Model')}</div>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={$i18n.t(
|
content={$i18n.t(
|
||||||
'A task model is used when performing tasks such as generating titles for chats and web search queries'
|
'A task model is used when performing tasks such as generating titles for chats and web search queries'
|
||||||
@ -134,7 +134,7 @@
|
|||||||
|
|
||||||
<div class=" mb-2.5 flex w-full gap-2">
|
<div class=" mb-2.5 flex w-full gap-2">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class=" text-xs mb-1">{$i18n.t('Local Models')}</div>
|
<div class=" text-xs mb-1">{$i18n.t('Local Task Model')}</div>
|
||||||
<select
|
<select
|
||||||
class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
|
class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
|
||||||
bind:value={taskConfig.TASK_MODEL}
|
bind:value={taskConfig.TASK_MODEL}
|
||||||
@ -159,7 +159,7 @@
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<option value="" selected>{$i18n.t('Current Model')}</option>
|
<option value="" selected>{$i18n.t('Current Model')}</option>
|
||||||
{#each models.filter((m) => m.owned_by === 'ollama') as model}
|
{#each models.filter((m) => m.connection_type === 'local') as model}
|
||||||
<option value={model.id} class="bg-gray-100 dark:bg-gray-700">
|
<option value={model.id} class="bg-gray-100 dark:bg-gray-700">
|
||||||
{model.name}
|
{model.name}
|
||||||
</option>
|
</option>
|
||||||
@ -168,7 +168,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class=" text-xs mb-1">{$i18n.t('External Models')}</div>
|
<div class=" text-xs mb-1">{$i18n.t('External Task Model')}</div>
|
||||||
<select
|
<select
|
||||||
class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
|
class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
|
||||||
bind:value={taskConfig.TASK_MODEL_EXTERNAL}
|
bind:value={taskConfig.TASK_MODEL_EXTERNAL}
|
||||||
|
@ -166,7 +166,7 @@
|
|||||||
hidden: !(model?.meta?.hidden ?? false)
|
hidden: !(model?.meta?.hidden ?? false)
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(model);
|
console.debug(model);
|
||||||
|
|
||||||
toast.success(
|
toast.success(
|
||||||
model.meta.hidden
|
model.meta.hidden
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
|
|
||||||
const updateModelsHandler = async () => {
|
const updateModelsHandler = async () => {
|
||||||
for (const model of ollamaModels) {
|
for (const model of ollamaModels) {
|
||||||
console.log(model);
|
console.debug(model);
|
||||||
|
|
||||||
updateModelId = model.id;
|
updateModelId = model.id;
|
||||||
const [res, controller] = await pullModel(localStorage.token, model.id, urlIdx).catch(
|
const [res, controller] = await pullModel(localStorage.token, model.id, urlIdx).catch(
|
||||||
@ -114,8 +114,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.log(error);
|
console.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,13 +215,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.log(error);
|
console.error(err);
|
||||||
if (typeof error !== 'string') {
|
if (typeof err !== 'string') {
|
||||||
error = error.message;
|
err = err.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.error(`${error}`);
|
toast.error(`${err}`);
|
||||||
// opts.callback({ success: false, error, modelName: opts.modelName });
|
// opts.callback({ success: false, error, modelName: opts.modelName });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -319,8 +319,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.log(error);
|
console.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -382,9 +382,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.log(error);
|
console.error(err);
|
||||||
toast.error(`${error}`);
|
toast.error(`${err}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -514,9 +514,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.log(error);
|
console.error(err);
|
||||||
toast.error(`${error}`);
|
toast.error(`${err}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@
|
|||||||
valves_spec = null;
|
valves_spec = null;
|
||||||
|
|
||||||
if (PIPELINES_LIST.length > 0) {
|
if (PIPELINES_LIST.length > 0) {
|
||||||
console.log(selectedPipelinesUrlIdx);
|
console.debug(selectedPipelinesUrlIdx);
|
||||||
pipelines = await getPipelines(localStorage.token, selectedPipelinesUrlIdx);
|
pipelines = await getPipelines(localStorage.token, selectedPipelinesUrlIdx);
|
||||||
|
|
||||||
if (pipelines.length > 0) {
|
if (pipelines.length > 0) {
|
||||||
@ -151,7 +151,7 @@
|
|||||||
|
|
||||||
const res = await uploadPipeline(localStorage.token, file, selectedPipelinesUrlIdx).catch(
|
const res = await uploadPipeline(localStorage.token, file, selectedPipelinesUrlIdx).catch(
|
||||||
(error) => {
|
(error) => {
|
||||||
console.log(error);
|
console.error(error);
|
||||||
toast.error('Something went wrong :/');
|
toast.error('Something went wrong :/');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateDefaultPermissionsHandler = async (group) => {
|
const updateDefaultPermissionsHandler = async (group) => {
|
||||||
console.log(group.permissions);
|
console.debug(group.permissions);
|
||||||
|
|
||||||
const res = await updateUserDefaultPermissions(localStorage.token, group.permissions).catch(
|
const res = await updateUserDefaultPermissions(localStorage.token, group.permissions).catch(
|
||||||
(error) => {
|
(error) => {
|
||||||
|
@ -31,10 +31,6 @@
|
|||||||
description = '';
|
description = '';
|
||||||
userIds = [];
|
userIds = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
console.log('mounted');
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal size="sm" bind:show>
|
<Modal size="sm" bind:show>
|
||||||
|
@ -91,7 +91,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
console.log(tabs);
|
|
||||||
selectedTab = tabs[0];
|
selectedTab = tabs[0];
|
||||||
init();
|
init();
|
||||||
});
|
});
|
||||||
|
@ -73,7 +73,7 @@
|
|||||||
|
|
||||||
for (const [idx, row] of rows.entries()) {
|
for (const [idx, row] of rows.entries()) {
|
||||||
const columns = row.split(',').map((col) => col.trim());
|
const columns = row.split(',').map((col) => col.trim());
|
||||||
console.log(idx, columns);
|
console.debug(idx, columns);
|
||||||
|
|
||||||
if (idx > 0) {
|
if (idx > 0) {
|
||||||
if (
|
if (
|
||||||
|
@ -80,7 +80,7 @@
|
|||||||
|
|
||||||
const inputFilesHandler = async (inputFiles) => {
|
const inputFilesHandler = async (inputFiles) => {
|
||||||
inputFiles.forEach((file) => {
|
inputFiles.forEach((file) => {
|
||||||
console.log('Processing file:', {
|
console.info('Processing file:', {
|
||||||
name: file.name,
|
name: file.name,
|
||||||
type: file.type,
|
type: file.type,
|
||||||
size: file.size,
|
size: file.size,
|
||||||
@ -91,7 +91,7 @@
|
|||||||
($config?.file?.max_size ?? null) !== null &&
|
($config?.file?.max_size ?? null) !== null &&
|
||||||
file.size > ($config?.file?.max_size ?? 0) * 1024 * 1024
|
file.size > ($config?.file?.max_size ?? 0) * 1024 * 1024
|
||||||
) {
|
) {
|
||||||
console.log('File exceeds max size limit:', {
|
console.error('File exceeds max size limit:', {
|
||||||
fileSize: file.size,
|
fileSize: file.size,
|
||||||
maxSize: ($config?.file?.max_size ?? 0) * 1024 * 1024
|
maxSize: ($config?.file?.max_size ?? 0) * 1024 * 1024
|
||||||
});
|
});
|
||||||
@ -163,14 +163,14 @@
|
|||||||
const uploadedFile = await uploadFile(localStorage.token, file);
|
const uploadedFile = await uploadFile(localStorage.token, file);
|
||||||
|
|
||||||
if (uploadedFile) {
|
if (uploadedFile) {
|
||||||
console.log('File upload completed:', {
|
console.info('File upload completed:', {
|
||||||
id: uploadedFile.id,
|
id: uploadedFile.id,
|
||||||
name: fileItem.name,
|
name: fileItem.name,
|
||||||
collection: uploadedFile?.meta?.collection_name
|
collection: uploadedFile?.meta?.collection_name
|
||||||
});
|
});
|
||||||
|
|
||||||
if (uploadedFile.error) {
|
if (uploadedFile.error) {
|
||||||
console.warn('File upload warning:', uploadedFile.error);
|
console.error('File upload warning:', uploadedFile.error);
|
||||||
toast.warning(uploadedFile.error);
|
toast.warning(uploadedFile.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +193,6 @@
|
|||||||
|
|
||||||
const handleKeyDown = (event: KeyboardEvent) => {
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
if (event.key === 'Escape') {
|
if (event.key === 'Escape') {
|
||||||
console.log('Escape');
|
|
||||||
draggedOver = false;
|
draggedOver = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -215,7 +214,6 @@
|
|||||||
|
|
||||||
const onDrop = async (e) => {
|
const onDrop = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
console.log(e);
|
|
||||||
|
|
||||||
if (e.dataTransfer?.files) {
|
if (e.dataTransfer?.files) {
|
||||||
const inputFiles = Array.from(e.dataTransfer?.files);
|
const inputFiles = Array.from(e.dataTransfer?.files);
|
||||||
@ -270,7 +268,6 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
console.log('destroy');
|
|
||||||
window.removeEventListener('keydown', handleKeyDown);
|
window.removeEventListener('keydown', handleKeyDown);
|
||||||
|
|
||||||
const dropzoneElement = document.getElementById('channel-container');
|
const dropzoneElement = document.getElementById('channel-container');
|
||||||
@ -479,12 +476,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
console.log('Escape');
|
console.info('Escape');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
on:paste={async (e) => {
|
on:paste={async (e) => {
|
||||||
e = e.detail.event;
|
e = e.detail.event;
|
||||||
console.log(e);
|
console.info(e);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
{#if !top}
|
{#if !top}
|
||||||
<Loader
|
<Loader
|
||||||
on:visible={(e) => {
|
on:visible={(e) => {
|
||||||
console.log('visible');
|
console.info('visible');
|
||||||
if (!messagesLoading) {
|
if (!messagesLoading) {
|
||||||
loadMoreMessages();
|
loadMoreMessages();
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const channelEventHandler = async (event) => {
|
const channelEventHandler = async (event) => {
|
||||||
console.log(event);
|
console.debug(event);
|
||||||
if (event.channel_id === channel.id) {
|
if (event.channel_id === channel.id) {
|
||||||
const type = event?.data?.type ?? null;
|
const type = event?.data?.type ?? null;
|
||||||
const data = event?.data?.data ?? null;
|
const data = event?.data?.data ?? null;
|
||||||
|
@ -4,13 +4,15 @@
|
|||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
import { chatId, settings, showArtifacts, showControls } from '$lib/stores';
|
import { artifactCode, chatId, settings, showArtifacts, showControls } from '$lib/stores';
|
||||||
import XMark from '../icons/XMark.svelte';
|
|
||||||
import { copyToClipboard, createMessagesList } from '$lib/utils';
|
import { copyToClipboard, createMessagesList } from '$lib/utils';
|
||||||
|
|
||||||
|
import XMark from '../icons/XMark.svelte';
|
||||||
import ArrowsPointingOut from '../icons/ArrowsPointingOut.svelte';
|
import ArrowsPointingOut from '../icons/ArrowsPointingOut.svelte';
|
||||||
import Tooltip from '../common/Tooltip.svelte';
|
import Tooltip from '../common/Tooltip.svelte';
|
||||||
import SvgPanZoom from '../common/SVGPanZoom.svelte';
|
import SvgPanZoom from '../common/SVGPanZoom.svelte';
|
||||||
import ArrowLeft from '../icons/ArrowLeft.svelte';
|
import ArrowLeft from '../icons/ArrowLeft.svelte';
|
||||||
|
import ArrowDownTray from '../icons/ArrowDownTray.svelte';
|
||||||
|
|
||||||
export let overlay = false;
|
export let overlay = false;
|
||||||
export let history;
|
export let history;
|
||||||
@ -154,7 +156,7 @@
|
|||||||
url.pathname + url.search + url.hash
|
url.pathname + url.search + url.hash
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log('External navigation blocked:', url.href);
|
console.info('External navigation blocked:', url.href);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -180,7 +182,26 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMount(() => {});
|
const downloadArtifact = () => {
|
||||||
|
const blob = new Blob([contents[selectedContentIdx].content], { type: 'text/html' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = `artifact-${$chatId}-${selectedContentIdx}.html`;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
artifactCode.subscribe((value) => {
|
||||||
|
if (contents) {
|
||||||
|
const codeIdx = contents.findIndex((content) => content.content.includes(value));
|
||||||
|
selectedContentIdx = codeIdx !== -1 ? codeIdx : 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class=" w-full h-full relative flex flex-col bg-gray-50 dark:bg-gray-850">
|
<div class=" w-full h-full relative flex flex-col bg-gray-50 dark:bg-gray-850">
|
||||||
@ -198,7 +219,7 @@
|
|||||||
<ArrowLeft className="size-3.5 text-gray-900 dark:text-white" />
|
<ArrowLeft className="size-3.5 text-gray-900 dark:text-white" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="flex-1 flex items-center justify-between">
|
<div class="flex-1 flex items-center justify-between pr-1">
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<div class="flex items-center gap-0.5 self-center min-w-fit" dir="ltr">
|
<div class="flex items-center gap-0.5 self-center min-w-fit" dir="ltr">
|
||||||
<button
|
<button
|
||||||
@ -252,7 +273,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1.5">
|
||||||
<button
|
<button
|
||||||
class="copy-code-button bg-none border-none text-xs bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition rounded-md px-1.5 py-0.5"
|
class="copy-code-button bg-none border-none text-xs bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition rounded-md px-1.5 py-0.5"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
@ -265,6 +286,15 @@
|
|||||||
}}>{copied ? $i18n.t('Copied') : $i18n.t('Copy')}</button
|
}}>{copied ? $i18n.t('Copied') : $i18n.t('Copy')}</button
|
||||||
>
|
>
|
||||||
|
|
||||||
|
<Tooltip content={$i18n.t('Download')}>
|
||||||
|
<button
|
||||||
|
class=" bg-none border-none text-xs bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition rounded-md p-0.5"
|
||||||
|
on:click={downloadArtifact}
|
||||||
|
>
|
||||||
|
<ArrowDownTray className="size-3.5" />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
{#if contents[selectedContentIdx].type === 'iframe'}
|
{#if contents[selectedContentIdx].type === 'iframe'}
|
||||||
<Tooltip content={$i18n.t('Open in full screen')}>
|
<Tooltip content={$i18n.t('Open in full screen')}>
|
||||||
<button
|
<button
|
||||||
|
@ -119,6 +119,7 @@
|
|||||||
$: selectedModelIds = atSelectedModel !== undefined ? [atSelectedModel.id] : selectedModels;
|
$: selectedModelIds = atSelectedModel !== undefined ? [atSelectedModel.id] : selectedModels;
|
||||||
|
|
||||||
let selectedToolIds = [];
|
let selectedToolIds = [];
|
||||||
|
let selectedFilterIds = [];
|
||||||
let imageGenerationEnabled = false;
|
let imageGenerationEnabled = false;
|
||||||
let webSearchEnabled = false;
|
let webSearchEnabled = false;
|
||||||
let codeInterpreterEnabled = false;
|
let codeInterpreterEnabled = false;
|
||||||
@ -146,6 +147,7 @@
|
|||||||
prompt = '';
|
prompt = '';
|
||||||
files = [];
|
files = [];
|
||||||
selectedToolIds = [];
|
selectedToolIds = [];
|
||||||
|
selectedFilterIds = [];
|
||||||
webSearchEnabled = false;
|
webSearchEnabled = false;
|
||||||
imageGenerationEnabled = false;
|
imageGenerationEnabled = false;
|
||||||
|
|
||||||
@ -159,6 +161,7 @@
|
|||||||
prompt = input.prompt;
|
prompt = input.prompt;
|
||||||
files = input.files;
|
files = input.files;
|
||||||
selectedToolIds = input.selectedToolIds;
|
selectedToolIds = input.selectedToolIds;
|
||||||
|
selectedFilterIds = input.selectedFilterIds;
|
||||||
webSearchEnabled = input.webSearchEnabled;
|
webSearchEnabled = input.webSearchEnabled;
|
||||||
imageGenerationEnabled = input.imageGenerationEnabled;
|
imageGenerationEnabled = input.imageGenerationEnabled;
|
||||||
codeInterpreterEnabled = input.codeInterpreterEnabled;
|
codeInterpreterEnabled = input.codeInterpreterEnabled;
|
||||||
@ -192,10 +195,12 @@
|
|||||||
|
|
||||||
$: if (selectedModels) {
|
$: if (selectedModels) {
|
||||||
setToolIds();
|
setToolIds();
|
||||||
|
setFilterIds();
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if (atSelectedModel || selectedModels) {
|
$: if (atSelectedModel || selectedModels) {
|
||||||
setToolIds();
|
setToolIds();
|
||||||
|
setFilterIds();
|
||||||
}
|
}
|
||||||
|
|
||||||
const setToolIds = async () => {
|
const setToolIds = async () => {
|
||||||
@ -209,9 +214,19 @@
|
|||||||
|
|
||||||
const model = atSelectedModel ?? $models.find((m) => m.id === selectedModels[0]);
|
const model = atSelectedModel ?? $models.find((m) => m.id === selectedModels[0]);
|
||||||
if (model) {
|
if (model) {
|
||||||
selectedToolIds = (model?.info?.meta?.toolIds ?? []).filter((id) =>
|
selectedToolIds = [
|
||||||
|
...new Set(
|
||||||
|
[...selectedToolIds, ...(model?.info?.meta?.toolIds ?? [])].filter((id) =>
|
||||||
$tools.find((t) => t.id === id)
|
$tools.find((t) => t.id === id)
|
||||||
);
|
)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setFilterIds = async () => {
|
||||||
|
if (selectedModels.length !== 1 && !atSelectedModel) {
|
||||||
|
selectedFilterIds = [];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -424,6 +439,7 @@
|
|||||||
prompt = '';
|
prompt = '';
|
||||||
files = [];
|
files = [];
|
||||||
selectedToolIds = [];
|
selectedToolIds = [];
|
||||||
|
selectedFilterIds = [];
|
||||||
webSearchEnabled = false;
|
webSearchEnabled = false;
|
||||||
imageGenerationEnabled = false;
|
imageGenerationEnabled = false;
|
||||||
codeInterpreterEnabled = false;
|
codeInterpreterEnabled = false;
|
||||||
@ -437,6 +453,7 @@
|
|||||||
prompt = input.prompt;
|
prompt = input.prompt;
|
||||||
files = input.files;
|
files = input.files;
|
||||||
selectedToolIds = input.selectedToolIds;
|
selectedToolIds = input.selectedToolIds;
|
||||||
|
selectedFilterIds = input.selectedFilterIds;
|
||||||
webSearchEnabled = input.webSearchEnabled;
|
webSearchEnabled = input.webSearchEnabled;
|
||||||
imageGenerationEnabled = input.imageGenerationEnabled;
|
imageGenerationEnabled = input.imageGenerationEnabled;
|
||||||
codeInterpreterEnabled = input.codeInterpreterEnabled;
|
codeInterpreterEnabled = input.codeInterpreterEnabled;
|
||||||
@ -881,6 +898,7 @@
|
|||||||
...(m.usage ? { usage: m.usage } : {}),
|
...(m.usage ? { usage: m.usage } : {}),
|
||||||
...(m.sources ? { sources: m.sources } : {})
|
...(m.sources ? { sources: m.sources } : {})
|
||||||
})),
|
})),
|
||||||
|
filter_ids: selectedFilterIds.length > 0 ? selectedFilterIds : undefined,
|
||||||
model_item: $models.find((m) => m.id === modelId),
|
model_item: $models.find((m) => m.id === modelId),
|
||||||
chat_id: chatId,
|
chat_id: chatId,
|
||||||
session_id: $socket?.id,
|
session_id: $socket?.id,
|
||||||
@ -1617,6 +1635,8 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
files: (files?.length ?? 0) > 0 ? files : undefined,
|
files: (files?.length ?? 0) > 0 ? files : undefined,
|
||||||
|
|
||||||
|
filter_ids: selectedFilterIds.length > 0 ? selectedFilterIds : undefined,
|
||||||
tool_ids: selectedToolIds.length > 0 ? selectedToolIds : undefined,
|
tool_ids: selectedToolIds.length > 0 ? selectedToolIds : undefined,
|
||||||
tool_servers: $toolServers,
|
tool_servers: $toolServers,
|
||||||
|
|
||||||
@ -2058,6 +2078,7 @@
|
|||||||
bind:prompt
|
bind:prompt
|
||||||
bind:autoScroll
|
bind:autoScroll
|
||||||
bind:selectedToolIds
|
bind:selectedToolIds
|
||||||
|
bind:selectedFilterIds
|
||||||
bind:imageGenerationEnabled
|
bind:imageGenerationEnabled
|
||||||
bind:codeInterpreterEnabled
|
bind:codeInterpreterEnabled
|
||||||
bind:webSearchEnabled
|
bind:webSearchEnabled
|
||||||
@ -2114,6 +2135,7 @@
|
|||||||
bind:prompt
|
bind:prompt
|
||||||
bind:autoScroll
|
bind:autoScroll
|
||||||
bind:selectedToolIds
|
bind:selectedToolIds
|
||||||
|
bind:selectedFilterIds
|
||||||
bind:imageGenerationEnabled
|
bind:imageGenerationEnabled
|
||||||
bind:codeInterpreterEnabled
|
bind:codeInterpreterEnabled
|
||||||
bind:webSearchEnabled
|
bind:webSearchEnabled
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
import VoiceRecording from './MessageInput/VoiceRecording.svelte';
|
import VoiceRecording from './MessageInput/VoiceRecording.svelte';
|
||||||
import FilesOverlay from './MessageInput/FilesOverlay.svelte';
|
import FilesOverlay from './MessageInput/FilesOverlay.svelte';
|
||||||
import Commands from './MessageInput/Commands.svelte';
|
import Commands from './MessageInput/Commands.svelte';
|
||||||
|
import ToolServersModal from './ToolServersModal.svelte';
|
||||||
|
|
||||||
import RichTextInput from '../common/RichTextInput.svelte';
|
import RichTextInput from '../common/RichTextInput.svelte';
|
||||||
import Tooltip from '../common/Tooltip.svelte';
|
import Tooltip from '../common/Tooltip.svelte';
|
||||||
@ -47,12 +48,12 @@
|
|||||||
import XMark from '../icons/XMark.svelte';
|
import XMark from '../icons/XMark.svelte';
|
||||||
import Headphone from '../icons/Headphone.svelte';
|
import Headphone from '../icons/Headphone.svelte';
|
||||||
import GlobeAlt from '../icons/GlobeAlt.svelte';
|
import GlobeAlt from '../icons/GlobeAlt.svelte';
|
||||||
import PhotoSolid from '../icons/PhotoSolid.svelte';
|
|
||||||
import Photo from '../icons/Photo.svelte';
|
import Photo from '../icons/Photo.svelte';
|
||||||
import CommandLine from '../icons/CommandLine.svelte';
|
|
||||||
import { KokoroWorker } from '$lib/workers/KokoroWorker';
|
|
||||||
import ToolServersModal from './ToolServersModal.svelte';
|
|
||||||
import Wrench from '../icons/Wrench.svelte';
|
import Wrench from '../icons/Wrench.svelte';
|
||||||
|
import CommandLine from '../icons/CommandLine.svelte';
|
||||||
|
import Sparkles from '../icons/Sparkles.svelte';
|
||||||
|
|
||||||
|
import { KokoroWorker } from '$lib/workers/KokoroWorker';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@ -79,6 +80,7 @@
|
|||||||
export let toolServers = [];
|
export let toolServers = [];
|
||||||
|
|
||||||
export let selectedToolIds = [];
|
export let selectedToolIds = [];
|
||||||
|
export let selectedFilterIds = [];
|
||||||
|
|
||||||
export let imageGenerationEnabled = false;
|
export let imageGenerationEnabled = false;
|
||||||
export let webSearchEnabled = false;
|
export let webSearchEnabled = false;
|
||||||
@ -88,6 +90,7 @@
|
|||||||
prompt,
|
prompt,
|
||||||
files: files.filter((file) => file.type !== 'image'),
|
files: files.filter((file) => file.type !== 'image'),
|
||||||
selectedToolIds,
|
selectedToolIds,
|
||||||
|
selectedFilterIds,
|
||||||
imageGenerationEnabled,
|
imageGenerationEnabled,
|
||||||
webSearchEnabled,
|
webSearchEnabled,
|
||||||
codeInterpreterEnabled
|
codeInterpreterEnabled
|
||||||
@ -113,10 +116,41 @@
|
|||||||
export let placeholder = '';
|
export let placeholder = '';
|
||||||
|
|
||||||
let visionCapableModels = [];
|
let visionCapableModels = [];
|
||||||
$: visionCapableModels = [...(atSelectedModel ? [atSelectedModel] : selectedModels)].filter(
|
$: visionCapableModels = (atSelectedModel?.id ? [atSelectedModel.id] : selectedModels).filter(
|
||||||
(model) => $models.find((m) => m.id === model)?.info?.meta?.capabilities?.vision ?? true
|
(model) => $models.find((m) => m.id === model)?.info?.meta?.capabilities?.vision ?? true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let fileUploadCapableModels = [];
|
||||||
|
$: fileUploadCapableModels = (atSelectedModel?.id ? [atSelectedModel.id] : selectedModels).filter(
|
||||||
|
(model) => $models.find((m) => m.id === model)?.info?.meta?.capabilities?.file_upload ?? true
|
||||||
|
);
|
||||||
|
|
||||||
|
let webSearchCapableModels = [];
|
||||||
|
$: webSearchCapableModels = (atSelectedModel?.id ? [atSelectedModel.id] : selectedModels).filter(
|
||||||
|
(model) => $models.find((m) => m.id === model)?.info?.meta?.capabilities?.web_search ?? true
|
||||||
|
);
|
||||||
|
|
||||||
|
let imageGenerationCapableModels = [];
|
||||||
|
$: imageGenerationCapableModels = (
|
||||||
|
atSelectedModel?.id ? [atSelectedModel.id] : selectedModels
|
||||||
|
).filter(
|
||||||
|
(model) =>
|
||||||
|
$models.find((m) => m.id === model)?.info?.meta?.capabilities?.image_generation ?? true
|
||||||
|
);
|
||||||
|
|
||||||
|
let codeInterpreterCapableModels = [];
|
||||||
|
$: codeInterpreterCapableModels = (
|
||||||
|
atSelectedModel?.id ? [atSelectedModel.id] : selectedModels
|
||||||
|
).filter(
|
||||||
|
(model) =>
|
||||||
|
$models.find((m) => m.id === model)?.info?.meta?.capabilities?.code_interpreter ?? true
|
||||||
|
);
|
||||||
|
|
||||||
|
let toggleFilters = [];
|
||||||
|
$: toggleFilters = (atSelectedModel?.id ? [atSelectedModel.id] : selectedModels)
|
||||||
|
.map((id) => ($models.find((model) => model.id === id) || {})?.filters ?? [])
|
||||||
|
.reduce((acc, filters) => acc.filter((f1) => filters.some((f2) => f2.id === f1.id)));
|
||||||
|
|
||||||
const scrollToBottom = () => {
|
const scrollToBottom = () => {
|
||||||
const element = document.getElementById('messages-container');
|
const element = document.getElementById('messages-container');
|
||||||
element.scrollTo({
|
element.scrollTo({
|
||||||
@ -355,7 +389,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FilesOverlay show={dragged} />
|
<FilesOverlay show={dragged} />
|
||||||
|
|
||||||
<ToolServersModal bind:show={showTools} {selectedToolIds} />
|
<ToolServersModal bind:show={showTools} {selectedToolIds} />
|
||||||
|
|
||||||
{#if loaded}
|
{#if loaded}
|
||||||
@ -581,12 +614,16 @@
|
|||||||
dismissible={true}
|
dismissible={true}
|
||||||
edit={true}
|
edit={true}
|
||||||
on:dismiss={async () => {
|
on:dismiss={async () => {
|
||||||
|
try {
|
||||||
if (file.type !== 'collection' && !file?.collection) {
|
if (file.type !== 'collection' && !file?.collection) {
|
||||||
if (file.id) {
|
if (file.id) {
|
||||||
// This will handle both file deletion and Chroma cleanup
|
// This will handle both file deletion and Chroma cleanup
|
||||||
await deleteFileById(localStorage.token, file.id);
|
await deleteFileById(localStorage.token, file.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting file:', error);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove from UI state
|
// Remove from UI state
|
||||||
files.splice(fileIdx, 1);
|
files.splice(fileIdx, 1);
|
||||||
@ -771,8 +808,11 @@
|
|||||||
console.log('Escape');
|
console.log('Escape');
|
||||||
atSelectedModel = undefined;
|
atSelectedModel = undefined;
|
||||||
selectedToolIds = [];
|
selectedToolIds = [];
|
||||||
|
selectedFilterIds = [];
|
||||||
|
|
||||||
webSearchEnabled = false;
|
webSearchEnabled = false;
|
||||||
imageGenerationEnabled = false;
|
imageGenerationEnabled = false;
|
||||||
|
codeInterpreterEnabled = false;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
on:paste={async (e) => {
|
on:paste={async (e) => {
|
||||||
@ -823,7 +863,7 @@
|
|||||||
id="chat-input"
|
id="chat-input"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
bind:this={chatInputElement}
|
bind:this={chatInputElement}
|
||||||
class="scrollbar-hidden bg-transparent dark:text-gray-100 outline-hidden w-full pt-3 px-1 resize-none"
|
class="scrollbar-hidden bg-transparent dark:text-gray-200 outline-hidden w-full pt-3 px-1 resize-none"
|
||||||
placeholder={placeholder ? placeholder : $i18n.t('Send a Message')}
|
placeholder={placeholder ? placeholder : $i18n.t('Send a Message')}
|
||||||
bind:value={prompt}
|
bind:value={prompt}
|
||||||
on:compositionstart={() => (isComposing = true)}
|
on:compositionstart={() => (isComposing = true)}
|
||||||
@ -869,7 +909,7 @@
|
|||||||
|
|
||||||
console.log(userMessageElement);
|
console.log(userMessageElement);
|
||||||
|
|
||||||
userMessageElement.scrollIntoView({ block: 'center' });
|
userMessageElement?.scrollIntoView({ block: 'center' });
|
||||||
editButton?.click();
|
editButton?.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -878,20 +918,38 @@
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
commandsElement.selectUp();
|
commandsElement.selectUp();
|
||||||
|
|
||||||
|
const container = document.getElementById('command-options-container');
|
||||||
const commandOptionButton = [
|
const commandOptionButton = [
|
||||||
...document.getElementsByClassName('selected-command-option-button')
|
...document.getElementsByClassName('selected-command-option-button')
|
||||||
]?.at(-1);
|
]?.at(-1);
|
||||||
commandOptionButton.scrollIntoView({ block: 'center' });
|
|
||||||
|
if (commandOptionButton && container) {
|
||||||
|
const elTop = commandOptionButton.offsetTop;
|
||||||
|
const elHeight = commandOptionButton.offsetHeight;
|
||||||
|
const containerHeight = container.clientHeight;
|
||||||
|
|
||||||
|
// Center the selected button in the container
|
||||||
|
container.scrollTop = elTop - containerHeight / 2 + elHeight / 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commandsContainerElement && e.key === 'ArrowDown') {
|
if (commandsContainerElement && e.key === 'ArrowDown') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
commandsElement.selectDown();
|
commandsElement.selectDown();
|
||||||
|
|
||||||
|
const container = document.getElementById('command-options-container');
|
||||||
const commandOptionButton = [
|
const commandOptionButton = [
|
||||||
...document.getElementsByClassName('selected-command-option-button')
|
...document.getElementsByClassName('selected-command-option-button')
|
||||||
]?.at(-1);
|
]?.at(-1);
|
||||||
commandOptionButton.scrollIntoView({ block: 'center' });
|
|
||||||
|
if (commandOptionButton && container) {
|
||||||
|
const elTop = commandOptionButton.offsetTop;
|
||||||
|
const elHeight = commandOptionButton.offsetHeight;
|
||||||
|
const containerHeight = container.clientHeight;
|
||||||
|
|
||||||
|
// Center the selected button in the container
|
||||||
|
container.scrollTop = elTop - containerHeight / 2 + elHeight / 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commandsContainerElement && e.key === 'Enter') {
|
if (commandsContainerElement && e.key === 'Enter') {
|
||||||
@ -939,8 +997,6 @@
|
|||||||
? (e.key === 'Enter' || e.keyCode === 13) && isCtrlPressed
|
? (e.key === 'Enter' || e.keyCode === 13) && isCtrlPressed
|
||||||
: (e.key === 'Enter' || e.keyCode === 13) && !e.shiftKey;
|
: (e.key === 'Enter' || e.keyCode === 13) && !e.shiftKey;
|
||||||
|
|
||||||
console.log('Enter pressed:', enterPressed);
|
|
||||||
|
|
||||||
if (enterPressed) {
|
if (enterPressed) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
@ -978,8 +1034,10 @@
|
|||||||
console.log('Escape');
|
console.log('Escape');
|
||||||
atSelectedModel = undefined;
|
atSelectedModel = undefined;
|
||||||
selectedToolIds = [];
|
selectedToolIds = [];
|
||||||
|
selectedFilterIds = [];
|
||||||
webSearchEnabled = false;
|
webSearchEnabled = false;
|
||||||
imageGenerationEnabled = false;
|
imageGenerationEnabled = false;
|
||||||
|
codeInterpreterEnabled = false;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
rows="1"
|
rows="1"
|
||||||
@ -1037,6 +1095,8 @@
|
|||||||
<div class="ml-1 self-end flex items-center flex-1 max-w-[80%] gap-0.5">
|
<div class="ml-1 self-end flex items-center flex-1 max-w-[80%] gap-0.5">
|
||||||
<InputMenu
|
<InputMenu
|
||||||
bind:selectedToolIds
|
bind:selectedToolIds
|
||||||
|
selectedModels={atSelectedModel ? [atSelectedModel.id] : selectedModels}
|
||||||
|
{fileUploadCapableModels}
|
||||||
{screenCaptureHandler}
|
{screenCaptureHandler}
|
||||||
{inputFilesHandler}
|
{inputFilesHandler}
|
||||||
uploadFilesHandler={() => {
|
uploadFilesHandler={() => {
|
||||||
@ -1127,7 +1187,48 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if $_user}
|
{#if $_user}
|
||||||
{#if $config?.features?.enable_web_search && ($_user.role === 'admin' || $_user?.permissions?.features?.web_search)}
|
{#each toggleFilters as filter, filterIdx (filter.id)}
|
||||||
|
<Tooltip content={filter?.description} placement="top">
|
||||||
|
<button
|
||||||
|
on:click|preventDefault={() => {
|
||||||
|
if (selectedFilterIds.includes(filter.id)) {
|
||||||
|
selectedFilterIds = selectedFilterIds.filter(
|
||||||
|
(id) => id !== filter.id
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
selectedFilterIds = [...selectedFilterIds, filter.id];
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden border {selectedFilterIds.includes(
|
||||||
|
filter.id
|
||||||
|
)
|
||||||
|
? 'bg-gray-50 dark:bg-gray-400/10 border-gray-100 dark:border-gray-700 text-gray-600 dark:text-gray-400'
|
||||||
|
: 'bg-transparent border-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 '} capitalize"
|
||||||
|
>
|
||||||
|
{#if filter?.icon}
|
||||||
|
<div class="size-5 items-center flex justify-center">
|
||||||
|
<img
|
||||||
|
src={filter.icon}
|
||||||
|
class="size-4.5 {filter.icon.includes('svg')
|
||||||
|
? 'dark:invert-[80%]'
|
||||||
|
: ''}"
|
||||||
|
style="fill: currentColor;"
|
||||||
|
alt={filter.name}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<Sparkles className="size-5" strokeWidth="1.75" />
|
||||||
|
{/if}
|
||||||
|
<span
|
||||||
|
class="hidden @xl:block whitespace-nowrap overflow-hidden text-ellipsis translate-y-[0.5px]"
|
||||||
|
>{filter?.name}</span
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
{#if (atSelectedModel?.id ? [atSelectedModel.id] : selectedModels).length === webSearchCapableModels.length && $config?.features?.enable_web_search && ($_user.role === 'admin' || $_user?.permissions?.features?.web_search)}
|
||||||
<Tooltip content={$i18n.t('Search the internet')} placement="top">
|
<Tooltip content={$i18n.t('Search the internet')} placement="top">
|
||||||
<button
|
<button
|
||||||
on:click|preventDefault={() => (webSearchEnabled = !webSearchEnabled)}
|
on:click|preventDefault={() => (webSearchEnabled = !webSearchEnabled)}
|
||||||
@ -1135,7 +1236,7 @@
|
|||||||
class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden border {webSearchEnabled ||
|
class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden border {webSearchEnabled ||
|
||||||
($settings?.webSearch ?? false) === 'always'
|
($settings?.webSearch ?? false) === 'always'
|
||||||
? 'bg-blue-100 dark:bg-blue-500/20 border-blue-400/20 text-blue-500 dark:text-blue-400'
|
? 'bg-blue-100 dark:bg-blue-500/20 border-blue-400/20 text-blue-500 dark:text-blue-400'
|
||||||
: 'bg-transparent border-transparent text-gray-600 dark:text-gray-300 border-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800'}"
|
: 'bg-transparent border-transparent text-gray-600 dark:text-gray-300 border-gray-200 hover:bg-gray-50 dark:hover:bg-gray-800'}"
|
||||||
>
|
>
|
||||||
<GlobeAlt className="size-5" strokeWidth="1.75" />
|
<GlobeAlt className="size-5" strokeWidth="1.75" />
|
||||||
<span
|
<span
|
||||||
@ -1146,7 +1247,7 @@
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if $config?.features?.enable_image_generation && ($_user.role === 'admin' || $_user?.permissions?.features?.image_generation)}
|
{#if (atSelectedModel?.id ? [atSelectedModel.id] : selectedModels).length === imageGenerationCapableModels.length && $config?.features?.enable_image_generation && ($_user.role === 'admin' || $_user?.permissions?.features?.image_generation)}
|
||||||
<Tooltip content={$i18n.t('Generate an image')} placement="top">
|
<Tooltip content={$i18n.t('Generate an image')} placement="top">
|
||||||
<button
|
<button
|
||||||
on:click|preventDefault={() =>
|
on:click|preventDefault={() =>
|
||||||
@ -1154,7 +1255,7 @@
|
|||||||
type="button"
|
type="button"
|
||||||
class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden border {imageGenerationEnabled
|
class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden border {imageGenerationEnabled
|
||||||
? 'bg-gray-50 dark:bg-gray-400/10 border-gray-100 dark:border-gray-700 text-gray-600 dark:text-gray-400'
|
? 'bg-gray-50 dark:bg-gray-400/10 border-gray-100 dark:border-gray-700 text-gray-600 dark:text-gray-400'
|
||||||
: 'bg-transparent border-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 '}"
|
: 'bg-transparent border-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 '}"
|
||||||
>
|
>
|
||||||
<Photo className="size-5" strokeWidth="1.75" />
|
<Photo className="size-5" strokeWidth="1.75" />
|
||||||
<span
|
<span
|
||||||
@ -1165,7 +1266,7 @@
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if $config?.features?.enable_code_interpreter && ($_user.role === 'admin' || $_user?.permissions?.features?.code_interpreter)}
|
{#if (atSelectedModel?.id ? [atSelectedModel.id] : selectedModels).length === codeInterpreterCapableModels.length && $config?.features?.enable_code_interpreter && ($_user.role === 'admin' || $_user?.permissions?.features?.code_interpreter)}
|
||||||
<Tooltip content={$i18n.t('Execute code for analysis')} placement="top">
|
<Tooltip content={$i18n.t('Execute code for analysis')} placement="top">
|
||||||
<button
|
<button
|
||||||
on:click|preventDefault={() =>
|
on:click|preventDefault={() =>
|
||||||
@ -1173,7 +1274,7 @@
|
|||||||
type="button"
|
type="button"
|
||||||
class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden border {codeInterpreterEnabled
|
class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden border {codeInterpreterEnabled
|
||||||
? 'bg-gray-50 dark:bg-gray-400/10 border-gray-100 dark:border-gray-700 text-gray-600 dark:text-gray-400 '
|
? 'bg-gray-50 dark:bg-gray-400/10 border-gray-100 dark:border-gray-700 text-gray-600 dark:text-gray-400 '
|
||||||
: 'bg-transparent border-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 '}"
|
: 'bg-transparent border-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 '}"
|
||||||
>
|
>
|
||||||
<CommandLine className="size-5" strokeWidth="1.75" />
|
<CommandLine className="size-5" strokeWidth="1.75" />
|
||||||
<span
|
<span
|
||||||
|
@ -170,10 +170,11 @@
|
|||||||
class="px-2 mb-2 text-left w-full absolute bottom-0 left-0 right-0 z-10"
|
class="px-2 mb-2 text-left w-full absolute bottom-0 left-0 right-0 z-10"
|
||||||
>
|
>
|
||||||
<div class="flex w-full rounded-xl border border-gray-100 dark:border-gray-850">
|
<div class="flex w-full rounded-xl border border-gray-100 dark:border-gray-850">
|
||||||
|
<div class="flex flex-col w-full rounded-xl bg-white dark:bg-gray-900 dark:text-gray-100">
|
||||||
<div
|
<div
|
||||||
class="max-h-60 flex flex-col w-full rounded-xl bg-white dark:bg-gray-900 dark:text-gray-100"
|
class="m-1 overflow-y-auto p-1 rounded-r-xl space-y-0.5 scrollbar-hidden max-h-60"
|
||||||
|
id="command-options-container"
|
||||||
>
|
>
|
||||||
<div class="m-1 overflow-y-auto p-1 rounded-r-xl space-y-0.5 scrollbar-hidden">
|
|
||||||
{#each filteredItems as item, idx}
|
{#each filteredItems as item, idx}
|
||||||
<button
|
<button
|
||||||
class=" px-3 py-1.5 rounded-xl w-full text-left flex justify-between items-center {idx ===
|
class=" px-3 py-1.5 rounded-xl w-full text-left flex justify-between items-center {idx ===
|
||||||
|
@ -71,10 +71,11 @@
|
|||||||
class="px-2 mb-2 text-left w-full absolute bottom-0 left-0 right-0 z-10"
|
class="px-2 mb-2 text-left w-full absolute bottom-0 left-0 right-0 z-10"
|
||||||
>
|
>
|
||||||
<div class="flex w-full rounded-xl border border-gray-100 dark:border-gray-850">
|
<div class="flex w-full rounded-xl border border-gray-100 dark:border-gray-850">
|
||||||
|
<div class="flex flex-col w-full rounded-xl bg-white dark:bg-gray-900 dark:text-gray-100">
|
||||||
<div
|
<div
|
||||||
class="max-h-60 flex flex-col w-full rounded-xl bg-white dark:bg-gray-900 dark:text-gray-100"
|
class="m-1 overflow-y-auto p-1 rounded-r-lg space-y-0.5 scrollbar-hidden max-h-60"
|
||||||
|
id="command-options-container"
|
||||||
>
|
>
|
||||||
<div class="m-1 overflow-y-auto p-1 rounded-r-lg space-y-0.5 scrollbar-hidden">
|
|
||||||
{#each filteredItems as model, modelIdx}
|
{#each filteredItems as model, modelIdx}
|
||||||
<button
|
<button
|
||||||
class="px-3 py-1.5 rounded-xl w-full text-left {modelIdx === selectedIdx
|
class="px-3 py-1.5 rounded-xl w-full text-left {modelIdx === selectedIdx
|
||||||
|
@ -180,10 +180,11 @@
|
|||||||
class="px-2 mb-2 text-left w-full absolute bottom-0 left-0 right-0 z-10"
|
class="px-2 mb-2 text-left w-full absolute bottom-0 left-0 right-0 z-10"
|
||||||
>
|
>
|
||||||
<div class="flex w-full rounded-xl border border-gray-100 dark:border-gray-850">
|
<div class="flex w-full rounded-xl border border-gray-100 dark:border-gray-850">
|
||||||
|
<div class="flex flex-col w-full rounded-xl bg-white dark:bg-gray-900 dark:text-gray-100">
|
||||||
<div
|
<div
|
||||||
class="max-h-60 flex flex-col w-full rounded-xl bg-white dark:bg-gray-900 dark:text-gray-100"
|
class="m-1 overflow-y-auto p-1 space-y-0.5 scrollbar-hidden max-h-60"
|
||||||
|
id="command-options-container"
|
||||||
>
|
>
|
||||||
<div class="m-1 overflow-y-auto p-1 space-y-0.5 scrollbar-hidden">
|
|
||||||
{#each filteredPrompts as prompt, promptIdx}
|
{#each filteredPrompts as prompt, promptIdx}
|
||||||
<button
|
<button
|
||||||
class=" px-3 py-1.5 rounded-xl w-full text-left {promptIdx === selectedPromptIdx
|
class=" px-3 py-1.5 rounded-xl w-full text-left {promptIdx === selectedPromptIdx
|
||||||
|
@ -20,6 +20,11 @@
|
|||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
|
export let selectedToolIds: string[] = [];
|
||||||
|
|
||||||
|
export let selectedModels: string[] = [];
|
||||||
|
export let fileUploadCapableModels: string[] = [];
|
||||||
|
|
||||||
export let screenCaptureHandler: Function;
|
export let screenCaptureHandler: Function;
|
||||||
export let uploadFilesHandler: Function;
|
export let uploadFilesHandler: Function;
|
||||||
export let inputFilesHandler: Function;
|
export let inputFilesHandler: Function;
|
||||||
@ -27,8 +32,6 @@
|
|||||||
export let uploadGoogleDriveHandler: Function;
|
export let uploadGoogleDriveHandler: Function;
|
||||||
export let uploadOneDriveHandler: Function;
|
export let uploadOneDriveHandler: Function;
|
||||||
|
|
||||||
export let selectedToolIds: string[] = [];
|
|
||||||
|
|
||||||
export let onClose: Function;
|
export let onClose: Function;
|
||||||
|
|
||||||
let tools = {};
|
let tools = {};
|
||||||
@ -40,7 +43,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let fileUploadEnabled = true;
|
let fileUploadEnabled = true;
|
||||||
$: fileUploadEnabled = $user?.role === 'admin' || $user?.permissions?.chat?.file_upload;
|
$: fileUploadEnabled =
|
||||||
|
fileUploadCapableModels.length === selectedModels.length &&
|
||||||
|
($user?.role === 'admin' || $user?.permissions?.chat?.file_upload);
|
||||||
|
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
if ($_tools === null) {
|
if ($_tools === null) {
|
||||||
@ -169,7 +174,11 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={!fileUploadEnabled ? $i18n.t('You do not have permission to upload files.') : ''}
|
content={fileUploadCapableModels.length !== selectedModels.length
|
||||||
|
? $i18n.t('Model(s) do not support file upload')
|
||||||
|
: !fileUploadEnabled
|
||||||
|
? $i18n.t('You do not have permission to upload files.')
|
||||||
|
: ''}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
>
|
>
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Item
|
||||||
@ -196,7 +205,11 @@
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={!fileUploadEnabled ? $i18n.t('You do not have permission to upload files.') : ''}
|
content={fileUploadCapableModels.length !== selectedModels.length
|
||||||
|
? $i18n.t('Model(s) do not support file upload')
|
||||||
|
: !fileUploadEnabled
|
||||||
|
? $i18n.t('You do not have permission to upload files.')
|
||||||
|
: ''}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
>
|
>
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Item
|
||||||
@ -214,6 +227,7 @@
|
|||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
|
{#if fileUploadEnabled}
|
||||||
{#if $config?.features?.enable_google_drive_integration}
|
{#if $config?.features?.enable_google_drive_integration}
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Item
|
||||||
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl"
|
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-xl"
|
||||||
@ -256,7 +270,12 @@
|
|||||||
<DropdownMenu.SubTrigger
|
<DropdownMenu.SubTrigger
|
||||||
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-xl w-full"
|
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-xl w-full"
|
||||||
>
|
>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" class="w-5 h-5" fill="none">
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 32 32"
|
||||||
|
class="w-5 h-5"
|
||||||
|
fill="none"
|
||||||
|
>
|
||||||
<mask
|
<mask
|
||||||
id="mask0_87_7796"
|
id="mask0_87_7796"
|
||||||
style="mask-type:alpha"
|
style="mask-type:alpha"
|
||||||
@ -366,6 +385,7 @@
|
|||||||
</DropdownMenu.SubContent>
|
</DropdownMenu.SubContent>
|
||||||
</DropdownMenu.Sub>
|
</DropdownMenu.Sub>
|
||||||
{/if}
|
{/if}
|
||||||
|
{/if}
|
||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
</div>
|
</div>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
@ -17,16 +17,19 @@
|
|||||||
import ChevronUp from '$lib/components/icons/ChevronUp.svelte';
|
import ChevronUp from '$lib/components/icons/ChevronUp.svelte';
|
||||||
import ChevronUpDown from '$lib/components/icons/ChevronUpDown.svelte';
|
import ChevronUpDown from '$lib/components/icons/ChevronUpDown.svelte';
|
||||||
import CommandLine from '$lib/components/icons/CommandLine.svelte';
|
import CommandLine from '$lib/components/icons/CommandLine.svelte';
|
||||||
|
import Cube from '$lib/components/icons/Cube.svelte';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
export let id = '';
|
export let id = '';
|
||||||
|
|
||||||
export let onSave = (e) => {};
|
export let onSave = (e) => {};
|
||||||
export let onCode = (e) => {};
|
export let onUpdate = (e) => {};
|
||||||
|
export let onPreview = (e) => {};
|
||||||
|
|
||||||
export let save = false;
|
export let save = false;
|
||||||
export let run = true;
|
export let run = true;
|
||||||
|
export let preview = false;
|
||||||
export let collapsed = false;
|
export let collapsed = false;
|
||||||
|
|
||||||
export let token;
|
export let token;
|
||||||
@ -88,6 +91,10 @@
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const previewCode = () => {
|
||||||
|
onPreview(code);
|
||||||
|
};
|
||||||
|
|
||||||
const checkPythonCode = (str) => {
|
const checkPythonCode = (str) => {
|
||||||
// Check if the string contains typical Python syntax characters
|
// Check if the string contains typical Python syntax characters
|
||||||
const pythonSyntax = [
|
const pythonSyntax = [
|
||||||
@ -333,6 +340,8 @@
|
|||||||
await drawMermaidDiagram();
|
await drawMermaidDiagram();
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onUpdate(token);
|
||||||
};
|
};
|
||||||
|
|
||||||
$: if (token) {
|
$: if (token) {
|
||||||
@ -345,8 +354,6 @@
|
|||||||
render();
|
render();
|
||||||
}
|
}
|
||||||
|
|
||||||
$: onCode({ lang, code });
|
|
||||||
|
|
||||||
$: if (attributes) {
|
$: if (attributes) {
|
||||||
onAttributesUpdate();
|
onAttributesUpdate();
|
||||||
}
|
}
|
||||||
@ -379,10 +386,10 @@
|
|||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
console.log('codeblock', lang, code);
|
console.log('codeblock', lang, code);
|
||||||
|
if (token) {
|
||||||
if (lang) {
|
onUpdate(token);
|
||||||
onCode({ lang, code });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.documentElement.classList.contains('dark')) {
|
if (document.documentElement.classList.contains('dark')) {
|
||||||
mermaid.initialize({
|
mermaid.initialize({
|
||||||
startOnLoad: true,
|
startOnLoad: true,
|
||||||
@ -430,7 +437,7 @@
|
|||||||
class="flex gap-1 items-center bg-none border-none bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition rounded-md px-1.5 py-0.5"
|
class="flex gap-1 items-center bg-none border-none bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition rounded-md px-1.5 py-0.5"
|
||||||
on:click={collapseCodeBlock}
|
on:click={collapseCodeBlock}
|
||||||
>
|
>
|
||||||
<div>
|
<div class=" -translate-y-[0.5px]">
|
||||||
<ChevronUpDown className="size-3" />
|
<ChevronUpDown className="size-3" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -439,6 +446,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{#if preview && ['html', 'svg'].includes(lang)}
|
||||||
|
<button
|
||||||
|
class="flex gap-1 items-center run-code-button bg-none border-none bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition rounded-md px-1.5 py-0.5"
|
||||||
|
on:click={previewCode}
|
||||||
|
>
|
||||||
|
<div class=" -translate-y-[0.5px]">
|
||||||
|
<Cube className="size-3" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{$i18n.t('Preview')}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if ($config?.features?.enable_code_execution ?? true) && (lang.toLowerCase() === 'python' || lang.toLowerCase() === 'py' || (lang === '' && checkPythonCode(code)))}
|
{#if ($config?.features?.enable_code_execution ?? true) && (lang.toLowerCase() === 'python' || lang.toLowerCase() === 'py' || (lang === '' && checkPythonCode(code)))}
|
||||||
{#if executing}
|
{#if executing}
|
||||||
<div class="run-code-button bg-none border-none p-1 cursor-not-allowed">
|
<div class="run-code-button bg-none border-none p-1 cursor-not-allowed">
|
||||||
@ -453,7 +475,7 @@
|
|||||||
executePython(code);
|
executePython(code);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>
|
<div class=" -translate-y-[0.5px]">
|
||||||
<CommandLine className="size-3" />
|
<CommandLine className="size-3" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onDestroy, onMount, tick, getContext, createEventDispatcher } from 'svelte';
|
import { onDestroy, onMount, tick, getContext } from 'svelte';
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
|
|
||||||
import Markdown from './Markdown.svelte';
|
import Markdown from './Markdown.svelte';
|
||||||
import { chatId, mobile, settings, showArtifacts, showControls, showOverview } from '$lib/stores';
|
import {
|
||||||
|
artifactCode,
|
||||||
|
chatId,
|
||||||
|
mobile,
|
||||||
|
settings,
|
||||||
|
showArtifacts,
|
||||||
|
showControls,
|
||||||
|
showOverview
|
||||||
|
} from '$lib/stores';
|
||||||
import FloatingButtons from '../ContentRenderer/FloatingButtons.svelte';
|
import FloatingButtons from '../ContentRenderer/FloatingButtons.svelte';
|
||||||
import { createMessagesList } from '$lib/utils';
|
import { createMessagesList } from '$lib/utils';
|
||||||
|
|
||||||
@ -15,8 +22,10 @@
|
|||||||
export let sources = null;
|
export let sources = null;
|
||||||
|
|
||||||
export let save = false;
|
export let save = false;
|
||||||
|
export let preview = false;
|
||||||
export let floatingButtons = true;
|
export let floatingButtons = true;
|
||||||
|
|
||||||
|
export let onSave = () => {};
|
||||||
export let onSourceClick = () => {};
|
export let onSourceClick = () => {};
|
||||||
export let onTaskClick = () => {};
|
export let onTaskClick = () => {};
|
||||||
|
|
||||||
@ -122,6 +131,7 @@
|
|||||||
{content}
|
{content}
|
||||||
{model}
|
{model}
|
||||||
{save}
|
{save}
|
||||||
|
{preview}
|
||||||
sourceIds={(sources ?? []).reduce((acc, s) => {
|
sourceIds={(sources ?? []).reduce((acc, s) => {
|
||||||
let ids = [];
|
let ids = [];
|
||||||
s.document.forEach((document, index) => {
|
s.document.forEach((document, index) => {
|
||||||
@ -154,11 +164,9 @@
|
|||||||
}, [])}
|
}, [])}
|
||||||
{onSourceClick}
|
{onSourceClick}
|
||||||
{onTaskClick}
|
{onTaskClick}
|
||||||
onUpdate={(value) => {
|
{onSave}
|
||||||
dispatch('update', value);
|
onUpdate={(token) => {
|
||||||
}}
|
const { lang, text: code } = token;
|
||||||
onCode={(value) => {
|
|
||||||
const { lang, code } = value;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
($settings?.detectArtifacts ?? true) &&
|
($settings?.detectArtifacts ?? true) &&
|
||||||
@ -170,6 +178,13 @@
|
|||||||
showControls.set(true);
|
showControls.set(true);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
onPreview={async (value) => {
|
||||||
|
console.log('Preview', value);
|
||||||
|
await artifactCode.set(value);
|
||||||
|
await showControls.set(true);
|
||||||
|
await showArtifacts.set(true);
|
||||||
|
await showOverview.set(false);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -12,11 +12,14 @@
|
|||||||
export let content;
|
export let content;
|
||||||
export let model = null;
|
export let model = null;
|
||||||
export let save = false;
|
export let save = false;
|
||||||
|
export let preview = false;
|
||||||
|
|
||||||
export let sourceIds = [];
|
export let sourceIds = [];
|
||||||
|
|
||||||
|
export let onSave = () => {};
|
||||||
export let onUpdate = () => {};
|
export let onUpdate = () => {};
|
||||||
export let onCode = () => {};
|
|
||||||
|
export let onPreview = () => {};
|
||||||
|
|
||||||
export let onSourceClick = () => {};
|
export let onSourceClick = () => {};
|
||||||
export let onTaskClick = () => {};
|
export let onTaskClick = () => {};
|
||||||
@ -40,5 +43,15 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#key id}
|
{#key id}
|
||||||
<MarkdownTokens {tokens} {id} {save} {onTaskClick} {onSourceClick} {onUpdate} {onCode} />
|
<MarkdownTokens
|
||||||
|
{tokens}
|
||||||
|
{id}
|
||||||
|
{save}
|
||||||
|
{preview}
|
||||||
|
{onTaskClick}
|
||||||
|
{onSourceClick}
|
||||||
|
{onSave}
|
||||||
|
{onUpdate}
|
||||||
|
{onPreview}
|
||||||
|
/>
|
||||||
{/key}
|
{/key}
|
||||||
|
@ -29,9 +29,11 @@
|
|||||||
export let attributes = {};
|
export let attributes = {};
|
||||||
|
|
||||||
export let save = false;
|
export let save = false;
|
||||||
|
export let preview = false;
|
||||||
|
|
||||||
|
export let onSave: Function = () => {};
|
||||||
export let onUpdate: Function = () => {};
|
export let onUpdate: Function = () => {};
|
||||||
export let onCode: Function = () => {};
|
export let onPreview: Function = () => {};
|
||||||
|
|
||||||
export let onTaskClick: Function = () => {};
|
export let onTaskClick: Function = () => {};
|
||||||
export let onSourceClick: Function = () => {};
|
export let onSourceClick: Function = () => {};
|
||||||
@ -95,14 +97,16 @@
|
|||||||
code={token?.text ?? ''}
|
code={token?.text ?? ''}
|
||||||
{attributes}
|
{attributes}
|
||||||
{save}
|
{save}
|
||||||
{onCode}
|
{preview}
|
||||||
onSave={(value) => {
|
onSave={(value) => {
|
||||||
onUpdate({
|
onSave({
|
||||||
raw: token.raw,
|
raw: token.raw,
|
||||||
oldContent: token.text,
|
oldContent: token.text,
|
||||||
newContent: value
|
newContent: value
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
{onUpdate}
|
||||||
|
{onPreview}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
{token.text}
|
{token.text}
|
||||||
|
@ -157,6 +157,10 @@
|
|||||||
const copyToClipboard = async (text) => {
|
const copyToClipboard = async (text) => {
|
||||||
text = removeAllDetails(text);
|
text = removeAllDetails(text);
|
||||||
|
|
||||||
|
if (($config?.ui?.response_watermark ?? '').trim() !== '') {
|
||||||
|
text = `${text}\n\n${$config?.ui?.response_watermark}`;
|
||||||
|
}
|
||||||
|
|
||||||
const res = await _copyToClipboard(text, $settings?.copyFormatted ?? false);
|
const res = await _copyToClipboard(text, $settings?.copyFormatted ?? false);
|
||||||
if (res) {
|
if (res) {
|
||||||
toast.success($i18n.t('Copying to clipboard was successful!'));
|
toast.success($i18n.t('Copying to clipboard was successful!'));
|
||||||
@ -560,17 +564,30 @@
|
|||||||
await tick();
|
await tick();
|
||||||
if (buttonsContainerElement) {
|
if (buttonsContainerElement) {
|
||||||
console.log(buttonsContainerElement);
|
console.log(buttonsContainerElement);
|
||||||
buttonsContainerElement.addEventListener('wheel', function (event) {
|
|
||||||
// console.log(event.deltaY);
|
|
||||||
|
|
||||||
|
buttonsContainerElement.addEventListener('wheel', function (event) {
|
||||||
|
if (buttonsContainerElement.scrollWidth <= buttonsContainerElement.clientWidth) {
|
||||||
|
// If the container is not scrollable, horizontal scroll
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (event.deltaY !== 0) {
|
if (event.deltaY !== 0) {
|
||||||
// Adjust horizontal scroll position based on vertical scroll
|
// Adjust horizontal scroll position based on vertical scroll
|
||||||
buttonsContainerElement.scrollLeft += event.deltaY;
|
buttonsContainerElement.scrollLeft += event.deltaY;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let screenReaderDiv: HTMLDivElement;
|
||||||
|
|
||||||
|
$: if (message.done) {
|
||||||
|
if (screenReaderDiv) {
|
||||||
|
screenReaderDiv.textContent = message.content;
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<DeleteConfirmDialog
|
<DeleteConfirmDialog
|
||||||
@ -581,6 +598,10 @@
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div bind:this={screenReaderDiv} aria-live="polite" class="sr-only">
|
||||||
|
{message.done ? message.content : ''}
|
||||||
|
</div>
|
||||||
|
|
||||||
{#key message.id}
|
{#key message.id}
|
||||||
<div
|
<div
|
||||||
class=" flex w-full message-{message.id}"
|
class=" flex w-full message-{message.id}"
|
||||||
@ -785,6 +806,7 @@
|
|||||||
sources={message.sources}
|
sources={message.sources}
|
||||||
floatingButtons={message?.done && !readOnly}
|
floatingButtons={message?.done && !readOnly}
|
||||||
save={!readOnly}
|
save={!readOnly}
|
||||||
|
preview={!readOnly}
|
||||||
{model}
|
{model}
|
||||||
onTaskClick={async (e) => {
|
onTaskClick={async (e) => {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
@ -819,28 +841,13 @@
|
|||||||
onAddMessages={({ modelId, parentId, messages }) => {
|
onAddMessages={({ modelId, parentId, messages }) => {
|
||||||
addMessages({ modelId, parentId, messages });
|
addMessages({ modelId, parentId, messages });
|
||||||
}}
|
}}
|
||||||
on:update={(e) => {
|
onSave={({ raw, oldContent, newContent }) => {
|
||||||
const { raw, oldContent, newContent } = e.detail;
|
|
||||||
|
|
||||||
history.messages[message.id].content = history.messages[
|
history.messages[message.id].content = history.messages[
|
||||||
message.id
|
message.id
|
||||||
].content.replace(raw, raw.replace(oldContent, newContent));
|
].content.replace(raw, raw.replace(oldContent, newContent));
|
||||||
|
|
||||||
updateChat();
|
updateChat();
|
||||||
}}
|
}}
|
||||||
on:select={(e) => {
|
|
||||||
const { type, content } = e.detail;
|
|
||||||
|
|
||||||
if (type === 'explain') {
|
|
||||||
submitMessage(
|
|
||||||
message.id,
|
|
||||||
`Explain this section to me in more detail\n\n\`\`\`\n${content}\n\`\`\``
|
|
||||||
);
|
|
||||||
} else if (type === 'ask') {
|
|
||||||
const input = e.detail?.input ?? '';
|
|
||||||
submitMessage(message.id, `\`\`\`\n${content}\n\`\`\`\n${input}`);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@ -1394,11 +1401,11 @@
|
|||||||
actionMessage(action.id, message);
|
actionMessage(action.id, message);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{#if action.icon_url}
|
{#if action?.icon}
|
||||||
<div class="size-4">
|
<div class="size-4">
|
||||||
<img
|
<img
|
||||||
src={action.icon_url}
|
src={action.icon}
|
||||||
class="w-4 h-4 {action.icon_url.includes('svg')
|
class="w-4 h-4 {action.icon.includes('svg')
|
||||||
? 'dark:invert-[80%]'
|
? 'dark:invert-[80%]'
|
||||||
: ''}"
|
: ''}"
|
||||||
style="fill: currentColor;"
|
style="fill: currentColor;"
|
||||||
|
@ -114,7 +114,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if showSetDefault}
|
{#if showSetDefault}
|
||||||
<div class=" absolute text-left mt-[1px] ml-1 text-[0.7rem] text-gray-500 font-primary">
|
<div
|
||||||
|
class="absolute text-left mt-[1px] ml-1 text-[0.7rem] text-gray-600 dark:text-gray-400 font-primary"
|
||||||
|
>
|
||||||
<button on:click={saveDefaultModel}> {$i18n.t('Set as default')}</button>
|
<button on:click={saveDefaultModel}> {$i18n.t('Set as default')}</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -100,10 +100,10 @@
|
|||||||
.filter((item) => {
|
.filter((item) => {
|
||||||
if (selectedConnectionType === '') {
|
if (selectedConnectionType === '') {
|
||||||
return true;
|
return true;
|
||||||
} else if (selectedConnectionType === 'ollama') {
|
} else if (selectedConnectionType === 'local') {
|
||||||
return item.model?.owned_by === 'ollama';
|
return item.model?.connection_type === 'local';
|
||||||
} else if (selectedConnectionType === 'openai') {
|
} else if (selectedConnectionType === 'external') {
|
||||||
return item.model?.owned_by === 'openai';
|
return item.model?.connection_type === 'external';
|
||||||
} else if (selectedConnectionType === 'direct') {
|
} else if (selectedConnectionType === 'direct') {
|
||||||
return item.model?.direct;
|
return item.model?.direct;
|
||||||
}
|
}
|
||||||
@ -118,10 +118,10 @@
|
|||||||
.filter((item) => {
|
.filter((item) => {
|
||||||
if (selectedConnectionType === '') {
|
if (selectedConnectionType === '') {
|
||||||
return true;
|
return true;
|
||||||
} else if (selectedConnectionType === 'ollama') {
|
} else if (selectedConnectionType === 'local') {
|
||||||
return item.model?.owned_by === 'ollama';
|
return item.model?.connection_type === 'local';
|
||||||
} else if (selectedConnectionType === 'openai') {
|
} else if (selectedConnectionType === 'external') {
|
||||||
return item.model?.owned_by === 'openai';
|
return item.model?.connection_type === 'external';
|
||||||
} else if (selectedConnectionType === 'direct') {
|
} else if (selectedConnectionType === 'direct') {
|
||||||
return item.model?.direct;
|
return item.model?.direct;
|
||||||
}
|
}
|
||||||
@ -393,7 +393,7 @@
|
|||||||
class="flex gap-1 w-fit text-center text-sm font-medium rounded-full bg-transparent px-1.5 pb-0.5"
|
class="flex gap-1 w-fit text-center text-sm font-medium rounded-full bg-transparent px-1.5 pb-0.5"
|
||||||
bind:this={tagsContainerElement}
|
bind:this={tagsContainerElement}
|
||||||
>
|
>
|
||||||
{#if (items.find((item) => item.model?.owned_by === 'ollama') && items.find((item) => item.model?.owned_by === 'openai')) || items.find((item) => item.model?.direct) || tags.length > 0}
|
{#if (items.find((item) => item.model?.connection_type === 'local') && items.find((item) => item.model?.connection_type === 'external')) || items.find((item) => item.model?.direct) || tags.length > 0}
|
||||||
<button
|
<button
|
||||||
class="min-w-fit outline-none p-1.5 {selectedTag === '' &&
|
class="min-w-fit outline-none p-1.5 {selectedTag === '' &&
|
||||||
selectedConnectionType === ''
|
selectedConnectionType === ''
|
||||||
@ -408,25 +408,25 @@
|
|||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if items.find((item) => item.model?.owned_by === 'ollama') && items.find((item) => item.model?.owned_by === 'openai')}
|
{#if items.find((item) => item.model?.connection_type === 'local') && items.find((item) => item.model?.connection_type === 'external')}
|
||||||
<button
|
<button
|
||||||
class="min-w-fit outline-none p-1.5 {selectedConnectionType === 'ollama'
|
class="min-w-fit outline-none p-1.5 {selectedConnectionType === 'local'
|
||||||
? ''
|
? ''
|
||||||
: 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition capitalize"
|
: 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition capitalize"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
selectedTag = '';
|
selectedTag = '';
|
||||||
selectedConnectionType = 'ollama';
|
selectedConnectionType = 'local';
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{$i18n.t('Local')}
|
{$i18n.t('Local')}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="min-w-fit outline-none p-1.5 {selectedConnectionType === 'openai'
|
class="min-w-fit outline-none p-1.5 {selectedConnectionType === 'external'
|
||||||
? ''
|
? ''
|
||||||
: 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition capitalize"
|
: 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition capitalize"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
selectedTag = '';
|
selectedTag = '';
|
||||||
selectedConnectionType = 'openai';
|
selectedConnectionType = 'external';
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{$i18n.t('External')}
|
{$i18n.t('External')}
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
export let files = [];
|
export let files = [];
|
||||||
|
|
||||||
export let selectedToolIds = [];
|
export let selectedToolIds = [];
|
||||||
|
export let selectedFilterIds = [];
|
||||||
|
|
||||||
export let imageGenerationEnabled = false;
|
export let imageGenerationEnabled = false;
|
||||||
export let codeInterpreterEnabled = false;
|
export let codeInterpreterEnabled = false;
|
||||||
export let webSearchEnabled = false;
|
export let webSearchEnabled = false;
|
||||||
@ -192,6 +194,7 @@
|
|||||||
bind:prompt
|
bind:prompt
|
||||||
bind:autoScroll
|
bind:autoScroll
|
||||||
bind:selectedToolIds
|
bind:selectedToolIds
|
||||||
|
bind:selectedFilterIds
|
||||||
bind:imageGenerationEnabled
|
bind:imageGenerationEnabled
|
||||||
bind:codeInterpreterEnabled
|
bind:codeInterpreterEnabled
|
||||||
bind:webSearchEnabled
|
bind:webSearchEnabled
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
let notificationSound = true;
|
let notificationSound = true;
|
||||||
let notificationSoundAlways = false;
|
let notificationSoundAlways = false;
|
||||||
|
|
||||||
|
let highContrastMode = false;
|
||||||
|
|
||||||
let detectArtifacts = true;
|
let detectArtifacts = true;
|
||||||
|
|
||||||
let richTextInput = true;
|
let richTextInput = true;
|
||||||
@ -85,6 +87,11 @@
|
|||||||
saveSettings({ splitLargeChunks: splitLargeChunks });
|
saveSettings({ splitLargeChunks: splitLargeChunks });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleHighContrastMode = async () => {
|
||||||
|
highContrastMode = !highContrastMode;
|
||||||
|
saveSettings({ highContrastMode: highContrastMode });
|
||||||
|
};
|
||||||
|
|
||||||
const togglePromptAutocomplete = async () => {
|
const togglePromptAutocomplete = async () => {
|
||||||
promptAutocomplete = !promptAutocomplete;
|
promptAutocomplete = !promptAutocomplete;
|
||||||
saveSettings({ promptAutocomplete: promptAutocomplete });
|
saveSettings({ promptAutocomplete: promptAutocomplete });
|
||||||
@ -281,6 +288,8 @@
|
|||||||
titleAutoGenerate = $settings?.title?.auto ?? true;
|
titleAutoGenerate = $settings?.title?.auto ?? true;
|
||||||
autoTags = $settings.autoTags ?? true;
|
autoTags = $settings.autoTags ?? true;
|
||||||
|
|
||||||
|
highContrastMode = $settings.highContrastMode ?? false;
|
||||||
|
|
||||||
detectArtifacts = $settings.detectArtifacts ?? true;
|
detectArtifacts = $settings.detectArtifacts ?? true;
|
||||||
responseAutoCopy = $settings.responseAutoCopy ?? false;
|
responseAutoCopy = $settings.responseAutoCopy ?? false;
|
||||||
|
|
||||||
@ -370,6 +379,28 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class=" mb-1.5 text-sm font-medium">{$i18n.t('UI')}</div>
|
<div class=" mb-1.5 text-sm font-medium">{$i18n.t('UI')}</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class=" py-0.5 flex w-full justify-between">
|
||||||
|
<div class=" self-center text-xs">
|
||||||
|
{$i18n.t('High Contrast Mode')} ({$i18n.t('Beta')})
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="p-1 px-3 text-xs flex rounded-sm transition"
|
||||||
|
on:click={() => {
|
||||||
|
toggleHighContrastMode();
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{#if highContrastMode === true}
|
||||||
|
<span class="ml-2 self-center">{$i18n.t('On')}</span>
|
||||||
|
{:else}
|
||||||
|
<span class="ml-2 self-center">{$i18n.t('Off')}</span>
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class=" py-0.5 flex w-full justify-between">
|
<div class=" py-0.5 flex w-full justify-between">
|
||||||
<div class=" self-center text-xs">{$i18n.t('Landing Page Mode')}</div>
|
<div class=" self-center text-xs">{$i18n.t('Landing Page Mode')}</div>
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="mb-1 flex gap-1 text-xs font-medium items-center text-gray-400 dark:text-gray-600">
|
<div class="mb-1 flex gap-1 text-xs font-medium items-center text-gray-600 dark:text-gray-400">
|
||||||
{#if filteredPrompts.length > 0}
|
{#if filteredPrompts.length > 0}
|
||||||
<Bolt />
|
<Bolt />
|
||||||
{$i18n.t('Suggested')}
|
{$i18n.t('Suggested')}
|
||||||
@ -74,7 +74,7 @@
|
|||||||
<div
|
<div
|
||||||
class="flex w-full {$settings?.landingPageMode === 'chat'
|
class="flex w-full {$settings?.landingPageMode === 'chat'
|
||||||
? ' -mt-1'
|
? ' -mt-1'
|
||||||
: 'text-center items-center justify-center'} self-start text-gray-400 dark:text-gray-600"
|
: 'text-center items-center justify-center'} self-start text-gray-600 dark:text-gray-400"
|
||||||
>
|
>
|
||||||
{$WEBUI_NAME} ‧ v{WEBUI_VERSION}
|
{$WEBUI_NAME} ‧ v{WEBUI_VERSION}
|
||||||
</div>
|
</div>
|
||||||
@ -98,7 +98,7 @@
|
|||||||
>
|
>
|
||||||
{prompt.title[0]}
|
{prompt.title[0]}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs text-gray-500 font-normal line-clamp-1">
|
<div class="text-xs text-gray-600 dark:text-gray-400 font-normal line-clamp-1">
|
||||||
{prompt.title[1]}
|
{prompt.title[1]}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
@ -107,7 +107,9 @@
|
|||||||
>
|
>
|
||||||
{prompt.content}
|
{prompt.content}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs text-gray-500 font-normal line-clamp-1">{$i18n.t('Prompt')}</div>
|
<div class="text-xs text-gray-600 dark:text-gray-400 font-normal line-clamp-1">
|
||||||
|
{$i18n.t('Prompt')}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
export let minSize = null;
|
export let minSize = null;
|
||||||
export let required = false;
|
export let required = false;
|
||||||
export let className =
|
export let className =
|
||||||
'w-full rounded-lg px-3 py-2 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden h-full';
|
'w-full rounded-lg px-3.5 py-2 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden h-full';
|
||||||
|
|
||||||
let textareaElement;
|
let textareaElement;
|
||||||
|
|
||||||
|
19
src/lib/components/icons/LightBulb.svelte
Normal file
19
src/lib/components/icons/LightBulb.svelte
Normal 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 18v-5.25m0 0a6.01 6.01 0 0 0 1.5-.189m-1.5.189a6.01 6.01 0 0 1-1.5-.189m3.75 7.478a12.06 12.06 0 0 1-4.5 0m3.75 2.383a14.406 14.406 0 0 1-3 0M14.25 18v-.192c0-.983.658-1.823 1.508-2.316a7.5 7.5 0 1 0-7.517 0c.85.493 1.509 1.333 1.509 2.316V18"
|
||||||
|
/>
|
||||||
|
</svg>
|
@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getAdminDetails } from '$lib/apis/auths';
|
import { getAdminDetails } from '$lib/apis/auths';
|
||||||
import { onMount, tick, getContext } from 'svelte';
|
import { onMount, tick, getContext } from 'svelte';
|
||||||
|
import { config } from '$lib/stores';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@ -20,16 +21,29 @@
|
|||||||
>
|
>
|
||||||
<div class="m-auto pb-10 flex flex-col justify-center">
|
<div class="m-auto pb-10 flex flex-col justify-center">
|
||||||
<div class="max-w-md">
|
<div class="max-w-md">
|
||||||
<div class="text-center dark:text-white text-2xl font-medium z-50">
|
<div
|
||||||
|
class="text-center dark:text-white text-2xl font-medium z-50"
|
||||||
|
style="white-space: pre-wrap;"
|
||||||
|
>
|
||||||
|
{#if ($config?.ui?.pending_user_overlay_title ?? '').trim() !== ''}
|
||||||
|
{$config.ui.pending_user_overlay_title}
|
||||||
|
{:else}
|
||||||
{$i18n.t('Account Activation Pending')}<br />
|
{$i18n.t('Account Activation Pending')}<br />
|
||||||
{$i18n.t('Contact Admin for WebUI Access')}
|
{$i18n.t('Contact Admin for WebUI Access')}
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=" mt-4 text-center text-sm dark:text-gray-200 w-full">
|
<div
|
||||||
{$i18n.t('Your account status is currently pending activation.')}<br />
|
class=" mt-4 text-center text-sm dark:text-gray-200 w-full"
|
||||||
{$i18n.t(
|
style="white-space: pre-wrap;"
|
||||||
|
>
|
||||||
|
{#if ($config?.ui?.pending_user_overlay_content ?? '').trim() !== ''}
|
||||||
|
{$config.ui.pending_user_overlay_content}
|
||||||
|
{:else}
|
||||||
|
{$i18n.t('Your account status is currently pending activation.')}{'\n'}{$i18n.t(
|
||||||
'To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.'
|
'To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.'
|
||||||
)}
|
)}
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if adminDetails}
|
{#if adminDetails}
|
||||||
|
@ -156,12 +156,11 @@
|
|||||||
<button
|
<button
|
||||||
class="flex rounded-md py-2 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition"
|
class="flex rounded-md py-2 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition"
|
||||||
on:click={async () => {
|
on:click={async () => {
|
||||||
await userSignOut();
|
const res = await userSignOut();
|
||||||
user.set(null);
|
user.set(null);
|
||||||
|
|
||||||
localStorage.removeItem('token');
|
localStorage.removeItem('token');
|
||||||
location.href = '/auth';
|
|
||||||
|
|
||||||
|
location.href = res?.redirect_url ?? '/auth';
|
||||||
show = false;
|
show = false;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="flex items-start bg-[#F1F8FE] dark:bg-[#020C1D] border border-[3371D5] dark:border-[#03113B] text-[#3371D5] dark:text-[#6795EC] rounded-lg px-3.5 py-3 text-xs max-w-80 pr-2 w-full shadow-lg"
|
class="flex items-start bg-[#F1F8FE] dark:bg-[#020C1D] border border-[3371D5] dark:border-[#03113B] text-[#2B6CD4] dark:text-[#6795EC] rounded-lg px-3.5 py-3 text-xs max-w-80 pr-2 w-full shadow-lg"
|
||||||
>
|
>
|
||||||
<div class="flex-1 font-medium">
|
<div class="flex-1 font-medium">
|
||||||
{$i18n.t(`A new version (v{{LATEST_VERSION}}) is now available.`, {
|
{$i18n.t(`A new version (v{{LATEST_VERSION}}) is now available.`, {
|
||||||
|
@ -243,7 +243,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=" my-2 mb-5 gap-2 grid lg:grid-cols-2 xl:grid-cols-3" id="model-list">
|
<div class=" my-2 mb-5 gap-2 grid lg:grid-cols-2 xl:grid-cols-3" id="model-list">
|
||||||
{#each filteredModels as model}
|
{#each filteredModels as model (model.id)}
|
||||||
<div
|
<div
|
||||||
class=" flex flex-col cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl transition"
|
class=" flex flex-col cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl transition"
|
||||||
id="model-item-{model.id}"
|
id="model-item-{model.id}"
|
||||||
|
@ -6,16 +6,45 @@
|
|||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
const helpText = {
|
const capabilityLabels = {
|
||||||
vision: $i18n.t('Model accepts image inputs'),
|
vision: {
|
||||||
usage: $i18n.t(
|
label: $i18n.t('Vision'),
|
||||||
|
description: $i18n.t('Model accepts image inputs')
|
||||||
|
},
|
||||||
|
file_upload: {
|
||||||
|
label: $i18n.t('File Upload'),
|
||||||
|
description: $i18n.t('Model accepts file inputs')
|
||||||
|
},
|
||||||
|
web_search: {
|
||||||
|
label: $i18n.t('Web Search'),
|
||||||
|
description: $i18n.t('Model can search the web for information')
|
||||||
|
},
|
||||||
|
image_generation: {
|
||||||
|
label: $i18n.t('Image Generation'),
|
||||||
|
description: $i18n.t('Model can generate images based on text prompts')
|
||||||
|
},
|
||||||
|
code_interpreter: {
|
||||||
|
label: $i18n.t('Code Interpreter'),
|
||||||
|
description: $i18n.t('Model can execute code and perform calculations')
|
||||||
|
},
|
||||||
|
usage: {
|
||||||
|
label: $i18n.t('Usage'),
|
||||||
|
description: $i18n.t(
|
||||||
'Sends `stream_options: { include_usage: true }` in the request.\nSupported providers will return token usage information in the response when set.'
|
'Sends `stream_options: { include_usage: true }` in the request.\nSupported providers will return token usage information in the response when set.'
|
||||||
),
|
)
|
||||||
citations: $i18n.t('Displays citations in the response')
|
},
|
||||||
|
citations: {
|
||||||
|
label: $i18n.t('Citations'),
|
||||||
|
description: $i18n.t('Displays citations in the response')
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export let capabilities: {
|
export let capabilities: {
|
||||||
vision?: boolean;
|
vision?: boolean;
|
||||||
|
file_upload?: boolean;
|
||||||
|
web_search?: boolean;
|
||||||
|
image_generation?: boolean;
|
||||||
|
code_interpreter?: boolean;
|
||||||
usage?: boolean;
|
usage?: boolean;
|
||||||
citations?: boolean;
|
citations?: boolean;
|
||||||
} = {};
|
} = {};
|
||||||
@ -26,7 +55,7 @@
|
|||||||
<div class=" self-center text-sm font-semibold">{$i18n.t('Capabilities')}</div>
|
<div class=" self-center text-sm font-semibold">{$i18n.t('Capabilities')}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
{#each Object.keys(capabilities) as capability}
|
{#each Object.keys(capabilityLabels) as capability}
|
||||||
<div class=" flex items-center gap-2 mr-3">
|
<div class=" flex items-center gap-2 mr-3">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
state={capabilities[capability] ? 'checked' : 'unchecked'}
|
state={capabilities[capability] ? 'checked' : 'unchecked'}
|
||||||
@ -36,8 +65,8 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div class=" py-0.5 text-sm capitalize">
|
<div class=" py-0.5 text-sm capitalize">
|
||||||
<Tooltip content={marked.parse(helpText[capability])}>
|
<Tooltip content={marked.parse(capabilityLabels[capability].description)}>
|
||||||
{$i18n.t(capability)}
|
{$i18n.t(capabilityLabels[capability].label)}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -77,8 +77,12 @@
|
|||||||
};
|
};
|
||||||
let capabilities = {
|
let capabilities = {
|
||||||
vision: true,
|
vision: true,
|
||||||
usage: undefined,
|
file_upload: true,
|
||||||
citations: true
|
web_search: true,
|
||||||
|
image_generation: true,
|
||||||
|
code_interpreter: true,
|
||||||
|
citations: true,
|
||||||
|
usage: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
let knowledge = [];
|
let knowledge = [];
|
||||||
|
@ -74,6 +74,8 @@
|
|||||||
"Allow User Location": "",
|
"Allow User Location": "",
|
||||||
"Allow Voice Interruption in Call": "",
|
"Allow Voice Interruption in Call": "",
|
||||||
"Allowed Endpoints": "",
|
"Allowed Endpoints": "",
|
||||||
|
"Allowed File Extensions": "",
|
||||||
|
"Allowed file extensions for upload. Separate multiple extensions with commas. Leave empty for all file types.": "",
|
||||||
"Already have an account?": "هل تملك حساب ؟",
|
"Already have an account?": "هل تملك حساب ؟",
|
||||||
"Alternative to the top_p, and aims to ensure a balance of quality and variety. The parameter p represents the minimum probability for a token to be considered, relative to the probability of the most likely token. For example, with p=0.05 and the most likely token having a probability of 0.9, logits with a value less than 0.045 are filtered out.": "",
|
"Alternative to the top_p, and aims to ensure a balance of quality and variety. The parameter p represents the minimum probability for a token to be considered, relative to the probability of the most likely token. For example, with p=0.05 and the most likely token having a probability of 0.9, logits with a value less than 0.045 are filtered out.": "",
|
||||||
"Always": "",
|
"Always": "",
|
||||||
@ -184,6 +186,7 @@
|
|||||||
"Chunk Size": "Chunk حجم",
|
"Chunk Size": "Chunk حجم",
|
||||||
"Ciphers": "",
|
"Ciphers": "",
|
||||||
"Citation": "اقتباس",
|
"Citation": "اقتباس",
|
||||||
|
"Citations": "",
|
||||||
"Clear memory": "",
|
"Clear memory": "",
|
||||||
"Clear Memory": "",
|
"Clear Memory": "",
|
||||||
"click here": "",
|
"click here": "",
|
||||||
@ -316,6 +319,7 @@
|
|||||||
"Deleted {{deleteModelTag}}": "{{deleteModelTag}} حذف",
|
"Deleted {{deleteModelTag}}": "{{deleteModelTag}} حذف",
|
||||||
"Deleted {{name}}": "حذف {{name}}",
|
"Deleted {{name}}": "حذف {{name}}",
|
||||||
"Deleted User": "",
|
"Deleted User": "",
|
||||||
|
"Describe Pictures in Documents": "",
|
||||||
"Describe your knowledge base and objectives": "",
|
"Describe your knowledge base and objectives": "",
|
||||||
"Description": "وصف",
|
"Description": "وصف",
|
||||||
"Detect Artifacts Automatically": "",
|
"Detect Artifacts Automatically": "",
|
||||||
@ -373,6 +377,7 @@
|
|||||||
"e.g. My Tools": "",
|
"e.g. My Tools": "",
|
||||||
"e.g. my_filter": "",
|
"e.g. my_filter": "",
|
||||||
"e.g. my_tools": "",
|
"e.g. my_tools": "",
|
||||||
|
"e.g. pdf, docx, txt": "",
|
||||||
"e.g. Tools for performing various operations": "",
|
"e.g. Tools for performing various operations": "",
|
||||||
"e.g., 3, 4, 5 (leave blank for default)": "",
|
"e.g., 3, 4, 5 (leave blank for default)": "",
|
||||||
"e.g., en-US,ja-JP (leave blank for auto-detect)": "",
|
"e.g., en-US,ja-JP (leave blank for auto-detect)": "",
|
||||||
@ -410,6 +415,8 @@
|
|||||||
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "تأكد من أن ملف CSV الخاص بك يتضمن 4 أعمدة بهذا الترتيب: Name, Email, Password, Role.",
|
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "تأكد من أن ملف CSV الخاص بك يتضمن 4 أعمدة بهذا الترتيب: Name, Email, Password, Role.",
|
||||||
"Enter {{role}} message here": "أدخل رسالة {{role}} هنا",
|
"Enter {{role}} message here": "أدخل رسالة {{role}} هنا",
|
||||||
"Enter a detail about yourself for your LLMs to recall": "ادخل معلومات عنك تريد أن يتذكرها الموديل",
|
"Enter a detail about yourself for your LLMs to recall": "ادخل معلومات عنك تريد أن يتذكرها الموديل",
|
||||||
|
"Enter a title for the pending user info overlay. Leave empty for default.": "",
|
||||||
|
"Enter a watermark for the response. Leave empty for none.": "",
|
||||||
"Enter api auth string (e.g. username:password)": "",
|
"Enter api auth string (e.g. username:password)": "",
|
||||||
"Enter Application DN": "",
|
"Enter Application DN": "",
|
||||||
"Enter Application DN Password": "",
|
"Enter Application DN Password": "",
|
||||||
@ -422,6 +429,7 @@
|
|||||||
"Enter Chunk Overlap": "أدخل الChunk Overlap",
|
"Enter Chunk Overlap": "أدخل الChunk Overlap",
|
||||||
"Enter Chunk Size": "أدخل Chunk الحجم",
|
"Enter Chunk Size": "أدخل Chunk الحجم",
|
||||||
"Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "",
|
"Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "",
|
||||||
|
"Enter content for the pending user info overlay. Leave empty for default.": "",
|
||||||
"Enter description": "",
|
"Enter description": "",
|
||||||
"Enter Docling OCR Engine": "",
|
"Enter Docling OCR Engine": "",
|
||||||
"Enter Docling OCR Language(s)": "",
|
"Enter Docling OCR Language(s)": "",
|
||||||
@ -430,6 +438,8 @@
|
|||||||
"Enter Document Intelligence Key": "",
|
"Enter Document Intelligence Key": "",
|
||||||
"Enter domains separated by commas (e.g., example.com,site.org)": "",
|
"Enter domains separated by commas (e.g., example.com,site.org)": "",
|
||||||
"Enter Exa API Key": "",
|
"Enter Exa API Key": "",
|
||||||
|
"Enter External Document Loader API Key": "",
|
||||||
|
"Enter External Document Loader URL": "",
|
||||||
"Enter External Web Loader API Key": "",
|
"Enter External Web Loader API Key": "",
|
||||||
"Enter External Web Loader URL": "",
|
"Enter External Web Loader URL": "",
|
||||||
"Enter External Web Search API Key": "",
|
"Enter External Web Search API Key": "",
|
||||||
@ -537,6 +547,7 @@
|
|||||||
"Export to CSV": "",
|
"Export to CSV": "",
|
||||||
"Export Tools": "",
|
"Export Tools": "",
|
||||||
"External": "",
|
"External": "",
|
||||||
|
"External Document Loader URL required.": "",
|
||||||
"External Models": "",
|
"External Models": "",
|
||||||
"External Web Loader API Key": "",
|
"External Web Loader API Key": "",
|
||||||
"External Web Loader URL": "",
|
"External Web Loader URL": "",
|
||||||
@ -566,6 +577,7 @@
|
|||||||
"File not found.": "لم يتم العثور على الملف.",
|
"File not found.": "لم يتم العثور على الملف.",
|
||||||
"File removed successfully.": "",
|
"File removed successfully.": "",
|
||||||
"File size should not exceed {{maxSize}} MB.": "",
|
"File size should not exceed {{maxSize}} MB.": "",
|
||||||
|
"File Upload": "",
|
||||||
"File uploaded successfully": "",
|
"File uploaded successfully": "",
|
||||||
"Files": "",
|
"Files": "",
|
||||||
"Filter is now globally disabled": "",
|
"Filter is now globally disabled": "",
|
||||||
@ -631,6 +643,7 @@
|
|||||||
"Hex Color - Leave empty for default color": "",
|
"Hex Color - Leave empty for default color": "",
|
||||||
"Hide": "أخفاء",
|
"Hide": "أخفاء",
|
||||||
"Hide Model": "",
|
"Hide Model": "",
|
||||||
|
"High Contrast Mode": "",
|
||||||
"Home": "",
|
"Home": "",
|
||||||
"Host": "",
|
"Host": "",
|
||||||
"How can I help you today?": "كيف استطيع مساعدتك اليوم؟",
|
"How can I help you today?": "كيف استطيع مساعدتك اليوم؟",
|
||||||
@ -774,7 +787,11 @@
|
|||||||
"Model {{name}} is now {{status}}": "نموذج {{name}} هو الآن {{status}}",
|
"Model {{name}} is now {{status}}": "نموذج {{name}} هو الآن {{status}}",
|
||||||
"Model {{name}} is now hidden": "",
|
"Model {{name}} is now hidden": "",
|
||||||
"Model {{name}} is now visible": "",
|
"Model {{name}} is now visible": "",
|
||||||
|
"Model accepts file inputs": "",
|
||||||
"Model accepts image inputs": "",
|
"Model accepts image inputs": "",
|
||||||
|
"Model can execute code and perform calculations": "",
|
||||||
|
"Model can generate images based on text prompts": "",
|
||||||
|
"Model can search the web for information": "",
|
||||||
"Model created successfully!": "",
|
"Model created successfully!": "",
|
||||||
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "تم اكتشاف مسار نظام الملفات النموذجي. الاسم المختصر للنموذج مطلوب للتحديث، ولا يمكن الاستمرار.",
|
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "تم اكتشاف مسار نظام الملفات النموذجي. الاسم المختصر للنموذج مطلوب للتحديث، ولا يمكن الاستمرار.",
|
||||||
"Model Filtering": "",
|
"Model Filtering": "",
|
||||||
@ -785,6 +802,7 @@
|
|||||||
"Model Params": "معلمات النموذج",
|
"Model Params": "معلمات النموذج",
|
||||||
"Model Permissions": "",
|
"Model Permissions": "",
|
||||||
"Model updated successfully": "",
|
"Model updated successfully": "",
|
||||||
|
"Model(s) do not support file upload": "",
|
||||||
"Modelfile Content": "محتوى الملف النموذجي",
|
"Modelfile Content": "محتوى الملف النموذجي",
|
||||||
"Models": "الموديلات",
|
"Models": "الموديلات",
|
||||||
"Models Access": "",
|
"Models Access": "",
|
||||||
@ -881,6 +899,8 @@
|
|||||||
"PDF document (.pdf)": "PDF ملف (.pdf)",
|
"PDF document (.pdf)": "PDF ملف (.pdf)",
|
||||||
"PDF Extract Images (OCR)": "PDF أستخرج الصور (OCR)",
|
"PDF Extract Images (OCR)": "PDF أستخرج الصور (OCR)",
|
||||||
"pending": "قيد الانتظار",
|
"pending": "قيد الانتظار",
|
||||||
|
"Pending User Overlay Content": "",
|
||||||
|
"Pending User Overlay Title": "",
|
||||||
"Permission denied when accessing media devices": "",
|
"Permission denied when accessing media devices": "",
|
||||||
"Permission denied when accessing microphone": "",
|
"Permission denied when accessing microphone": "",
|
||||||
"Permission denied when accessing microphone: {{error}}": "{{error}} تم رفض الإذن عند الوصول إلى الميكروفون ",
|
"Permission denied when accessing microphone: {{error}}": "{{error}} تم رفض الإذن عند الوصول إلى الميكروفون ",
|
||||||
@ -914,6 +934,7 @@
|
|||||||
"Prefix ID": "",
|
"Prefix ID": "",
|
||||||
"Prefix ID is used to avoid conflicts with other connections by adding a prefix to the model IDs - leave empty to disable": "",
|
"Prefix ID is used to avoid conflicts with other connections by adding a prefix to the model IDs - leave empty to disable": "",
|
||||||
"Presence Penalty": "",
|
"Presence Penalty": "",
|
||||||
|
"Preview": "",
|
||||||
"Previous 30 days": "أخر 30 يوم",
|
"Previous 30 days": "أخر 30 يوم",
|
||||||
"Previous 7 days": "أخر 7 أيام",
|
"Previous 7 days": "أخر 7 أيام",
|
||||||
"Private": "",
|
"Private": "",
|
||||||
@ -968,6 +989,7 @@
|
|||||||
"Reset view": "",
|
"Reset view": "",
|
||||||
"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.": "",
|
||||||
"Response splitting": "",
|
"Response splitting": "",
|
||||||
|
"Response Watermark": "",
|
||||||
"Result": "",
|
"Result": "",
|
||||||
"Retrieval": "",
|
"Retrieval": "",
|
||||||
"Retrieval Query Generation": "",
|
"Retrieval Query Generation": "",
|
||||||
@ -1233,6 +1255,7 @@
|
|||||||
"Upload Progress": "جاري التحميل",
|
"Upload Progress": "جاري التحميل",
|
||||||
"URL": "",
|
"URL": "",
|
||||||
"URL Mode": "رابط الموديل",
|
"URL Mode": "رابط الموديل",
|
||||||
|
"Usage": "",
|
||||||
"Use '#' in the prompt input to load and include your knowledge.": "",
|
"Use '#' in the prompt input to load and include your knowledge.": "",
|
||||||
"Use Gravatar": "Gravatar أستخدم",
|
"Use Gravatar": "Gravatar أستخدم",
|
||||||
"Use groups to group your users and assign permissions.": "",
|
"Use groups to group your users and assign permissions.": "",
|
||||||
@ -1262,6 +1285,7 @@
|
|||||||
"View Replies": "",
|
"View Replies": "",
|
||||||
"View Result from **{{NAME}}**": "",
|
"View Result from **{{NAME}}**": "",
|
||||||
"Visibility": "",
|
"Visibility": "",
|
||||||
|
"Vision": "",
|
||||||
"Voice": "",
|
"Voice": "",
|
||||||
"Voice Input": "",
|
"Voice Input": "",
|
||||||
"Warning": "تحذير",
|
"Warning": "تحذير",
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user