diff --git a/README.md b/README.md
index 0fb03537d..56ab09b05 100644
--- a/README.md
+++ b/README.md
@@ -174,7 +174,7 @@ docker run --rm --volume /var/run/docker.sock:/var/run/docker.sock containrrr/wa
In the last part of the command, replace `open-webui` with your container name if it is different.
-Check our Migration Guide available in our [Open WebUI Documentation](https://docs.openwebui.com/tutorials/migration/).
+Check our Updating Guide available in our [Open WebUI Documentation](https://docs.openwebui.com/getting-started/updating).
### Using the Dev Branch 🌙
diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py
index c10dde406..c62fb3ac9 100644
--- a/backend/open_webui/config.py
+++ b/backend/open_webui/config.py
@@ -660,6 +660,7 @@ S3_ACCESS_KEY_ID = os.environ.get("S3_ACCESS_KEY_ID", None)
S3_SECRET_ACCESS_KEY = os.environ.get("S3_SECRET_ACCESS_KEY", None)
S3_REGION_NAME = os.environ.get("S3_REGION_NAME", None)
S3_BUCKET_NAME = os.environ.get("S3_BUCKET_NAME", None)
+S3_KEY_PREFIX = os.environ.get("S3_KEY_PREFIX", None)
S3_ENDPOINT_URL = os.environ.get("S3_ENDPOINT_URL", None)
GCS_BUCKET_NAME = os.environ.get("GCS_BUCKET_NAME", None)
@@ -1645,7 +1646,7 @@ RAG_WEB_SEARCH_ENGINE = PersistentConfig(
# This ensures the highest level of safety and reliability of the information sources.
RAG_WEB_SEARCH_DOMAIN_FILTER_LIST = PersistentConfig(
"RAG_WEB_SEARCH_DOMAIN_FILTER_LIST",
- "rag.rag.web.search.domain.filter_list",
+ "rag.web.search.domain.filter_list",
[
# "wikipedia.com",
# "wikimedia.org",
@@ -2023,6 +2024,12 @@ WHISPER_MODEL_AUTO_UPDATE = (
and os.environ.get("WHISPER_MODEL_AUTO_UPDATE", "").lower() == "true"
)
+# Add Deepgram configuration
+DEEPGRAM_API_KEY = PersistentConfig(
+ "DEEPGRAM_API_KEY",
+ "audio.stt.deepgram.api_key",
+ os.getenv("DEEPGRAM_API_KEY", ""),
+)
AUDIO_STT_OPENAI_API_BASE_URL = PersistentConfig(
"AUDIO_STT_OPENAI_API_BASE_URL",
diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py
index 00605e15d..0be3887f8 100644
--- a/backend/open_webui/env.py
+++ b/backend/open_webui/env.py
@@ -92,6 +92,7 @@ log_sources = [
"RAG",
"WEBHOOK",
"SOCKET",
+ "OAUTH",
]
SRC_LOG_LEVELS = {}
diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py
index 43e9ceb65..dfd5a254b 100644
--- a/backend/open_webui/main.py
+++ b/backend/open_webui/main.py
@@ -132,6 +132,7 @@ from open_webui.config import (
PLAYWRIGHT_WS_URI,
RAG_WEB_LOADER,
WHISPER_MODEL,
+ DEEPGRAM_API_KEY,
WHISPER_MODEL_AUTO_UPDATE,
WHISPER_MODEL_DIR,
# Retrieval
@@ -615,6 +616,7 @@ app.state.config.STT_ENGINE = AUDIO_STT_ENGINE
app.state.config.STT_MODEL = AUDIO_STT_MODEL
app.state.config.WHISPER_MODEL = WHISPER_MODEL
+app.state.config.DEEPGRAM_API_KEY = DEEPGRAM_API_KEY
app.state.config.TTS_OPENAI_API_BASE_URL = AUDIO_TTS_OPENAI_API_BASE_URL
app.state.config.TTS_OPENAI_API_KEY = AUDIO_TTS_OPENAI_API_KEY
@@ -1021,6 +1023,7 @@ async def get_app_config(request: Request):
"enable_image_generation": app.state.config.ENABLE_IMAGE_GENERATION,
"enable_community_sharing": app.state.config.ENABLE_COMMUNITY_SHARING,
"enable_message_rating": app.state.config.ENABLE_MESSAGE_RATING,
+ "enable_autocomplete_generation": app.state.config.ENABLE_AUTOCOMPLETE_GENERATION,
"enable_admin_export": ENABLE_ADMIN_EXPORT,
"enable_admin_chat_access": ENABLE_ADMIN_CHAT_ACCESS,
}
diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py
index 73ff6c102..9e0a5865e 100644
--- a/backend/open_webui/models/chats.py
+++ b/backend/open_webui/models/chats.py
@@ -470,7 +470,7 @@ class ChatTable:
try:
with get_db() as db:
# it is possible that the shared link was deleted. hence,
- # we check if the chat is still shared by checkng if a chat with the share_id exists
+ # we check if the chat is still shared by checking if a chat with the share_id exists
chat = db.query(Chat).filter_by(share_id=id).first()
if chat:
diff --git a/backend/open_webui/retrieval/vector/dbs/opensearch.py b/backend/open_webui/retrieval/vector/dbs/opensearch.py
index b3d8b5eb8..41d634391 100644
--- a/backend/open_webui/retrieval/vector/dbs/opensearch.py
+++ b/backend/open_webui/retrieval/vector/dbs/opensearch.py
@@ -113,6 +113,40 @@ class OpenSearchClient:
return self._result_to_search_result(result)
+ def query(
+ self, collection_name: str, filter: dict, limit: Optional[int] = None
+ ) -> Optional[GetResult]:
+ if not self.has_collection(collection_name):
+ return None
+
+ query_body = {
+ "query": {
+ "bool": {
+ "filter": []
+ }
+ },
+ "_source": ["text", "metadata"],
+ }
+
+ for field, value in filter.items():
+ query_body["query"]["bool"]["filter"].append({
+ "term": {field: value}
+ })
+
+ size = limit if limit else 10
+
+ try:
+ result = self.client.search(
+ index=f"{self.index_prefix}_{collection_name}",
+ body=query_body,
+ size=size
+ )
+
+ return self._result_to_get_result(result)
+
+ except Exception as e:
+ return None
+
def get_or_create_index(self, index_name: str, dimension: int):
if not self.has_index(index_name):
self._create_index(index_name, dimension)
diff --git a/backend/open_webui/retrieval/web/jina_search.py b/backend/open_webui/retrieval/web/jina_search.py
index 3de6c1807..02af42ea6 100644
--- a/backend/open_webui/retrieval/web/jina_search.py
+++ b/backend/open_webui/retrieval/web/jina_search.py
@@ -20,14 +20,26 @@ def search_jina(api_key: str, query: str, count: int) -> list[SearchResult]:
list[SearchResult]: A list of search results
"""
jina_search_endpoint = "https://s.jina.ai/"
- headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
- url = str(URL(jina_search_endpoint + query))
- response = requests.get(url, headers=headers)
+
+ headers = {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "Authorization": api_key,
+ "X-Retain-Images": "none"
+ }
+
+ payload = {
+ "q": query,
+ "count": count if count <= 10 else 10
+ }
+
+ url = str(URL(jina_search_endpoint))
+ response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
data = response.json()
results = []
- for result in data["data"][:count]:
+ for result in data["data"]:
results.append(
SearchResult(
link=result["url"],
diff --git a/backend/open_webui/routers/audio.py b/backend/open_webui/routers/audio.py
index c1b15772b..7242042e2 100644
--- a/backend/open_webui/routers/audio.py
+++ b/backend/open_webui/routers/audio.py
@@ -11,6 +11,7 @@ from pydub.silence import split_on_silence
import aiohttp
import aiofiles
import requests
+import mimetypes
from fastapi import (
Depends,
@@ -138,6 +139,7 @@ class STTConfigForm(BaseModel):
ENGINE: str
MODEL: str
WHISPER_MODEL: str
+ DEEPGRAM_API_KEY: str
class AudioConfigUpdateForm(BaseModel):
@@ -165,6 +167,7 @@ async def get_audio_config(request: Request, user=Depends(get_admin_user)):
"ENGINE": request.app.state.config.STT_ENGINE,
"MODEL": request.app.state.config.STT_MODEL,
"WHISPER_MODEL": request.app.state.config.WHISPER_MODEL,
+ "DEEPGRAM_API_KEY": request.app.state.config.DEEPGRAM_API_KEY,
},
}
@@ -190,6 +193,7 @@ async def update_audio_config(
request.app.state.config.STT_ENGINE = form_data.stt.ENGINE
request.app.state.config.STT_MODEL = form_data.stt.MODEL
request.app.state.config.WHISPER_MODEL = form_data.stt.WHISPER_MODEL
+ request.app.state.config.DEEPGRAM_API_KEY = form_data.stt.DEEPGRAM_API_KEY
if request.app.state.config.STT_ENGINE == "":
request.app.state.faster_whisper_model = set_faster_whisper_model(
@@ -214,6 +218,7 @@ async def update_audio_config(
"ENGINE": request.app.state.config.STT_ENGINE,
"MODEL": request.app.state.config.STT_MODEL,
"WHISPER_MODEL": request.app.state.config.WHISPER_MODEL,
+ "DEEPGRAM_API_KEY": request.app.state.config.DEEPGRAM_API_KEY,
},
}
@@ -521,6 +526,65 @@ def transcribe(request: Request, file_path):
raise Exception(detail if detail else "Open WebUI: Server Connection Error")
+ elif request.app.state.config.STT_ENGINE == "deepgram":
+ try:
+ # Determine the MIME type of the file
+ mime, _ = mimetypes.guess_type(file_path)
+ if not mime:
+ mime = "audio/wav" # fallback to wav if undetectable
+
+ # Read the audio file
+ with open(file_path, "rb") as f:
+ file_data = f.read()
+
+ # Build headers and parameters
+ headers = {
+ "Authorization": f"Token {request.app.state.config.DEEPGRAM_API_KEY}",
+ "Content-Type": mime,
+ }
+
+ # Add model if specified
+ params = {}
+ if request.app.state.config.STT_MODEL:
+ params["model"] = request.app.state.config.STT_MODEL
+
+ # Make request to Deepgram API
+ r = requests.post(
+ "https://api.deepgram.com/v1/listen",
+ headers=headers,
+ params=params,
+ data=file_data,
+ )
+ r.raise_for_status()
+ response_data = r.json()
+
+ # Extract transcript from Deepgram response
+ try:
+ transcript = response_data["results"]["channels"][0]["alternatives"][0].get("transcript", "")
+ except (KeyError, IndexError) as e:
+ log.error(f"Malformed response from Deepgram: {str(e)}")
+ raise Exception("Failed to parse Deepgram response - unexpected response format")
+ data = {"text": transcript.strip()}
+
+ # Save transcript
+ transcript_file = f"{file_dir}/{id}.json"
+ with open(transcript_file, "w") as f:
+ json.dump(data, f)
+
+ return data
+
+ except Exception as e:
+ log.exception(e)
+ detail = None
+ if r is not None:
+ try:
+ res = r.json()
+ if "error" in res:
+ detail = f"External: {res['error'].get('message', '')}"
+ except Exception:
+ detail = f"External: {e}"
+ raise Exception(detail if detail else "Open WebUI: Server Connection Error")
+
def compress_audio(file_path):
if os.path.getsize(file_path) > MAX_FILE_SIZE:
diff --git a/backend/open_webui/routers/ollama.py b/backend/open_webui/routers/ollama.py
index 2ab06eb95..1c6365683 100644
--- a/backend/open_webui/routers/ollama.py
+++ b/backend/open_webui/routers/ollama.py
@@ -11,10 +11,8 @@ import re
import time
from typing import Optional, Union
from urllib.parse import urlparse
-
import aiohttp
from aiocache import cached
-
import requests
from fastapi import (
@@ -990,6 +988,8 @@ async def generate_chat_completion(
)
payload = {**form_data.model_dump(exclude_none=True)}
+ if "metadata" in payload:
+ del payload["metadata"]
model_id = payload["model"]
model_info = Models.get_model_by_id(model_id)
@@ -1408,9 +1408,10 @@ async def download_model(
return None
+# TODO: Progress bar does not reflect size & duration of upload.
@router.post("/models/upload")
@router.post("/models/upload/{url_idx}")
-def upload_model(
+async def upload_model(
request: Request,
file: UploadFile = File(...),
url_idx: Optional[int] = None,
@@ -1419,62 +1420,90 @@ def upload_model(
if url_idx is None:
url_idx = 0
ollama_url = request.app.state.config.OLLAMA_BASE_URLS[url_idx]
+ file_path = os.path.join(UPLOAD_DIR, file.filename)
+ os.makedirs(UPLOAD_DIR, exist_ok=True)
- file_path = f"{UPLOAD_DIR}/{file.filename}"
+ # --- P1: save file locally ---
+ chunk_size = 1024 * 1024 * 2 # 2 MB chunks
+ with open(file_path, "wb") as out_f:
+ while True:
+ chunk = file.file.read(chunk_size)
+ #log.info(f"Chunk: {str(chunk)}") # DEBUG
+ if not chunk:
+ break
+ out_f.write(chunk)
- # Save file in chunks
- with open(file_path, "wb+") as f:
- for chunk in file.file:
- f.write(chunk)
-
- def file_process_stream():
+ async def file_process_stream():
nonlocal ollama_url
total_size = os.path.getsize(file_path)
- chunk_size = 1024 * 1024
+ log.info(f"Total Model Size: {str(total_size)}") # DEBUG
+
+ # --- P2: SSE progress + calculate sha256 hash ---
+ file_hash = calculate_sha256(file_path, chunk_size)
+ log.info(f"Model Hash: {str(file_hash)}") # DEBUG
try:
with open(file_path, "rb") as f:
- total = 0
- done = False
-
- while not done:
- chunk = f.read(chunk_size)
- if not chunk:
- done = True
- continue
-
- total += len(chunk)
- progress = round((total / total_size) * 100, 2)
-
- res = {
+ bytes_read = 0
+ while chunk := f.read(chunk_size):
+ bytes_read += len(chunk)
+ progress = round(bytes_read / total_size * 100, 2)
+ data_msg = {
"progress": progress,
"total": total_size,
- "completed": total,
+ "completed": bytes_read,
}
- yield f"data: {json.dumps(res)}\n\n"
+ yield f"data: {json.dumps(data_msg)}\n\n"
- if done:
- f.seek(0)
- hashed = calculate_sha256(f)
- f.seek(0)
+ # --- P3: Upload to ollama /api/blobs ---
+ with open(file_path, "rb") as f:
+ url = f"{ollama_url}/api/blobs/sha256:{file_hash}"
+ response = requests.post(url, data=f)
- url = f"{ollama_url}/api/blobs/sha256:{hashed}"
- response = requests.post(url, data=f)
+ if response.ok:
+ log.info(f"Uploaded to /api/blobs") # DEBUG
+ # Remove local file
+ os.remove(file_path)
- if response.ok:
- res = {
- "done": done,
- "blob": f"sha256:{hashed}",
- "name": file.filename,
- }
- os.remove(file_path)
- yield f"data: {json.dumps(res)}\n\n"
- else:
- raise Exception(
- "Ollama: Could not create blob, Please try again."
- )
+ # Create model in ollama
+ model_name, ext = os.path.splitext(file.filename)
+ log.info(f"Created Model: {model_name}") # DEBUG
+
+ create_payload = {
+ "model": model_name,
+ # Reference the file by its original name => the uploaded blob's digest
+ "files": {
+ file.filename: f"sha256:{file_hash}"
+ },
+ }
+ log.info(f"Model Payload: {create_payload}") # DEBUG
+
+ # Call ollama /api/create
+ #https://github.com/ollama/ollama/blob/main/docs/api.md#create-a-model
+ create_resp = requests.post(
+ url=f"{ollama_url}/api/create",
+ headers={"Content-Type": "application/json"},
+ data=json.dumps(create_payload),
+ )
+
+ if create_resp.ok:
+ log.info(f"API SUCCESS!") # DEBUG
+ done_msg = {
+ "done": True,
+ "blob": f"sha256:{file_hash}",
+ "name": file.filename,
+ "model_created": model_name,
+ }
+ yield f"data: {json.dumps(done_msg)}\n\n"
+ else:
+ raise Exception(
+ f"Failed to create model in Ollama. {create_resp.text}"
+ )
+
+ else:
+ raise Exception("Ollama: Could not create blob, Please try again.")
except Exception as e:
res = {"error": str(e)}
yield f"data: {json.dumps(res)}\n\n"
- return StreamingResponse(file_process_stream(), media_type="text/event-stream")
+ return StreamingResponse(file_process_stream(), media_type="text/event-stream")
\ No newline at end of file
diff --git a/backend/open_webui/routers/openai.py b/backend/open_webui/routers/openai.py
index d18f2a8ff..afda36237 100644
--- a/backend/open_webui/routers/openai.py
+++ b/backend/open_webui/routers/openai.py
@@ -75,9 +75,9 @@ async def cleanup_response(
await session.close()
-def openai_o1_handler(payload):
+def openai_o1_o3_handler(payload):
"""
- Handle O1 specific parameters
+ Handle o1, o3 specific parameters
"""
if "max_tokens" in payload:
# Remove "max_tokens" from the payload
@@ -621,10 +621,10 @@ async def generate_chat_completion(
url = request.app.state.config.OPENAI_API_BASE_URLS[idx]
key = request.app.state.config.OPENAI_API_KEYS[idx]
- # Fix: O1 does not support the "max_tokens" parameter, Modify "max_tokens" to "max_completion_tokens"
- is_o1 = payload["model"].lower().startswith("o1-")
- if is_o1:
- payload = openai_o1_handler(payload)
+ # Fix: o1,o3 does not support the "max_tokens" parameter, Modify "max_tokens" to "max_completion_tokens"
+ is_o1_o3 = payload["model"].lower().startswith(("o1", "o3-"))
+ if is_o1_o3:
+ payload = openai_o1_o3_handler(payload)
elif "api.openai.com" not in url:
# Remove "max_completion_tokens" from the payload for backward compatibility
if "max_completion_tokens" in payload:
diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py
index 5772db6de..1fb58ae3d 100644
--- a/backend/open_webui/routers/retrieval.py
+++ b/backend/open_webui/routers/retrieval.py
@@ -392,6 +392,7 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)):
"exa_api_key": request.app.state.config.EXA_API_KEY,
"result_count": request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
"concurrent_requests": request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS,
+ "domain_filter_list": request.app.state.config.RAG_WEB_SEARCH_DOMAIN_FILTER_LIST,
},
},
}
@@ -441,6 +442,7 @@ class WebSearchConfig(BaseModel):
exa_api_key: Optional[str] = None
result_count: Optional[int] = None
concurrent_requests: Optional[int] = None
+ domain_filter_list: Optional[List[str]] = []
class WebConfig(BaseModel):
@@ -553,6 +555,9 @@ async def update_rag_config(
request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS = (
form_data.web.search.concurrent_requests
)
+ request.app.state.config.RAG_WEB_SEARCH_DOMAIN_FILTER_LIST = (
+ form_data.web.search.domain_filter_list
+ )
return {
"status": True,
@@ -599,6 +604,7 @@ async def update_rag_config(
"exa_api_key": request.app.state.config.EXA_API_KEY,
"result_count": request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
"concurrent_requests": request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS,
+ "domain_filter_list": request.app.state.config.RAG_WEB_SEARCH_DOMAIN_FILTER_LIST,
},
},
}
diff --git a/backend/open_webui/storage/provider.py b/backend/open_webui/storage/provider.py
index 0c0a8aacf..afc50b397 100644
--- a/backend/open_webui/storage/provider.py
+++ b/backend/open_webui/storage/provider.py
@@ -10,6 +10,7 @@ from open_webui.config import (
S3_ACCESS_KEY_ID,
S3_BUCKET_NAME,
S3_ENDPOINT_URL,
+ S3_KEY_PREFIX,
S3_REGION_NAME,
S3_SECRET_ACCESS_KEY,
GCS_BUCKET_NAME,
@@ -93,34 +94,36 @@ class S3StorageProvider(StorageProvider):
aws_secret_access_key=S3_SECRET_ACCESS_KEY,
)
self.bucket_name = S3_BUCKET_NAME
+ self.key_prefix = S3_KEY_PREFIX if S3_KEY_PREFIX else ""
def upload_file(self, file: BinaryIO, filename: str) -> Tuple[bytes, str]:
"""Handles uploading of the file to S3 storage."""
_, file_path = LocalStorageProvider.upload_file(file, filename)
try:
- self.s3_client.upload_file(file_path, self.bucket_name, filename)
+ s3_key = os.path.join(self.key_prefix, filename)
+ self.s3_client.upload_file(file_path, self.bucket_name, s3_key)
return (
open(file_path, "rb").read(),
- "s3://" + self.bucket_name + "/" + filename,
+ "s3://" + self.bucket_name + "/" + s3_key,
)
except ClientError as e:
raise RuntimeError(f"Error uploading file to S3: {e}")
-
+
def get_file(self, file_path: str) -> str:
"""Handles downloading of the file from S3 storage."""
try:
- bucket_name, key = file_path.split("//")[1].split("/")
- local_file_path = f"{UPLOAD_DIR}/{key}"
- self.s3_client.download_file(bucket_name, key, local_file_path)
+ s3_key = self._extract_s3_key(file_path)
+ local_file_path = self._get_local_file_path(s3_key)
+ self.s3_client.download_file(self.bucket_name, s3_key, local_file_path)
return local_file_path
except ClientError as e:
raise RuntimeError(f"Error downloading file from S3: {e}")
def delete_file(self, file_path: str) -> None:
"""Handles deletion of the file from S3 storage."""
- filename = file_path.split("/")[-1]
try:
- self.s3_client.delete_object(Bucket=self.bucket_name, Key=filename)
+ s3_key = self._extract_s3_key(file_path)
+ self.s3_client.delete_object(Bucket=self.bucket_name, Key=s3_key)
except ClientError as e:
raise RuntimeError(f"Error deleting file from S3: {e}")
@@ -133,6 +136,9 @@ class S3StorageProvider(StorageProvider):
response = self.s3_client.list_objects_v2(Bucket=self.bucket_name)
if "Contents" in response:
for content in response["Contents"]:
+ # Skip objects that were not uploaded from open-webui in the first place
+ if not content["Key"].startswith(self.key_prefix): continue
+
self.s3_client.delete_object(
Bucket=self.bucket_name, Key=content["Key"]
)
@@ -142,6 +148,12 @@ class S3StorageProvider(StorageProvider):
# Always delete from local storage
LocalStorageProvider.delete_all_files()
+ # The s3 key is the name assigned to an object. It excludes the bucket name, but includes the internal path and the file name.
+ def _extract_s3_key(self, full_file_path: str) -> str:
+ return '/'.join(full_file_path.split("//")[1].split("/")[1:])
+
+ def _get_local_file_path(self, s3_key: str) -> str:
+ return f"{UPLOAD_DIR}/{s3_key.split('/')[-1]}"
class GCSStorageProvider(StorageProvider):
def __init__(self):
diff --git a/backend/open_webui/utils/chat.py b/backend/open_webui/utils/chat.py
index 0719f6af5..3b6d5ea04 100644
--- a/backend/open_webui/utils/chat.py
+++ b/backend/open_webui/utils/chat.py
@@ -44,6 +44,10 @@ from open_webui.utils.response import (
convert_response_ollama_to_openai,
convert_streaming_response_ollama_to_openai,
)
+from open_webui.utils.filter import (
+ get_sorted_filter_ids,
+ process_filter_functions,
+)
from open_webui.env import SRC_LOG_LEVELS, GLOBAL_LOG_LEVEL, BYPASS_MODEL_ACCESS_CONTROL
@@ -177,116 +181,38 @@ async def chat_completed(request: Request, form_data: dict, user: Any):
except Exception as e:
return Exception(f"Error: {e}")
- __event_emitter__ = get_event_emitter(
- {
- "chat_id": data["chat_id"],
- "message_id": data["id"],
- "session_id": data["session_id"],
- "user_id": user.id,
- }
- )
+ metadata = {
+ "chat_id": data["chat_id"],
+ "message_id": data["id"],
+ "session_id": data["session_id"],
+ "user_id": user.id,
+ }
- __event_call__ = get_event_call(
- {
- "chat_id": data["chat_id"],
- "message_id": data["id"],
- "session_id": data["session_id"],
- "user_id": user.id,
- }
- )
+ extra_params = {
+ "__event_emitter__": get_event_emitter(metadata),
+ "__event_call__": get_event_call(metadata),
+ "__user__": {
+ "id": user.id,
+ "email": user.email,
+ "name": user.name,
+ "role": user.role,
+ },
+ "__metadata__": metadata,
+ "__request__": request,
+ "__model__": model,
+ }
- def get_priority(function_id):
- function = Functions.get_function_by_id(function_id)
- if function is not None and hasattr(function, "valves"):
- # TODO: Fix FunctionModel to include vavles
- return (function.valves if function.valves else {}).get("priority", 0)
- return 0
-
- filter_ids = [function.id for function in Functions.get_global_filter_functions()]
- if "info" in model and "meta" in model["info"]:
- filter_ids.extend(model["info"]["meta"].get("filterIds", []))
- filter_ids = list(set(filter_ids))
-
- enabled_filter_ids = [
- function.id
- for function in Functions.get_functions_by_type("filter", active_only=True)
- ]
- filter_ids = [
- filter_id for filter_id in filter_ids if filter_id in enabled_filter_ids
- ]
-
- # Sort filter_ids by priority, using the get_priority function
- filter_ids.sort(key=get_priority)
-
- for filter_id in filter_ids:
- filter = Functions.get_function_by_id(filter_id)
- if not filter:
- continue
-
- if filter_id in request.app.state.FUNCTIONS:
- 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
-
- if hasattr(function_module, "valves") and hasattr(function_module, "Valves"):
- valves = Functions.get_function_valves_by_id(filter_id)
- function_module.valves = function_module.Valves(
- **(valves if valves else {})
- )
-
- if not hasattr(function_module, "outlet"):
- continue
- try:
- outlet = function_module.outlet
-
- # Get the signature of the function
- sig = inspect.signature(outlet)
- params = {"body": data}
-
- # Extra parameters to be passed to the function
- extra_params = {
- "__model__": model,
- "__id__": filter_id,
- "__event_emitter__": __event_emitter__,
- "__event_call__": __event_call__,
- "__request__": request,
- }
-
- # Add extra params in contained in function signature
- for key, value in extra_params.items():
- if key in sig.parameters:
- params[key] = value
-
- if "__user__" in sig.parameters:
- __user__ = {
- "id": user.id,
- "email": user.email,
- "name": user.name,
- "role": user.role,
- }
-
- try:
- if hasattr(function_module, "UserValves"):
- __user__["valves"] = function_module.UserValves(
- **Functions.get_user_valves_by_id_and_user_id(
- filter_id, user.id
- )
- )
- except Exception as e:
- print(e)
-
- params = {**params, "__user__": __user__}
-
- if inspect.iscoroutinefunction(outlet):
- data = await outlet(**params)
- else:
- data = outlet(**params)
-
- except Exception as e:
- return Exception(f"Error: {e}")
-
- return data
+ try:
+ result, _ = await process_filter_functions(
+ request=request,
+ filter_ids=get_sorted_filter_ids(model),
+ filter_type="outlet",
+ form_data=data,
+ extra_params=extra_params,
+ )
+ return result
+ except Exception as e:
+ return Exception(f"Error: {e}")
async def chat_action(request: Request, action_id: str, form_data: dict, user: Any):
diff --git a/backend/open_webui/utils/filter.py b/backend/open_webui/utils/filter.py
new file mode 100644
index 000000000..de51bd46e
--- /dev/null
+++ b/backend/open_webui/utils/filter.py
@@ -0,0 +1,99 @@
+import inspect
+from open_webui.utils.plugin import load_function_module_by_id
+from open_webui.models.functions import Functions
+
+
+def get_sorted_filter_ids(model):
+ def get_priority(function_id):
+ function = Functions.get_function_by_id(function_id)
+ if function is not None and hasattr(function, "valves"):
+ # TODO: Fix FunctionModel to include vavles
+ return (function.valves if function.valves else {}).get("priority", 0)
+ return 0
+
+ filter_ids = [function.id for function in Functions.get_global_filter_functions()]
+ if "info" in model and "meta" in model["info"]:
+ filter_ids.extend(model["info"]["meta"].get("filterIds", []))
+ filter_ids = list(set(filter_ids))
+
+ enabled_filter_ids = [
+ function.id
+ for function in Functions.get_functions_by_type("filter", active_only=True)
+ ]
+
+ filter_ids = [fid for fid in filter_ids if fid in enabled_filter_ids]
+ filter_ids.sort(key=get_priority)
+ return filter_ids
+
+
+async def process_filter_functions(
+ request, filter_ids, filter_type, form_data, extra_params
+):
+ skip_files = None
+
+ for filter_id in filter_ids:
+ filter = Functions.get_function_by_id(filter_id)
+ if not filter:
+ continue
+
+ if filter_id in request.app.state.FUNCTIONS:
+ 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
+
+ # Check if the function has a file_handler variable
+ if filter_type == "inlet" and hasattr(function_module, "file_handler"):
+ skip_files = function_module.file_handler
+
+ # Apply valves to the function
+ if hasattr(function_module, "valves") and hasattr(function_module, "Valves"):
+ valves = Functions.get_function_valves_by_id(filter_id)
+ function_module.valves = function_module.Valves(
+ **(valves if valves else {})
+ )
+
+ # Prepare handler function
+ handler = getattr(function_module, filter_type, None)
+ if not handler:
+ continue
+
+ try:
+ # Prepare parameters
+ sig = inspect.signature(handler)
+ params = {"body": form_data} | {
+ k: v
+ for k, v in {
+ **extra_params,
+ "__id__": filter_id,
+ }.items()
+ if k in sig.parameters
+ }
+
+ # Handle user parameters
+ if "__user__" in sig.parameters:
+ if hasattr(function_module, "UserValves"):
+ try:
+ params["__user__"]["valves"] = function_module.UserValves(
+ **Functions.get_user_valves_by_id_and_user_id(
+ filter_id, params["__user__"]["id"]
+ )
+ )
+ except Exception as e:
+ print(e)
+
+ # Execute handler
+ if inspect.iscoroutinefunction(handler):
+ form_data = await handler(**params)
+ else:
+ form_data = handler(**params)
+
+ except Exception as e:
+ print(f"Error in {filter_type} handler {filter_id}: {e}")
+ raise e
+
+ # Handle file cleanup for inlet
+ if skip_files and "files" in form_data.get("metadata", {}):
+ del form_data["metadata"]["files"]
+
+ return form_data, {}
diff --git a/backend/open_webui/utils/images/comfyui.py b/backend/open_webui/utils/images/comfyui.py
index 679fff9f6..b86c25759 100644
--- a/backend/open_webui/utils/images/comfyui.py
+++ b/backend/open_webui/utils/images/comfyui.py
@@ -161,7 +161,7 @@ async def comfyui_generate_image(
seed = (
payload.seed
if payload.seed
- else random.randint(0, 18446744073709551614)
+ else random.randint(0, 1125899906842624)
)
for node_id in node.node_ids:
workflow[node_id]["inputs"][node.key] = seed
diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py
index 91bd7b525..1d2768087 100644
--- a/backend/open_webui/utils/middleware.py
+++ b/backend/open_webui/utils/middleware.py
@@ -68,6 +68,10 @@ from open_webui.utils.misc import (
)
from open_webui.utils.tools import get_tools
from open_webui.utils.plugin import load_function_module_by_id
+from open_webui.utils.filter import (
+ get_sorted_filter_ids,
+ process_filter_functions,
+)
from open_webui.tasks import create_task
@@ -91,99 +95,6 @@ log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["MAIN"])
-async def chat_completion_filter_functions_handler(request, body, model, extra_params):
- skip_files = None
-
- def get_filter_function_ids(model):
- def get_priority(function_id):
- function = Functions.get_function_by_id(function_id)
- if function is not None and hasattr(function, "valves"):
- # TODO: Fix FunctionModel
- return (function.valves if function.valves else {}).get("priority", 0)
- return 0
-
- filter_ids = [
- function.id for function in Functions.get_global_filter_functions()
- ]
- if "info" in model and "meta" in model["info"]:
- filter_ids.extend(model["info"]["meta"].get("filterIds", []))
- filter_ids = list(set(filter_ids))
-
- enabled_filter_ids = [
- function.id
- for function in Functions.get_functions_by_type("filter", active_only=True)
- ]
-
- filter_ids = [
- filter_id for filter_id in filter_ids if filter_id in enabled_filter_ids
- ]
-
- filter_ids.sort(key=get_priority)
- return filter_ids
-
- filter_ids = get_filter_function_ids(model)
- for filter_id in filter_ids:
- filter = Functions.get_function_by_id(filter_id)
- if not filter:
- continue
-
- if filter_id in request.app.state.FUNCTIONS:
- 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
-
- # Check if the function has a file_handler variable
- if hasattr(function_module, "file_handler"):
- skip_files = function_module.file_handler
-
- # Apply valves to the function
- if hasattr(function_module, "valves") and hasattr(function_module, "Valves"):
- valves = Functions.get_function_valves_by_id(filter_id)
- function_module.valves = function_module.Valves(
- **(valves if valves else {})
- )
-
- if hasattr(function_module, "inlet"):
- try:
- inlet = function_module.inlet
-
- # Create a dictionary of parameters to be passed to the function
- params = {"body": body} | {
- k: v
- for k, v in {
- **extra_params,
- "__model__": model,
- "__id__": filter_id,
- }.items()
- if k in inspect.signature(inlet).parameters
- }
-
- if "__user__" in params and hasattr(function_module, "UserValves"):
- try:
- params["__user__"]["valves"] = function_module.UserValves(
- **Functions.get_user_valves_by_id_and_user_id(
- filter_id, params["__user__"]["id"]
- )
- )
- except Exception as e:
- print(e)
-
- if inspect.iscoroutinefunction(inlet):
- body = await inlet(**params)
- else:
- body = inlet(**params)
-
- except Exception as e:
- print(f"Error: {e}")
- raise e
-
- if skip_files and "files" in body.get("metadata", {}):
- del body["metadata"]["files"]
-
- return body, {}
-
-
async def chat_completion_tools_handler(
request: Request, body: dict, user: UserModel, models, tools
) -> tuple[dict, dict]:
@@ -566,13 +477,13 @@ async def chat_image_generation_handler(
{
"type": "status",
"data": {
- "description": f"An error occured while generating an image",
+ "description": f"An error occurred while generating an image",
"done": True,
},
}
)
- system_message_content = "Unable to generate an image, tell the user that an error occured"
+ system_message_content = "Unable to generate an image, tell the user that an error occurred"
if system_message_content:
form_data["messages"] = add_or_update_system_message(
@@ -700,6 +611,7 @@ async def process_chat_payload(request, form_data, metadata, user, model):
},
"__metadata__": metadata,
"__request__": request,
+ "__model__": model,
}
# Initialize events to store additional event to be sent to the client
@@ -776,8 +688,12 @@ async def process_chat_payload(request, form_data, metadata, user, model):
)
try:
- form_data, flags = await chat_completion_filter_functions_handler(
- request, form_data, model, extra_params
+ form_data, flags = await process_filter_functions(
+ request=request,
+ filter_ids=get_sorted_filter_ids(model),
+ filter_type="inlet",
+ form_data=form_data,
+ extra_params=extra_params,
)
except Exception as e:
raise Exception(f"Error: {e}")
@@ -1116,6 +1032,20 @@ async def process_chat_response(
},
)
+ def split_content_and_whitespace(content):
+ content_stripped = content.rstrip()
+ original_whitespace = (
+ content[len(content_stripped) :]
+ if len(content) > len(content_stripped)
+ else ""
+ )
+ return content_stripped, original_whitespace
+
+ def is_opening_code_block(content):
+ backtick_segments = content.split("```")
+ # Even number of segments means the last backticks are opening a new block
+ return len(backtick_segments) > 1 and len(backtick_segments) % 2 == 0
+
# Handle as a background task
async def post_response_handler(response, events):
def serialize_content_blocks(content_blocks, raw=False):
@@ -1182,6 +1112,19 @@ async def process_chat_response(
output = block.get("output", None)
lang = attributes.get("lang", "")
+ content_stripped, original_whitespace = (
+ split_content_and_whitespace(content)
+ )
+ if is_opening_code_block(content_stripped):
+ # Remove trailing backticks that would open a new block
+ content = (
+ content_stripped.rstrip("`").rstrip()
+ + original_whitespace
+ )
+ else:
+ # Keep content as is - either closing backticks or no backticks
+ content = content_stripped + original_whitespace
+
if output:
output = html.escape(json.dumps(output))
@@ -1236,10 +1179,10 @@ async def process_chat_response(
match.end() :
] # Content after opening tag
- # Remove the start tag from the currently handling text block
+ # Remove the start tag and after from the currently handling text block
content_blocks[-1]["content"] = content_blocks[-1][
"content"
- ].replace(match.group(0), "")
+ ].replace(match.group(0) + after_tag, "")
if before_tag:
content_blocks[-1]["content"] = before_tag
diff --git a/backend/open_webui/utils/misc.py b/backend/open_webui/utils/misc.py
index b07393921..eb90ea5ea 100644
--- a/backend/open_webui/utils/misc.py
+++ b/backend/open_webui/utils/misc.py
@@ -244,11 +244,12 @@ def get_gravatar_url(email):
return f"https://www.gravatar.com/avatar/{hash_hex}?d=mp"
-def calculate_sha256(file):
+def calculate_sha256(file_path, chunk_size):
+ #Compute SHA-256 hash of a file efficiently in chunks
sha256 = hashlib.sha256()
- # Read the file in chunks to efficiently handle large files
- for chunk in iter(lambda: file.read(8192), b""):
- sha256.update(chunk)
+ with open(file_path, "rb") as f:
+ while chunk := f.read(chunk_size):
+ sha256.update(chunk)
return sha256.hexdigest()
diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py
index 7c0c53c2d..5182a1b17 100644
--- a/backend/open_webui/utils/oauth.py
+++ b/backend/open_webui/utils/oauth.py
@@ -1,6 +1,7 @@
import base64
import logging
import mimetypes
+import sys
import uuid
import aiohttp
@@ -40,7 +41,11 @@ from open_webui.utils.misc import parse_duration
from open_webui.utils.auth import get_password_hash, create_token
from open_webui.utils.webhook import post_webhook
+from open_webui.env import SRC_LOG_LEVELS, GLOBAL_LOG_LEVEL
+
+logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL)
log = logging.getLogger(__name__)
+log.setLevel(SRC_LOG_LEVELS["OAUTH"])
auth_manager_config = AppConfig()
auth_manager_config.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE
@@ -72,12 +77,15 @@ class OAuthManager:
def get_user_role(self, user, user_data):
if user and Users.get_num_users() == 1:
# If the user is the only user, assign the role "admin" - actually repairs role for single user on login
+ log.debug("Assigning the only user the admin role")
return "admin"
if not user and Users.get_num_users() == 0:
# If there are no users, assign the role "admin", as the first user will be an admin
+ log.debug("Assigning the first user the admin role")
return "admin"
if auth_manager_config.ENABLE_OAUTH_ROLE_MANAGEMENT:
+ log.debug("Running OAUTH Role management")
oauth_claim = auth_manager_config.OAUTH_ROLES_CLAIM
oauth_allowed_roles = auth_manager_config.OAUTH_ALLOWED_ROLES
oauth_admin_roles = auth_manager_config.OAUTH_ADMIN_ROLES
@@ -93,17 +101,24 @@ class OAuthManager:
claim_data = claim_data.get(nested_claim, {})
oauth_roles = claim_data if isinstance(claim_data, list) else None
+ log.debug(f"Oauth Roles claim: {oauth_claim}")
+ log.debug(f"User roles from oauth: {oauth_roles}")
+ log.debug(f"Accepted user roles: {oauth_allowed_roles}")
+ log.debug(f"Accepted admin roles: {oauth_admin_roles}")
+
# If any roles are found, check if they match the allowed or admin roles
if oauth_roles:
# If role management is enabled, and matching roles are provided, use the roles
for allowed_role in oauth_allowed_roles:
# If the user has any of the allowed roles, assign the role "user"
if allowed_role in oauth_roles:
+ log.debug("Assigned user the user role")
role = "user"
break
for admin_role in oauth_admin_roles:
# If the user has any of the admin roles, assign the role "admin"
if admin_role in oauth_roles:
+ log.debug("Assigned user the admin role")
role = "admin"
break
else:
@@ -117,16 +132,23 @@ class OAuthManager:
return role
def update_user_groups(self, user, user_data, default_permissions):
+ log.debug("Running OAUTH Group management")
oauth_claim = auth_manager_config.OAUTH_GROUPS_CLAIM
user_oauth_groups: list[str] = user_data.get(oauth_claim, list())
user_current_groups: list[GroupModel] = Groups.get_groups_by_member_id(user.id)
all_available_groups: list[GroupModel] = Groups.get_groups()
+ log.debug(f"Oauth Groups claim: {oauth_claim}")
+ log.debug(f"User oauth groups: {user_oauth_groups}")
+ log.debug(f"User's current groups: {[g.name for g in user_current_groups]}")
+ log.debug(f"All groups available in OpenWebUI: {[g.name for g in all_available_groups]}")
+
# Remove groups that user is no longer a part of
for group_model in user_current_groups:
if group_model.name not in user_oauth_groups:
# Remove group from user
+ log.debug(f"Removing user from group {group_model.name} as it is no longer in their oauth groups")
user_ids = group_model.user_ids
user_ids = [i for i in user_ids if i != user.id]
@@ -152,6 +174,7 @@ class OAuthManager:
gm.name == group_model.name for gm in user_current_groups
):
# Add user to group
+ log.debug(f"Adding user to group {group_model.name} as it was found in their oauth groups")
user_ids = group_model.user_ids
user_ids.append(user.id)
@@ -193,7 +216,7 @@ class OAuthManager:
log.warning(f"OAuth callback error: {e}")
raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED)
user_data: UserInfo = token.get("userinfo")
- if not user_data:
+ if not user_data or "email" not in user_data:
user_data: UserInfo = await client.userinfo(token=token)
if not user_data:
log.warning(f"OAuth callback failed, user data is missing: {token}")
@@ -261,15 +284,18 @@ class OAuthManager:
}
async with aiohttp.ClientSession() as session:
async with session.get(picture_url, **get_kwargs) as resp:
- picture = await resp.read()
- base64_encoded_picture = base64.b64encode(
- picture
- ).decode("utf-8")
- guessed_mime_type = mimetypes.guess_type(picture_url)[0]
- if guessed_mime_type is None:
- # assume JPG, browsers are tolerant enough of image formats
- guessed_mime_type = "image/jpeg"
- picture_url = f"data:{guessed_mime_type};base64,{base64_encoded_picture}"
+ if resp.ok:
+ picture = await resp.read()
+ base64_encoded_picture = base64.b64encode(
+ picture
+ ).decode("utf-8")
+ guessed_mime_type = mimetypes.guess_type(picture_url)[0]
+ if guessed_mime_type is None:
+ # assume JPG, browsers are tolerant enough of image formats
+ guessed_mime_type = "image/jpeg"
+ picture_url = f"data:{guessed_mime_type};base64,{base64_encoded_picture}"
+ else:
+ picture_url = "/user.png"
except Exception as e:
log.error(
f"Error downloading profile image '{picture_url}': {e}"
@@ -281,7 +307,7 @@ class OAuthManager:
username_claim = auth_manager_config.OAUTH_USERNAME_CLAIM
name = user_data.get(username_claim)
- if not isinstance(user, str):
+ if not isinstance(name, str):
name = email
role = self.get_user_role(None, user_data)
diff --git a/backend/requirements.txt b/backend/requirements.txt
index 473231710..c150e468e 100644
--- a/backend/requirements.txt
+++ b/backend/requirements.txt
@@ -32,6 +32,8 @@ boto3==1.35.53
argon2-cffi==23.1.0
APScheduler==3.10.4
+RestrictedPython==8.0
+
# AI libraries
openai
anthropic
@@ -45,7 +47,7 @@ fake-useragent==1.5.1
chromadb==0.6.2
pymilvus==2.5.0
qdrant-client~=1.12.0
-opensearch-py==2.7.1
+opensearch-py==2.8.0
playwright==1.49.1 # Caution: version must match docker-compose.playwright.yaml
transformers
@@ -77,7 +79,7 @@ opencv-python-headless==4.11.0.86
rapidocr-onnxruntime==1.3.24
rank-bm25==0.2.2
-faster-whisper==1.0.3
+faster-whisper==1.1.1
PyJWT[crypto]==2.10.1
authlib==1.4.1
diff --git a/package-lock.json b/package-lock.json
index e079e1536..e5c18101b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -42,6 +42,7 @@
"idb": "^7.1.1",
"js-sha256": "^0.10.1",
"katex": "^0.16.21",
+ "kokoro-js": "^1.1.1",
"marked": "^9.1.0",
"mermaid": "^10.9.3",
"paneforge": "^0.0.6",
@@ -62,7 +63,8 @@
"svelte-sonner": "^0.3.19",
"tippy.js": "^6.3.7",
"turndown": "^7.2.0",
- "uuid": "^9.0.1"
+ "uuid": "^9.0.1",
+ "vite-plugin-static-copy": "^2.2.0"
},
"devDependencies": {
"@sveltejs/adapter-auto": "3.2.2",
@@ -91,7 +93,7 @@
"tslib": "^2.4.1",
"typescript": "^5.5.4",
"vite": "^5.4.14",
- "vitest": "^1.6.0"
+ "vitest": "^1.6.1"
},
"engines": {
"node": ">=18.13.0 <=22.x.x",
@@ -1078,21 +1080,23 @@
}
},
"node_modules/@huggingface/jinja": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.3.1.tgz",
- "integrity": "sha512-SbcBWUKDQ76lzlVYOloscUk0SJjuL1LcbZsfQv/Bxxc7dwJMYuS+DAQ+HhVw6ZkTFXArejaX5HQRuCuleYwYdA==",
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.3.3.tgz",
+ "integrity": "sha512-vQQr2JyWvVFba3Lj9es4q9vCl1sAc74fdgnEMoX8qHrXtswap9ge9uO3ONDzQB0cQ0PUyaKY2N6HaVbTBvSXvw==",
+ "license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/@huggingface/transformers": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@huggingface/transformers/-/transformers-3.0.0.tgz",
- "integrity": "sha512-OWIPnTijAw4DQ+IFHBOrej2SDdYyykYlTtpTLCEt5MZq/e9Cb65RS2YVhdGcgbaW/6JAL3i8ZA5UhDeWGm4iRQ==",
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/@huggingface/transformers/-/transformers-3.3.3.tgz",
+ "integrity": "sha512-OcMubhBjW6u1xnp0zSt5SvCxdGHuhP2k+w2Vlm3i0vNcTJhJTZWxxYQmPBfcb7PX+Q6c43lGSzWD6tsJFwka4Q==",
+ "license": "Apache-2.0",
"dependencies": {
- "@huggingface/jinja": "^0.3.0",
- "onnxruntime-node": "1.19.2",
- "onnxruntime-web": "1.20.0-dev.20241016-2b8fc5529b",
+ "@huggingface/jinja": "^0.3.3",
+ "onnxruntime-node": "1.20.1",
+ "onnxruntime-web": "1.21.0-dev.20250206-d981b153d3",
"sharp": "^0.33.5"
}
},
@@ -1546,6 +1550,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+ "license": "ISC",
"dependencies": {
"minipass": "^7.0.4"
},
@@ -1558,6 +1563,7 @@
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
"integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@sinclair/typebox": "^0.27.8"
},
@@ -1798,7 +1804,6 @@
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
"dependencies": {
"@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9"
@@ -1811,7 +1816,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true,
"engines": {
"node": ">= 8"
}
@@ -1820,7 +1824,6 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
"dependencies": {
"@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0"
@@ -1856,27 +1859,32 @@
"node_modules/@protobufjs/aspromise": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
- "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
+ "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
+ "license": "BSD-3-Clause"
},
"node_modules/@protobufjs/base64": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
- "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
+ "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
+ "license": "BSD-3-Clause"
},
"node_modules/@protobufjs/codegen": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
- "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
+ "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
+ "license": "BSD-3-Clause"
},
"node_modules/@protobufjs/eventemitter": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
- "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
+ "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
+ "license": "BSD-3-Clause"
},
"node_modules/@protobufjs/fetch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+ "license": "BSD-3-Clause",
"dependencies": {
"@protobufjs/aspromise": "^1.1.1",
"@protobufjs/inquire": "^1.1.0"
@@ -1885,27 +1893,32 @@
"node_modules/@protobufjs/float": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
- "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
+ "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
+ "license": "BSD-3-Clause"
},
"node_modules/@protobufjs/inquire": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
- "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
+ "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
+ "license": "BSD-3-Clause"
},
"node_modules/@protobufjs/path": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
- "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
+ "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
+ "license": "BSD-3-Clause"
},
"node_modules/@protobufjs/pool": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
- "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
+ "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
+ "license": "BSD-3-Clause"
},
"node_modules/@protobufjs/utf8": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
- "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
+ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
+ "license": "BSD-3-Clause"
},
"node_modules/@pyscript/core": {
"version": "0.4.32",
@@ -2210,7 +2223,8 @@
"version": "0.27.8",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@socket.io/component-emitter": {
"version": "3.1.2",
@@ -3146,13 +3160,14 @@
"integrity": "sha512-g7f0IkJdPW2xhY7H4iE72DAsIyfuwEFc6JWc2tYFwKDMWWAF699vGjrM348cwQuOXgHpe1gWFe+Eiyjx/ewvvw=="
},
"node_modules/@vitest/expect": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz",
- "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==",
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.1.tgz",
+ "integrity": "sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@vitest/spy": "1.6.0",
- "@vitest/utils": "1.6.0",
+ "@vitest/spy": "1.6.1",
+ "@vitest/utils": "1.6.1",
"chai": "^4.3.10"
},
"funding": {
@@ -3160,12 +3175,13 @@
}
},
"node_modules/@vitest/runner": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz",
- "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==",
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.1.tgz",
+ "integrity": "sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@vitest/utils": "1.6.0",
+ "@vitest/utils": "1.6.1",
"p-limit": "^5.0.0",
"pathe": "^1.1.1"
},
@@ -3178,6 +3194,7 @@
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz",
"integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"yocto-queue": "^1.0.0"
},
@@ -3189,10 +3206,11 @@
}
},
"node_modules/@vitest/runner/node_modules/yocto-queue": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
- "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz",
+ "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12.20"
},
@@ -3201,10 +3219,11 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz",
- "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==",
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.1.tgz",
+ "integrity": "sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"magic-string": "^0.30.5",
"pathe": "^1.1.1",
@@ -3215,10 +3234,11 @@
}
},
"node_modules/@vitest/spy": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz",
- "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==",
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.1.tgz",
+ "integrity": "sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"tinyspy": "^2.2.0"
},
@@ -3227,10 +3247,11 @@
}
},
"node_modules/@vitest/utils": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz",
- "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==",
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.1.tgz",
+ "integrity": "sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"diff-sequences": "^29.6.3",
"estree-walker": "^3.0.3",
@@ -3246,6 +3267,7 @@
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0"
}
@@ -3416,7 +3438,6 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
- "dev": true,
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
@@ -3496,6 +3517,7 @@
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "*"
}
@@ -3644,7 +3666,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
- "dev": true,
"engines": {
"node": ">=8"
},
@@ -3720,7 +3741,6 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
- "dev": true,
"dependencies": {
"fill-range": "^7.1.1"
},
@@ -3895,6 +3915,7 @@
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
@@ -3972,10 +3993,11 @@
"dev": true
},
"node_modules/chai": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz",
- "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz",
+ "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"assertion-error": "^1.1.0",
"check-error": "^1.0.3",
@@ -3983,7 +4005,7 @@
"get-func-name": "^2.0.2",
"loupe": "^2.3.6",
"pathval": "^1.1.1",
- "type-detect": "^4.0.8"
+ "type-detect": "^4.1.0"
},
"engines": {
"node": ">=4"
@@ -4019,6 +4041,7 @@
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
"integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"get-func-name": "^2.0.2"
},
@@ -4077,7 +4100,6 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
- "dev": true,
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -4101,7 +4123,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
"dependencies": {
"is-glob": "^4.0.1"
},
@@ -4113,6 +4134,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+ "license": "BlueOak-1.0.0",
"engines": {
"node": ">=18"
}
@@ -5135,10 +5157,11 @@
}
},
"node_modules/deep-eql": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
- "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz",
+ "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"type-detect": "^4.0.0"
},
@@ -5257,6 +5280,7 @@
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
"integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
@@ -5899,7 +5923,6 @@
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
- "dev": true,
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@@ -5915,7 +5938,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
"dependencies": {
"is-glob": "^4.0.1"
},
@@ -5939,7 +5961,6 @@
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
- "dev": true,
"dependencies": {
"reusify": "^1.0.4"
}
@@ -5998,7 +6019,6 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
- "dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -6037,9 +6057,10 @@
}
},
"node_modules/flatbuffers": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz",
- "integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ=="
+ "version": "25.1.24",
+ "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-25.1.24.tgz",
+ "integrity": "sha512-Ni+KCqYquU30UEgGkrrwpbYtUcUmNuLFcQ5Xdy9DK7WUaji+AAov+Bf12FEYmu0eI15y31oD38utnBexe0cAYA==",
+ "license": "Apache-2.0"
},
"node_modules/flatted": {
"version": "3.3.1",
@@ -6110,7 +6131,6 @@
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
"integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
- "dev": true,
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@@ -6238,6 +6258,7 @@
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
"integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "*"
}
@@ -6429,8 +6450,7 @@
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
- "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
- "dev": true
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
},
"node_modules/graphemer": {
"version": "1.4.0",
@@ -6441,7 +6461,8 @@
"node_modules/guid-typescript": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz",
- "integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ=="
+ "integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==",
+ "license": "ISC"
},
"node_modules/gulp-sort": {
"version": "2.0.0",
@@ -6809,7 +6830,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
"dependencies": {
"binary-extensions": "^2.0.0"
},
@@ -6858,7 +6878,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -6875,7 +6894,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
"dependencies": {
"is-extglob": "^2.1.1"
},
@@ -6917,7 +6935,6 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
"engines": {
"node": ">=0.12.0"
}
@@ -7097,7 +7114,6 @@
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
- "dev": true,
"dependencies": {
"universalify": "^2.0.0"
},
@@ -7172,6 +7188,16 @@
"integrity": "sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==",
"dev": true
},
+ "node_modules/kokoro-js": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/kokoro-js/-/kokoro-js-1.1.1.tgz",
+ "integrity": "sha512-cyLO34iI8nBJXPnd3fI4fGeQGS+a6Uatg7eXNL6QS8TLSxaa30WD6Fj7/XoIZYaHg8q6d+TCrui/f74MTY2g1g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@huggingface/transformers": "^3.3.3",
+ "phonemizer": "^1.2.1"
+ }
+ },
"node_modules/layout-base": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz",
@@ -7455,15 +7481,17 @@
}
},
"node_modules/long": {
- "version": "5.2.3",
- "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
- "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
+ "version": "5.2.4",
+ "resolved": "https://registry.npmjs.org/long/-/long-5.2.4.tgz",
+ "integrity": "sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==",
+ "license": "Apache-2.0"
},
"node_modules/loupe": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz",
"integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"get-func-name": "^2.0.1"
}
@@ -7609,7 +7637,6 @@
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true,
"engines": {
"node": ">= 8"
}
@@ -8066,7 +8093,6 @@
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
- "dev": true,
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
@@ -8150,6 +8176,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.1.tgz",
"integrity": "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==",
+ "license": "MIT",
"dependencies": {
"minipass": "^7.0.4",
"rimraf": "^5.0.5"
@@ -8162,6 +8189,7 @@
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "license": "ISC",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^3.1.2",
@@ -8181,6 +8209,7 @@
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
@@ -8195,6 +8224,7 @@
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@@ -8209,6 +8239,7 @@
"version": "5.0.10",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
"integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
+ "license": "ISC",
"dependencies": {
"glob": "^10.3.7"
},
@@ -8329,7 +8360,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -8433,42 +8463,46 @@
}
},
"node_modules/onnxruntime-common": {
- "version": "1.19.2",
- "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.19.2.tgz",
- "integrity": "sha512-a4R7wYEVFbZBlp0BfhpbFWqe4opCor3KM+5Wm22Az3NGDcQMiU2hfG/0MfnBs+1ZrlSGmlgWeMcXQkDk1UFb8Q=="
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.20.1.tgz",
+ "integrity": "sha512-YiU0s0IzYYC+gWvqD1HzLc46Du1sXpSiwzKb63PACIJr6LfL27VsXSXQvt68EzD3V0D5Bc0vyJTjmMxp0ylQiw==",
+ "license": "MIT"
},
"node_modules/onnxruntime-node": {
- "version": "1.19.2",
- "resolved": "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.19.2.tgz",
- "integrity": "sha512-9eHMP/HKbbeUcqte1JYzaaRC8JPn7ojWeCeoyShO86TOR97OCyIyAIOGX3V95ErjslVhJRXY8Em/caIUc0hm1Q==",
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.20.1.tgz",
+ "integrity": "sha512-di/I4HDXRw+FLgq+TyHmQEDd3cEp9iFFZm0r4uJ1Wd7b/WE1VXtKWo8yemex347c6GNF/3Pv86ZfPhIWxORr0w==",
"hasInstallScript": true,
+ "license": "MIT",
"os": [
"win32",
"darwin",
"linux"
],
"dependencies": {
- "onnxruntime-common": "1.19.2",
+ "onnxruntime-common": "1.20.1",
"tar": "^7.0.1"
}
},
"node_modules/onnxruntime-web": {
- "version": "1.20.0-dev.20241016-2b8fc5529b",
- "resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.20.0-dev.20241016-2b8fc5529b.tgz",
- "integrity": "sha512-1XovqtgqeEFtupuyzdDQo7Tqj4GRyNHzOoXjapCEo4rfH3JrXok5VtqucWfRXHPsOI5qoNxMQ9VE+drDIp6woQ==",
+ "version": "1.21.0-dev.20250206-d981b153d3",
+ "resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.21.0-dev.20250206-d981b153d3.tgz",
+ "integrity": "sha512-esDVQdRic6J44VBMFLumYvcGfioMh80ceLmzF1yheJyuLKq/Th8VT2aj42XWQst+2bcWnAhw4IKmRQaqzU8ugg==",
+ "license": "MIT",
"dependencies": {
- "flatbuffers": "^1.12.0",
+ "flatbuffers": "^25.1.24",
"guid-typescript": "^1.0.9",
"long": "^5.2.3",
- "onnxruntime-common": "1.20.0-dev.20241016-2b8fc5529b",
+ "onnxruntime-common": "1.21.0-dev.20250206-d981b153d3",
"platform": "^1.3.6",
"protobufjs": "^7.2.4"
}
},
"node_modules/onnxruntime-web/node_modules/onnxruntime-common": {
- "version": "1.20.0-dev.20241016-2b8fc5529b",
- "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.20.0-dev.20241016-2b8fc5529b.tgz",
- "integrity": "sha512-KZK8b6zCYGZFjd4ANze0pqBnqnFTS3GIVeclQpa2qseDpXrCQJfkWBixRcrZShNhm3LpFOZ8qJYFC5/qsJK9WQ=="
+ "version": "1.21.0-dev.20250206-d981b153d3",
+ "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.21.0-dev.20250206-d981b153d3.tgz",
+ "integrity": "sha512-TwaE51xV9q2y8pM61q73rbywJnusw9ivTEHAJ39GVWNZqxCoDBpe/tQkh/w9S+o/g+zS7YeeL0I/2mEWd+dgyA==",
+ "license": "MIT"
},
"node_modules/optionator": {
"version": "0.9.3",
@@ -8546,7 +8580,8 @@
"node_modules/package-json-from-dist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
- "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+ "license": "BlueOak-1.0.0"
},
"node_modules/paneforge": {
"version": "0.0.6",
@@ -8686,6 +8721,7 @@
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "*"
}
@@ -8728,6 +8764,12 @@
"@types/estree": "*"
}
},
+ "node_modules/phonemizer": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/phonemizer/-/phonemizer-1.2.1.tgz",
+ "integrity": "sha512-v0KJ4mi2T4Q7eJQ0W15Xd4G9k4kICSXE8bpDeJ8jisL4RyJhNWsweKTOi88QXFc4r4LZlz5jVL5lCHhkpdT71A==",
+ "license": "Apache-2.0"
+ },
"node_modules/picocolors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
@@ -8781,7 +8823,8 @@
"node_modules/platform": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
- "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg=="
+ "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==",
+ "license": "MIT"
},
"node_modules/polyscript": {
"version": "0.12.8",
@@ -9064,6 +9107,7 @@
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
"integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@jest/schemas": "^29.6.3",
"ansi-styles": "^5.0.0",
@@ -9078,6 +9122,7 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10"
},
@@ -9314,6 +9359,7 @@
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
"integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
"hasInstallScript": true,
+ "license": "BSD-3-Clause",
"dependencies": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
@@ -9413,7 +9459,6 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -9504,7 +9549,8 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/read-cache": {
"version": "1.0.0",
@@ -9534,7 +9580,6 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
"dependencies": {
"picomatch": "^2.2.1"
},
@@ -9637,7 +9682,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true,
"engines": {
"iojs": ">=1.0.0",
"node": ">=0.10.0"
@@ -9763,7 +9807,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -11131,6 +11174,7 @@
"version": "7.4.3",
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
+ "license": "ISC",
"dependencies": {
"@isaacs/fs-minipass": "^4.0.0",
"chownr": "^3.0.0",
@@ -11147,6 +11191,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
+ "license": "MIT",
"bin": {
"mkdirp": "dist/cjs/src/bin.js"
},
@@ -11247,6 +11292,7 @@
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz",
"integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=14.0.0"
}
@@ -11277,7 +11323,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
"dependencies": {
"is-number": "^7.0.0"
},
@@ -11406,10 +11451,11 @@
"integrity": "sha512-fLIydlJy7IG9XL4wjRwEcKhxx/ekLXiWiMvcGo01cOMF+TN+5ZqajM1mRNRz2bNNi1bzou2yofhjZEQi7kgl9A=="
},
"node_modules/type-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz",
+ "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=4"
}
@@ -11484,7 +11530,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
- "dev": true,
"engines": {
"node": ">= 10.0.0"
}
@@ -11749,10 +11794,11 @@
}
},
"node_modules/vite-node": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz",
- "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==",
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.1.tgz",
+ "integrity": "sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"cac": "^6.7.14",
"debug": "^4.3.4",
@@ -11770,6 +11816,24 @@
"url": "https://opencollective.com/vitest"
}
},
+ "node_modules/vite-plugin-static-copy": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-2.2.0.tgz",
+ "integrity": "sha512-ytMrKdR9iWEYHbUxs6x53m+MRl4SJsOSoMu1U1+Pfg0DjPeMlsRVx3RR5jvoonineDquIue83Oq69JvNsFSU5w==",
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^3.5.3",
+ "fast-glob": "^3.2.11",
+ "fs-extra": "^11.1.0",
+ "picocolors": "^1.0.0"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^5.0.0 || ^6.0.0"
+ }
+ },
"node_modules/vite/node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@@ -12166,16 +12230,17 @@
}
},
"node_modules/vitest": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz",
- "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==",
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.1.tgz",
+ "integrity": "sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@vitest/expect": "1.6.0",
- "@vitest/runner": "1.6.0",
- "@vitest/snapshot": "1.6.0",
- "@vitest/spy": "1.6.0",
- "@vitest/utils": "1.6.0",
+ "@vitest/expect": "1.6.1",
+ "@vitest/runner": "1.6.1",
+ "@vitest/snapshot": "1.6.1",
+ "@vitest/spy": "1.6.1",
+ "@vitest/utils": "1.6.1",
"acorn-walk": "^8.3.2",
"chai": "^4.3.10",
"debug": "^4.3.4",
@@ -12189,7 +12254,7 @@
"tinybench": "^2.5.1",
"tinypool": "^0.8.3",
"vite": "^5.0.0",
- "vite-node": "1.6.0",
+ "vite-node": "1.6.1",
"why-is-node-running": "^2.2.2"
},
"bin": {
@@ -12204,8 +12269,8 @@
"peerDependencies": {
"@edge-runtime/vm": "*",
"@types/node": "^18.0.0 || >=20.0.0",
- "@vitest/browser": "1.6.0",
- "@vitest/ui": "1.6.0",
+ "@vitest/browser": "1.6.1",
+ "@vitest/ui": "1.6.1",
"happy-dom": "*",
"jsdom": "*"
},
@@ -12567,6 +12632,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+ "license": "BlueOak-1.0.0",
"engines": {
"node": ">=18"
}
diff --git a/package.json b/package.json
index 02228ee8b..aa43f6a75 100644
--- a/package.json
+++ b/package.json
@@ -47,7 +47,7 @@
"tslib": "^2.4.1",
"typescript": "^5.5.4",
"vite": "^5.4.14",
- "vitest": "^1.6.0"
+ "vitest": "^1.6.1"
},
"type": "module",
"dependencies": {
@@ -85,6 +85,7 @@
"idb": "^7.1.1",
"js-sha256": "^0.10.1",
"katex": "^0.16.21",
+ "kokoro-js": "^1.1.1",
"marked": "^9.1.0",
"mermaid": "^10.9.3",
"paneforge": "^0.0.6",
@@ -105,7 +106,8 @@
"svelte-sonner": "^0.3.19",
"tippy.js": "^6.3.7",
"turndown": "^7.2.0",
- "uuid": "^9.0.1"
+ "uuid": "^9.0.1",
+ "vite-plugin-static-copy": "^2.2.0"
},
"engines": {
"node": ">=18.13.0 <=22.x.x",
diff --git a/pyproject.toml b/pyproject.toml
index 12ec9f3fd..39f0bf004 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -40,6 +40,9 @@ dependencies = [
"argon2-cffi==23.1.0",
"APScheduler==3.10.4",
+
+ "RestrictedPython==8.0",
+
"openai",
"anthropic",
"google-generativeai==0.7.2",
@@ -83,7 +86,7 @@ dependencies = [
"rapidocr-onnxruntime==1.3.24",
"rank-bm25==0.2.2",
- "faster-whisper==1.0.3",
+ "faster-whisper==1.1.1",
"PyJWT[crypto]==2.10.1",
"authlib==1.4.1",
diff --git a/src/lib/components/admin/Evaluations/Leaderboard.svelte b/src/lib/components/admin/Evaluations/Leaderboard.svelte
index 59f6df916..07e19e979 100644
--- a/src/lib/components/admin/Evaluations/Leaderboard.svelte
+++ b/src/lib/components/admin/Evaluations/Leaderboard.svelte
@@ -1,6 +1,8 @@