diff --git a/README.md b/README.md index eb2575e7..5ff32d4c 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,9 @@ This repository hosts the code of LightRAG. The structure of this code is based -## Install +## Installation + +### Install LightRAG Core * Install from source (Recommend) @@ -92,6 +94,26 @@ pip install -e . pip install lightrag-hku ``` +### Install LightRAG Server + +The LightRAG Server is designed to provide Web UI and API support. The Web UI facilitates document indexing, knowledge graph exploration, and a simple RAG query interface. LightRAG Server also provide an Ollama compatible interfaces, aiming to emulate LightRAG as an Ollama chat model. This allows AI chat bot, such as Open WebUI, to access LightRAG easily. + +* Install from PyPI + +```bash +pip install "lightrag-hku[api]" +``` + +* Installation from Source + +```bash +# create a Python virtual enviroment if neccesary +# Install in editable mode with API support +pip install -e ".[api]" +``` + +**For more information about LightRAG Server, please refer to [LightRAG Server](./lightrag/api/README.md).** + ## Quick Start * [Video demo](https://www.youtube.com/watch?v=g21royNJ4fw) of running LightRAG locally. diff --git a/env.example b/env.example index fffa89a4..46404582 100644 --- a/env.example +++ b/env.example @@ -30,11 +30,6 @@ # LOG_MAX_BYTES=10485760 # Log file max size in bytes, defaults to 10MB # LOG_BACKUP_COUNT=5 # Number of backup files to keep, defaults to 5 -### Max async calls for LLM -# MAX_ASYNC=4 -### Optional Timeout for LLM -# TIMEOUT=150 # Time out in seconds, None for infinite timeout - ### Settings for RAG query # HISTORY_TURNS=3 # COSINE_THRESHOLD=0.2 @@ -44,16 +39,21 @@ # MAX_TOKEN_ENTITY_DESC=4000 ### Settings for document indexing +# SUMMARY_LANGUAGE=English # CHUNK_SIZE=1200 # CHUNK_OVERLAP_SIZE=100 -# MAX_TOKENS=32768 # Max tokens send to LLM for summarization -# MAX_TOKEN_SUMMARY=500 # Max tokens for entity or relations summary -# SUMMARY_LANGUAGE=English +# MAX_TOKEN_SUMMARY=500 # Max tokens for entity or relations summary +# MAX_PARALLEL_INSERT=2 # Number of parallel processing documents in one patch +# MAX_ASYNC=4 # Max concurrency requests of LLM +# ENABLE_LLM_CACHE_FOR_EXTRACT=true # Enable LLM cache for entity extraction + +# EMBEDDING_BATCH_NUM=32 # num of chunks send to Embedding in one request +# EMBEDDING_FUNC_MAX_ASYNC=16 # Max concurrency requests for Embedding # MAX_EMBED_TOKENS=8192 -# ENABLE_LLM_CACHE_FOR_EXTRACT=true # Enable LLM cache for entity extraction -# MAX_PARALLEL_INSERT=2 # Maximum number of parallel processing documents in pipeline ### LLM Configuration (Use valid host. For local services installed with docker, you can use host.docker.internal) +# MAX_TOKENS=32768 # Max tokens send to LLM (less than context size of the model) +# TIMEOUT=150 # Time out in seconds for LLM, None for infinite timeout LLM_BINDING=ollama LLM_MODEL=mistral-nemo:latest LLM_BINDING_API_KEY=your_api_key @@ -73,8 +73,6 @@ LLM_BINDING_HOST=http://localhost:11434 ### Embedding Configuration (Use valid host. For local services installed with docker, you can use host.docker.internal) EMBEDDING_MODEL=bge-m3:latest EMBEDDING_DIM=1024 -EMBEDDING_BATCH_NUM=32 -EMBEDDING_FUNC_MAX_ASYNC=16 # EMBEDDING_BINDING_API_KEY=your_api_key ### ollama example EMBEDDING_BINDING=ollama diff --git a/lightrag/__init__.py b/lightrag/__init__.py index f7dee888..b5ed66b5 100644 --- a/lightrag/__init__.py +++ b/lightrag/__init__.py @@ -1,5 +1,5 @@ from .lightrag import LightRAG as LightRAG, QueryParam as QueryParam -__version__ = "1.2.7" +__version__ = "1.2.8" __author__ = "Zirui Guo" __url__ = "https://github.com/HKUDS/LightRAG" diff --git a/lightrag/api/README.assets/image-20250323122538997.png b/lightrag/api/README.assets/image-20250323122538997.png new file mode 100644 index 00000000..38743f7e Binary files /dev/null and b/lightrag/api/README.assets/image-20250323122538997.png differ diff --git a/lightrag/api/README.assets/image-20250323122754387.png b/lightrag/api/README.assets/image-20250323122754387.png new file mode 100644 index 00000000..4c91829c Binary files /dev/null and b/lightrag/api/README.assets/image-20250323122754387.png differ diff --git a/lightrag/api/README.assets/image-20250323123011220.png b/lightrag/api/README.assets/image-20250323123011220.png new file mode 100644 index 00000000..c05ec62f Binary files /dev/null and b/lightrag/api/README.assets/image-20250323123011220.png differ diff --git a/lightrag/api/README.assets/image-20250323194750379.png b/lightrag/api/README.assets/image-20250323194750379.png new file mode 100644 index 00000000..649a456e Binary files /dev/null and b/lightrag/api/README.assets/image-20250323194750379.png differ diff --git a/lightrag/api/README.md b/lightrag/api/README.md index 8dcba7a2..9d92f65f 100644 --- a/lightrag/api/README.md +++ b/lightrag/api/README.md @@ -1,14 +1,24 @@ -## Install LightRAG as an API Server +# LightRAG Server and WebUI -LightRAG provides optional API support through FastAPI servers that add RAG capabilities to existing LLM services. You can install LightRAG API Server in two ways: +The LightRAG Server is designed to provide Web UI and API support. The Web UI facilitates document indexing, knowledge graph exploration, and a simple RAG query interface. LightRAG Server also provide an Ollama compatible interfaces, aiming to emulate LightRAG as an Ollama chat model. This allows AI chat bot, such as Open WebUI, to access LightRAG easily. -### Installation from PyPI +![image-20250323122538997](./README.assets/image-20250323122538997.png) + +![image-20250323122754387](./README.assets/image-20250323122754387.png) + +![image-20250323123011220](./README.assets/image-20250323123011220.png) + +## Getting Start + +### Installation + +* Install from PyPI ```bash pip install "lightrag-hku[api]" ``` -### Installation from Source (Development) +* Installation from Source ```bash # Clone the repository @@ -22,143 +32,94 @@ cd lightrag pip install -e ".[api]" ``` -### Starting API Server with Default Settings +### Before Starting LightRAG Server -After installing LightRAG with API support, you can start LightRAG by this command: `lightrag-server` - -LightRAG requires both LLM and Embedding Model to work together to complete document indexing and querying tasks. LightRAG supports binding to various LLM/Embedding backends: +LightRAG necessitates the integration of both an LLM (Large Language Model) and an Embedding Model to effectively execute document indexing and querying operations. Prior to the initial deployment of the LightRAG server, it is essential to configure the settings for both the LLM and the Embedding Model. LightRAG supports binding to various LLM/Embedding backends: * ollama * lollms -* openai & openai compatible +* openai or openai compatible * azure_openai -Before running any of the servers, ensure you have the corresponding backend service running for both llm and embedding. -The LightRAG API Server provides default parameters for LLM and Embedding, allowing users to easily start the service through command line. These default configurations are: +It is recommended to use environment variables to configure the LightRAG Server. There is an example environment variable file named `env.example` in the root directory of the project. Please copy this file to the startup directory and rename it to `.env`. After that, you can modify the parameters related to the LLM and Embedding models in the `.env` file. It is important to note that the LightRAG Server will load the environment variables from `.env` into the system environment variables each time it starts. Since the LightRAG Server will prioritize the settings in the system environment variables, if you modify the `.env` file after starting the LightRAG Server via the command line, you need to execute `source .env` to make the new settings take effect. -* Default endpoint of LLM/Embeding backend(LLM_BINDING_HOST or EMBEDDING_BINDING_HOST) +Here are some examples of common settings for LLM and Embedding models: + +* OpenAI LLM + Ollama Embedding ``` -# for lollms backend -LLM_BINDING_HOST=http://localhost:11434 -EMBEDDING_BINDING_HOST=http://localhost:11434 - -# for lollms backend -LLM_BINDING_HOST=http://localhost:9600 -EMBEDDING_BINDING_HOST=http://localhost:9600 - -# for openai, openai compatible or azure openai backend +LLM_BINDING=openai +LLM_MODEL=gpt-4o LLM_BINDING_HOST=https://api.openai.com/v1 -EMBEDDING_BINDING_HOST=http://localhost:9600 -``` - -* Default model config - -``` -LLM_MODEL=mistral-nemo:latest +LLM_BINDING_API_KEY=your_api_key +MAX_TOKENS=32768 # Max tokens send to LLM (less than model context size) +EMBEDDING_BINDING=ollama +EMBEDDING_BINDING_HOST=http://localhost:11434 EMBEDDING_MODEL=bge-m3:latest EMBEDDING_DIM=1024 -MAX_EMBED_TOKENS=8192 +# EMBEDDING_BINDING_API_KEY=your_api_key ``` -* API keys for LLM/Embedding backend - -When connecting to backend require API KEY, corresponding environment variables must be provided: +* Ollama LLM + Ollama Embedding ``` -LLM_BINDING_API_KEY=your_api_key -EMBEDDING_BINDING_API_KEY=your_api_key +LLM_BINDING=ollama +LLM_MODEL=mistral-nemo:latest +LLM_BINDING_HOST=http://localhost:11434 +# LLM_BINDING_API_KEY=your_api_key +MAX_TOKENS=8192 # Max tokens send to LLM (base on your Ollama Server capacity) + +EMBEDDING_BINDING=ollama +EMBEDDING_BINDING_HOST=http://localhost:11434 +EMBEDDING_MODEL=bge-m3:latest +EMBEDDING_DIM=1024 +# EMBEDDING_BINDING_API_KEY=your_api_key ``` -* Use command line arguments to choose LLM/Embeding backend +### Starting LightRAG Server -Use `--llm-binding` to select LLM backend type, and use `--embedding-binding` to select the embedding backend type. All the supported backend types are: +The LightRAG Server supports two operational modes: +* The simple and efficient Uvicorn mode ``` -openai: LLM default type -ollama: Embedding defult type -lollms: -azure_openai: -openai-ollama: select openai for LLM and ollama for embedding(only valid for --llm-binding) +lightrag-server ``` - -The LightRAG API Server allows you to mix different bindings for llm/embeddings. For example, you have the possibility to use ollama for the embedding and openai for the llm.With the above default parameters, you can start API Server with simple CLI arguments like these: +* The multiprocess Gunicorn + Uvicorn mode (production mode, not supported on Windows environments) ``` -# start with openai llm and ollama embedding -LLM_BINDING_API_KEY=your_api_key Light_server -LLM_BINDING_API_KEY=your_api_key Light_server --llm-binding openai-ollama - -# start with openai llm and openai embedding -LLM_BINDING_API_KEY=your_api_key Light_server --llm-binding openai --embedding-binding openai - -# start with ollama llm and ollama embedding (no apikey is needed) -light-server --llm-binding ollama --embedding-binding ollama -``` - -### Starting API Server with Gunicorn (Production) - -For production deployments, it's recommended to use Gunicorn as the WSGI server to handle concurrent requests efficiently. LightRAG provides a dedicated Gunicorn startup script that handles shared data initialization, process management, and other critical functionalities. - -```bash -# Start with lightrag-gunicorn command lightrag-gunicorn --workers 4 - -# Alternatively, you can use the module directly -python -m lightrag.api.run_with_gunicorn --workers 4 ``` +The `.env` file must be placed in the startup directory. Upon launching, the LightRAG Server will create a documents directory (default is `./inputs`) and a data directory (default is `./rag_storage`). This allows you to initiate multiple instances of LightRAG Server from different directories, with each instance configured to listen on a distinct network port. -The `--workers` parameter is crucial for performance: - -- Determines how many worker processes Gunicorn will spawn to handle requests -- Each worker can handle concurrent requests using asyncio -- Recommended value is (2 x number_of_cores) + 1 -- For example, on a 4-core machine, use 9 workers: (2 x 4) + 1 = 9 -- Consider your server's memory when setting this value, as each worker consumes memory - -Other important startup parameters: +Here are some common used startup parameters: - `--host`: Server listening address (default: 0.0.0.0) - `--port`: Server listening port (default: 9621) -- `--timeout`: Request handling timeout (default: 150 seconds) +- `--timeout`: LLM request timeout (default: 150 seconds) - `--log-level`: Logging level (default: INFO) -- `--ssl`: Enable HTTPS -- `--ssl-certfile`: Path to SSL certificate file -- `--ssl-keyfile`: Path to SSL private key file +- --input-dir: specifying the directory to scan for documents (default: ./input) -The command line parameters and enviroment variable run_with_gunicorn.py is exactly the same as `light-server`. +### Auto scan on startup -### For Azure OpenAI Backend +When starting any of the servers with the `--auto-scan-at-startup` parameter, the system will automatically: -Azure OpenAI API can be created using the following commands in Azure CLI (you need to install Azure CLI first from [https://docs.microsoft.com/en-us/cli/azure/install-azure-cli](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli)): -```bash -# Change the resource group name, location and OpenAI resource name as needed -RESOURCE_GROUP_NAME=LightRAG -LOCATION=swedencentral -RESOURCE_NAME=LightRAG-OpenAI +1. Scan for new files in the input directory +2. Indexing new documents that aren't already in the database +3. Make all content immediately available for RAG queries -az login -az group create --name $RESOURCE_GROUP_NAME --location $LOCATION -az cognitiveservices account create --name $RESOURCE_NAME --resource-group $RESOURCE_GROUP_NAME --kind OpenAI --sku S0 --location swedencentral -az cognitiveservices account deployment create --resource-group $RESOURCE_GROUP_NAME --model-format OpenAI --name $RESOURCE_NAME --deployment-name gpt-4o --model-name gpt-4o --model-version "2024-08-06" --sku-capacity 100 --sku-name "Standard" -az cognitiveservices account deployment create --resource-group $RESOURCE_GROUP_NAME --model-format OpenAI --name $RESOURCE_NAME --deployment-name text-embedding-3-large --model-name text-embedding-3-large --model-version "1" --sku-capacity 80 --sku-name "Standard" -az cognitiveservices account show --name $RESOURCE_NAME --resource-group $RESOURCE_GROUP_NAME --query "properties.endpoint" -az cognitiveservices account keys list --name $RESOURCE_NAME -g $RESOURCE_GROUP_NAME +> The `--input-dir` parameter specify the input directory to scan for. You can trigger input diretory scan from webui. + +### Multiple workers for Gunicorn + Uvicorn + +The LightRAG Server can operate in the `Gunicorn + Uvicorn` preload mode. Gunicorn's Multiple Worker (multiprocess) capability prevents document indexing tasks from blocking RAG queries. Using CPU-exhaustive document extraction tools, such as docling, can lead to the entire system being blocked in pure Uvicorn mode. + +Though LightRAG Server uses one workers to process the document indexing pipeline, with aysnc task supporting of Uvicorn, multiple files can be processed in parallell. The bottleneck of document indexing speed mainly lies with the LLM. If your LLM supports high concurrency, you can accelerate document indexing by increasing the concurrency level of the LLM. Below are several environment variables related to concurrent processing, along with their default values: ``` -The output of the last command will give you the endpoint and the key for the OpenAI API. You can use these values to set the environment variables in the `.env` file. - -``` -# Azure OpenAI Configuration in .env -LLM_BINDING=azure_openai -LLM_BINDING_HOST=your-azure-endpoint -LLM_MODEL=your-model-deployment-name -LLM_BINDING_API_KEY=your-azure-api-key -AZURE_OPENAI_API_VERSION=2024-08-01-preview # optional, defaults to latest version -EMBEDDING_BINDING=azure_openai # if using Azure OpenAI for embeddings -EMBEDDING_MODEL=your-embedding-deployment-name - +WORKERS=2 # Num of worker processes, not greater then (2 x number_of_cores) + 1 +MAX_PARALLEL_INSERT=2 # Num of parallel files to process in one batch +MAX_ASYNC=4 # Max concurrency requests of LLM ``` ### Install Lightrag as a Linux Service @@ -192,17 +153,106 @@ sudo systemctl status lightrag.service sudo systemctl enable lightrag.service ``` -### Automatic Document Indexing -When starting any of the servers with the `--auto-scan-at-startup` parameter, the system will automatically: -1. Scan for new files in the input directory -2. Indexing new documents that aren't already in the database -3. Make all content immediately available for RAG queries -> The `--input-dir` parameter specify the input directory to scan for. -## API Server Configuration +## Ollama Emulation + +We provide an Ollama-compatible interfaces for LightRAG, aiming to emulate LightRAG as an Ollama chat model. This allows AI chat frontends supporting Ollama, such as Open WebUI, to access LightRAG easily. + +### Connect Open WebUI to LightRAG + +After starting the lightrag-server, you can add an Ollama-type connection in the Open WebUI admin pannel. And then a model named lightrag:latest will appear in Open WebUI's model management interface. Users can then send queries to LightRAG through the chat interface. You'd better install LightRAG as service for this use case. + +Open WebUI's use LLM to do the session title and session keyword generation task. So the Ollama chat chat completion API detects and forwards OpenWebUI session-related requests directly to underlying LLM. Screen shot from Open WebUI: + +![image-20250323194750379](./README.assets/image-20250323194750379.png) + +### Choose Query mode in chat + +A query prefix in the query string can determines which LightRAG query mode is used to generate the respond for the query. The supported prefixes include: + +``` +/local +/global +/hybrid +/naive +/mix +/bypass +``` + +For example, chat message "/mix 唐僧有几个徒弟" will trigger a mix mode query for LighRAG. A chat message without query prefix will trigger a hybrid mode query by default。 + +"/bypass" is not a LightRAG query mode, it will tell API Server to pass the query directly to the underlying LLM with chat history. So user can use LLM to answer question base on the chat history. If you are using Open WebUI as front end, you can just switch the model to a normal LLM instead of using /bypass prefix. + + + +## API-Key and Authentication + +By default, the LightRAG Server can be accessed without any authentication. We can configure the server with an API-Key or account credentials to secure it. + +* API-KEY + +``` +LIGHTRAG_API_KEY=your-secure-api-key-here +``` + +* Account credentials (the web UI requires login before access) + +LightRAG API Server implements JWT-based authentication using HS256 algorithm. To enable secure access control, the following environment variables are required: + +```bash +# For jwt auth +AUTH_USERNAME=admin # login name +AUTH_PASSWORD=admin123 # password +TOKEN_SECRET=your-key # JWT key +TOKEN_EXPIRE_HOURS=4 # expire duration +``` + +> Currently, only the configuration of an administrator account and password is supported. A comprehensive account system is yet to be developed and implemented. + +If Account credentials are not configured, the web UI will access the system as a Guest. Therefore, even if only API-KEY is configured, all API can still be accessed through the Guest account, which remains insecure. Hence, to safeguard the API, it is necessary to configure both authentication methods simultaneously. + + + +## For Azure OpenAI Backend + +Azure OpenAI API can be created using the following commands in Azure CLI (you need to install Azure CLI first from [https://docs.microsoft.com/en-us/cli/azure/install-azure-cli](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli)): + +```bash +# Change the resource group name, location and OpenAI resource name as needed +RESOURCE_GROUP_NAME=LightRAG +LOCATION=swedencentral +RESOURCE_NAME=LightRAG-OpenAI + +az login +az group create --name $RESOURCE_GROUP_NAME --location $LOCATION +az cognitiveservices account create --name $RESOURCE_NAME --resource-group $RESOURCE_GROUP_NAME --kind OpenAI --sku S0 --location swedencentral +az cognitiveservices account deployment create --resource-group $RESOURCE_GROUP_NAME --model-format OpenAI --name $RESOURCE_NAME --deployment-name gpt-4o --model-name gpt-4o --model-version "2024-08-06" --sku-capacity 100 --sku-name "Standard" +az cognitiveservices account deployment create --resource-group $RESOURCE_GROUP_NAME --model-format OpenAI --name $RESOURCE_NAME --deployment-name text-embedding-3-large --model-name text-embedding-3-large --model-version "1" --sku-capacity 80 --sku-name "Standard" +az cognitiveservices account show --name $RESOURCE_NAME --resource-group $RESOURCE_GROUP_NAME --query "properties.endpoint" +az cognitiveservices account keys list --name $RESOURCE_NAME -g $RESOURCE_GROUP_NAME + +``` + +The output of the last command will give you the endpoint and the key for the OpenAI API. You can use these values to set the environment variables in the `.env` file. + +``` +# Azure OpenAI Configuration in .env +LLM_BINDING=azure_openai +LLM_BINDING_HOST=your-azure-endpoint +LLM_MODEL=your-model-deployment-name +LLM_BINDING_API_KEY=your-azure-api-key +AZURE_OPENAI_API_VERSION=2024-08-01-preview # optional, defaults to latest version +EMBEDDING_BINDING=azure_openai # if using Azure OpenAI for embeddings +EMBEDDING_MODEL=your-embedding-deployment-name + +``` + + + +## LightRAG Server Configuration in Detail API Server can be config in three way (highest priority first): @@ -392,19 +442,6 @@ Note: If you don't need the API functionality, you can install the base package pip install lightrag-hku ``` -## Authentication Endpoints - -### JWT Authentication Mechanism -LightRAG API Server implements JWT-based authentication using HS256 algorithm. To enable secure access control, the following environment variables are required: -```bash -# For jwt auth -AUTH_USERNAME=admin # login name -AUTH_PASSWORD=admin123 # password -TOKEN_SECRET=your-key # JWT key -TOKEN_EXPIRE_HOURS=4 # expire duration -WHITELIST_PATHS=/api1,/api2 # white list. /login,/health,/docs,/redoc,/openapi.json are whitelisted by default. -``` - ## API Endpoints All servers (LoLLMs, Ollama, OpenAI and Azure OpenAI) provide the same REST API endpoints for RAG functionality. When API Server is running, visit: @@ -528,30 +565,3 @@ Check server health and configuration. ```bash curl "http://localhost:9621/health" ``` - -## Ollama Emulation - -We provide an Ollama-compatible interfaces for LightRAG, aiming to emulate LightRAG as an Ollama chat model. This allows AI chat frontends supporting Ollama, such as Open WebUI, to access LightRAG easily. - -### Connect Open WebUI to LightRAG - -After starting the lightrag-server, you can add an Ollama-type connection in the Open WebUI admin pannel. And then a model named lightrag:latest will appear in Open WebUI's model management interface. Users can then send queries to LightRAG through the chat interface. You'd better install LightRAG as service for this use case. - -Open WebUI's use LLM to do the session title and session keyword generation task. So the Ollama chat chat completion API detects and forwards OpenWebUI session-related requests directly to underlying LLM. - -### Choose Query mode in chat - -A query prefix in the query string can determines which LightRAG query mode is used to generate the respond for the query. The supported prefixes include: - -``` -/local -/global -/hybrid -/naive -/mix -/bypass -``` - -For example, chat message "/mix 唐僧有几个徒弟" will trigger a mix mode query for LighRAG. A chat message without query prefix will trigger a hybrid mode query by default。 - -"/bypass" is not a LightRAG query mode, it will tell API Server to pass the query directly to the underlying LLM with chat history. So user can use LLM to answer question base on the chat history. If you are using Open WebUI as front end, you can just switch the model to a normal LLM instead of using /bypass prefix. diff --git a/lightrag/api/__init__.py b/lightrag/api/__init__.py index 7eadf511..005c738a 100644 --- a/lightrag/api/__init__.py +++ b/lightrag/api/__init__.py @@ -1 +1 @@ -__api_version__ = "1.0.5" +__api_version__ = "1.2.2" diff --git a/lightrag/api/auth.py b/lightrag/api/auth.py index 78a1da1a..5d9b00ac 100644 --- a/lightrag/api/auth.py +++ b/lightrag/api/auth.py @@ -3,6 +3,9 @@ from datetime import datetime, timedelta import jwt from fastapi import HTTPException, status from pydantic import BaseModel +from dotenv import load_dotenv + +load_dotenv() class TokenPayload(BaseModel): diff --git a/lightrag/api/gunicorn_config.py b/lightrag/api/gunicorn_config.py index 23e46807..0aef108e 100644 --- a/lightrag/api/gunicorn_config.py +++ b/lightrag/api/gunicorn_config.py @@ -29,7 +29,9 @@ preload_app = True worker_class = "uvicorn.workers.UvicornWorker" # Other Gunicorn configurations -timeout = int(os.getenv("TIMEOUT", 150)) # Default 150s to match run_with_gunicorn.py +timeout = int( + os.getenv("TIMEOUT", 150 * 2) +) # Default 150s *2 to match run_with_gunicorn.py keepalive = int(os.getenv("KEEPALIVE", 5)) # Default 5s # Logging configuration diff --git a/lightrag/api/lightrag_server.py b/lightrag/api/lightrag_server.py index 4d4896fc..584d020f 100644 --- a/lightrag/api/lightrag_server.py +++ b/lightrag/api/lightrag_server.py @@ -23,9 +23,9 @@ from lightrag.api.utils_api import ( get_default_host, display_splash_screen, ) -from lightrag import LightRAG -from lightrag.types import GPTKeywordExtractionFormat +from lightrag import LightRAG, __version__ as core_version from lightrag.api import __api_version__ +from lightrag.types import GPTKeywordExtractionFormat from lightrag.utils import EmbeddingFunc from lightrag.api.routers.document_routes import ( DocumentManager, @@ -49,7 +49,7 @@ from .auth import auth_handler # Load environment variables # Updated to use the .env that is inside the current folder # This update allows the user to put a different.env file for each lightrag folder -load_dotenv(".env", override=True) +load_dotenv() # Initialize config parser config = configparser.ConfigParser() @@ -364,9 +364,16 @@ def create_app(args): "token_type": "bearer", "auth_mode": "disabled", "message": "Authentication is disabled. Using guest access.", + "core_version": core_version, + "api_version": __api_version__, } - return {"auth_configured": True, "auth_mode": "enabled"} + return { + "auth_configured": True, + "auth_mode": "enabled", + "core_version": core_version, + "api_version": __api_version__, + } @app.post("/login", dependencies=[Depends(optional_api_key)]) async def login(form_data: OAuth2PasswordRequestForm = Depends()): @@ -383,6 +390,8 @@ def create_app(args): "token_type": "bearer", "auth_mode": "disabled", "message": "Authentication is disabled. Using guest access.", + "core_version": core_version, + "api_version": __api_version__, } if form_data.username != username or form_data.password != password: @@ -398,6 +407,8 @@ def create_app(args): "access_token": user_token, "token_type": "bearer", "auth_mode": "enabled", + "core_version": core_version, + "api_version": __api_version__, } @app.get("/health", dependencies=[Depends(optional_api_key)]) @@ -406,6 +417,13 @@ def create_app(args): # Get update flags status for all namespaces update_status = await get_all_update_flags_status() + username = os.getenv("AUTH_USERNAME") + password = os.getenv("AUTH_PASSWORD") + if not (username and password): + auth_mode = "disabled" + else: + auth_mode = "enabled" + return { "status": "healthy", "working_directory": str(args.working_dir), @@ -427,6 +445,9 @@ def create_app(args): "enable_llm_cache_for_extract": args.enable_llm_cache_for_extract, }, "update_status": update_status, + "core_version": core_version, + "api_version": __api_version__, + "auth_mode": auth_mode, } # Custom StaticFiles class to prevent caching of HTML files diff --git a/lightrag/api/routers/document_routes.py b/lightrag/api/routers/document_routes.py index 7b6f11c1..e0c8f545 100644 --- a/lightrag/api/routers/document_routes.py +++ b/lightrag/api/routers/document_routes.py @@ -405,7 +405,7 @@ async def pipeline_index_file(rag: LightRAG, file_path: Path): async def pipeline_index_files(rag: LightRAG, file_paths: List[Path]): - """Index multiple files concurrently + """Index multiple files sequentially to avoid high CPU load Args: rag: LightRAG instance @@ -416,12 +416,12 @@ async def pipeline_index_files(rag: LightRAG, file_paths: List[Path]): try: enqueued = False - if len(file_paths) == 1: - enqueued = await pipeline_enqueue_file(rag, file_paths[0]) - else: - tasks = [pipeline_enqueue_file(rag, path) for path in file_paths] - enqueued = any(await asyncio.gather(*tasks)) + # Process files sequentially + for file_path in file_paths: + if await pipeline_enqueue_file(rag, file_path): + enqueued = True + # Process the queue only if at least one file was successfully enqueued if enqueued: await rag.apipeline_process_enqueue_documents() except Exception as e: @@ -472,14 +472,34 @@ async def run_scanning_process(rag: LightRAG, doc_manager: DocumentManager): total_files = len(new_files) logger.info(f"Found {total_files} new files to index.") - for idx, file_path in enumerate(new_files): - try: - await pipeline_index_file(rag, file_path) - except Exception as e: - logger.error(f"Error indexing file {file_path}: {str(e)}") + if not new_files: + return + + # Get MAX_PARALLEL_INSERT from global_args + max_parallel = global_args["max_parallel_insert"] + # Calculate batch size as 2 * MAX_PARALLEL_INSERT + batch_size = 2 * max_parallel + + # Process files in batches + for i in range(0, total_files, batch_size): + batch_files = new_files[i : i + batch_size] + batch_num = i // batch_size + 1 + total_batches = (total_files + batch_size - 1) // batch_size + + logger.info( + f"Processing batch {batch_num}/{total_batches} with {len(batch_files)} files" + ) + await pipeline_index_files(rag, batch_files) + + # Log progress + processed = min(i + batch_size, total_files) + logger.info( + f"Processed {processed}/{total_files} files ({processed/total_files*100:.1f}%)" + ) except Exception as e: logger.error(f"Error during scanning process: {str(e)}") + logger.error(traceback.format_exc()) def create_document_routes( diff --git a/lightrag/api/run_with_gunicorn.py b/lightrag/api/run_with_gunicorn.py index cf9b3b91..126d772d 100644 --- a/lightrag/api/run_with_gunicorn.py +++ b/lightrag/api/run_with_gunicorn.py @@ -13,7 +13,7 @@ from dotenv import load_dotenv # Updated to use the .env that is inside the current folder # This update allows the user to put a different.env file for each lightrag folder -load_dotenv(".env") +load_dotenv() def check_and_install_dependencies(): @@ -140,7 +140,7 @@ def main(): # Timeout configuration prioritizes command line arguments gunicorn_config.timeout = ( - args.timeout if args.timeout else int(os.getenv("TIMEOUT", 150)) + args.timeout if args.timeout * 2 else int(os.getenv("TIMEOUT", 150 * 2)) ) # Keepalive configuration diff --git a/lightrag/api/utils_api.py b/lightrag/api/utils_api.py index 9a8aaf57..25136bd2 100644 --- a/lightrag/api/utils_api.py +++ b/lightrag/api/utils_api.py @@ -16,7 +16,7 @@ from starlette.status import HTTP_403_FORBIDDEN from .auth import auth_handler # Load environment variables -load_dotenv(override=True) +load_dotenv() global_args = {"main_args": None} @@ -365,6 +365,9 @@ def parse_args(is_uvicorn_mode: bool = False) -> argparse.Namespace: "LIGHTRAG_VECTOR_STORAGE", DefaultRAGStorageConfig.VECTOR_STORAGE ) + # Get MAX_PARALLEL_INSERT from environment + global_args["max_parallel_insert"] = get_env_value("MAX_PARALLEL_INSERT", 2, int) + # Handle openai-ollama special case if args.llm_binding == "openai-ollama": args.llm_binding = "openai" @@ -441,8 +444,8 @@ def display_splash_screen(args: argparse.Namespace) -> None: ASCIIColors.yellow(f"{args.log_level}") ASCIIColors.white(" ├─ Verbose Debug: ", end="") ASCIIColors.yellow(f"{args.verbose}") - ASCIIColors.white(" ├─ Timeout: ", end="") - ASCIIColors.yellow(f"{args.timeout if args.timeout else 'None (infinite)'}") + ASCIIColors.white(" ├─ History Turns: ", end="") + ASCIIColors.yellow(f"{args.history_turns}") ASCIIColors.white(" └─ API Key: ", end="") ASCIIColors.yellow("Set" if args.key else "Not Set") @@ -459,8 +462,10 @@ def display_splash_screen(args: argparse.Namespace) -> None: ASCIIColors.yellow(f"{args.llm_binding}") ASCIIColors.white(" ├─ Host: ", end="") ASCIIColors.yellow(f"{args.llm_binding_host}") - ASCIIColors.white(" └─ Model: ", end="") + ASCIIColors.white(" ├─ Model: ", end="") ASCIIColors.yellow(f"{args.llm_model}") + ASCIIColors.white(" └─ Timeout: ", end="") + ASCIIColors.yellow(f"{args.timeout if args.timeout else 'None (infinite)'}") # Embedding Configuration ASCIIColors.magenta("\n📊 Embedding Configuration:") @@ -475,8 +480,10 @@ def display_splash_screen(args: argparse.Namespace) -> None: # RAG Configuration ASCIIColors.magenta("\n⚙️ RAG Configuration:") - ASCIIColors.white(" ├─ Max Async Operations: ", end="") + ASCIIColors.white(" ├─ Max Async for LLM: ", end="") ASCIIColors.yellow(f"{args.max_async}") + ASCIIColors.white(" ├─ Max Parallel Insert: ", end="") + ASCIIColors.yellow(f"{global_args['max_parallel_insert']}") ASCIIColors.white(" ├─ Max Tokens: ", end="") ASCIIColors.yellow(f"{args.max_tokens}") ASCIIColors.white(" ├─ Max Embed Tokens: ", end="") @@ -485,8 +492,6 @@ def display_splash_screen(args: argparse.Namespace) -> None: ASCIIColors.yellow(f"{args.chunk_size}") ASCIIColors.white(" ├─ Chunk Overlap Size: ", end="") ASCIIColors.yellow(f"{args.chunk_overlap_size}") - ASCIIColors.white(" ├─ History Turns: ", end="") - ASCIIColors.yellow(f"{args.history_turns}") ASCIIColors.white(" ├─ Cosine Threshold: ", end="") ASCIIColors.yellow(f"{args.cosine_threshold}") ASCIIColors.white(" ├─ Top-K: ", end="") diff --git a/lightrag/api/webui/assets/index-4I5HV9Fr.js b/lightrag/api/webui/assets/index-4I5HV9Fr.js deleted file mode 100644 index 297c5542..00000000 --- a/lightrag/api/webui/assets/index-4I5HV9Fr.js +++ /dev/null @@ -1,1178 +0,0 @@ -var l9=Object.defineProperty;var u9=(e,t,n)=>t in e?l9(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var Xr=(e,t,n)=>u9(e,typeof t!="symbol"?t+"":t,n);function c9(e,t){for(var n=0;nr[a]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const a of document.querySelectorAll('link[rel="modulepreload"]'))r(a);new MutationObserver(a=>{for(const o of a)if(o.type==="childList")for(const s of o.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&r(s)}).observe(document,{childList:!0,subtree:!0});function n(a){const o={};return a.integrity&&(o.integrity=a.integrity),a.referrerPolicy&&(o.referrerPolicy=a.referrerPolicy),a.crossOrigin==="use-credentials"?o.credentials="include":a.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function r(a){if(a.ep)return;a.ep=!0;const o=n(a);fetch(a.href,o)}})();var df=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function un(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function d9(e){if(e.__esModule)return e;var t=e.default;if(typeof t=="function"){var n=function r(){return this instanceof r?Reflect.construct(t,arguments,this.constructor):t.apply(this,arguments)};n.prototype=t.prototype}else n={};return Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(e).forEach(function(r){var a=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(n,r,a.get?a:{enumerable:!0,get:function(){return e[r]}})}),n}var $h={exports:{}},Xl={};/** - * @license React - * react-jsx-runtime.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var q_;function f9(){if(q_)return Xl;q_=1;var e=Symbol.for("react.transitional.element"),t=Symbol.for("react.fragment");function n(r,a,o){var s=null;if(o!==void 0&&(s=""+o),a.key!==void 0&&(s=""+a.key),"key"in a){o={};for(var u in a)u!=="key"&&(o[u]=a[u])}else o=a;return a=o.ref,{$$typeof:e,type:r,key:s,ref:a!==void 0?a:null,props:o}}return Xl.Fragment=t,Xl.jsx=n,Xl.jsxs=n,Xl}var V_;function p9(){return V_||(V_=1,$h.exports=f9()),$h.exports}var w=p9(),qh={exports:{}},it={};/** - * @license React - * react.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var W_;function g9(){if(W_)return it;W_=1;var e=Symbol.for("react.transitional.element"),t=Symbol.for("react.portal"),n=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),a=Symbol.for("react.profiler"),o=Symbol.for("react.consumer"),s=Symbol.for("react.context"),u=Symbol.for("react.forward_ref"),c=Symbol.for("react.suspense"),d=Symbol.for("react.memo"),p=Symbol.for("react.lazy"),g=Symbol.iterator;function m(D){return D===null||typeof D!="object"?null:(D=g&&D[g]||D["@@iterator"],typeof D=="function"?D:null)}var b={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},y=Object.assign,S={};function x(D,V,B){this.props=D,this.context=V,this.refs=S,this.updater=B||b}x.prototype.isReactComponent={},x.prototype.setState=function(D,V){if(typeof D!="object"&&typeof D!="function"&&D!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,D,V,"setState")},x.prototype.forceUpdate=function(D){this.updater.enqueueForceUpdate(this,D,"forceUpdate")};function R(){}R.prototype=x.prototype;function k(D,V,B){this.props=D,this.context=V,this.refs=S,this.updater=B||b}var A=k.prototype=new R;A.constructor=k,y(A,x.prototype),A.isPureReactComponent=!0;var C=Array.isArray,N={H:null,A:null,T:null,S:null},_=Object.prototype.hasOwnProperty;function O(D,V,B,M,W,Q){return B=Q.ref,{$$typeof:e,type:D,key:V,ref:B!==void 0?B:null,props:Q}}function F(D,V){return O(D.type,V,void 0,void 0,void 0,D.props)}function L(D){return typeof D=="object"&&D!==null&&D.$$typeof===e}function I(D){var V={"=":"=0",":":"=2"};return"$"+D.replace(/[=:]/g,function(B){return V[B]})}var H=/\/+/g;function $(D,V){return typeof D=="object"&&D!==null&&D.key!=null?I(""+D.key):V.toString(36)}function U(){}function Y(D){switch(D.status){case"fulfilled":return D.value;case"rejected":throw D.reason;default:switch(typeof D.status=="string"?D.then(U,U):(D.status="pending",D.then(function(V){D.status==="pending"&&(D.status="fulfilled",D.value=V)},function(V){D.status==="pending"&&(D.status="rejected",D.reason=V)})),D.status){case"fulfilled":return D.value;case"rejected":throw D.reason}}throw D}function Z(D,V,B,M,W){var Q=typeof D;(Q==="undefined"||Q==="boolean")&&(D=null);var oe=!1;if(D===null)oe=!0;else switch(Q){case"bigint":case"string":case"number":oe=!0;break;case"object":switch(D.$$typeof){case e:case t:oe=!0;break;case p:return oe=D._init,Z(oe(D._payload),V,B,M,W)}}if(oe)return W=W(D),oe=M===""?"."+$(D,0):M,C(W)?(B="",oe!=null&&(B=oe.replace(H,"$&/")+"/"),Z(W,V,B,"",function(Se){return Se})):W!=null&&(L(W)&&(W=F(W,B+(W.key==null||D&&D.key===W.key?"":(""+W.key).replace(H,"$&/")+"/")+oe)),V.push(W)),1;oe=0;var re=M===""?".":M+":";if(C(D))for(var ie=0;ie>>1,D=j[K];if(0>>1;Ka(M,z))Wa(Q,M)?(j[K]=Q,j[W]=z,K=W):(j[K]=M,j[B]=z,K=B);else if(Wa(Q,z))j[K]=Q,j[W]=z,K=W;else break e}}return G}function a(j,G){var z=j.sortIndex-G.sortIndex;return z!==0?z:j.id-G.id}if(e.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var o=performance;e.unstable_now=function(){return o.now()}}else{var s=Date,u=s.now();e.unstable_now=function(){return s.now()-u}}var c=[],d=[],p=1,g=null,m=3,b=!1,y=!1,S=!1,x=typeof setTimeout=="function"?setTimeout:null,R=typeof clearTimeout=="function"?clearTimeout:null,k=typeof setImmediate<"u"?setImmediate:null;function A(j){for(var G=n(d);G!==null;){if(G.callback===null)r(d);else if(G.startTime<=j)r(d),G.sortIndex=G.expirationTime,t(c,G);else break;G=n(d)}}function C(j){if(S=!1,A(j),!y)if(n(c)!==null)y=!0,Y();else{var G=n(d);G!==null&&Z(C,G.startTime-j)}}var N=!1,_=-1,O=5,F=-1;function L(){return!(e.unstable_now()-Fj&&L());){var K=g.callback;if(typeof K=="function"){g.callback=null,m=g.priorityLevel;var D=K(g.expirationTime<=j);if(j=e.unstable_now(),typeof D=="function"){g.callback=D,A(j),G=!0;break t}g===n(c)&&r(c),A(j)}else r(c);g=n(c)}if(g!==null)G=!0;else{var V=n(d);V!==null&&Z(C,V.startTime-j),G=!1}}break e}finally{g=null,m=z,b=!1}G=void 0}}finally{G?H():N=!1}}}var H;if(typeof k=="function")H=function(){k(I)};else if(typeof MessageChannel<"u"){var $=new MessageChannel,U=$.port2;$.port1.onmessage=I,H=function(){U.postMessage(null)}}else H=function(){x(I,0)};function Y(){N||(N=!0,H())}function Z(j,G){_=x(function(){j(e.unstable_now())},G)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(j){j.callback=null},e.unstable_continueExecution=function(){y||b||(y=!0,Y())},e.unstable_forceFrameRate=function(j){0>j||125K?(j.sortIndex=z,t(d,j),n(c)===null&&j===n(d)&&(S?(R(_),_=-1):S=!0,Z(C,z-K))):(j.sortIndex=D,t(c,j),y||b||(y=!0,Y())),j},e.unstable_shouldYield=L,e.unstable_wrapCallback=function(j){var G=m;return function(){var z=m;m=G;try{return j.apply(this,arguments)}finally{m=z}}}}(Yh)),Yh}var X_;function b9(){return X_||(X_=1,Wh.exports=m9()),Wh.exports}var Kh={exports:{}},wn={};/** - * @license React - * react-dom.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Z_;function y9(){if(Z_)return wn;Z_=1;var e=$f();function t(c){var d="https://react.dev/errors/"+c;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}return e(),Kh.exports=y9(),Kh.exports}/** - * @license React - * react-dom-client.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var J_;function v9(){if(J_)return Zl;J_=1;var e=b9(),t=$f(),n=Pz();function r(i){var l="https://react.dev/errors/"+i;if(1)":-1v||X[h]!==ne[v]){var be=` -`+X[h].replace(" at new "," at ");return i.displayName&&be.includes("")&&(be=be.replace("",i.displayName)),be}while(1<=h&&0<=v);break}}}finally{Y=!1,Error.prepareStackTrace=f}return(f=i?i.displayName||i.name:"")?U(f):""}function j(i){switch(i.tag){case 26:case 27:case 5:return U(i.type);case 16:return U("Lazy");case 13:return U("Suspense");case 19:return U("SuspenseList");case 0:case 15:return i=Z(i.type,!1),i;case 11:return i=Z(i.type.render,!1),i;case 1:return i=Z(i.type,!0),i;default:return""}}function G(i){try{var l="";do l+=j(i),i=i.return;while(i);return l}catch(f){return` -Error generating stack: `+f.message+` -`+f.stack}}function z(i){var l=i,f=i;if(i.alternate)for(;l.return;)l=l.return;else{i=l;do l=i,l.flags&4098&&(f=l.return),i=l.return;while(i)}return l.tag===3?f:null}function K(i){if(i.tag===13){var l=i.memoizedState;if(l===null&&(i=i.alternate,i!==null&&(l=i.memoizedState)),l!==null)return l.dehydrated}return null}function D(i){if(z(i)!==i)throw Error(r(188))}function V(i){var l=i.alternate;if(!l){if(l=z(i),l===null)throw Error(r(188));return l!==i?null:i}for(var f=i,h=l;;){var v=f.return;if(v===null)break;var T=v.alternate;if(T===null){if(h=v.return,h!==null){f=h;continue}break}if(v.child===T.child){for(T=v.child;T;){if(T===f)return D(v),i;if(T===h)return D(v),l;T=T.sibling}throw Error(r(188))}if(f.return!==h.return)f=v,h=T;else{for(var P=!1,q=v.child;q;){if(q===f){P=!0,f=v,h=T;break}if(q===h){P=!0,h=v,f=T;break}q=q.sibling}if(!P){for(q=T.child;q;){if(q===f){P=!0,f=T,h=v;break}if(q===h){P=!0,h=T,f=v;break}q=q.sibling}if(!P)throw Error(r(189))}}if(f.alternate!==h)throw Error(r(190))}if(f.tag!==3)throw Error(r(188));return f.stateNode.current===f?i:l}function B(i){var l=i.tag;if(l===5||l===26||l===27||l===6)return i;for(i=i.child;i!==null;){if(l=B(i),l!==null)return l;i=i.sibling}return null}var M=Array.isArray,W=n.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,Q={pending:!1,data:null,method:null,action:null},oe=[],re=-1;function ie(i){return{current:i}}function Se(i){0>re||(i.current=oe[re],oe[re]=null,re--)}function ae(i,l){re++,oe[re]=i.current,i.current=l}var ve=ie(null),xe=ie(null),Ie=ie(null),Ce=ie(null);function ke(i,l){switch(ae(Ie,l),ae(xe,i),ae(ve,null),i=l.nodeType,i){case 9:case 11:l=(l=l.documentElement)&&(l=l.namespaceURI)?S_(l):0;break;default:if(i=i===8?l.parentNode:l,l=i.tagName,i=i.namespaceURI)i=S_(i),l=E_(i,l);else switch(l){case"svg":l=1;break;case"math":l=2;break;default:l=0}}Se(ve),ae(ve,l)}function J(){Se(ve),Se(xe),Se(Ie)}function fe(i){i.memoizedState!==null&&ae(Ce,i);var l=ve.current,f=E_(l,i.type);l!==f&&(ae(xe,i),ae(ve,f))}function Te(i){xe.current===i&&(Se(ve),Se(xe)),Ce.current===i&&(Se(Ce),ql._currentValue=Q)}var me=Object.prototype.hasOwnProperty,Ee=e.unstable_scheduleCallback,le=e.unstable_cancelCallback,Be=e.unstable_shouldYield,Ue=e.unstable_requestPaint,he=e.unstable_now,Ne=e.unstable_getCurrentPriorityLevel,ee=e.unstable_ImmediatePriority,ce=e.unstable_UserBlockingPriority,_e=e.unstable_NormalPriority,Pe=e.unstable_LowPriority,We=e.unstable_IdlePriority,yt=e.log,kt=e.unstable_setDisableYieldValue,ht=null,et=null;function Tt(i){if(et&&typeof et.onCommitFiberRoot=="function")try{et.onCommitFiberRoot(ht,i,void 0,(i.current.flags&128)===128)}catch{}}function ot(i){if(typeof yt=="function"&&kt(i),et&&typeof et.setStrictMode=="function")try{et.setStrictMode(ht,i)}catch{}}var St=Math.clz32?Math.clz32:zt,Ht=Math.log,fn=Math.LN2;function zt(i){return i>>>=0,i===0?32:31-(Ht(i)/fn|0)|0}var or=128,$r=4194304;function Jt(i){var l=i&42;if(l!==0)return l;switch(i&-i){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return i&4194176;case 4194304:case 8388608:case 16777216:case 33554432:return i&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return i}}function fa(i,l){var f=i.pendingLanes;if(f===0)return 0;var h=0,v=i.suspendedLanes,T=i.pingedLanes,P=i.warmLanes;i=i.finishedLanes!==0;var q=f&134217727;return q!==0?(f=q&~v,f!==0?h=Jt(f):(T&=q,T!==0?h=Jt(T):i||(P=q&~P,P!==0&&(h=Jt(P))))):(q=f&~v,q!==0?h=Jt(q):T!==0?h=Jt(T):i||(P=f&~P,P!==0&&(h=Jt(P)))),h===0?0:l!==0&&l!==h&&!(l&v)&&(v=h&-h,P=l&-l,v>=P||v===32&&(P&4194176)!==0)?l:h}function Xe(i,l){return(i.pendingLanes&~(i.suspendedLanes&~i.pingedLanes)&l)===0}function mt(i,l){switch(i){case 1:case 2:case 4:case 8:return l+250;case 16:case 32:case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return l+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Ct(){var i=or;return or<<=1,!(or&4194176)&&(or=128),i}function Dn(){var i=$r;return $r<<=1,!($r&62914560)&&($r=4194304),i}function _n(i){for(var l=[],f=0;31>f;f++)l.push(i);return l}function In(i,l){i.pendingLanes|=l,l!==268435456&&(i.suspendedLanes=0,i.pingedLanes=0,i.warmLanes=0)}function pa(i,l,f,h,v,T){var P=i.pendingLanes;i.pendingLanes=f,i.suspendedLanes=0,i.pingedLanes=0,i.warmLanes=0,i.expiredLanes&=f,i.entangledLanes&=f,i.errorRecoveryDisabledLanes&=f,i.shellSuspendCounter=0;var q=i.entanglements,X=i.expirationTimes,ne=i.hiddenUpdates;for(f=P&~f;0"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),t$=RegExp("^[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD][:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$"),EA={},wA={};function n$(i){return me.call(wA,i)?!0:me.call(EA,i)?!1:t$.test(i)?wA[i]=!0:(EA[i]=!0,!1)}function sc(i,l,f){if(n$(l))if(f===null)i.removeAttribute(l);else{switch(typeof f){case"undefined":case"function":case"symbol":i.removeAttribute(l);return;case"boolean":var h=l.toLowerCase().slice(0,5);if(h!=="data-"&&h!=="aria-"){i.removeAttribute(l);return}}i.setAttribute(l,""+f)}}function lc(i,l,f){if(f===null)i.removeAttribute(l);else{switch(typeof f){case"undefined":case"function":case"symbol":case"boolean":i.removeAttribute(l);return}i.setAttribute(l,""+f)}}function ha(i,l,f,h){if(h===null)i.removeAttribute(f);else{switch(typeof h){case"undefined":case"function":case"symbol":case"boolean":i.removeAttribute(f);return}i.setAttributeNS(l,f,""+h)}}function ir(i){switch(typeof i){case"bigint":case"boolean":case"number":case"string":case"undefined":return i;case"object":return i;default:return""}}function xA(i){var l=i.type;return(i=i.nodeName)&&i.toLowerCase()==="input"&&(l==="checkbox"||l==="radio")}function r$(i){var l=xA(i)?"checked":"value",f=Object.getOwnPropertyDescriptor(i.constructor.prototype,l),h=""+i[l];if(!i.hasOwnProperty(l)&&typeof f<"u"&&typeof f.get=="function"&&typeof f.set=="function"){var v=f.get,T=f.set;return Object.defineProperty(i,l,{configurable:!0,get:function(){return v.call(this)},set:function(P){h=""+P,T.call(this,P)}}),Object.defineProperty(i,l,{enumerable:f.enumerable}),{getValue:function(){return h},setValue:function(P){h=""+P},stopTracking:function(){i._valueTracker=null,delete i[l]}}}}function uc(i){i._valueTracker||(i._valueTracker=r$(i))}function kA(i){if(!i)return!1;var l=i._valueTracker;if(!l)return!0;var f=l.getValue(),h="";return i&&(h=xA(i)?i.checked?"true":"false":i.value),i=h,i!==f?(l.setValue(i),!0):!1}function cc(i){if(i=i||(typeof document<"u"?document:void 0),typeof i>"u")return null;try{return i.activeElement||i.body}catch{return i.body}}var a$=/[\n"\\]/g;function sr(i){return i.replace(a$,function(l){return"\\"+l.charCodeAt(0).toString(16)+" "})}function Gp(i,l,f,h,v,T,P,q){i.name="",P!=null&&typeof P!="function"&&typeof P!="symbol"&&typeof P!="boolean"?i.type=P:i.removeAttribute("type"),l!=null?P==="number"?(l===0&&i.value===""||i.value!=l)&&(i.value=""+ir(l)):i.value!==""+ir(l)&&(i.value=""+ir(l)):P!=="submit"&&P!=="reset"||i.removeAttribute("value"),l!=null?Hp(i,P,ir(l)):f!=null?Hp(i,P,ir(f)):h!=null&&i.removeAttribute("value"),v==null&&T!=null&&(i.defaultChecked=!!T),v!=null&&(i.checked=v&&typeof v!="function"&&typeof v!="symbol"),q!=null&&typeof q!="function"&&typeof q!="symbol"&&typeof q!="boolean"?i.name=""+ir(q):i.removeAttribute("name")}function TA(i,l,f,h,v,T,P,q){if(T!=null&&typeof T!="function"&&typeof T!="symbol"&&typeof T!="boolean"&&(i.type=T),l!=null||f!=null){if(!(T!=="submit"&&T!=="reset"||l!=null))return;f=f!=null?""+ir(f):"",l=l!=null?""+ir(l):f,q||l===i.value||(i.value=l),i.defaultValue=l}h=h??v,h=typeof h!="function"&&typeof h!="symbol"&&!!h,i.checked=q?i.checked:!!h,i.defaultChecked=!!h,P!=null&&typeof P!="function"&&typeof P!="symbol"&&typeof P!="boolean"&&(i.name=P)}function Hp(i,l,f){l==="number"&&cc(i.ownerDocument)===i||i.defaultValue===""+f||(i.defaultValue=""+f)}function Oi(i,l,f,h){if(i=i.options,l){l={};for(var v=0;v=ul),zA=" ",BA=!1;function UA(i,l){switch(i){case"keyup":return D$.indexOf(l.keyCode)!==-1;case"keydown":return l.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function jA(i){return i=i.detail,typeof i=="object"&&"data"in i?i.data:null}var Mi=!1;function L$(i,l){switch(i){case"compositionend":return jA(l);case"keypress":return l.which!==32?null:(BA=!0,zA);case"textInput":return i=l.data,i===zA&&BA?null:i;default:return null}}function M$(i,l){if(Mi)return i==="compositionend"||!eg&&UA(i,l)?(i=DA(),fc=Kp=Xa=null,Mi=!1,i):null;switch(i){case"paste":return null;case"keypress":if(!(l.ctrlKey||l.altKey||l.metaKey)||l.ctrlKey&&l.altKey){if(l.char&&1=l)return{node:f,offset:l-i};i=h}e:{for(;f;){if(f.nextSibling){f=f.nextSibling;break e}f=f.parentNode}f=void 0}f=KA(f)}}function ZA(i,l){return i&&l?i===l?!0:i&&i.nodeType===3?!1:l&&l.nodeType===3?ZA(i,l.parentNode):"contains"in i?i.contains(l):i.compareDocumentPosition?!!(i.compareDocumentPosition(l)&16):!1:!1}function QA(i){i=i!=null&&i.ownerDocument!=null&&i.ownerDocument.defaultView!=null?i.ownerDocument.defaultView:window;for(var l=cc(i.document);l instanceof i.HTMLIFrameElement;){try{var f=typeof l.contentWindow.location.href=="string"}catch{f=!1}if(f)i=l.contentWindow;else break;l=cc(i.document)}return l}function rg(i){var l=i&&i.nodeName&&i.nodeName.toLowerCase();return l&&(l==="input"&&(i.type==="text"||i.type==="search"||i.type==="tel"||i.type==="url"||i.type==="password")||l==="textarea"||i.contentEditable==="true")}function H$(i,l){var f=QA(l);l=i.focusedElem;var h=i.selectionRange;if(f!==l&&l&&l.ownerDocument&&ZA(l.ownerDocument.documentElement,l)){if(h!==null&&rg(l)){if(i=h.start,f=h.end,f===void 0&&(f=i),"selectionStart"in l)l.selectionStart=i,l.selectionEnd=Math.min(f,l.value.length);else if(f=(i=l.ownerDocument||document)&&i.defaultView||window,f.getSelection){f=f.getSelection();var v=l.textContent.length,T=Math.min(h.start,v);h=h.end===void 0?T:Math.min(h.end,v),!f.extend&&T>h&&(v=h,h=T,T=v),v=XA(l,T);var P=XA(l,h);v&&P&&(f.rangeCount!==1||f.anchorNode!==v.node||f.anchorOffset!==v.offset||f.focusNode!==P.node||f.focusOffset!==P.offset)&&(i=i.createRange(),i.setStart(v.node,v.offset),f.removeAllRanges(),T>h?(f.addRange(i),f.extend(P.node,P.offset)):(i.setEnd(P.node,P.offset),f.addRange(i)))}}for(i=[],f=l;f=f.parentNode;)f.nodeType===1&&i.push({element:f,left:f.scrollLeft,top:f.scrollTop});for(typeof l.focus=="function"&&l.focus(),l=0;l=document.documentMode,Fi=null,ag=null,pl=null,og=!1;function JA(i,l,f){var h=f.window===f?f.document:f.nodeType===9?f:f.ownerDocument;og||Fi==null||Fi!==cc(h)||(h=Fi,"selectionStart"in h&&rg(h)?h={start:h.selectionStart,end:h.selectionEnd}:(h=(h.ownerDocument&&h.ownerDocument.defaultView||window).getSelection(),h={anchorNode:h.anchorNode,anchorOffset:h.anchorOffset,focusNode:h.focusNode,focusOffset:h.focusOffset}),pl&&fl(pl,h)||(pl=h,h=Jc(ag,"onSelect"),0>=P,v-=P,ma=1<<32-St(l)+v|f<Je?(sn=Ye,Ye=null):sn=Ye.sibling;var wt=de(se,Ye,ue[Je],we);if(wt===null){Ye===null&&(Ye=sn);break}i&&Ye&&wt.alternate===null&&l(se,Ye),te=T(wt,te,Je),lt===null?Ge=wt:lt.sibling=wt,lt=wt,Ye=sn}if(Je===ue.length)return f(se,Ye),Et&&Go(se,Je),Ge;if(Ye===null){for(;JeJe?(sn=Ye,Ye=null):sn=Ye.sibling;var bo=de(se,Ye,wt.value,we);if(bo===null){Ye===null&&(Ye=sn);break}i&&Ye&&bo.alternate===null&&l(se,Ye),te=T(bo,te,Je),lt===null?Ge=bo:lt.sibling=bo,lt=bo,Ye=sn}if(wt.done)return f(se,Ye),Et&&Go(se,Je),Ge;if(Ye===null){for(;!wt.done;Je++,wt=ue.next())wt=Ae(se,wt.value,we),wt!==null&&(te=T(wt,te,Je),lt===null?Ge=wt:lt.sibling=wt,lt=wt);return Et&&Go(se,Je),Ge}for(Ye=h(Ye);!wt.done;Je++,wt=ue.next())wt=ge(Ye,se,Je,wt.value,we),wt!==null&&(i&&wt.alternate!==null&&Ye.delete(wt.key===null?Je:wt.key),te=T(wt,te,Je),lt===null?Ge=wt:lt.sibling=wt,lt=wt);return i&&Ye.forEach(function(s9){return l(se,s9)}),Et&&Go(se,Je),Ge}function Vt(se,te,ue,we){if(typeof ue=="object"&&ue!==null&&ue.type===c&&ue.key===null&&(ue=ue.props.children),typeof ue=="object"&&ue!==null){switch(ue.$$typeof){case s:e:{for(var Ge=ue.key;te!==null;){if(te.key===Ge){if(Ge=ue.type,Ge===c){if(te.tag===7){f(se,te.sibling),we=v(te,ue.props.children),we.return=se,se=we;break e}}else if(te.elementType===Ge||typeof Ge=="object"&&Ge!==null&&Ge.$$typeof===k&&m1(Ge)===te.type){f(se,te.sibling),we=v(te,ue.props),Sl(we,ue),we.return=se,se=we;break e}f(se,te);break}else l(se,te);te=te.sibling}ue.type===c?(we=Jo(ue.props.children,se.mode,we,ue.key),we.return=se,se=we):(we=Hc(ue.type,ue.key,ue.props,null,se.mode,we),Sl(we,ue),we.return=se,se=we)}return P(se);case u:e:{for(Ge=ue.key;te!==null;){if(te.key===Ge)if(te.tag===4&&te.stateNode.containerInfo===ue.containerInfo&&te.stateNode.implementation===ue.implementation){f(se,te.sibling),we=v(te,ue.children||[]),we.return=se,se=we;break e}else{f(se,te);break}else l(se,te);te=te.sibling}we=sh(ue,se.mode,we),we.return=se,se=we}return P(se);case k:return Ge=ue._init,ue=Ge(ue._payload),Vt(se,te,ue,we)}if(M(ue))return qe(se,te,ue,we);if(_(ue)){if(Ge=_(ue),typeof Ge!="function")throw Error(r(150));return ue=Ge.call(ue),nt(se,te,ue,we)}if(typeof ue.then=="function")return Vt(se,te,kc(ue),we);if(ue.$$typeof===b)return Vt(se,te,Uc(se,ue),we);Tc(se,ue)}return typeof ue=="string"&&ue!==""||typeof ue=="number"||typeof ue=="bigint"?(ue=""+ue,te!==null&&te.tag===6?(f(se,te.sibling),we=v(te,ue),we.return=se,se=we):(f(se,te),we=ih(ue,se.mode,we),we.return=se,se=we),P(se)):f(se,te)}return function(se,te,ue,we){try{vl=0;var Ge=Vt(se,te,ue,we);return Gi=null,Ge}catch(Ye){if(Ye===bl)throw Ye;var lt=hr(29,Ye,null,se.mode);return lt.lanes=we,lt.return=se,lt}finally{}}}var $o=b1(!0),y1=b1(!1),Hi=ie(null),Ac=ie(0);function v1(i,l){i=_a,ae(Ac,i),ae(Hi,l),_a=i|l.baseLanes}function pg(){ae(Ac,_a),ae(Hi,Hi.current)}function gg(){_a=Ac.current,Se(Hi),Se(Ac)}var fr=ie(null),Vr=null;function Qa(i){var l=i.alternate;ae(en,en.current&1),ae(fr,i),Vr===null&&(l===null||Hi.current!==null||l.memoizedState!==null)&&(Vr=i)}function S1(i){if(i.tag===22){if(ae(en,en.current),ae(fr,i),Vr===null){var l=i.alternate;l!==null&&l.memoizedState!==null&&(Vr=i)}}else Ja()}function Ja(){ae(en,en.current),ae(fr,fr.current)}function ya(i){Se(fr),Vr===i&&(Vr=null),Se(en)}var en=ie(0);function Rc(i){for(var l=i;l!==null;){if(l.tag===13){var f=l.memoizedState;if(f!==null&&(f=f.dehydrated,f===null||f.data==="$?"||f.data==="$!"))return l}else if(l.tag===19&&l.memoizedProps.revealOrder!==void 0){if(l.flags&128)return l}else if(l.child!==null){l.child.return=l,l=l.child;continue}if(l===i)break;for(;l.sibling===null;){if(l.return===null||l.return===i)return null;l=l.return}l.sibling.return=l.return,l=l.sibling}return null}var Y$=typeof AbortController<"u"?AbortController:function(){var i=[],l=this.signal={aborted:!1,addEventListener:function(f,h){i.push(h)}};this.abort=function(){l.aborted=!0,i.forEach(function(f){return f()})}},K$=e.unstable_scheduleCallback,X$=e.unstable_NormalPriority,tn={$$typeof:b,Consumer:null,Provider:null,_currentValue:null,_currentValue2:null,_threadCount:0};function hg(){return{controller:new Y$,data:new Map,refCount:0}}function El(i){i.refCount--,i.refCount===0&&K$(X$,function(){i.controller.abort()})}var wl=null,mg=0,$i=0,qi=null;function Z$(i,l){if(wl===null){var f=wl=[];mg=0,$i=wh(),qi={status:"pending",value:void 0,then:function(h){f.push(h)}}}return mg++,l.then(E1,E1),l}function E1(){if(--mg===0&&wl!==null){qi!==null&&(qi.status="fulfilled");var i=wl;wl=null,$i=0,qi=null;for(var l=0;lT?T:8;var P=L.T,q={};L.T=q,Ig(i,!1,l,f);try{var X=v(),ne=L.S;if(ne!==null&&ne(q,X),X!==null&&typeof X=="object"&&typeof X.then=="function"){var be=Q$(X,h);Tl(i,l,be,Qn(i))}else Tl(i,l,h,Qn(i))}catch(Ae){Tl(i,l,{then:function(){},status:"rejected",reason:Ae},Qn())}finally{W.p=T,L.T=P}}function r6(){}function Og(i,l,f,h){if(i.tag!==5)throw Error(r(476));var v=Q1(i).queue;Z1(i,v,l,Q,f===null?r6:function(){return J1(i),f(h)})}function Q1(i){var l=i.memoizedState;if(l!==null)return l;l={memoizedState:Q,baseState:Q,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:va,lastRenderedState:Q},next:null};var f={};return l.next={memoizedState:f,baseState:f,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:va,lastRenderedState:f},next:null},i.memoizedState=l,i=i.alternate,i!==null&&(i.memoizedState=l),l}function J1(i){var l=Q1(i).next.queue;Tl(i,l,{},Qn())}function Dg(){return En(ql)}function eR(){return Xt().memoizedState}function tR(){return Xt().memoizedState}function a6(i){for(var l=i.return;l!==null;){switch(l.tag){case 24:case 3:var f=Qn();i=ao(f);var h=oo(l,i,f);h!==null&&(Nn(h,l,f),_l(h,l,f)),l={cache:hg()},i.payload=l;return}l=l.return}}function o6(i,l,f){var h=Qn();f={lane:h,revertLane:0,action:f,hasEagerState:!1,eagerState:null,next:null},Fc(i)?rR(l,f):(f=lg(i,l,f,h),f!==null&&(Nn(f,i,h),aR(f,l,h)))}function nR(i,l,f){var h=Qn();Tl(i,l,f,h)}function Tl(i,l,f,h){var v={lane:h,revertLane:0,action:f,hasEagerState:!1,eagerState:null,next:null};if(Fc(i))rR(l,v);else{var T=i.alternate;if(i.lanes===0&&(T===null||T.lanes===0)&&(T=l.lastRenderedReducer,T!==null))try{var P=l.lastRenderedState,q=T(P,f);if(v.hasEagerState=!0,v.eagerState=q,Yn(q,P))return vc(i,l,v,0),It===null&&yc(),!1}catch{}finally{}if(f=lg(i,l,v,h),f!==null)return Nn(f,i,h),aR(f,l,h),!0}return!1}function Ig(i,l,f,h){if(h={lane:2,revertLane:wh(),action:h,hasEagerState:!1,eagerState:null,next:null},Fc(i)){if(l)throw Error(r(479))}else l=lg(i,f,h,2),l!==null&&Nn(l,i,2)}function Fc(i){var l=i.alternate;return i===st||l!==null&&l===st}function rR(i,l){Vi=Cc=!0;var f=i.pending;f===null?l.next=l:(l.next=f.next,f.next=l),i.pending=l}function aR(i,l,f){if(f&4194176){var h=l.lanes;h&=i.pendingLanes,f|=h,l.lanes=f,Rr(i,f)}}var Wr={readContext:En,use:Dc,useCallback:Wt,useContext:Wt,useEffect:Wt,useImperativeHandle:Wt,useLayoutEffect:Wt,useInsertionEffect:Wt,useMemo:Wt,useReducer:Wt,useRef:Wt,useState:Wt,useDebugValue:Wt,useDeferredValue:Wt,useTransition:Wt,useSyncExternalStore:Wt,useId:Wt};Wr.useCacheRefresh=Wt,Wr.useMemoCache=Wt,Wr.useHostTransitionStatus=Wt,Wr.useFormState=Wt,Wr.useActionState=Wt,Wr.useOptimistic=Wt;var Wo={readContext:En,use:Dc,useCallback:function(i,l){return Pn().memoizedState=[i,l===void 0?null:l],i},useContext:En,useEffect:H1,useImperativeHandle:function(i,l,f){f=f!=null?f.concat([i]):null,Lc(4194308,4,V1.bind(null,l,i),f)},useLayoutEffect:function(i,l){return Lc(4194308,4,i,l)},useInsertionEffect:function(i,l){Lc(4,2,i,l)},useMemo:function(i,l){var f=Pn();l=l===void 0?null:l;var h=i();if(Vo){ot(!0);try{i()}finally{ot(!1)}}return f.memoizedState=[h,l],h},useReducer:function(i,l,f){var h=Pn();if(f!==void 0){var v=f(l);if(Vo){ot(!0);try{f(l)}finally{ot(!1)}}}else v=l;return h.memoizedState=h.baseState=v,i={pending:null,lanes:0,dispatch:null,lastRenderedReducer:i,lastRenderedState:v},h.queue=i,i=i.dispatch=o6.bind(null,st,i),[h.memoizedState,i]},useRef:function(i){var l=Pn();return i={current:i},l.memoizedState=i},useState:function(i){i=Ag(i);var l=i.queue,f=nR.bind(null,st,l);return l.dispatch=f,[i.memoizedState,f]},useDebugValue:Cg,useDeferredValue:function(i,l){var f=Pn();return Ng(f,i,l)},useTransition:function(){var i=Ag(!1);return i=Z1.bind(null,st,i.queue,!0,!1),Pn().memoizedState=i,[!1,i]},useSyncExternalStore:function(i,l,f){var h=st,v=Pn();if(Et){if(f===void 0)throw Error(r(407));f=f()}else{if(f=l(),It===null)throw Error(r(349));bt&60||R1(h,l,f)}v.memoizedState=f;var T={value:f,getSnapshot:l};return v.queue=T,H1(C1.bind(null,h,T,i),[i]),h.flags|=2048,Yi(9,_1.bind(null,h,T,f,l),{destroy:void 0},null),f},useId:function(){var i=Pn(),l=It.identifierPrefix;if(Et){var f=ba,h=ma;f=(h&~(1<<32-St(h)-1)).toString(32)+f,l=":"+l+"R"+f,f=Nc++,0 title"))),hn(T,h,f),T[Sn]=i,rn(T),h=T;break e;case"link":var P=O_("link","href",v).get(h+(f.href||""));if(P){for(var q=0;q<\/script>",i=i.removeChild(i.firstChild);break;case"select":i=typeof h.is=="string"?v.createElement("select",{is:h.is}):v.createElement("select"),h.multiple?i.multiple=!0:h.size&&(i.size=h.size);break;default:i=typeof h.is=="string"?v.createElement(f,{is:h.is}):v.createElement(f)}}i[Sn]=l,i[Mn]=h;e:for(v=l.child;v!==null;){if(v.tag===5||v.tag===6)i.appendChild(v.stateNode);else if(v.tag!==4&&v.tag!==27&&v.child!==null){v.child.return=v,v=v.child;continue}if(v===l)break e;for(;v.sibling===null;){if(v.return===null||v.return===l)break e;v=v.return}v.sibling.return=v.return,v=v.sibling}l.stateNode=i;e:switch(hn(i,f,h),f){case"button":case"input":case"select":case"textarea":i=!!h.autoFocus;break e;case"img":i=!0;break e;default:i=!1}i&&Aa(l)}}return Bt(l),l.flags&=-16777217,null;case 6:if(i&&l.stateNode!=null)i.memoizedProps!==h&&Aa(l);else{if(typeof h!="string"&&l.stateNode===null)throw Error(r(166));if(i=Ie.current,gl(l)){if(i=l.stateNode,f=l.memoizedProps,h=null,v=Cn,v!==null)switch(v.tag){case 27:case 5:h=v.memoizedProps}i[Sn]=l,i=!!(i.nodeValue===f||h!==null&&h.suppressHydrationWarning===!0||v_(i.nodeValue,f)),i||Ho(l)}else i=td(i).createTextNode(h),i[Sn]=l,l.stateNode=i}return Bt(l),null;case 13:if(h=l.memoizedState,i===null||i.memoizedState!==null&&i.memoizedState.dehydrated!==null){if(v=gl(l),h!==null&&h.dehydrated!==null){if(i===null){if(!v)throw Error(r(318));if(v=l.memoizedState,v=v!==null?v.dehydrated:null,!v)throw Error(r(317));v[Sn]=l}else hl(),!(l.flags&128)&&(l.memoizedState=null),l.flags|=4;Bt(l),v=!1}else Cr!==null&&(hh(Cr),Cr=null),v=!0;if(!v)return l.flags&256?(ya(l),l):(ya(l),null)}if(ya(l),l.flags&128)return l.lanes=f,l;if(f=h!==null,i=i!==null&&i.memoizedState!==null,f){h=l.child,v=null,h.alternate!==null&&h.alternate.memoizedState!==null&&h.alternate.memoizedState.cachePool!==null&&(v=h.alternate.memoizedState.cachePool.pool);var T=null;h.memoizedState!==null&&h.memoizedState.cachePool!==null&&(T=h.memoizedState.cachePool.pool),T!==v&&(h.flags|=2048)}return f!==i&&f&&(l.child.flags|=8192),$c(l,l.updateQueue),Bt(l),null;case 4:return J(),i===null&&Ah(l.stateNode.containerInfo),Bt(l),null;case 10:return wa(l.type),Bt(l),null;case 19:if(Se(en),v=l.memoizedState,v===null)return Bt(l),null;if(h=(l.flags&128)!==0,T=v.rendering,T===null)if(h)Ml(v,!1);else{if(qt!==0||i!==null&&i.flags&128)for(i=l.child;i!==null;){if(T=Rc(i),T!==null){for(l.flags|=128,Ml(v,!1),i=T.updateQueue,l.updateQueue=i,$c(l,i),l.subtreeFlags=0,i=f,f=l.child;f!==null;)WR(f,i),f=f.sibling;return ae(en,en.current&1|2),l.child}i=i.sibling}v.tail!==null&&he()>qc&&(l.flags|=128,h=!0,Ml(v,!1),l.lanes=4194304)}else{if(!h)if(i=Rc(T),i!==null){if(l.flags|=128,h=!0,i=i.updateQueue,l.updateQueue=i,$c(l,i),Ml(v,!0),v.tail===null&&v.tailMode==="hidden"&&!T.alternate&&!Et)return Bt(l),null}else 2*he()-v.renderingStartTime>qc&&f!==536870912&&(l.flags|=128,h=!0,Ml(v,!1),l.lanes=4194304);v.isBackwards?(T.sibling=l.child,l.child=T):(i=v.last,i!==null?i.sibling=T:l.child=T,v.last=T)}return v.tail!==null?(l=v.tail,v.rendering=l,v.tail=l.sibling,v.renderingStartTime=he(),l.sibling=null,i=en.current,ae(en,h?i&1|2:i&1),l):(Bt(l),null);case 22:case 23:return ya(l),gg(),h=l.memoizedState!==null,i!==null?i.memoizedState!==null!==h&&(l.flags|=8192):h&&(l.flags|=8192),h?f&536870912&&!(l.flags&128)&&(Bt(l),l.subtreeFlags&6&&(l.flags|=8192)):Bt(l),f=l.updateQueue,f!==null&&$c(l,f.retryQueue),f=null,i!==null&&i.memoizedState!==null&&i.memoizedState.cachePool!==null&&(f=i.memoizedState.cachePool.pool),h=null,l.memoizedState!==null&&l.memoizedState.cachePool!==null&&(h=l.memoizedState.cachePool.pool),h!==f&&(l.flags|=2048),i!==null&&Se(qo),null;case 24:return f=null,i!==null&&(f=i.memoizedState.cache),l.memoizedState.cache!==f&&(l.flags|=2048),wa(tn),Bt(l),null;case 25:return null}throw Error(r(156,l.tag))}function f6(i,l){switch(cg(l),l.tag){case 1:return i=l.flags,i&65536?(l.flags=i&-65537|128,l):null;case 3:return wa(tn),J(),i=l.flags,i&65536&&!(i&128)?(l.flags=i&-65537|128,l):null;case 26:case 27:case 5:return Te(l),null;case 13:if(ya(l),i=l.memoizedState,i!==null&&i.dehydrated!==null){if(l.alternate===null)throw Error(r(340));hl()}return i=l.flags,i&65536?(l.flags=i&-65537|128,l):null;case 19:return Se(en),null;case 4:return J(),null;case 10:return wa(l.type),null;case 22:case 23:return ya(l),gg(),i!==null&&Se(qo),i=l.flags,i&65536?(l.flags=i&-65537|128,l):null;case 24:return wa(tn),null;case 25:return null;default:return null}}function XR(i,l){switch(cg(l),l.tag){case 3:wa(tn),J();break;case 26:case 27:case 5:Te(l);break;case 4:J();break;case 13:ya(l);break;case 19:Se(en);break;case 10:wa(l.type);break;case 22:case 23:ya(l),gg(),i!==null&&Se(qo);break;case 24:wa(tn)}}var p6={getCacheForType:function(i){var l=En(tn),f=l.data.get(i);return f===void 0&&(f=i(),l.data.set(i,f)),f}},g6=typeof WeakMap=="function"?WeakMap:Map,Ut=0,It=null,ct=null,bt=0,Lt=0,Zn=null,Ra=!1,Qi=!1,lh=!1,_a=0,qt=0,co=0,ei=0,uh=0,mr=0,Ji=0,Fl=null,Yr=null,ch=!1,dh=0,qc=1/0,Vc=null,fo=null,Wc=!1,ti=null,Pl=0,fh=0,ph=null,zl=0,gh=null;function Qn(){if(Ut&2&&bt!==0)return bt&-bt;if(L.T!==null){var i=$i;return i!==0?i:wh()}return bA()}function ZR(){mr===0&&(mr=!(bt&536870912)||Et?Ct():536870912);var i=fr.current;return i!==null&&(i.flags|=32),mr}function Nn(i,l,f){(i===It&&Lt===2||i.cancelPendingCommit!==null)&&(es(i,0),Ca(i,bt,mr,!1)),In(i,f),(!(Ut&2)||i!==It)&&(i===It&&(!(Ut&2)&&(ei|=f),qt===4&&Ca(i,bt,mr,!1)),Kr(i))}function QR(i,l,f){if(Ut&6)throw Error(r(327));var h=!f&&(l&60)===0&&(l&i.expiredLanes)===0||Xe(i,l),v=h?b6(i,l):yh(i,l,!0),T=h;do{if(v===0){Qi&&!h&&Ca(i,l,0,!1);break}else if(v===6)Ca(i,l,0,!Ra);else{if(f=i.current.alternate,T&&!h6(f)){v=yh(i,l,!1),T=!1;continue}if(v===2){if(T=l,i.errorRecoveryDisabledLanes&T)var P=0;else P=i.pendingLanes&-536870913,P=P!==0?P:P&536870912?536870912:0;if(P!==0){l=P;e:{var q=i;v=Fl;var X=q.current.memoizedState.isDehydrated;if(X&&(es(q,P).flags|=256),P=yh(q,P,!1),P!==2){if(lh&&!X){q.errorRecoveryDisabledLanes|=T,ei|=T,v=4;break e}T=Yr,Yr=v,T!==null&&hh(T)}v=P}if(T=!1,v!==2)continue}}if(v===1){es(i,0),Ca(i,l,0,!0);break}e:{switch(h=i,v){case 0:case 1:throw Error(r(345));case 4:if((l&4194176)===l){Ca(h,l,mr,!Ra);break e}break;case 2:Yr=null;break;case 3:case 5:break;default:throw Error(r(329))}if(h.finishedWork=f,h.finishedLanes=l,(l&62914560)===l&&(T=dh+300-he(),10f?32:f,L.T=null,ti===null)var T=!1;else{f=ph,ph=null;var P=ti,q=Pl;if(ti=null,Pl=0,Ut&6)throw Error(r(331));var X=Ut;if(Ut|=4,qR(P.current),GR(P,P.current,q,f),Ut=X,Bl(0,!1),et&&typeof et.onPostCommitFiberRoot=="function")try{et.onPostCommitFiberRoot(ht,P)}catch{}T=!0}return T}finally{W.p=v,L.T=h,s_(i,l)}}return!1}function l_(i,l,f){l=ur(f,l),l=Fg(i.stateNode,l,2),i=oo(i,l,2),i!==null&&(In(i,2),Kr(i))}function Nt(i,l,f){if(i.tag===3)l_(i,i,f);else for(;l!==null;){if(l.tag===3){l_(l,i,f);break}else if(l.tag===1){var h=l.stateNode;if(typeof l.type.getDerivedStateFromError=="function"||typeof h.componentDidCatch=="function"&&(fo===null||!fo.has(h))){i=ur(f,i),f=dR(2),h=oo(l,f,2),h!==null&&(fR(f,h,l,i),In(h,2),Kr(h));break}}l=l.return}}function vh(i,l,f){var h=i.pingCache;if(h===null){h=i.pingCache=new g6;var v=new Set;h.set(l,v)}else v=h.get(l),v===void 0&&(v=new Set,h.set(l,v));v.has(f)||(lh=!0,v.add(f),i=S6.bind(null,i,l,f),l.then(i,i))}function S6(i,l,f){var h=i.pingCache;h!==null&&h.delete(l),i.pingedLanes|=i.suspendedLanes&f,i.warmLanes&=~f,It===i&&(bt&f)===f&&(qt===4||qt===3&&(bt&62914560)===bt&&300>he()-dh?!(Ut&2)&&es(i,0):uh|=f,Ji===bt&&(Ji=0)),Kr(i)}function u_(i,l){l===0&&(l=Dn()),i=Za(i,l),i!==null&&(In(i,l),Kr(i))}function E6(i){var l=i.memoizedState,f=0;l!==null&&(f=l.retryLane),u_(i,f)}function w6(i,l){var f=0;switch(i.tag){case 13:var h=i.stateNode,v=i.memoizedState;v!==null&&(f=v.retryLane);break;case 19:h=i.stateNode;break;case 22:h=i.stateNode._retryCache;break;default:throw Error(r(314))}h!==null&&h.delete(l),u_(i,f)}function x6(i,l){return Ee(i,l)}var Xc=null,rs=null,Sh=!1,Zc=!1,Eh=!1,ni=0;function Kr(i){i!==rs&&i.next===null&&(rs===null?Xc=rs=i:rs=rs.next=i),Zc=!0,Sh||(Sh=!0,T6(k6))}function Bl(i,l){if(!Eh&&Zc){Eh=!0;do for(var f=!1,h=Xc;h!==null;){if(i!==0){var v=h.pendingLanes;if(v===0)var T=0;else{var P=h.suspendedLanes,q=h.pingedLanes;T=(1<<31-St(42|i)+1)-1,T&=v&~(P&~q),T=T&201326677?T&201326677|1:T?T|2:0}T!==0&&(f=!0,f_(h,T))}else T=bt,T=fa(h,h===It?T:0),!(T&3)||Xe(h,T)||(f=!0,f_(h,T));h=h.next}while(f);Eh=!1}}function k6(){Zc=Sh=!1;var i=0;ni!==0&&(I6()&&(i=ni),ni=0);for(var l=he(),f=null,h=Xc;h!==null;){var v=h.next,T=c_(h,l);T===0?(h.next=null,f===null?Xc=v:f.next=v,v===null&&(rs=f)):(f=h,(i!==0||T&3)&&(Zc=!0)),h=v}Bl(i)}function c_(i,l){for(var f=i.suspendedLanes,h=i.pingedLanes,v=i.expirationTimes,T=i.pendingLanes&-62914561;0"u"?null:document;function R_(i,l,f){var h=os;if(h&&typeof l=="string"&&l){var v=sr(l);v='link[rel="'+i+'"][href="'+v+'"]',typeof f=="string"&&(v+='[crossorigin="'+f+'"]'),A_.has(v)||(A_.add(v),i={rel:i,crossOrigin:f,href:l},h.querySelector(v)===null&&(l=h.createElement("link"),hn(l,"link",i),rn(l),h.head.appendChild(l)))}}function j6(i){Na.D(i),R_("dns-prefetch",i,null)}function G6(i,l){Na.C(i,l),R_("preconnect",i,l)}function H6(i,l,f){Na.L(i,l,f);var h=os;if(h&&i&&l){var v='link[rel="preload"][as="'+sr(l)+'"]';l==="image"&&f&&f.imageSrcSet?(v+='[imagesrcset="'+sr(f.imageSrcSet)+'"]',typeof f.imageSizes=="string"&&(v+='[imagesizes="'+sr(f.imageSizes)+'"]')):v+='[href="'+sr(i)+'"]';var T=v;switch(l){case"style":T=is(i);break;case"script":T=ss(i)}br.has(T)||(i=I({rel:"preload",href:l==="image"&&f&&f.imageSrcSet?void 0:i,as:l},f),br.set(T,i),h.querySelector(v)!==null||l==="style"&&h.querySelector(Gl(T))||l==="script"&&h.querySelector(Hl(T))||(l=h.createElement("link"),hn(l,"link",i),rn(l),h.head.appendChild(l)))}}function $6(i,l){Na.m(i,l);var f=os;if(f&&i){var h=l&&typeof l.as=="string"?l.as:"script",v='link[rel="modulepreload"][as="'+sr(h)+'"][href="'+sr(i)+'"]',T=v;switch(h){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":T=ss(i)}if(!br.has(T)&&(i=I({rel:"modulepreload",href:i},l),br.set(T,i),f.querySelector(v)===null)){switch(h){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(f.querySelector(Hl(T)))return}h=f.createElement("link"),hn(h,"link",i),rn(h),f.head.appendChild(h)}}}function q6(i,l,f){Na.S(i,l,f);var h=os;if(h&&i){var v=Ci(h).hoistableStyles,T=is(i);l=l||"default";var P=v.get(T);if(!P){var q={loading:0,preload:null};if(P=h.querySelector(Gl(T)))q.loading=5;else{i=I({rel:"stylesheet",href:i,"data-precedence":l},f),(f=br.get(T))&&Mh(i,f);var X=P=h.createElement("link");rn(X),hn(X,"link",i),X._p=new Promise(function(ne,be){X.onload=ne,X.onerror=be}),X.addEventListener("load",function(){q.loading|=1}),X.addEventListener("error",function(){q.loading|=2}),q.loading|=4,rd(P,l,h)}P={type:"stylesheet",instance:P,count:1,state:q},v.set(T,P)}}}function V6(i,l){Na.X(i,l);var f=os;if(f&&i){var h=Ci(f).hoistableScripts,v=ss(i),T=h.get(v);T||(T=f.querySelector(Hl(v)),T||(i=I({src:i,async:!0},l),(l=br.get(v))&&Fh(i,l),T=f.createElement("script"),rn(T),hn(T,"link",i),f.head.appendChild(T)),T={type:"script",instance:T,count:1,state:null},h.set(v,T))}}function W6(i,l){Na.M(i,l);var f=os;if(f&&i){var h=Ci(f).hoistableScripts,v=ss(i),T=h.get(v);T||(T=f.querySelector(Hl(v)),T||(i=I({src:i,async:!0,type:"module"},l),(l=br.get(v))&&Fh(i,l),T=f.createElement("script"),rn(T),hn(T,"link",i),f.head.appendChild(T)),T={type:"script",instance:T,count:1,state:null},h.set(v,T))}}function __(i,l,f,h){var v=(v=Ie.current)?nd(v):null;if(!v)throw Error(r(446));switch(i){case"meta":case"title":return null;case"style":return typeof f.precedence=="string"&&typeof f.href=="string"?(l=is(f.href),f=Ci(v).hoistableStyles,h=f.get(l),h||(h={type:"style",instance:null,count:0,state:null},f.set(l,h)),h):{type:"void",instance:null,count:0,state:null};case"link":if(f.rel==="stylesheet"&&typeof f.href=="string"&&typeof f.precedence=="string"){i=is(f.href);var T=Ci(v).hoistableStyles,P=T.get(i);if(P||(v=v.ownerDocument||v,P={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},T.set(i,P),(T=v.querySelector(Gl(i)))&&!T._p&&(P.instance=T,P.state.loading=5),br.has(i)||(f={rel:"preload",as:"style",href:f.href,crossOrigin:f.crossOrigin,integrity:f.integrity,media:f.media,hrefLang:f.hrefLang,referrerPolicy:f.referrerPolicy},br.set(i,f),T||Y6(v,i,f,P.state))),l&&h===null)throw Error(r(528,""));return P}if(l&&h!==null)throw Error(r(529,""));return null;case"script":return l=f.async,f=f.src,typeof f=="string"&&l&&typeof l!="function"&&typeof l!="symbol"?(l=ss(f),f=Ci(v).hoistableScripts,h=f.get(l),h||(h={type:"script",instance:null,count:0,state:null},f.set(l,h)),h):{type:"void",instance:null,count:0,state:null};default:throw Error(r(444,i))}}function is(i){return'href="'+sr(i)+'"'}function Gl(i){return'link[rel="stylesheet"]['+i+"]"}function C_(i){return I({},i,{"data-precedence":i.precedence,precedence:null})}function Y6(i,l,f,h){i.querySelector('link[rel="preload"][as="style"]['+l+"]")?h.loading=1:(l=i.createElement("link"),h.preload=l,l.addEventListener("load",function(){return h.loading|=1}),l.addEventListener("error",function(){return h.loading|=2}),hn(l,"link",f),rn(l),i.head.appendChild(l))}function ss(i){return'[src="'+sr(i)+'"]'}function Hl(i){return"script[async]"+i}function N_(i,l,f){if(l.count++,l.instance===null)switch(l.type){case"style":var h=i.querySelector('style[data-href~="'+sr(f.href)+'"]');if(h)return l.instance=h,rn(h),h;var v=I({},f,{"data-href":f.href,"data-precedence":f.precedence,href:null,precedence:null});return h=(i.ownerDocument||i).createElement("style"),rn(h),hn(h,"style",v),rd(h,f.precedence,i),l.instance=h;case"stylesheet":v=is(f.href);var T=i.querySelector(Gl(v));if(T)return l.state.loading|=4,l.instance=T,rn(T),T;h=C_(f),(v=br.get(v))&&Mh(h,v),T=(i.ownerDocument||i).createElement("link"),rn(T);var P=T;return P._p=new Promise(function(q,X){P.onload=q,P.onerror=X}),hn(T,"link",h),l.state.loading|=4,rd(T,f.precedence,i),l.instance=T;case"script":return T=ss(f.src),(v=i.querySelector(Hl(T)))?(l.instance=v,rn(v),v):(h=f,(v=br.get(T))&&(h=I({},f),Fh(h,v)),i=i.ownerDocument||i,v=i.createElement("script"),rn(v),hn(v,"link",h),i.head.appendChild(v),l.instance=v);case"void":return null;default:throw Error(r(443,l.type))}else l.type==="stylesheet"&&!(l.state.loading&4)&&(h=l.instance,l.state.loading|=4,rd(h,f.precedence,i));return l.instance}function rd(i,l,f){for(var h=f.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),v=h.length?h[h.length-1]:null,T=v,P=0;P title"):null)}function K6(i,l,f){if(f===1||l.itemProp!=null)return!1;switch(i){case"meta":case"title":return!0;case"style":if(typeof l.precedence!="string"||typeof l.href!="string"||l.href==="")break;return!0;case"link":if(typeof l.rel!="string"||typeof l.href!="string"||l.href===""||l.onLoad||l.onError)break;switch(l.rel){case"stylesheet":return i=l.disabled,typeof l.precedence=="string"&&i==null;default:return!0}case"script":if(l.async&&typeof l.async!="function"&&typeof l.async!="symbol"&&!l.onLoad&&!l.onError&&l.src&&typeof l.src=="string")return!0}return!1}function I_(i){return!(i.type==="stylesheet"&&!(i.state.loading&3))}var $l=null;function X6(){}function Z6(i,l,f){if($l===null)throw Error(r(475));var h=$l;if(l.type==="stylesheet"&&(typeof f.media!="string"||matchMedia(f.media).matches!==!1)&&!(l.state.loading&4)){if(l.instance===null){var v=is(f.href),T=i.querySelector(Gl(v));if(T){i=T._p,i!==null&&typeof i=="object"&&typeof i.then=="function"&&(h.count++,h=od.bind(h),i.then(h,h)),l.state.loading|=4,l.instance=T,rn(T);return}T=i.ownerDocument||i,f=C_(f),(v=br.get(v))&&Mh(f,v),T=T.createElement("link"),rn(T);var P=T;P._p=new Promise(function(q,X){P.onload=q,P.onerror=X}),hn(T,"link",f),l.instance=T}h.stylesheets===null&&(h.stylesheets=new Map),h.stylesheets.set(l,i),(i=l.state.preload)&&!(l.state.loading&3)&&(h.count++,l=od.bind(h),i.addEventListener("load",l),i.addEventListener("error",l))}}function Q6(){if($l===null)throw Error(r(475));var i=$l;return i.stylesheets&&i.count===0&&Ph(i,i.stylesheets),0"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}return e(),Vh.exports=v9(),Vh.exports}var E9=S9(),Ql={},tC;function w9(){if(tC)return Ql;tC=1,Object.defineProperty(Ql,"__esModule",{value:!0}),Ql.parse=s,Ql.serialize=d;const e=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,t=/^[\u0021-\u003A\u003C-\u007E]*$/,n=/^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,r=/^[\u0020-\u003A\u003D-\u007E]*$/,a=Object.prototype.toString,o=(()=>{const m=function(){};return m.prototype=Object.create(null),m})();function s(m,b){const y=new o,S=m.length;if(S<2)return y;const x=(b==null?void 0:b.decode)||p;let R=0;do{const k=m.indexOf("=",R);if(k===-1)break;const A=m.indexOf(";",R),C=A===-1?S:A;if(k>C){R=m.lastIndexOf(";",k-1)+1;continue}const N=u(m,R,k),_=c(m,k,N),O=m.slice(N,_);if(y[O]===void 0){let F=u(m,k+1,C),L=c(m,C,F);const I=x(m.slice(F,L));y[O]=I}R=C+1}while(Ry;){const S=m.charCodeAt(--b);if(S!==32&&S!==9)return b+1}return y}function d(m,b,y){const S=(y==null?void 0:y.encode)||encodeURIComponent;if(!e.test(m))throw new TypeError(`argument name is invalid: ${m}`);const x=S(b);if(!t.test(x))throw new TypeError(`argument val is invalid: ${b}`);let R=m+"="+x;if(!y)return R;if(y.maxAge!==void 0){if(!Number.isInteger(y.maxAge))throw new TypeError(`option maxAge is invalid: ${y.maxAge}`);R+="; Max-Age="+y.maxAge}if(y.domain){if(!n.test(y.domain))throw new TypeError(`option domain is invalid: ${y.domain}`);R+="; Domain="+y.domain}if(y.path){if(!r.test(y.path))throw new TypeError(`option path is invalid: ${y.path}`);R+="; Path="+y.path}if(y.expires){if(!g(y.expires)||!Number.isFinite(y.expires.valueOf()))throw new TypeError(`option expires is invalid: ${y.expires}`);R+="; Expires="+y.expires.toUTCString()}if(y.httpOnly&&(R+="; HttpOnly"),y.secure&&(R+="; Secure"),y.partitioned&&(R+="; Partitioned"),y.priority)switch(typeof y.priority=="string"?y.priority.toLowerCase():void 0){case"low":R+="; Priority=Low";break;case"medium":R+="; Priority=Medium";break;case"high":R+="; Priority=High";break;default:throw new TypeError(`option priority is invalid: ${y.priority}`)}if(y.sameSite)switch(typeof y.sameSite=="string"?y.sameSite.toLowerCase():y.sameSite){case!0:case"strict":R+="; SameSite=Strict";break;case"lax":R+="; SameSite=Lax";break;case"none":R+="; SameSite=None";break;default:throw new TypeError(`option sameSite is invalid: ${y.sameSite}`)}return R}function p(m){if(m.indexOf("%")===-1)return m;try{return decodeURIComponent(m)}catch{return m}}function g(m){return a.call(m)==="[object Date]"}return Ql}w9();/** - * react-router v7.3.0 - * - * Copyright (c) Remix Software Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE.md file in the root directory of this source tree. - * - * @license MIT - */var nC="popstate";function x9(e={}){function t(a,o){let{pathname:s="/",search:u="",hash:c=""}=Ei(a.location.hash.substring(1));return!s.startsWith("/")&&!s.startsWith(".")&&(s="/"+s),rk("",{pathname:s,search:u,hash:c},o.state&&o.state.usr||null,o.state&&o.state.key||"default")}function n(a,o){let s=a.document.querySelector("base"),u="";if(s&&s.getAttribute("href")){let c=a.location.href,d=c.indexOf("#");u=d===-1?c:c.slice(0,d)}return u+"#"+(typeof o=="string"?o:Eu(o))}function r(a,o){Br(a.pathname.charAt(0)==="/",`relative pathnames are not supported in hash history.push(${JSON.stringify(o)})`)}return T9(t,n,r,e)}function Gt(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function Br(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function k9(){return Math.random().toString(36).substring(2,10)}function rC(e,t){return{usr:e.state,key:e.key,idx:t}}function rk(e,t,n=null,r){return{pathname:typeof e=="string"?e:e.pathname,search:"",hash:"",...typeof t=="string"?Ei(t):t,state:n,key:t&&t.key||r||k9()}}function Eu({pathname:e="/",search:t="",hash:n=""}){return t&&t!=="?"&&(e+=t.charAt(0)==="?"?t:"?"+t),n&&n!=="#"&&(e+=n.charAt(0)==="#"?n:"#"+n),e}function Ei(e){let t={};if(e){let n=e.indexOf("#");n>=0&&(t.hash=e.substring(n),e=e.substring(0,n));let r=e.indexOf("?");r>=0&&(t.search=e.substring(r),e=e.substring(0,r)),e&&(t.pathname=e)}return t}function T9(e,t,n,r={}){let{window:a=document.defaultView,v5Compat:o=!1}=r,s=a.history,u="POP",c=null,d=p();d==null&&(d=0,s.replaceState({...s.state,idx:d},""));function p(){return(s.state||{idx:null}).idx}function g(){u="POP";let x=p(),R=x==null?null:x-d;d=x,c&&c({action:u,location:S.location,delta:R})}function m(x,R){u="PUSH";let k=rk(S.location,x,R);n&&n(k,x),d=p()+1;let A=rC(k,d),C=S.createHref(k);try{s.pushState(A,"",C)}catch(N){if(N instanceof DOMException&&N.name==="DataCloneError")throw N;a.location.assign(C)}o&&c&&c({action:u,location:S.location,delta:1})}function b(x,R){u="REPLACE";let k=rk(S.location,x,R);n&&n(k,x),d=p();let A=rC(k,d),C=S.createHref(k);s.replaceState(A,"",C),o&&c&&c({action:u,location:S.location,delta:0})}function y(x){let R=a.location.origin!=="null"?a.location.origin:a.location.href,k=typeof x=="string"?x:Eu(x);return k=k.replace(/ $/,"%20"),Gt(R,`No window.location.(origin|href) available to create URL for href: ${k}`),new URL(k,R)}let S={get action(){return u},get location(){return e(a,s)},listen(x){if(c)throw new Error("A history only accepts one active listener");return a.addEventListener(nC,g),c=x,()=>{a.removeEventListener(nC,g),c=null}},createHref(x){return t(a,x)},createURL:y,encodeLocation(x){let R=y(x);return{pathname:R.pathname,search:R.search,hash:R.hash}},push:m,replace:b,go(x){return s.go(x)}};return S}function zz(e,t,n="/"){return A9(e,t,n,!1)}function A9(e,t,n,r){let a=typeof t=="string"?Ei(t):t,o=Ua(a.pathname||"/",n);if(o==null)return null;let s=Bz(e);R9(s);let u=null;for(let c=0;u==null&&c{let c={relativePath:u===void 0?o.path||"":u,caseSensitive:o.caseSensitive===!0,childrenIndex:s,route:o};c.relativePath.startsWith("/")&&(Gt(c.relativePath.startsWith(r),`Absolute route path "${c.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),c.relativePath=c.relativePath.slice(r.length));let d=za([r,c.relativePath]),p=n.concat(c);o.children&&o.children.length>0&&(Gt(o.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${d}".`),Bz(o.children,t,p,d)),!(o.path==null&&!o.index)&&t.push({path:d,score:L9(d,o.index),routesMeta:p})};return e.forEach((o,s)=>{var u;if(o.path===""||!((u=o.path)!=null&&u.includes("?")))a(o,s);else for(let c of Uz(o.path))a(o,s,c)}),t}function Uz(e){let t=e.split("/");if(t.length===0)return[];let[n,...r]=t,a=n.endsWith("?"),o=n.replace(/\?$/,"");if(r.length===0)return a?[o,""]:[o];let s=Uz(r.join("/")),u=[];return u.push(...s.map(c=>c===""?o:[o,c].join("/"))),a&&u.push(...s),u.map(c=>e.startsWith("/")&&c===""?"/":c)}function R9(e){e.sort((t,n)=>t.score!==n.score?n.score-t.score:M9(t.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}var _9=/^:[\w-]+$/,C9=3,N9=2,O9=1,D9=10,I9=-2,aC=e=>e==="*";function L9(e,t){let n=e.split("/"),r=n.length;return n.some(aC)&&(r+=I9),t&&(r+=N9),n.filter(a=>!aC(a)).reduce((a,o)=>a+(_9.test(o)?C9:o===""?O9:D9),r)}function M9(e,t){return e.length===t.length&&e.slice(0,-1).every((r,a)=>r===t[a])?e[e.length-1]-t[t.length-1]:0}function F9(e,t,n=!1){let{routesMeta:r}=e,a={},o="/",s=[];for(let u=0;u{if(p==="*"){let y=u[m]||"";s=o.slice(0,o.length-y.length).replace(/(.)\/+$/,"$1")}const b=u[m];return g&&!b?d[p]=void 0:d[p]=(b||"").replace(/%2F/g,"/"),d},{}),pathname:o,pathnameBase:s,pattern:e}}function P9(e,t=!1,n=!0){Br(e==="*"||!e.endsWith("*")||e.endsWith("/*"),`Route path "${e}" will be treated as if it were "${e.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${e.replace(/\*$/,"/*")}".`);let r=[],a="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(s,u,c)=>(r.push({paramName:u,isOptional:c!=null}),c?"/?([^\\/]+)?":"/([^\\/]+)"));return e.endsWith("*")?(r.push({paramName:"*"}),a+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?a+="\\/*$":e!==""&&e!=="/"&&(a+="(?:(?=\\/|$))"),[new RegExp(a,t?void 0:"i"),r]}function z9(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return Br(!1,`The URL path "${e}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${t}).`),e}}function Ua(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith("/")?t.length-1:t.length,r=e.charAt(n);return r&&r!=="/"?null:e.slice(n)||"/"}function B9(e,t="/"){let{pathname:n,search:r="",hash:a=""}=typeof e=="string"?Ei(e):e;return{pathname:n?n.startsWith("/")?n:U9(n,t):t,search:H9(r),hash:$9(a)}}function U9(e,t){let n=t.replace(/\/+$/,"").split("/");return e.split("/").forEach(a=>{a===".."?n.length>1&&n.pop():a!=="."&&n.push(a)}),n.length>1?n.join("/"):"/"}function Xh(e,t,n,r){return`Cannot include a '${e}' character in a manually specified \`to.${t}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${n}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function j9(e){return e.filter((t,n)=>n===0||t.route.path&&t.route.path.length>0)}function jz(e){let t=j9(e);return t.map((n,r)=>r===t.length-1?n.pathname:n.pathnameBase)}function Gz(e,t,n,r=!1){let a;typeof e=="string"?a=Ei(e):(a={...e},Gt(!a.pathname||!a.pathname.includes("?"),Xh("?","pathname","search",a)),Gt(!a.pathname||!a.pathname.includes("#"),Xh("#","pathname","hash",a)),Gt(!a.search||!a.search.includes("#"),Xh("#","search","hash",a)));let o=e===""||a.pathname==="",s=o?"/":a.pathname,u;if(s==null)u=n;else{let g=t.length-1;if(!r&&s.startsWith("..")){let m=s.split("/");for(;m[0]==="..";)m.shift(),g-=1;a.pathname=m.join("/")}u=g>=0?t[g]:"/"}let c=B9(a,u),d=s&&s!=="/"&&s.endsWith("/"),p=(o||s===".")&&n.endsWith("/");return!c.pathname.endsWith("/")&&(d||p)&&(c.pathname+="/"),c}var za=e=>e.join("/").replace(/\/\/+/g,"/"),G9=e=>e.replace(/\/+$/,"").replace(/^\/*/,"/"),H9=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,$9=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e;function q9(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}var Hz=["POST","PUT","PATCH","DELETE"];new Set(Hz);var V9=["GET",...Hz];new Set(V9);var Bs=E.createContext(null);Bs.displayName="DataRouter";var qf=E.createContext(null);qf.displayName="DataRouterState";var $z=E.createContext({isTransitioning:!1});$z.displayName="ViewTransition";var W9=E.createContext(new Map);W9.displayName="Fetchers";var Y9=E.createContext(null);Y9.displayName="Await";var ia=E.createContext(null);ia.displayName="Navigation";var Bu=E.createContext(null);Bu.displayName="Location";var qa=E.createContext({outlet:null,matches:[],isDataRoute:!1});qa.displayName="Route";var v0=E.createContext(null);v0.displayName="RouteError";function K9(e,{relative:t}={}){Gt(Uu(),"useHref() may be used only in the context of a component.");let{basename:n,navigator:r}=E.useContext(ia),{hash:a,pathname:o,search:s}=ju(e,{relative:t}),u=o;return n!=="/"&&(u=o==="/"?n:za([n,o])),r.createHref({pathname:u,search:s,hash:a})}function Uu(){return E.useContext(Bu)!=null}function wi(){return Gt(Uu(),"useLocation() may be used only in the context of a component."),E.useContext(Bu).location}var qz="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function Vz(e){E.useContext(ia).static||E.useLayoutEffect(e)}function Vf(){let{isDataRoute:e}=E.useContext(qa);return e?lq():X9()}function X9(){Gt(Uu(),"useNavigate() may be used only in the context of a component.");let e=E.useContext(Bs),{basename:t,navigator:n}=E.useContext(ia),{matches:r}=E.useContext(qa),{pathname:a}=wi(),o=JSON.stringify(jz(r)),s=E.useRef(!1);return Vz(()=>{s.current=!0}),E.useCallback((c,d={})=>{if(Br(s.current,qz),!s.current)return;if(typeof c=="number"){n.go(c);return}let p=Gz(c,JSON.parse(o),a,d.relative==="path");e==null&&t!=="/"&&(p.pathname=p.pathname==="/"?t:za([t,p.pathname])),(d.replace?n.replace:n.push)(p,d.state,d)},[t,n,o,a,e])}E.createContext(null);function ju(e,{relative:t}={}){let{matches:n}=E.useContext(qa),{pathname:r}=wi(),a=JSON.stringify(jz(n));return E.useMemo(()=>Gz(e,JSON.parse(a),r,t==="path"),[e,a,r,t])}function Z9(e,t){return Wz(e,t)}function Wz(e,t,n,r){var k;Gt(Uu(),"useRoutes() may be used only in the context of a component.");let{navigator:a,static:o}=E.useContext(ia),{matches:s}=E.useContext(qa),u=s[s.length-1],c=u?u.params:{},d=u?u.pathname:"/",p=u?u.pathnameBase:"/",g=u&&u.route;{let A=g&&g.path||"";Yz(d,!g||A.endsWith("*")||A.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${d}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. - -Please change the parent to .`)}let m=wi(),b;if(t){let A=typeof t=="string"?Ei(t):t;Gt(p==="/"||((k=A.pathname)==null?void 0:k.startsWith(p)),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${p}" but pathname "${A.pathname}" was given in the \`location\` prop.`),b=A}else b=m;let y=b.pathname||"/",S=y;if(p!=="/"){let A=p.replace(/^\//,"").split("/");S="/"+y.replace(/^\//,"").split("/").slice(A.length).join("/")}let x=!o&&n&&n.matches&&n.matches.length>0?n.matches:zz(e,{pathname:S});Br(g||x!=null,`No routes matched location "${b.pathname}${b.search}${b.hash}" `),Br(x==null||x[x.length-1].route.element!==void 0||x[x.length-1].route.Component!==void 0||x[x.length-1].route.lazy!==void 0,`Matched leaf route at location "${b.pathname}${b.search}${b.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let R=nq(x&&x.map(A=>Object.assign({},A,{params:Object.assign({},c,A.params),pathname:za([p,a.encodeLocation?a.encodeLocation(A.pathname).pathname:A.pathname]),pathnameBase:A.pathnameBase==="/"?p:za([p,a.encodeLocation?a.encodeLocation(A.pathnameBase).pathname:A.pathnameBase])})),s,n,r);return t&&R?E.createElement(Bu.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",...b},navigationType:"POP"}},R):R}function Q9(){let e=sq(),t=q9(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,r="rgba(200,200,200, 0.5)",a={padding:"0.5rem",backgroundColor:r},o={padding:"2px 4px",backgroundColor:r},s=null;return console.error("Error handled by React Router default ErrorBoundary:",e),s=E.createElement(E.Fragment,null,E.createElement("p",null,"💿 Hey developer 👋"),E.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",E.createElement("code",{style:o},"ErrorBoundary")," or"," ",E.createElement("code",{style:o},"errorElement")," prop on your route.")),E.createElement(E.Fragment,null,E.createElement("h2",null,"Unexpected Application Error!"),E.createElement("h3",{style:{fontStyle:"italic"}},t),n?E.createElement("pre",{style:a},n):null,s)}var J9=E.createElement(Q9,null),eq=class extends E.Component{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,t){return t.location!==e.location||t.revalidation!=="idle"&&e.revalidation==="idle"?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:e.error!==void 0?e.error:t.error,location:t.location,revalidation:e.revalidation||t.revalidation}}componentDidCatch(e,t){console.error("React Router caught the following error during render",e,t)}render(){return this.state.error!==void 0?E.createElement(qa.Provider,{value:this.props.routeContext},E.createElement(v0.Provider,{value:this.state.error,children:this.props.component})):this.props.children}};function tq({routeContext:e,match:t,children:n}){let r=E.useContext(Bs);return r&&r.static&&r.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=t.route.id),E.createElement(qa.Provider,{value:e},n)}function nq(e,t=[],n=null,r=null){if(e==null){if(!n)return null;if(n.errors)e=n.matches;else if(t.length===0&&!n.initialized&&n.matches.length>0)e=n.matches;else return null}let a=e,o=n==null?void 0:n.errors;if(o!=null){let c=a.findIndex(d=>d.route.id&&(o==null?void 0:o[d.route.id])!==void 0);Gt(c>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(o).join(",")}`),a=a.slice(0,Math.min(a.length,c+1))}let s=!1,u=-1;if(n)for(let c=0;c=0?a=a.slice(0,u+1):a=[a[0]];break}}}return a.reduceRight((c,d,p)=>{let g,m=!1,b=null,y=null;n&&(g=o&&d.route.id?o[d.route.id]:void 0,b=d.route.errorElement||J9,s&&(u<0&&p===0?(Yz("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),m=!0,y=null):u===p&&(m=!0,y=d.route.hydrateFallbackElement||null)));let S=t.concat(a.slice(0,p+1)),x=()=>{let R;return g?R=b:m?R=y:d.route.Component?R=E.createElement(d.route.Component,null):d.route.element?R=d.route.element:R=c,E.createElement(tq,{match:d,routeContext:{outlet:c,matches:S,isDataRoute:n!=null},children:R})};return n&&(d.route.ErrorBoundary||d.route.errorElement||p===0)?E.createElement(eq,{location:n.location,revalidation:n.revalidation,component:b,error:g,children:x(),routeContext:{outlet:null,matches:S,isDataRoute:!0}}):x()},null)}function S0(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function rq(e){let t=E.useContext(Bs);return Gt(t,S0(e)),t}function aq(e){let t=E.useContext(qf);return Gt(t,S0(e)),t}function oq(e){let t=E.useContext(qa);return Gt(t,S0(e)),t}function E0(e){let t=oq(e),n=t.matches[t.matches.length-1];return Gt(n.route.id,`${e} can only be used on routes that contain a unique "id"`),n.route.id}function iq(){return E0("useRouteId")}function sq(){var r;let e=E.useContext(v0),t=aq("useRouteError"),n=E0("useRouteError");return e!==void 0?e:(r=t.errors)==null?void 0:r[n]}function lq(){let{router:e}=rq("useNavigate"),t=E0("useNavigate"),n=E.useRef(!1);return Vz(()=>{n.current=!0}),E.useCallback(async(a,o={})=>{Br(n.current,qz),n.current&&(typeof a=="number"?e.navigate(a):await e.navigate(a,{fromRouteId:t,...o}))},[e,t])}var oC={};function Yz(e,t,n){!t&&!oC[e]&&(oC[e]=!0,Br(!1,n))}E.memo(uq);function uq({routes:e,future:t,state:n}){return Wz(e,void 0,n,t)}function ak(e){Gt(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function cq({basename:e="/",children:t=null,location:n,navigationType:r="POP",navigator:a,static:o=!1}){Gt(!Uu(),"You cannot render a inside another . You should never have more than one in your app.");let s=e.replace(/^\/*/,"/"),u=E.useMemo(()=>({basename:s,navigator:a,static:o,future:{}}),[s,a,o]);typeof n=="string"&&(n=Ei(n));let{pathname:c="/",search:d="",hash:p="",state:g=null,key:m="default"}=n,b=E.useMemo(()=>{let y=Ua(c,s);return y==null?null:{location:{pathname:y,search:d,hash:p,state:g,key:m},navigationType:r}},[s,c,d,p,g,m,r]);return Br(b!=null,` is not able to match the URL "${c}${d}${p}" because it does not start with the basename, so the won't render anything.`),b==null?null:E.createElement(ia.Provider,{value:u},E.createElement(Bu.Provider,{children:t,value:b}))}function dq({children:e,location:t}){return Z9(ok(e),t)}function ok(e,t=[]){let n=[];return E.Children.forEach(e,(r,a)=>{if(!E.isValidElement(r))return;let o=[...t,a];if(r.type===E.Fragment){n.push.apply(n,ok(r.props.children,o));return}Gt(r.type===ak,`[${typeof r.type=="string"?r.type:r.type.name}] is not a component. All component children of must be a or `),Gt(!r.props.index||!r.props.children,"An index route cannot have child routes.");let s={id:r.props.id||o.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,loader:r.props.loader,action:r.props.action,hydrateFallbackElement:r.props.hydrateFallbackElement,HydrateFallback:r.props.HydrateFallback,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.hasErrorBoundary===!0||r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(s.children=ok(r.props.children,o)),n.push(s)}),n}var qd="get",Vd="application/x-www-form-urlencoded";function Wf(e){return e!=null&&typeof e.tagName=="string"}function fq(e){return Wf(e)&&e.tagName.toLowerCase()==="button"}function pq(e){return Wf(e)&&e.tagName.toLowerCase()==="form"}function gq(e){return Wf(e)&&e.tagName.toLowerCase()==="input"}function hq(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function mq(e,t){return e.button===0&&(!t||t==="_self")&&!hq(e)}var gd=null;function bq(){if(gd===null)try{new FormData(document.createElement("form"),0),gd=!1}catch{gd=!0}return gd}var yq=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function Zh(e){return e!=null&&!yq.has(e)?(Br(!1,`"${e}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${Vd}"`),null):e}function vq(e,t){let n,r,a,o,s;if(pq(e)){let u=e.getAttribute("action");r=u?Ua(u,t):null,n=e.getAttribute("method")||qd,a=Zh(e.getAttribute("enctype"))||Vd,o=new FormData(e)}else if(fq(e)||gq(e)&&(e.type==="submit"||e.type==="image")){let u=e.form;if(u==null)throw new Error('Cannot submit a - )} + {/* Always show refresh button */} + className="ml-2" triggerClassName="max-h-8" @@ -141,20 +105,23 @@ const GraphLabels = () => { placeholder={t('graphPanel.graphLabels.placeholder')} value={label !== null ? label : '*'} onChange={(newLabel) => { - const currentLabel = useSettingsStore.getState().queryLabel + const currentLabel = useSettingsStore.getState().queryLabel; // select the last item means query all if (newLabel === '...') { - newLabel = '*' + newLabel = '*'; } // Handle reselecting the same label if (newLabel === currentLabel && newLabel !== '*') { - newLabel = '*' + newLabel = '*'; } - // Update the label, which will trigger the useEffect to handle data loading - useSettingsStore.getState().setQueryLabel(newLabel) + // Reset graphDataFetchAttempted flag to ensure data fetch is triggered + useGraphStore.getState().setGraphDataFetchAttempted(false); + + // Update the label to trigger data loading + useSettingsStore.getState().setQueryLabel(newLabel); }} clearable={false} // Prevent clearing value on reselect /> diff --git a/lightrag_webui/src/components/graph/LayoutsControl.tsx b/lightrag_webui/src/components/graph/LayoutsControl.tsx index 2f0cc50a..1933ce19 100644 --- a/lightrag_webui/src/components/graph/LayoutsControl.tsx +++ b/lightrag_webui/src/components/graph/LayoutsControl.tsx @@ -218,8 +218,8 @@ const LayoutsControl = () => { maxIterations: maxIterations, settings: { attraction: 0.0003, // Lower attraction force to reduce oscillation - repulsion: 0.05, // Lower repulsion force to reduce oscillation - gravity: 0.01, // Increase gravity to make nodes converge to center faster + repulsion: 0.02, // Lower repulsion force to reduce oscillation + gravity: 0.02, // Increase gravity to make nodes converge to center faster inertia: 0.4, // Lower inertia to add damping effect maxMove: 100 // Limit maximum movement per step to prevent large jumps } diff --git a/lightrag_webui/src/features/LoginPage.tsx b/lightrag_webui/src/features/LoginPage.tsx index c5cccf5f..847a4c9e 100644 --- a/lightrag_webui/src/features/LoginPage.tsx +++ b/lightrag_webui/src/features/LoginPage.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react' +import { useState, useEffect, useRef } from 'react' import { useNavigate } from 'react-router-dom' import { useAuthStore } from '@/stores/state' import { loginToServer, getAuthStatus } from '@/api/lightrag' @@ -18,6 +18,7 @@ const LoginPage = () => { const [username, setUsername] = useState('') const [password, setPassword] = useState('') const [checkingAuth, setCheckingAuth] = useState(true) + const authCheckRef = useRef(false); // Prevent duplicate calls in Vite dev mode useEffect(() => { console.log('LoginPage mounted') @@ -25,9 +26,14 @@ const LoginPage = () => { // Check if authentication is configured, skip login if not useEffect(() => { - let isMounted = true; // Flag to prevent state updates after unmount const checkAuthConfig = async () => { + // Prevent duplicate calls in Vite dev mode + if (authCheckRef.current) { + return; + } + authCheckRef.current = true; + try { // If already authenticated, redirect to home if (isAuthenticated) { @@ -38,26 +44,30 @@ const LoginPage = () => { // Check auth status const status = await getAuthStatus() - // Only proceed if component is still mounted - if (!isMounted) return; + // Set session flag for version check to avoid duplicate checks in App component + if (status.core_version || status.api_version) { + sessionStorage.setItem('VERSION_CHECKED_FROM_LOGIN', 'true'); + } if (!status.auth_configured && status.access_token) { // If auth is not configured, use the guest token and redirect - login(status.access_token, true) + login(status.access_token, true, status.core_version, status.api_version) if (status.message) { toast.info(status.message) } navigate('/') - return // Exit early, no need to set checkingAuth to false + return } + + // Only set checkingAuth to false if we need to show the login page + setCheckingAuth(false); + } catch (error) { console.error('Failed to check auth configuration:', error) - } finally { - // Only update state if component is still mounted - if (isMounted) { - setCheckingAuth(false) - } + // Also set checkingAuth to false in case of error + setCheckingAuth(false); } + // Removed finally block as we're setting checkingAuth earlier } // Execute immediately @@ -65,7 +75,6 @@ const LoginPage = () => { // Cleanup function to prevent state updates after unmount return () => { - isMounted = false; } }, [isAuthenticated, login, navigate]) @@ -87,7 +96,12 @@ const LoginPage = () => { // Check authentication mode const isGuestMode = response.auth_mode === 'disabled' - login(response.access_token, isGuestMode) + login(response.access_token, isGuestMode, response.core_version, response.api_version) + + // Set session flag for version check + if (response.core_version || response.api_version) { + sessionStorage.setItem('VERSION_CHECKED_FROM_LOGIN', 'true'); + } if (isGuestMode) { // Show authentication disabled notification diff --git a/lightrag_webui/src/features/SiteHeader.tsx b/lightrag_webui/src/features/SiteHeader.tsx index c0b130fe..fb21df40 100644 --- a/lightrag_webui/src/features/SiteHeader.tsx +++ b/lightrag_webui/src/features/SiteHeader.tsx @@ -55,7 +55,11 @@ function TabsNavigation() { export default function SiteHeader() { const { t } = useTranslation() - const { isGuestMode } = useAuthStore() + const { isGuestMode, coreVersion, apiVersion } = useAuthStore() + + const versionDisplay = (coreVersion && apiVersion) + ? `${coreVersion}/${apiVersion}` + : null; const handleLogout = () => { navigationService.navigateToLogin(); @@ -67,6 +71,11 @@ export default function SiteHeader() {